diff --git a/HypothesisB/Macrophage_simple.mexw64 b/HypothesisB/Macrophage_simple.mexw64
new file mode 100644
index 0000000000000000000000000000000000000000..557769e64adefaf3a05c608db7257b118dce643c
Binary files /dev/null and b/HypothesisB/Macrophage_simple.mexw64 differ
diff --git a/HypothesisB/allGoodValues.dat b/HypothesisB/allGoodValues.dat
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/IQMtools V1.2.2.2/IQMlite/Contents.m b/IQMtools V1.2.2.2/IQMlite/Contents.m
new file mode 100644
index 0000000000000000000000000000000000000000..ef8c5395750ba5d1519ae71d1dfe96de488bb59f
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/Contents.m	
@@ -0,0 +1,336 @@
+% IQM Tools Lite
+% Version 1.2.2 (R2015B) 02.01.2017
+% 
+% IQMlite
+% =======
+% 	Contents                                - This help text
+% 	SETUP_PATHS_TOOLS_IQMLITE               - Setup script for IQMlite - please customize according to your needs
+% 	installIQMlite                          - This script installs the IQMlite package of the IQM Suite of modeling tools
+% 
+% 	IQMnewscript                            - Creates a new script with a short guide on how to  initialize IQM Tools.
+%     
+% 	IQMinitializeCompliance                 - Initializes the compliance check when compliance mode is activated in SETUP_PATHS_TOOLS_IQMLITE
+%                       
+% Model definition and handling
+% =============================
+% 	IQMmodel                                - Creates a model object 
+% 
+%   IQMeditBC                               - GUI for editing IQMmodels in a more biochemically oriented format
+% 	IQMedit                                 - GUI for editing IQMmodels
+%         
+% 	IQMalgebraic                            - Returns information about the algebraic equations in a model.
+% 	IQMcalcICvector                         - Determines an IC vector for models with  non-numeric initial conditions. 
+% 	IQMconvert2MA                           - Takes an IQMmodel and if possible returns the stoichiometric matrix, etc.
+% 	IQMconvertNonNum2NumIC                  - Converts non-numeric iniital conditions to numeric initial conditions in the model.
+% 	IQMcreateODEfile                        - Creates an m-file that can be simulated by using standard MATLAB integrators (ODE45, ODE23s, etc.)
+% 	IQMcreateTEXTBCfile                     - Creates a *.txtbc file with the models text  description in a biochemically oriented format
+% 	IQMcreateTEXTBCmodel                    - Creates a new TEXTBC model, saves the corresponding file in the current directory and opens it in the editor, if opening is  desired.
+% 	IQMcreateTEXTfile                       - creates a *.txt file with the models text description based on ordinary differential equations
+% 	IQMcreateTEXTmodel                      - Creates a new TEXT model, saves the corresponding file in the current directory and opens it in the editor, if opening is  desired.
+% 	IQMcreateTempODEfile                    - Creates a temporary ODE file, same as IQMcreateODEfile, but the file is written in the systems temporary  directory
+% 	
+%   IQMevents                               - Returns information about the events in an IQMmodel.
+% 	IQMexportSBML                           - Exports an IQMmodel to an SBML Level 2 Version 1 model using the OutputSBML function 
+% 	IQMfunctions                            - Returns information about the functions in an IQMmodel.
+% 	IQMfunctionsMATLAB                      - Returns information about the MATLAB functions in an IQMmodel.
+% 	IQMinitialconditions                    - Returns or sets  initial conditions in a model
+% 	IQMmodelnotes                           - Displays the notes of the model.
+% 	IQMoverwriteICs                         - Sets new initial conditions - overwrites non-numerical ones
+% 	IQMparameters                           - Returns information about the parameters in a model, can  also be used to set a parameter value.
+% 	IQMreactions                            - Returns information about the reactions in an IQMmodel. 
+% 	IQMstates                               - Returns information about the states in a model.
+% 	IQMvariables                            - Returns information about the variables in an IQMmodel.  
+% 	
+%   isIQMmodel                              - Checks if provided input argument is an IQMmodel.
+% 	
+% 	cleanmodelIQM                           - Remove unused reactions, variables and parameters from a model
+% 	reactionindexIQM                        - Returns the number of the reaction 'reactionname' in model  'model'. If the reaction does not exist then [] is returned.
+% 	stateindexIQM                           - Returns the number of the state 'statename' in model  'model'. If the state does not exist then [] is returned.
+% 	variableindexIQM                        - Returns the number of the variable 'variablename' in model  'model'. If the variable does not exist then [] is returned.
+% 	hasmoietyconservationsIQM               - Checks if the model contains moiety  conservations.
+% 	hasonlynumericICsIQM                    - Checks if the model contains only numeric initial  conditions. The model can be an IQMmodel or an ODE or MEX file model.
+% 	isparameterIQM                          - Checks if "name" is a parameter in the provided model. 
+% 	isreactionIQM                           - Checks if "name" is a reaction in the provided model. 
+% 	isstateIQM                              - Checks if "name" is a state in the provided model.  
+% 	isvariableIQM                           - Checks if "name" is a variable in the provided model.  
+% 	usealgebraicIQM                         - Checks if an IQMmodel contains algebraic rules.
+% 	usedelayIQM                             - Checks if an IQMmodel contains the delayIQM function.
+% 	useeventIQM                             - Checks if an IQMmodel contains events.
+% 	usefastIQM                              - Checks if an IQMmodel contains "fast" reactions.
+% 
+% Experiment creation and handling
+% ================================
+% 	IQMexperiment                           - Creates an experiment object defining experiment settings
+% 	
+%   IQMcreateEXPfile                        - Creates a *.exp file with the experiments text description
+% 	IQMmergemodexp                          - Combines an experiment with a model, and produces a "merged model", as output
+% 	
+%   isIQMexperiment                         - Checks if provided input argument is an IQMexperiment
+% 
+% Measurement creation and handling
+% =================================
+%   IQMmeasurement                          - Creates an object that is intended to contain measurement data - from real experiments or insilico computations
+% 	
+%   IQMexportCSVmeasurement                 - Exports an IQMmeasurement object to a CSV (comma separated value) file. 
+% 	IQMexportXLSmeasurement                 - Exports an IQMmeasurement object to an XLS (excel) file.  
+% 	IQMexportXLSmeasurements                - Exports several IQMmeasurement objects to the same XLS (excel) file. 
+% 	IQMimportCSVmeasurement                 - Imports experimental measurement data stored in an CSV (comma separated value) file
+% 	IQMimportXLSmeasurement                 - Imports experimental measurement data stored in an XLS Excel file 
+% 	IQMmeasurementdata                      - This functions allows to extract information from an IQMmeasurement structure
+% 	IQMvisualizemeasurement                 - Function allowing to visualize the content of an IQMmeasurement object.  
+% 	
+%   isIQMmeasurement                        - Checks if provided input argument is an IQMmeasurement
+% 
+% Dosing creation and handling    
+% ============================
+% 	IQMdosing                               - Creates an IQMdosing object defining a dosing schedule
+% 
+%   IQMcreateDOSING                         - Creates a dosing scheme as desired based on inputs
+% 	IQMcreateDOSfile                        - Creates a *.dos file with the dosing text description
+% 	IQMdoseupdatevalue                      - Allows to update the dosing amount for a given input, defined in an IQMdosing object.
+% 
+%   isIQMdosing                             - Checks if provided input argument is an IQMdosing
+% 
+% 	IQMmergemoddos                          - Based on a model and dosing object, a new IQMmodel is generated, that implements the defined dosings. 
+%   mergemoddosIQM                          - Similar to IQMmergemoddos but only preparing the model for taking dosings of this type, not implementing them in the model.
+% 
+% Analysis and simulation
+% =======================
+% simulation
+% 	IQMinsilicoexp                          - IQMinsilicoexp runs an in-silico experiment.
+% 	IQMsimdosing                            - Simulates the application of a dosing schedule to a model that has been prepared for it by mergemoddosIQM
+% 	IQMsimulate                             - Simulation of models and simulation of models and dosing schemes.
+% 	IQMstochsim                             - Stochastic simulation of IQMmodels that only contain mass action kinetics. 
+% 
+%   IQMjacobian                             - Determines the Jacobian of a given IQMmodel
+% 	IQMmakeirreversible                     - Makes reactions irreversible
+% 	IQMmoietyconservations                  - Determines the moitey conservations
+% 	IQMreactantstoichiometry                - Determines the stoichiometric coefficients of only the reactants
+% 	IQMreducemodel                          - Reduces an IQMmodel by identifying algebraic relations between time dependent variable
+% 	IQMsteadystate                          - Determines a steady-state of an IQMmodel 
+% 	IQMstoichiometry                        - Determines the stoichiometric matrix for the given model
+% 
+% behaviorlocalization
+% 	IQMlocbehavcomp                         - Determines the importance of components in the given biochemical system in the creation of an observed complex behavior
+% 	IQMlocbehavinteract                     - Determines the importance of direct interactions between components (states) in the given biochemical system in the creation of complex behavior
+% 	IQMlocbehavinteract2                    - Similar to IQMlocbehavinteract (see help text)
+% 
+% globalparametersensitivity
+% 	IQMsensglobalfast                       - Global sensitivity analysis method: Extended FAST method
+% 	IQMsensglobalprcc                       - Global sensitivity analysis method: PRCC method
+% 	IQMsensglobalsobol                      - Global sensitivity analysis method: SOBOL's method
+% 	IQMsensglobalwals                       - Global sensitivity analysis method: WALS (weighted average of local  sensitivities)
+% 
+% localparametersensitivity
+% 	IQMmca                                  - Metabolic control analysis  
+% 	IQMsensamplitude                        - Function evaluating local first order amplitude sensitivities.
+% 	IQMsensdataosc                          - Function allowing to generate data that subsequently can be used for different kinds of parametric sensitivity analyses. 
+% 	IQMsensdataoscevents                    - Function allowing to generate data that subsequently can be used for different kinds of parametric sensitivity analyses. 
+% 	IQMsensdatastat                         - Function allowing to generate steady-state data that subsequently can be used for different kinds of parametric sensitivity analyses.
+% 	IQMsensperiod                           - Function evaluating local first order period sensitivities.
+% 	IQMsensstat                             - Function evaluating local first order parameter sensitivities of the steady-state values of states and reaction rates.
+% 
+% modelreduction
+% 	IQMprepredreac                          - Prepares a model for subsequent reduction of reaction rate expressions. 
+% 	IQMredallreac                           - Wrapper for the IQMredreac function allowing to easily go through a whole model and reduce all reactions that are possible to reduce.
+% 	IQMredreac                              - Reduction of single reaction expressions with the goal of reducing complexity and number of parameters. 
+% 
+% Tools
+% =====
+% dataset
+%   Datasets used in IQM Tools use the MATLAB "table" type.
+%     
+% 	IQMdataset2wide                         - Expands a dataset from a row based format to a column based format. 
+% 	IQMexportCSVdataset                     - Exports a MATLAB table as standard comma separated (CSV) datafile. 
+% 	IQMgetdatasetHeader                     - Returns the column names of the dataset in a cell-array.  
+% 	IQMloadCSVdataset                       - Loads a standard CSV datafile with header as a TABLE object into MATLAB. 
+% 	IQMloadNONCSVdataset                    - Loads a NON CSV datafile with header as a dataset into MATLAB. 
+% 	IQMresampleDataset                      - Resamples a dataset. The structure and the number of subjects is preserved. Useful for bootstrapping. 
+% 	IQMsas7bdat2csv                         - Converts a sas7bdat file into a CSV file (requires SAS installation)
+% 	ixdataIQM                               - Is a wrapper that supports easier subsetting of data.  
+% 	subsetIQM                               - Allows to subset a dataset or table. Both numeric and cell-array with string columns are handled.
+% 
+% optimization
+% 	SSmIQM                                  - Global optimization algorithm for MINLP's based on Scatter Search.
+% 	fSSmIQM                                 - Global optimization algorithm for MINLP's based on Scatter Search ("fast" version).
+% 	isresIQM                                - Stochastic Ranking for Constrained Evolutionary Minimization.
+% 	pswarmIQM                               - Particle swarm pattern search algorithm for global optimization.
+% 	simannealingIQM                         - Minimization by simulated annealing
+% 	simplexIQM                              - Downhill Simplex Method in Multidimensions
+% 
+% plots
+% 	IQMbarplotErrors                        - Grouped bar plot with error bars, customizable.
+% 	IQMplotCovarianceCat                    - Plots the covariance relationship between a list of continuous variables and a list of categorical variables 
+% 	IQMplotHistogram                        - Plots histograms 
+% 	IQMplotQQ                               - QQ plot for provided input data.
+% 	IQMplotXY                               - Plots pairwise Ydata vs. Xdata. 
+% 	IQMplotfacetgrid                        - Plots a matrix version of a trellis plot.
+% 	IQMplotfill                             - Will fill a region with a color between upper and lower bounds provided 
+% 	IQMplotpairwiseCorr                     - Plots the pairwise correlation between variables passed in columns of a matrix or passed as a dataset.
+% 	IQMplottrellis                          - Plots a Trellis plot. Plenty of options available.
+% 	IQMplot                                 - IQMplot - plots given data.
+%   IQMplot2                                - IQMplot2 - plots bar diagrams for given data.
+%   IQMplotCatCat                           - This function plots a "bubble" plot for categorical data to assess correlations
+%   IQMplotKM                               - Kaplan-Meier plot
+% 
+% functions
+%   These functions can be used on IQMmodels but on command line as well. When used in models then these are also working when converting the IQMmodel to C-code
+%     
+% 	andIQM                                  - Is used instead of the MATLAB "and" function, allowing more than two input arguments
+% 	delayIQM                                - Realizes a time delay of "tau" time units (hande with care)
+% 	indexmaxIQM                             - Searches for the maximum input argument and returns the index of the max.
+% 	maxIQM                                  - Is used instead of the MATLAB "max" function, allowing more than two scalar input arguments
+% 	minIQM                                  - Is used instead of the MATLAB "min" function, allowing more than two scalar input arguments
+% 	multiplyIQM                             - Implementing the multiply MathML function
+% 	orIQM                                   - Is used instead of the MATLAB "or" function, allowing more than two input arguments
+% 	piecewiseIQM                            - Implements support for the SBML / MATHML piecewise operator.
+% 	piecewiseSmoothIQM                      - Implements a smoothing function between two values y0 and y1
+% 	piecewiseT0IQM                          - Is similar to the piecewiseIQM function (see help text)
+% 	xorIQM                                  - Is used instead of the MATLAB "or" function, allowing more than two input arguments
+% 
+% interpolation
+% 	interp0IQM                              - Zero order interpolation function (lookup table)
+% 	interp1IQM                              - Linear interpolation function (lookup table)  
+% 	interpcsIQM                             - Cubic spline interpolation function (lookup table)  
+% 	interpcseIQM                            - Cubic spline interpolation with endpoints
+% 	interpcseSlopeIQM                       - Cubic spline interpolation with endpoints, returning the derivative at the considered point.
+% 	interpcsexIQM                           - Cubic spline interpolation with endpoints 
+% 	interpcsexSlopeIQM                      - Cubic spline interpolation with endpoints 
+% 
+% signal
+% 	centeredfftIQM                          - Uses the fft function of MATLAB to determine a two sided spectrum 
+% 	positivefftIQM                          - Uses the fft function of MATLAB to determine a one sided spectrum 
+% 	resampleIQM                             - Resamples time series x1, which is sampled at the time instances t1 to time series x2 using a sampling defined by t2.
+% 	xcorrIQM                                - Compute correlation R_xy of X and Y for various lags k:
+% 
+% smoothing
+% 	binnedmeanIQM                           - Calcuate binned means
+% 	binnedmedianIQM                         - Calcuate binned medians
+% 	binnedquantilesIQM                      - Calcuate binned quantiles
+% 	movingAverageIQM                        - Compute moving averages over a range
+% 	movingMedianIQM                         - Compute moving medians over a range
+% 	movingQuantileIQM                       - Compute moving quantiles over a range
+%   smoothIQM                               - loess, lowess smoother
+%
+% solvers
+% 	fsolveIQM                               - Attempts to solve equations of the form FUN(X)=0 with Newton iteration
+% 
+% statistic
+% 	boxplotIQM                              - Plot a boxplot for given data
+% 	centerIQM                               - Center by subtracting means
+% 	clusteringIQM                           - Performs UPGMA on distance matrix and produces a denddrogram plot.
+% 	kurtosisIQM                             - Returns the kurtosis over the first non-singleton dimension. 
+% 	mvnrndIQM                               - Draw n random d-dimensional vectors from a multivariate Gaussian distribution with mean mu and covariance matrix Sigma.
+% 	nanmeanIQM                              - Determines the mean of x along the dimension dim by treating NaNs as missing values.
+% 	nanmedianIQM                            - Determines the median of x along the dimension dim by treating NaNs as  missing values.
+% 	nanstdIQM                               - Determines the std of x along the dimension dim by treating NaNs as missing values.
+% 	pdistIQM                                - Determines the distance matrix for a set of points whose coordinates are given as row-vectors in the data matrix.
+% 	prctileIQM                              - prctileIQM calculates the percentiles of histograms and sample arrays.
+% 	princompIQM                             - Compute principal components of X
+% 	qqplotIQM                               - Perform a QQ-plot (quantile plot). Only for comparison to standard normal  distribution.
+% 	quantileIQM                             - quantileIQM calculates the quantiles of histograms and sample arrays.
+% 	regressIQM                              - Multiple Linear Regression using Least Squares Fit of y on X  with the model y = X * beta + e.
+% 	sumsqIQM                                - Sum of squares of elements along dimension dim.
+% 	swtestIQM                               - Shapiro-Wilk parametric hypothesis test of composite normality.
+% 	zscoreIQM                               - Compute the z-score of each element of X relative to the data  in the columns of X.
+% 
+% distributions
+% 	betacdfIQM                              - Cumulative density function of the Beta distribution
+% 	betainvIQM                              - Quantile function of the Beta distribution
+% 	betapdfIQM                              - Probability density function of the Beta distribution
+% 	chi2cdfIQM                              - Cumulative density function of the chi-square distribution
+% 	chi2invIQM                              - Quantile function of the chi-square distribution
+% 	chi2pdfIQM                              - Probability density function of the chi-square distribution
+% 	fcdfIQM                                 - Cumulative density function of the f distribution.
+% 	finvIQM                                 - Quantile function of the f distribution
+% 	fpdfIQM                                 - Probability density function of the f distribution
+% 	gamcdfIQM                               - Cumulative density function of the Gamma distribution
+% 	gaminvIQM                               - Quantile function of the Gamma distribution
+% 	gampdfIQM                               - Probability density function of the Gamma distribution
+% 	normcdfIQM                              - Cumulative densitiy function of the normal distribution
+% 	norminvIQM                              - Quantile function of the normal distribution
+% 	normpdfIQM                              - Probability density function of the normal distribution
+% 	stdnormalcdfIQM                         - Cumulative density function of the standard normal distribution
+% 	stdnormalinvIQM                         - Quantile function of the standard normal distribution
+% 	stdnormalpdfIQM                         - Probability density function of the standard normal distribution
+% 	tcdfIQM                                 - Cumulative density function of the t distribution
+% 	tinvIQM                                 - Quantile function of the t distribution
+% 	tpdfIQM                                 - Probability density function of the t distribution
+% 
+% symbolic
+%   Function that do symbolic computations require the symbolic toolbox to be present
+%     
+% 	IQMsymjacobian                          - Determines a symbolic Jacobian and the derivative of the ODE right hand side with respect to given parameters. 
+%     
+% kineticlaws
+%   These kinetic laws can be used in IQMmodels, allowing for more informative coding and less complex formulas.
+%     
+% 	kin_allosteric_inihib_empirical_rev     - Allosteric inhibition (reversible) kinetics
+% 	kin_allosteric_inihib_mwc_irr           - Allosteric inhibition (irreversible) kinetics
+% 	kin_catalytic_activation_irr            - Catalytic activation (irreversible) kinetics
+% 	kin_catalytic_activation_rev            - Catalytic activation (reversible) kinetics
+% 	kin_comp_inihib_irr                     - Competitive inhibition (irreversible) kinetics
+% 	kin_comp_inihib_rev                     - Competitive inhibition (reversible) kinetics
+% 	kin_constantflux                        - Competitive inhibition (reversible) kinetics
+% 	kin_degradation                         - Linear degradation kinetics
+% 	kin_hill_1_modifier_rev                 - Reversible Hill type kinetics with one modifier
+% 	kin_hill_2_modifiers_rev                - Reversible Hill type kinetics with one modifier
+% 	kin_hill_cooperativity_irr              - Hill type (irreversible) kinetics
+% 	kin_hill_rev                            - Hill type (reversible) kinetics
+% 	kin_hyperbolic_modifier_irr             - Hyperbolic modifier (irreversible) kinetics
+% 	kin_hyperbolic_modifier_rev             - Hyperbolic modifier (reversible) kinetics
+% 	kin_iso_uni_uni_rev                     - enzyme isomerization product inhibition
+% 	kin_mass_action_irr                     - Mass action (irreversible) kinetics
+% 	kin_mass_action_rev                     - Mass action (reversible) kinetics
+% 	kin_michaelis_menten_irr                - Michaelis Menten (irreversible) kinetics
+% 	kin_michaelis_menten_rev                - Michaelis Menten (reversible) kinetics
+% 	kin_mixed_activation_irr                - Mixed activation irreversible
+% 	kin_mixed_activation_rev                - Mixed activation reversible
+% 	kin_mixed_inihib_irr                    - Mixed inhibition (irreversible) kinetics
+% 	kin_mixed_inihib_rev                    - Mixed inhibition (reversible) kinetics
+% 	kin_noncomp_inihib_irr                  - Noncompetitive inhibition (irreversible) kinetics
+% 	kin_noncomp_inihib_rev                  - Noncompetitive inhibition (reversible) kinetics
+% 	kin_ordered_bi_bi_rev                   - Ordered bi-bi reversible
+% 	kin_ordered_bi_uni_rev                  - Ordered bi-uni reversible
+% 	kin_ordered_uni_bi_rev                  - Ordered uni-bi reversible
+% 	kin_ping_pong_bi_bi_rev                 - Ping pong bi bi kinetics (reversible)
+% 	kin_specific_activation_irr             - Specific activation (irreversible) kinetics
+% 	kin_specific_activation_rev             - Specific activation (reversible) kinetics
+% 	kin_substrate_activation_irr            - Substrate activation (irreversible) kinetics
+% 	kin_substrate_inihib_irr                - Substrate inhibition (irreversible) kinetics
+% 	kin_substrate_inihib_rev                - Substrate inhibition (reversible) kinetics
+% 	kin_uncomp_inihib_irr                   - Uncompetitive inhibition (irreversible) kinetics
+% 	kin_uncomp_inihib_rev                   - Uncompetitive inhibition (reversible) kinetics
+% 	kin_uni_uni_rev                         - Uni uni reversible kinetics
+% 
+% survival
+%   IQMcoxExt 								- Parameter estimation for the extended Cox model
+%   IQMcoxPH								- Parameter estimation for the Cox proportional hazards model
+%   IQMcoxStratPH 							- Parameter estimation for the Stratified Cox proportional hazards model
+%   IQMhr 									- Hazard ratio estimate for Cox models
+%   IQMkm 									- Kaplan-Meier curves estimation and plot (see also IQMplotKM)
+%   IQMphTest 								- Schoenfeld residuals test for the proportional hazards assumption
+%   IQMxext 								- Extension to time varying covariates (input to IQMcoxExt)
+%    
+% Auxiliary
+% =========
+% 	getDefaultIntegratorOptionsIQM          - Inside this function/file default values for integrator options are set. This function also retrieves them
+% 	lookforIQML                             - Allows to search IQM Lite folders recursively for a given text
+% 	setseedIQM                              - Set the default stream to defaultSeed
+% 	usernameIQM                             - Returns the username of the current user
+%   compareFilesEqualIQM 					- Compare two text files for equality
+%
+% output
+% 	IQMconvert2pdf                          - Converts a PS file to a PDF file.  
+% 	IQMgetcolors                            - Generate colors for plotting and for black and white plotting also line types.
+% 	IQMprintFigure                          - Print a MATLAB figure to png, ps, jpg, or pdf.
+% 	IQMstartNewPrintFigure                  - Function starts a new file in which figures are to be printed.  
+% 	IQMwriteText2File                       - Allows to write a given string (text) to a file (filename) 
+% 
+% parallel
+%   These functions require the presence of the parallel toolbox in MATLAB
+%     
+% 	startParallelIQM                        - Requests parallel nodes from the MATLAB parallel toolbox.
+% 	stopParallelIQM                         - Closes the connection to parallel nodes via the parallel    toolbox in MATLAB
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
diff --git a/IQMtools V1.2.2.2/IQMlite/SETUP_PATHS_TOOLS_IQMLITE.m b/IQMtools V1.2.2.2/IQMlite/SETUP_PATHS_TOOLS_IQMLITE.m
new file mode 100644
index 0000000000000000000000000000000000000000..ed553faed0cf85feaec156e46f4922464864efc4
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/SETUP_PATHS_TOOLS_IQMLITE.m	
@@ -0,0 +1,35 @@
+% In this file you need to provide the names and potentially the paths to
+% the executables for tools, such as SAS, libSBML, etc.
+% If executables in the system path, then only the names of the executables 
+% are needed.
+%
+% It is possible to define paths for Windows and Unix independently,
+% allowing to use the package on different systems without the need to
+% re-edit the paths. If a tool is not available on a system, then just
+% leave the path empty.
+
+% SAS
+PATH_SYSTEM_SAS_WINDOWS             = '';
+PATH_SYSTEM_SAS_UNIX                = '';
+
+% SBML import and export
+% In this path the functions TranslateSBML and OutputSBML need to be located.
+% On windows you do not need to define anything, since it is part of IQM Tools Lite.
+% On other operating systems you need to install it yourself and then provide here the path.
+PATH_SYSTEM_SBML_WINDOWS             = ''; % Leave empty
+PATH_SYSTEM_SBML_UNIX                = ''; % Need to define
+
+% Set compliance mode
+% In the "compliance mode" each figure and text that is exported using the
+% functions "IQMprintFigure" and "IQMwriteText2File" will be annotated with
+% a log file that specifies the username, the location of the created file,
+% the scripts and functions used to generate this file, its size and the
+% date of creation.
+% If this mode is enabled, then a global variable
+% "Current_ROOT_file_IQMtools_compliance" has to be set in each root script for
+% the analysis - this is needed since when working interactively, the root
+% script name is unknown. The information gathering function will check
+% that this name is defined and if not in the list of functions that will
+% lead to the output generation it will add it. If undefined, there will be
+% an error, explaining that this variable needs to be set.
+COMPLIANCE_OUTPUT_MODE               = 0;  % 1=enabled, 0=off
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/THIRD_PARTY_SOFTWARE/SBMLimportExport/OutputSBML.m b/IQMtools V1.2.2.2/IQMlite/auxiliary/THIRD_PARTY_SOFTWARE/SBMLimportExport/OutputSBML.m
new file mode 100644
index 0000000000000000000000000000000000000000..08bc9cce2a970a63b89fd023a52922b28ed44752
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/THIRD_PARTY_SOFTWARE/SBMLimportExport/OutputSBML.m	
@@ -0,0 +1,55 @@
+% OutputSBML(model, filename(optional)) outputs an xml file
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% NOTE: This version enables support for SBML L3 FBC package.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% The function OutputSBML is the converse of TranslateSBML: 
+% it writes an MATLAB_SBML structure to an XML file. It accepts two arguments:
+%
+%   * model: This argument must be a MATLAB_SBML structure representing the 
+%            model to be written out to a file. Note that the structure will 
+%            not be validated to check if it is fully correct SBML; OutputSBML 
+%            will only verify the basic integrity of the structure (i.e., to 
+%            make sure it has the form expected of a MATLAB_SBML structure), 
+%            but nothing more.
+%
+%   * filename: The name of the file where the SBML content should be written.
+%
+%      NOTE: This argument is optional where a graphical user interface is
+%            available, in which case a missing argument will open a browse window.
+%
+
+%  Filename    : OutputSBML.m
+%  Description : MATLAB help file for OutputSBML
+%  Author(s)   : SBML Development Group <sbml-team@caltech.edu>
+%
+%
+%<!---------------------------------------------------------------------------
+% This file is part of SBMLToolbox.  Please visit http://sbml.org for more
+% information about SBML, and the latest version of SBMLToolbox.
+%
+% Copyright (C) 2013-2014 jointly by the following organizations:
+%     1. California Institute of Technology, Pasadena, CA, USA
+%     2. EMBL European Bioinformatics Institute (EMBL-EBI), Hinxton, UK
+%     3. University of Heidelberg, Heidelberg, Germany
+%
+% Copyright (C) 2009-2013 jointly by the following organizations: 
+%     1. California Institute of Technology, Pasadena, CA, USA
+%     2. EMBL European Bioinformatics Institute (EMBL-EBI), Hinxton, UK
+%  
+% Copyright (C) 2006-2008 by the California Institute of Technology,
+%     Pasadena, CA, USA 
+%  
+% Copyright (C) 2002-2005 jointly by the following organizations: 
+%     1. California Institute of Technology, Pasadena, CA, USA
+%     2. Japan Science and Technology Agency, Japan
+% 
+% This library is free software; you can redistribute it and/or modify it
+% under the terms of the GNU Lesser General Public License as published by
+% the Free Software Foundation.  A copy of the license agreement is provided
+% in the file named "LICENSE.txt" included with this software distribution.
+% and also available online as http://sbml.org/software/sbmltoolbox/license.html
+%----------------------------------------------------------------------- -->
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/THIRD_PARTY_SOFTWARE/SBMLimportExport/OutputSBML.mexw32 b/IQMtools V1.2.2.2/IQMlite/auxiliary/THIRD_PARTY_SOFTWARE/SBMLimportExport/OutputSBML.mexw32
new file mode 100644
index 0000000000000000000000000000000000000000..e26570d9d62183dd5575ebd757c19e656ef30f6a
Binary files /dev/null and b/IQMtools V1.2.2.2/IQMlite/auxiliary/THIRD_PARTY_SOFTWARE/SBMLimportExport/OutputSBML.mexw32 differ
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/THIRD_PARTY_SOFTWARE/SBMLimportExport/OutputSBML.mexw64 b/IQMtools V1.2.2.2/IQMlite/auxiliary/THIRD_PARTY_SOFTWARE/SBMLimportExport/OutputSBML.mexw64
new file mode 100644
index 0000000000000000000000000000000000000000..2454b144de5011da056e7579e6f5817dbcd4203e
Binary files /dev/null and b/IQMtools V1.2.2.2/IQMlite/auxiliary/THIRD_PARTY_SOFTWARE/SBMLimportExport/OutputSBML.mexw64 differ
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/THIRD_PARTY_SOFTWARE/SBMLimportExport/README.txt b/IQMtools V1.2.2.2/IQMlite/auxiliary/THIRD_PARTY_SOFTWARE/SBMLimportExport/README.txt
new file mode 100644
index 0000000000000000000000000000000000000000..1f557c94f08dbaadf7953318b1eb2b6f04ed840e
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/THIRD_PARTY_SOFTWARE/SBMLimportExport/README.txt	
@@ -0,0 +1,5 @@
+This is the compiled version of the SBML Toolbox and libSBML that is necessary to handle SBML import and export by the 
+Systems Biology Toolbox 2 for MATLAB. WINDOWS ONLY with MATLAB 32bit.
+
+All unnecessary files have been deleted in order to reduce the size.
+
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/THIRD_PARTY_SOFTWARE/SBMLimportExport/TranslateSBML.m b/IQMtools V1.2.2.2/IQMlite/auxiliary/THIRD_PARTY_SOFTWARE/SBMLimportExport/TranslateSBML.m
new file mode 100644
index 0000000000000000000000000000000000000000..87f7759810b80d9e360cd81392ab685fd4c63935
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/THIRD_PARTY_SOFTWARE/SBMLimportExport/TranslateSBML.m	
@@ -0,0 +1,77 @@
+% TranslateSBML('filename' (optional), validateFlag (optional), verboseFlag (optional))
+% reads an SBML document and converts it to a MATLAB_SBML structure.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% NOTE: This version enables support for SBML L3 FBC package.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% It accepts three optional arguments:
+%
+%   * filename: This is the name of the file to be imported. 
+%               If the file is not in the current directory, then the 
+%               argument must be a full pathname (either absolute or 
+%               relative to the current working directory). 
+%
+%        NOTE: In Octave the filename is a required argument.
+%
+%   * validateFlag: This flag tells libSBML whether to perform full 
+%                   validation of the SBML file being read. The default 
+%                   value is 0, which signifies not to perform validation. 
+%                   (Note libSBML will still check for and report basic 
+%                   XML parsing errors regardless of the value of this flag.)
+%
+%   * verboseFlag: A value of 1 (the default) indicates that TranslateSBML 
+%                  should perform the validation process interactively, 
+%                  displaying errors and prompting the user for feedback 
+%                  if the model is invalid. A value of 0 will suppress user 
+%                  interaction, and is useful when calling TranslateSBML 
+%                  from within another function/script.
+%
+
+
+% Filename    : TranslateSBML.m
+% Description : MATLAB help file for TranslateSBML
+% Author(s)   : SBML Team <sbml-team@caltech.edu>
+% Organization: University of Hertfordshire STRC
+% Created     : 2003-09-15
+%
+% This file is part of libSBML.  Please visit http://sbml.org for more
+% information about SBML, and the latest version of libSBML.
+%
+% Copyright (C) 2013-2014 jointly by the following organizations:
+%     1. California Institute of Technology, Pasadena, CA, USA
+%     2. EMBL European Bioinformatics Institute (EMBL-EBI), Hinxton, UK
+%     3. University of Heidelberg, Heidelberg, Germany
+%
+% Copyright (C) 2009-2013 jointly by the following organizations: 
+%     1. California Institute of Technology, Pasadena, CA, USA
+%     2. EMBL European Bioinformatics Institute (EMBL-EBI), Hinxton, UK
+%  
+% Copyright (C) 2006-2008 by the California Institute of Technology,
+%     Pasadena, CA, USA 
+%  
+% Copyright (C) 2002-2005 jointly by the following organizations: 
+%     1. California Institute of Technology, Pasadena, CA, USA
+%     2. Japan Science and Technology Agency, Japan
+% 
+% This library is free software; you can redistribute it and/or modify it
+% under the terms of the GNU Lesser General Public License as published by
+% the Free Software Foundation.  A copy of the license agreement is provided
+% in the file named "LICENSE.txt" included with this software distribution
+% and also available online as http://sbml.org/software/libsbml/license.html
+%
+% The original code contained here was initially developed by:
+%
+%      Sarah Keating
+%      Science and Technology Research Centre
+%      University of Hertfordshire
+%      Hatfield, AL10 9AB
+%      United Kingdom
+%
+%      http://www.sbml.org
+%      mailto:sbml-team@caltech.edu
+%
+% Contributor(s):
+%
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/THIRD_PARTY_SOFTWARE/SBMLimportExport/TranslateSBML.mexw32 b/IQMtools V1.2.2.2/IQMlite/auxiliary/THIRD_PARTY_SOFTWARE/SBMLimportExport/TranslateSBML.mexw32
new file mode 100644
index 0000000000000000000000000000000000000000..f992bce99736d23895c61d9a0dd9582a325f6e5a
Binary files /dev/null and b/IQMtools V1.2.2.2/IQMlite/auxiliary/THIRD_PARTY_SOFTWARE/SBMLimportExport/TranslateSBML.mexw32 differ
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/THIRD_PARTY_SOFTWARE/SBMLimportExport/TranslateSBML.mexw64 b/IQMtools V1.2.2.2/IQMlite/auxiliary/THIRD_PARTY_SOFTWARE/SBMLimportExport/TranslateSBML.mexw64
new file mode 100644
index 0000000000000000000000000000000000000000..f2ecff457779b751ef82d720b254b623f8d7f58c
Binary files /dev/null and b/IQMtools V1.2.2.2/IQMlite/auxiliary/THIRD_PARTY_SOFTWARE/SBMLimportExport/TranslateSBML.mexw64 differ
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/THIRD_PARTY_SOFTWARE/SBMLimportExport/auxiliary/CheckAndConvert.m b/IQMtools V1.2.2.2/IQMlite/auxiliary/THIRD_PARTY_SOFTWARE/SBMLimportExport/auxiliary/CheckAndConvert.m
new file mode 100644
index 0000000000000000000000000000000000000000..ee87730fae16d5221e66923c5c42d817019cd592
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/THIRD_PARTY_SOFTWARE/SBMLimportExport/auxiliary/CheckAndConvert.m	
@@ -0,0 +1,471 @@
+function Formula = CheckAndConvert(Input)
+% converts from MathML in-fix to MATLAB functions
+
+% Filename    : CheckAndConvert.m
+% Description : converts from MathML in-fix to MATLAB functions
+% Author(s)   : SBML Team <sbml-team@caltech.edu>
+% Organization: University of Hertfordshire STRC
+% Created     : 2004-12-13
+%
+% This file is part of libSBML.  Please visit http://sbml.org for more
+% information about SBML, and the latest version of libSBML.
+%
+% Copyright (C) 2013-2014 jointly by the following organizations:
+%     1. California Institute of Technology, Pasadena, CA, USA
+%     2. EMBL European Bioinformatics Institute (EMBL-EBI), Hinxton, UK
+%     3. University of Heidelberg, Heidelberg, Germany
+%
+% Copyright (C) 2009-2013 jointly by the following organizations: 
+%     1. California Institute of Technology, Pasadena, CA, USA
+%     2. EMBL European Bioinformatics Institute (EMBL-EBI), Hinxton, UK
+%  
+% Copyright (C) 2006-2008 by the California Institute of Technology,
+%     Pasadena, CA, USA 
+%  
+% Copyright (C) 2002-2005 jointly by the following organizations: 
+%     1. California Institute of Technology, Pasadena, CA, USA
+%     2. Japan Science and Technology Agency, Japan
+% 
+% This library is free software; you can redistribute it and/or modify it
+% under the terms of the GNU Lesser General Public License as published by
+% the Free Software Foundation.  A copy of the license agreement is provided
+% in the file named "LICENSE.txt" included with this software distribution
+% and also available online as http://sbml.org/software/libsbml/license.html
+%
+% The original code contained here was initially developed by:
+%
+%      Sarah Keating
+%      Science and Technology Research Centre
+%      University of Hertfordshire
+%      Hatfield, AL10 9AB
+%      United Kingdom
+%
+%      http://www.sbml.org
+%      mailto:sbml-team@caltech.edu
+%
+% Contributor(s):
+
+Formula = strrep(Input, 'arccosh', 'acosh');
+
+Formula = strrep(Formula, 'arccot', 'acot');
+
+Formula = strrep(Formula, 'arccoth', 'acoth');
+
+Formula = strrep(Formula, 'arccsc', 'acsc');
+
+Formula = strrep(Formula, 'arccsch', 'acsch');
+
+Formula = strrep(Formula, 'arcsec', 'asec');
+
+Formula = strrep(Formula, 'arcsech', 'asech');
+
+Formula = strrep(Formula, 'arcsinh', 'asinh');
+
+Formula = strrep(Formula, 'arctanh', 'atanh');
+
+Formula = strrep(Formula, 'exponentiale', 'exp(1)');
+
+Formula = strrep(Formula, 'geq', 'ge');
+
+Formula = strrep(Formula, 'leq', 'le');
+
+Formula = strrep(Formula, 'neq', 'ne');
+
+Formula = strrep(Formula, 'pow', 'power');
+
+% any logical expressions can only have two arguments
+Formula = SortLogicals(Formula);
+
+% log(2,x) must become log2(x)
+Formula = strrep(Formula, 'log(2,', 'log2(');
+
+
+% root(n,x) must become nthroot(x,n)
+Index = strfind(Formula, 'root(');
+
+for i = 1:length(Index)
+
+    % create a subformula root(n,x)
+    SubFormula = '';
+    j = 1;
+    nFunctions=0;   %number of functions in expression
+    closedFunctions=0; %number of closed functions
+    while(nFunctions==0 || nFunctions~=closedFunctions)
+        SubFormula(j) = Formula(Index(i)+j-1);
+        if(strcmp(SubFormula(j),')'))
+            closedFunctions=closedFunctions+1;
+        end;
+        if(strcmp(SubFormula(j),'('))
+            nFunctions=nFunctions+1;
+        end;  
+        j = j+1;
+    end;
+    
+    j = 6;
+     n = '';
+    while(~strcmp(SubFormula(j), ','))
+        n = strcat(n, SubFormula(j));
+        j = j+1;
+    end;
+    
+    j = j+1;
+    x = SubFormula(j:length(SubFormula)-1);
+
+    ReplaceFormula = strcat('nthroot(', x, ',', n, ')');
+
+    Formula = strrep(Formula, SubFormula, ReplaceFormula);
+    Index = strfind(Formula, 'root(');
+
+
+end;
+
+% log(n,x) must become (log(x)/log(n))
+% but log(x) must be left alone
+
+LogTypes = IsItLogBase(Formula);
+Index = strfind(Formula, 'log(');
+
+for i = 1:length(Index)
+
+    if (LogTypes(i) == 1)
+    % create a subformula log(n,x)
+    SubFormula = '';
+    j = 1;
+    while(~strcmp(Formula(Index(i)+j-1), ')'))
+        SubFormula(j) = Formula(Index(i)+j-1);
+        j = j+1;
+    end;
+    SubFormula = strcat(SubFormula, ')');
+    
+    j = 5;
+     n = '';
+    while(~strcmp(SubFormula(j), ','))
+        n = strcat(n, SubFormula(j));
+        j = j+1;
+    end;
+    
+    j = j+1;
+    x = '';
+    while(~strcmp(SubFormula(j), ')'))
+        x = strcat(x, SubFormula(j));
+        j = j+1;
+    end;
+    
+    ReplaceFormula = sprintf('(log(%s)/log(%s))', x, n);
+    
+    Formula = strrep(Formula, SubFormula, ReplaceFormula);
+    Index = Index + 7;
+    end;
+
+end;
+
+
+function y = IsItLogBase(Formula)
+
+% returns an array of 0/1 indicating whether each occurence of log is
+% a log(n,x) or a log(x)
+% e.g. Formula = 'log(2,3) + log(6)'
+%      IsItLogBase returns y = [1,0]
+
+
+y = 0;
+
+% find log
+
+LogIndex = strfind(Formula, 'log(');
+
+if (isempty(LogIndex))
+    return;
+else
+    OpenBracket = strfind(Formula, '(');
+    Comma = strfind(Formula, ',');
+    CloseBracket = strfind(Formula, ')');
+
+    for i = 1:length(LogIndex)
+        if (isempty(Comma))
+            % no commas so no logbase formulas
+            y(i) = 0;
+        else
+
+            % find the opening bracket
+            Open = find(ismember(OpenBracket, LogIndex(i)+3) == 1);
+
+            % find closing bracket
+            Close = find(CloseBracket > LogIndex(i)+3, 1);
+
+            % is there a comma between
+            Greater = find(Comma > OpenBracket(Open));
+            Less = find(Comma < CloseBracket(Close));
+
+            if (isempty(Greater) || isempty(Less))
+                y(i) = 0;
+            else
+                Equal = find(Greater == Less);
+                if (isempty(Equal))
+                    y(i) = 0;
+                else
+                    y(i) = 1;
+                end;
+            end;
+
+        end;
+    end;
+end;
+
+function Formula = CorrectFormula(OriginalFormula, LogicalExpression)
+% CorrectFormula takes an OriginalFormula (as a char array)
+%                 and  a Logical Expression (as a char array with following '(')
+% and returns the formula written so that the logical expression only takes 2 arguments
+% 
+% *************************************************************************************
+% 
+% EXAMPLE:    y = CorrectFormula('and(A,B,C)', 'and(')
+% 
+%             y = 'and(and(A,B), C)'
+%             
+
+% find all opening brackets, closing brackets and commas contained
+% within the original formula
+OpeningBracketIndex = find((ismember(OriginalFormula, '(')) == 1);
+
+ClosingBracketIndex = find((ismember(OriginalFormula, ')')) == 1);
+
+CommaIndex = find((ismember(OriginalFormula, ',')) == 1);
+
+% check that tha number of brackets matches 
+if (length(OpeningBracketIndex) ~= length(ClosingBracketIndex))
+    error('Bracket mismatch');
+end;
+
+% find the commas that are between the arguments of the logical expression
+% not those that may be part of the argument
+% in the OpeningBracketIndex the first element refers to the opening
+% bracket of the expression and the last element of ClosingBracketIndex
+% refers to the the closing bracket of the expression
+% commas between other pairs of brackets do not need to be considered
+% e.g.  'and(gt(d,e),lt(2,e),gt(f,d))'
+%                   |       |       
+%                  relevant commas
+
+for i = 1:length(CommaIndex)
+    for j = 2:length(OpeningBracketIndex)
+        if ((CommaIndex(i) > OpeningBracketIndex(j)) && (CommaIndex(i) < ClosingBracketIndex(j-1)))
+            CommaIndex(i) = 0;
+        end;
+    end;
+end;
+
+NonZeros = find(CommaIndex ~= 0);
+
+% if there is only one relevant comma
+% implies only two arguments
+% MATLAB can deal with the OriginalFormula
+
+if (length(NonZeros) == 1)
+     Formula = OriginalFormula;
+     return;
+end;
+
+% get elements that represent the arguments of the logical expression
+% as an array of character arrays
+% e.g. first element is between opening barcket and first relevant comma
+%      next elements are between relevant commas
+%      last element is between last relevant comma and closing bracket
+
+j = OpeningBracketIndex(1);
+ElementNumber = 1;
+
+for i = 1:length(NonZeros)
+    element = '';
+    j = j+1;
+    while (j <= CommaIndex(NonZeros(i)) - 1)
+        element = strcat(element, OriginalFormula(j));
+        j = j + 1;
+    end;
+
+    Elements{ElementNumber} = element;
+    ElementNumber = ElementNumber + 1;
+
+end;
+
+
+element = '';
+j = j+1;
+while (j < ClosingBracketIndex(length(ClosingBracketIndex)) - 1)
+    element = strcat(element, OriginalFormula(j));
+    j = j + 1;
+end;
+
+Elements{ElementNumber} = element;
+
+% iteratively replace the first two arguments with the logical expression applied to
+% the first two arguments
+% e.g. OriginalFormula = 'and(a,b,c,d)'
+% becomes                'and(and(a,b),c,d)'
+% which becomes          'and(and(and(a,b),c),d)'
+Formula = OriginalFormula;
+
+if (length(Elements) > 2)
+    for i = 2:length(Elements)-1
+        Find = strcat(Elements{i-1}, ',', Elements{i});
+        Replace = strcat(LogicalExpression, Find, ')');
+
+        Formula = strrep(Formula, Find, Replace);
+        Elements{i} = Replace;
+    end;
+end;
+
+
+function Arguments = CheckLogical(Formula, LogicalExpression)
+% CheckLogical takes a Formula (as a character array) 
+%               and  a LogicalExpression (as a char array)
+% and returns an array of character strings 
+% representing the application of the logical expression within the formula
+% 
+% NOTE the logical expression is followed by an '(' to prevent confusion 
+% with other character strings within the formula 
+% 
+% ******************************************************************
+%  EXAMPLE:       y = CheckLogical('piecewise(and(A,B,C), 0.2, 1)' , 'and(')
+%  
+%                 y = 'and(A,B,C)'
+%
+%  EXAMPLE:       y = CheckLogical('or(and(A,B), and(A,B,C))', 'and(')
+%
+%                 y = 'and(A,B)'    'and(A,B,C)'
+
+% find the starting indices of all occurences of the logical expression
+Start = strfind(Formula, LogicalExpression);
+
+% if not found; no arguments - return
+if (isempty(Start))
+    Arguments = {};
+    return;
+end;
+
+
+for j = 1:length(Start) % each occurence of the logical expression
+
+    Stop = 0;
+    flag = 0;
+    i = Start(j);
+    output = '';
+
+    for i = Start(j):Start(j)+length(LogicalExpression)
+        output = strcat(output, Formula(i));
+    end;
+    i = i + 1;
+
+    while ((Stop == 0) && (i <= length(Formula)))
+        c = Formula(i);
+
+        if (strcmp(c, '('))
+            flag = flag + 1;
+            output = strcat(output, c);
+        elseif (strcmp(c, ')'))
+            if (flag > 0)
+                output = strcat(output, c);
+                flag = flag - 1;
+            else
+                output = strcat(output, c);
+                Stop = 1;
+            end;
+
+        else
+            output = strcat(output, c);
+        end;
+
+        i = i + 1;
+
+    end;
+
+
+    Arguments{j} = output;
+
+end;
+
+function y = SortLogicals(Formula)
+% SortLogicals takes a formula as a char array
+% and returns the formula with and logical expressions applied to only two arguments
+
+Formula = LoseWhiteSpace(Formula);
+
+Find = CheckLogical(Formula, 'and(');
+
+for i = 1:length(Find)
+    Replace = CorrectFormula(Find{i}, 'and(');
+
+    Formula = strrep(Formula, Find{i}, Replace);
+
+end;
+
+Find = CheckLogical(Formula, 'xor(');
+
+for i = 1:length(Find)
+    Replace = CorrectFormula(Find{i}, 'xor(');
+
+    Formula = strrep(Formula, Find{i}, Replace);
+
+end;
+
+Find = CheckLogical(Formula, 'or(');
+
+for i = 1:length(Find)
+    Replace = CorrectFormula(Find{i}, 'or(');
+
+    Formula = strrep(Formula, Find{i}, Replace);
+
+end;
+y = Formula;
+
+%**********************************************************************
+% LoseWhiteSpace(charArray) takes an array of characters
+% and returns the array with any white space removed
+%
+%**********************************************************************
+
+function y = LoseWhiteSpace(charArray)
+% LoseWhiteSpace(charArray) takes an array of characters
+% and returns the array with any white space removed
+%
+%----------------------------------------------------------------
+% EXAMPLE:
+%           y = LoseWhiteSpace('     exa  mp le')
+%           y = 'example'
+%
+
+%------------------------------------------------------------
+% check input is an array of characters
+if (~ischar(charArray))
+    error('LoseWhiteSpace(input)\n%s', 'input must be an array of characters');
+end;
+
+%-------------------------------------------------------------
+% get the length of the array
+NoChars = length(charArray);
+
+%-------------------------------------------------------------
+% create an array that indicates whether the elements of charArray are
+% spaces
+% e.g. WSpace = isspace('  v b') = [1, 1, 0, 1, 0]
+% and determine how many
+
+WSpace = isspace(charArray);
+NoSpaces = sum(WSpace);
+
+%-----------------------------------------------------------
+% rewrite the array to leaving out any spaces
+% remove any numbers from the array of symbols
+if (NoSpaces > 0)
+    NewArrayCount = 1;
+    for i = 1:NoChars
+        if (~isspace(charArray(i)))
+            y(NewArrayCount) = charArray(i);
+            NewArrayCount = NewArrayCount + 1;
+        end;
+    end;    
+else
+    y = charArray;
+end;
+
+
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/THIRD_PARTY_SOFTWARE/SBMLimportExport/auxiliary/Contents.m b/IQMtools V1.2.2.2/IQMlite/auxiliary/THIRD_PARTY_SOFTWARE/SBMLimportExport/auxiliary/Contents.m
new file mode 100644
index 0000000000000000000000000000000000000000..f31b08292f97f6ae9ff0af80b5fd9f6b133e49fa
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/THIRD_PARTY_SOFTWARE/SBMLimportExport/auxiliary/Contents.m	
@@ -0,0 +1,93 @@
+%
+% These are the functions to import and export an SBML model into a 
+% MATLAB_SBML structure and back to an SBML file.
+%
+% FUNCTIONS include:
+%
+% TranslateSBML(varargin)
+%
+% - translates a sbml file into a matlab structure
+%    NOTE: this executable must be built in most environments
+%    (see README.txt)
+%
+% OutputSBML(varargin)
+%
+% - translates a appropriate matlab structure back into sbml and writes
+%   out the file
+%    NOTE: this executable must be built in most environments
+%    (see README.txt)
+%
+% CheckAndConvert.m
+%
+% - a script used by TranslateSBML to change some mathematical function names
+%   to those used by MATLAB
+%
+% ConvertFormulaToMathML.m
+%
+% - a script used by OutputSBML to change some mathematical function names
+%   to those used by MathML
+%
+% isSBML_Model.m
+%
+% - a script used by OutputSBML to check that a structure is an appropriate
+%   MATLAB_SBML structure for conversion to SBML
+%
+% isoctave.m
+%
+% - a script to determine if octave or matlab is being used
+%
+% buildSBML 
+%
+% - builds the TranslateSBML/OutputSBML executables from source
+%
+% installSBML
+%
+% - installs the libSBML MATLAB interface
+%
+
+% Description : This is the binding to translate 
+%				 sbml models into a MATLAB structure 
+% Author(s)   : SBML Team <sbml-team@caltech.edu>
+% Organization: University of Hertfordshire STRC
+% Created     : 2003-09-15
+%
+% This file is part of libSBML.  Please visit http://sbml.org for more
+% information about SBML, and the latest version of libSBML.
+%
+% Copyright (C) 2013-2014 jointly by the following organizations:
+%     1. California Institute of Technology, Pasadena, CA, USA
+%     2. EMBL European Bioinformatics Institute (EMBL-EBI), Hinxton, UK
+%     3. University of Heidelberg, Heidelberg, Germany
+%
+% Copyright (C) 2009-2013 jointly by the following organizations: 
+%     1. California Institute of Technology, Pasadena, CA, USA
+%     2. EMBL European Bioinformatics Institute (EMBL-EBI), Hinxton, UK
+%  
+% Copyright (C) 2006-2008 by the California Institute of Technology,
+%     Pasadena, CA, USA 
+%  
+% Copyright (C) 2002-2005 jointly by the following organizations: 
+%     1. California Institute of Technology, Pasadena, CA, USA
+%     2. Japan Science and Technology Agency, Japan
+% 
+% This library is free software; you can redistribute it and/or modify it
+% under the terms of the GNU Lesser General Public License as published by
+% the Free Software Foundation.  A copy of the license agreement is provided
+% in the file named "LICENSE.txt" included with this software distribution
+% and also available online as http://sbml.org/software/libsbml/license.html
+%
+% The original code contained here was initially developed by:
+%
+%      Sarah Keating
+%      Science and Technology Research Centre
+%      University of Hertfordshire
+%      Hatfield, AL10 9AB
+%      United Kingdom
+%
+%      http://www.sbml.org
+%      mailto:sbml-team@caltech.edu
+%
+% Contributor(s):
+%
+%
+%
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/THIRD_PARTY_SOFTWARE/SBMLimportExport/auxiliary/ConvertFormulaToMathML.m b/IQMtools V1.2.2.2/IQMlite/auxiliary/THIRD_PARTY_SOFTWARE/SBMLimportExport/auxiliary/ConvertFormulaToMathML.m
new file mode 100644
index 0000000000000000000000000000000000000000..7b9e59502222ed67177ed15c7f0e9b10fab44f52
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/THIRD_PARTY_SOFTWARE/SBMLimportExport/auxiliary/ConvertFormulaToMathML.m	
@@ -0,0 +1,344 @@
+function Formula = ConvertFormulaToMathML(Input)
+% converts from MATLAB to MathML in-fix functions
+
+% Filename    : ConvertFormulaToMathML.m
+% 
+% This file is part of libSBML.  Please visit http://sbml.org for more
+% information about SBML, and the latest version of libSBML.
+%
+% Copyright (C) 2013-2014 jointly by the following organizations:
+%     1. California Institute of Technology, Pasadena, CA, USA
+%     2. EMBL European Bioinformatics Institute (EMBL-EBI), Hinxton, UK
+%     3. University of Heidelberg, Heidelberg, Germany
+%
+% Copyright (C) 2009-2013 jointly by the following organizations: 
+%     1. California Institute of Technology, Pasadena, CA, USA
+%     2. EMBL European Bioinformatics Institute (EMBL-EBI), Hinxton, UK
+%  
+% Copyright (C) 2006-2008 by the California Institute of Technology,
+%     Pasadena, CA, USA 
+%  
+% Copyright (C) 2002-2005 jointly by the following organizations: 
+%     1. California Institute of Technology, Pasadena, CA, USA
+%     2. Japan Science and Technology Agency, Japan
+% 
+% This library is free software; you can redistribute it and/or modify it
+% under the terms of the GNU Lesser General Public License as published by
+% the Free Software Foundation.  A copy of the license agreement is provided
+% in the file named "LICENSE.txt" included with this software distribution
+% and also available online as http://sbml.org/software/libsbml/license.html
+%
+% The original code contained here was initially developed by:
+%
+%      Sarah Keating
+%      Science and Technology Research Centre
+%      University of Hertfordshire
+%      Hatfield, AL10 9AB
+%      United Kingdom
+%
+%      http://www.sbml.org
+%      mailto:sbml-team@caltech.edu
+%
+% Contributor(s):
+
+Input = LoseWhiteSpace(Input);
+
+Formula = strrep(Input, 'acosh(', 'arccosh(');
+
+Formula = strrep(Formula, 'acot(', 'arccot(');
+
+Formula = strrep(Formula, 'acoth(', 'arccoth(');
+
+Formula = strrep(Formula, 'acsc(', 'arccsc(');
+
+Formula = strrep(Formula, 'acsch(', 'arccsch(');
+
+Formula = strrep(Formula, 'asec(', 'arcsec(');
+
+Formula = strrep(Formula, 'asech(', 'arcsech(');
+
+Formula = strrep(Formula, 'asinh(', 'arcsinh(');
+
+Formula = strrep(Formula, 'atanh(', 'arctanh(');
+
+Formula = strrep(Formula, 'exp(1)', 'exponentiale');
+
+Formula = strrep(Formula, 'ge(', 'geq(');
+
+Formula = strrep(Formula, 'le(', 'leq(');
+
+Formula = strrep(Formula, 'ne(', 'neq(');
+
+Formula = strrep(Formula, 'power(', 'pow(');
+
+% log2(x) must become log(2, x)
+Formula = strrep(Formula, 'log2(', 'log(2, ');
+% 
+% 
+% nthroot(x,n) must become root(n,x)
+Index = strfind(Formula, 'nthroot(');
+
+for i = 1:length(Index)
+
+    % create a subformula nthroot(x,n)
+    SubFunction = '';
+    j = 1;
+    nFunctions=0;   %number of functions in expression
+    closedFunctions=0; %number of closed functions
+    while(nFunctions==0 || nFunctions~=closedFunctions)
+        SubFormula(j) = Formula(Index(i)+j-1);
+        if(strcmp(SubFormula(j),')'))
+            closedFunctions=closedFunctions+1;
+        end;
+        if(strcmp(SubFormula(j),'('))
+            nFunctions=nFunctions+1;
+        end;  
+        j = j+1;
+    end;
+    
+    j = 9;
+     n = '';
+    while(~strcmp(SubFormula(j), ','))
+        n = strcat(n, SubFormula(j));
+        j = j+1;
+    end;
+    
+    j = j+1;
+    x = SubFormula(j:length(SubFormula)-1);
+
+    if (exist('OCTAVE_VERSION'))
+      ReplaceFormula = myRegexprep(SubFormula, n, x, 'once');
+      ReplaceFormula = myRegexprep(ReplaceFormula,regexptranslate('escape',x),n,2);
+      ReplaceFormula = myRegexprep(ReplaceFormula, 'nthroot', 'root', 'once');
+   else
+      ReplaceFormula = regexprep(SubFormula, n, x, 'once');
+      ReplaceFormula = regexprep(ReplaceFormula,regexptranslate('escape',x),n,2);
+      ReplaceFormula = regexprep(ReplaceFormula, 'nthroot', 'root', 'once');
+    end;
+    
+    Formula = strrep(Formula, SubFormula, ReplaceFormula);
+    Index = strfind(Formula, 'nthroot(');
+
+
+end;
+
+% (log(x)/log(n)) must become log(n,x)
+% but log(x) must be left alone
+Formula = convertLog(Formula);
+
+% 
+function y = convertLog(Formula)
+y = Formula;
+LogTypes = IsItLogBase(Formula);
+num = sum(LogTypes);
+Index = strfind(Formula, '(log(');
+
+subIndex = 1;
+for i = 1:length(Index)
+
+    if (LogTypes(i) == 1)
+      % get x and n from (log(x)/log(n))
+      pairs = PairBrackets(Formula);
+      for j=1:length(pairs)
+        if (pairs(j,1) == Index(i))
+          break;
+        end;
+      end;
+      subFormula{subIndex} = Formula(Index(i):pairs(j,2));
+      ff = subFormula{subIndex};
+      subPairs = PairBrackets(ff);
+      x = ff(subPairs(2,1)+1:subPairs(2,2)-1);
+      n = ff(subPairs(3,1)+1:subPairs(3,2)-1);
+      newFormula{subIndex} = sprintf('log(%s,%s)', n, x);
+      subIndex = subIndex+1;
+    end;
+
+end;
+if (subIndex-1 > num)
+  error('Problem');
+end;
+for i=1:num
+  y = strrep(y, subFormula{i}, newFormula{i});
+end;
+function y = IsItLogBase(Formula)
+
+% returns an array of 0/1 indicating whether each occurence of log is
+% a (log(n)/log(x)) or a log(x)
+% e.g. Formula = '(log(2)/log(3)) + log(6)'
+%      IsItLogBase returns y = [1,0]
+
+
+y = 0;
+LogIndex = strfind(Formula, '(log(');
+
+if (isempty(LogIndex))
+    return;
+else
+    Divide = strfind(Formula, ')/log(');
+    pairs = PairBrackets(Formula);
+    
+    if (isempty(Divide))
+      return;
+    else
+      % check that the divide occurs between logs
+      for i=1:length(LogIndex)
+        match = 0;
+        for j=1:length(pairs)
+          if (pairs(j, 1) == LogIndex(i))
+            break;
+          end;
+        end;
+        for k = 1:length(Divide)
+          if (pairs(j+1,2) == Divide(k))
+            match = 1;
+            break;
+          end;
+        end;
+      
+        y(i) = match;       
+      end;
+    end;
+end;
+
+%**********************************************************************
+% LoseWhiteSpace(charArray) takes an array of characters
+% and returns the array with any white space removed
+%
+%**********************************************************************
+
+function y = LoseWhiteSpace(charArray)
+% LoseWhiteSpace(charArray) takes an array of characters
+% and returns the array with any white space removed
+%
+%----------------------------------------------------------------
+% EXAMPLE:
+%           y = LoseWhiteSpace('     exa  mp le')
+%           y = 'example'
+%
+
+%------------------------------------------------------------
+% check input is an array of characters
+if (~ischar(charArray))
+    error('LoseWhiteSpace(input)\n%s', 'input must be an array of characters');
+end;
+
+%-------------------------------------------------------------
+% get the length of the array
+NoChars = length(charArray);
+
+%-------------------------------------------------------------
+% create an array that indicates whether the elements of charArray are
+% spaces
+% e.g. WSpace = isspace('  v b') = [1, 1, 0, 1, 0]
+% and determine how many
+
+WSpace = isspace(charArray);
+NoSpaces = sum(WSpace);
+
+%-----------------------------------------------------------
+% rewrite the array to leaving out any spaces
+% remove any numbers from the array of symbols
+if (NoSpaces > 0)
+    NewArrayCount = 1;
+    for i = 1:NoChars
+        if (~isspace(charArray(i)))
+            y(NewArrayCount) = charArray(i);
+            NewArrayCount = NewArrayCount + 1;
+        end;
+    end;    
+else
+    y = charArray;
+end;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function pairs = PairBrackets(formula)
+% PairBrackets takes a string 
+%       and returns 
+%           an array of indices of each pair of brackets
+%               ordered from the opening bracket index
+%
+
+if (~ischar(formula))
+    error(sprintf('%s\n%s', 'PairBrackets(formula)', 'first argument must be a string'));
+end;
+
+OpeningBracketIndex = strfind(formula, '(');
+ClosingBracketIndex = strfind(formula, ')');
+
+% check that the number of brackets matches 
+if (length(OpeningBracketIndex) ~= length(ClosingBracketIndex))
+    error('Bracket mismatch');
+end;
+
+if (isempty(OpeningBracketIndex))
+    pairs = 0;
+    return;
+end;
+
+for i = 1:length(OpeningBracketIndex)
+    j = length(OpeningBracketIndex);
+    while(j > 0)
+        if (OpeningBracketIndex(j) < ClosingBracketIndex(i))
+            pairs(i,1) = OpeningBracketIndex(j);
+            pairs(i,2) = ClosingBracketIndex(i);
+            OpeningBracketIndex(j) = max(ClosingBracketIndex);
+            j = 0;
+        else
+            j = j - 1;
+        end;
+    end;
+end;
+
+% order the pairs so that the opening bracket index is in ascending order
+
+OriginalPairs = pairs;
+
+% function 'sort' changes in version 7.0.1
+
+v = version;
+v_num = str2num(v(1));
+
+if (v_num < 7)
+    TempPairs = sort(pairs, 1);
+else
+    TempPairs = sort(pairs, 1, 'ascend');
+end;
+
+for i = 1:length(OpeningBracketIndex)
+    pairs(i, 1) = TempPairs(i, 1);
+    j = find(OriginalPairs == pairs(i, 1));
+    pairs(i, 2) = OriginalPairs(j, 2);
+end;
+
+
+
+function string = myRegexprep(string, repre, repstr, number)
+
+  %% Parse input arguements
+
+  n = -1;
+  if isnumeric(number)
+    n = number;
+  elseif strcmpi(number, 'once')
+    n = 1;
+  else
+    error('Invalid argument to myRegexprep');
+  end;
+
+  [st, en] = regexp(string, repre);
+
+
+  if (n > 0)
+    if (length(st) >= n)
+      st = st(n);
+	  en = en(n);
+    else
+      error('Invalid number of matches in myRegexprep');
+	  st = [];
+    end;
+  end;
+
+  for i = length(st):-1:1
+    string = [string(1:st(i)-1) repstr string(en(i)+1:length(string))];
+  end;
+
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/THIRD_PARTY_SOFTWARE/SBMLimportExport/auxiliary/buildSBML.m b/IQMtools V1.2.2.2/IQMlite/auxiliary/THIRD_PARTY_SOFTWARE/SBMLimportExport/auxiliary/buildSBML.m
new file mode 100644
index 0000000000000000000000000000000000000000..cbbac684cfea0410e6c825b49337a12f74888749
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/THIRD_PARTY_SOFTWARE/SBMLimportExport/auxiliary/buildSBML.m	
@@ -0,0 +1,940 @@
+function buildSBML(varargin)
+% Builds the MATLAB language interface for libSBML.
+%
+% This script is meant to be invoked from libSBML's MATLAB bindings
+% source directory.  LibSBML must already have been compiled and
+% installed on your system.  This script makes the following
+% assumptions:
+%
+% * Linux and Mac systems: the compiled libSBML library must be on the
+%   appropriate library search paths, and/or the appropriate environment
+%   variables must have been set so that programs such as MATLAB can
+%   load the library dynamically.
+%
+% * Windows systems: the libSBML binaries (.dll and .lib files) and its
+%   dependencies (such as the XML parser library being used) must be
+%   located together in the same directory.  This script also assumes
+%   that libSBML was configured to use the libxml2 XML parser library.
+%   (This assumption is under Windows only.)
+%
+% After this script is executed successfully, a second step is necessary
+% to install the results.  This second step is performed by the
+% "installSBML" script found in the same location as this script.
+%
+% (File $Revision: 13171 $ of $Date:: 2011-03-04 10:30:24 +0000#$
+
+% Filename    : buildSBML.m
+% Description : Build MATLAB binding.
+% Author(s)   : SBML Team <sbml-team@caltech.edu>
+% Organization: EMBL-EBI, Caltech
+% Created     : 2011-02-08
+%
+% This file is part of libSBML.  Please visit http://sbml.org for more
+% information about SBML, and the latest version of libSBML.
+%
+% Copyright (C) 2013-2014 jointly by the following organizations:
+%     1. California Institute of Technology, Pasadena, CA, USA
+%     2. EMBL European Bioinformatics Institute (EMBL-EBI), Hinxton, UK
+%     3. University of Heidelberg, Heidelberg, Germany
+%
+% Copyright (C) 2009-2013 jointly by the following organizations:
+%     1. California Institute of Technology, Pasadena, CA, USA
+%     2. EMBL European Bioinformatics Institute (EMBL-EBI), Hinxton, UK
+%
+% Copyright (C) 2006-2008 by the California Institute of Technology,
+%     Pasadena, CA, USA
+%
+% Copyright (C) 2002-2005 jointly by the following organizations:
+%     1. California Institute of Technology, Pasadena, CA, USA
+%     2. Japan Science and Technology Agency, Japan
+%
+% This library is free software; you can redistribute it and/or modify
+% it under the terms of the GNU Lesser General Public License as
+% published by the Free Software Foundation.  A copy of the license
+% agreement is provided in the file named "LICENSE.txt" included with
+% this software distribution and also available online as
+% http://sbml.org/software/libsbml/license.html
+
+
+% =========================================================================
+% Main loop.
+% =========================================================================
+
+
+  [matlab_octave, bit64]  = check_system();
+
+  disp(sprintf('\nConstructing the libSBML %s interface.\n', matlab_octave));
+
+  [location, writeAccess, in_installer] = check_location(matlab_octave);
+
+  if isWindows()
+    build_win(matlab_octave, location, writeAccess, bit64, in_installer);
+  elseif ismac() || isunix()
+
+    % here we allow input arguments of include and library directories
+    % but we only use these if we are in the source tree
+
+    if (nargin > 0 && strcmp(location, 'source'))
+
+      % we need two arguments
+      % one must be the full path to the include directory
+      % two must be the full path to the library directory
+
+      correctArguments = 0;
+      if (nargin == 2)
+        include_dir_supplied = varargin{1};
+        lib_dir_supplied = varargin{2};
+        if checkSuppliedArguments(include_dir_supplied, lib_dir_supplied)
+          correctArguments = 1;
+        end;
+      end;
+      if correctArguments == 0
+        message = sprintf('\n%s\n%s\n%s\n', ...
+          'If arguments are passed to the buildSBML script we expect 2 arguments:', ...
+          '1) the full path to the include directory', ...
+          '2) the full path to the directory containing the libSBML library');
+        error(message);
+      else
+        % arguments are fine - go ahead and build
+        build_unix(matlab_octave, location, writeAccess, bit64, ...
+                   include_dir_supplied, lib_dir_supplied);
+      end;
+    else
+      build_unix(matlab_octave, location, writeAccess, bit64);
+    end;
+  else
+    message = sprintf('\n%s\n%s\n', ...
+      'Unable to determine the type of operating system in use.', ...
+      'Please contact libsbml-team@caltech.edu to help resolve this problem.');
+      error(message);
+  end;
+
+  disp(sprintf('\n%s%s\n', 'Successfully finished. ', ...
+               'If appropriate, please run "installSBML" next.'));
+
+
+% =========================================================================
+% Support functions.
+% =========================================================================
+
+%
+%
+% Is this windows
+% Mac OS X 10.7 Lion returns true for a call to ispc()
+% since we were using that to distinguish between windows and macs we need
+% to catch this
+% ------------------------------------------------------------------------
+function y = isWindows()
+
+  y = 1;
+
+  if isunix()
+    y = 0;
+    return;
+  end;
+
+  if ismac()
+    y = 0;
+    return;
+  end;
+
+  if ~ispc()
+    message = sprintf('\n%s\n%s\n', ...
+      'Unable to determine the type of operating system in use.', ...
+      'Please contact libsbml-team@caltech.edu to help resolve this problem.');
+    error(message);
+  end;
+
+%
+% Assess our computing environment.
+% -------------------------------------------------------------------------
+function [matlab_octave, bit64] = check_system()
+  disp('* Doing preliminary checks of runtime environment ...');
+
+  if (strcmp(isoctave(), '0'))
+    matlab_octave = 'MATLAB';
+    disp('  - This appears to be MATLAB and not Octave.');
+  else
+    matlab_octave = 'Octave';
+    disp('  - This appears to be Octave and not MATLAB.');
+  end;
+
+  bit64 = 32;
+  if isWindows()
+    if strcmp(computer(), 'PCWIN64') == 1
+      bit64 = 64;
+      disp(sprintf('  - %s reports the OS is Windows 64-bit.', matlab_octave));
+    else
+      disp(sprintf('  - %s reports the OS is Windows 32-bit.', matlab_octave));
+    end;
+  elseif ismac()
+    if strcmp(computer(), 'MACI64') == 1
+      bit64 = 64;
+      disp(sprintf('  - %s reports the OS is 64-bit MacOS.', matlab_octave));
+    else
+      % Reading http://www.mathworks.com/help/techdoc/ref/computer.html
+      % it is still not clear to me what a non-64-bit MacOS will report.
+      % Let's not assume the only other alternative is 32-bit, since we
+      % actually don't care here.  Let's just say "macos".
+      %
+      disp(sprintf('  - %s reports the OS is MacOS.', matlab_octave));
+    end;
+  elseif isunix()
+    if strcmp(computer(), 'GLNXA64') == 1
+      bit64 = 64;
+      disp(sprintf('  - %s reports the OS is 64-bit Linux.', matlab_octave));
+    else
+      disp(sprintf('  - %s reports the OS is 32-bit Linux.', matlab_octave));
+    end;
+  end;
+
+
+%
+% Assess our location in the file system.
+% -------------------------------------------------------------------------
+% Possible values returned:
+%   LOCATION:
+%     'installed'  -> installation directory
+%     'source'    -> libsbml source tree
+%
+%  WRITEACCESS:
+%     1 -> we can write in this directory
+%     0 -> we can't write in this directory
+%
+function [location, writeAccess, in_installer] = check_location(matlab_octave)
+  disp('* Trying to establish our location ...');
+
+  % This is where things get iffy.  There are a lot of possibilities, and
+  % we have to resort to heuristics.
+  %
+  % Linux and Mac: we look for 2 possibilities
+  % - installation dir ends in "libsbml/bindings/matlab"
+  %   Detect it by looking for ../../VERSION.txt.
+  %   Assume we're in .../share/libsbml/bindings/matlab and that our
+  %   library is in   .../lib/
+  %
+  % - source dir ends in "libsbml/src/bindings/matlab"
+  %   Detect it by looking for ../../../VERSION.txt.
+  %   Assume our library is in ../../
+  %
+
+  [remain, first] = fileparts(pwd);
+  if strcmpi(matlab_octave, 'matlab')
+    if ~strcmp(first, 'matlab')
+      error_incorrect_dir('matlab');
+    else
+      disp('  - We are in the libSBML subdirectory for Matlab.');
+    end;
+  else
+    if ~strcmp(first, 'octave')
+      error_incorrect_dir('octave');
+    else
+      disp('  - We are in the libSBML subdirectory for Octave.');
+    end;
+  end;
+
+  in_installer = 0;
+  [above_bindings, bindings] = fileparts(remain);
+  if exist(fullfile(above_bindings, 'VERSION.txt'))
+    disp('  - We appear to be in the installation target directory.');
+    in_installer = 1;
+    if isWindows()
+      location = above_bindings;
+    else
+      location = 'installed';
+    end;
+  else
+    [libsbml_root, src] = fileparts(above_bindings);
+    if exist(fullfile(libsbml_root, 'VERSION.txt'))
+      disp('  - We appear to be in the libSBML source tree.');
+      if isWindows()
+        location = libsbml_root;
+      else
+        location = 'source';
+      end;
+    else
+      % We don't know where we are.
+      if strcmpi(matlab_octave, 'MATLAB')
+        error_incorrect_dir('matlab');
+      else
+        error_incorrect_dir('octave');
+      end;
+    end;
+  end;
+
+  % Test that it looks like we have the expected pieces in this directory.
+  % We don't want to assume particular paths, because we might be
+  % getting run from the libSBML source tree or the installed copy of
+  % the matlab bindings sources.  So, we test for just a couple of
+  % things: the tail of the name of the directory in which this file is
+  % located (should be either "matlab" or "octave") and the presence of
+  % another file, "OutputSBML.c", which became part of libsbml at the
+  % same time this new build scheme was introduced.
+
+  our_name   = sprintf('%s.m', mfilename);
+  other_name = 'OutputSBML.c';
+  if ~exist(fullfile(pwd, our_name), 'file') ...
+        || ~exist(fullfile(pwd, other_name), 'file')
+    error_incorrect_dir('matlab');
+  end;
+
+  % Check whether we have write access to this directory.
+
+  fid = fopen('temp.txt', 'w');
+  writeAccess = 1;
+  if fid == -1
+    disp('  - We do not have write access here -- will write elsewhere.');
+    writeAccess = 0;
+  else
+    disp('  - We have write access here!  That makes us happy.');
+    fclose(fid);
+    delete('temp.txt');
+  end;
+
+
+%
+% Find include and library dirs (Linux & Mac case).
+% -------------------------------------------------------------------------
+% Return values:
+%   INCLUDE -> the full path to the include directory
+%   LIB     -> the full path to the libsbml library directory
+%
+function [include, lib] = find_unix_dirs(location, bit64)
+  disp('* Locating libSBML library and include files ...');
+
+  % The 'location' argument guides us:
+  % 'installed'  -> installation directory
+  %    look for libsbml.so or libsbml.dylib in ../../../lib{64}/
+  % 'source'    -> libsbml source tree
+  %    look for libsbml.so or libsbml.dylib in ../../.libs/
+
+  if ismac()
+    libname = 'libsbml.dylib';
+  else
+    libname = 'libsbml.so';
+  end;
+
+  if strcmpi(location, 'source')
+    [parent, here] = fileparts(pwd);     % ..
+    [parent, here] = fileparts(parent);  % ..
+    lib = fullfile(parent, '.libs');
+    libfile = fullfile(lib, libname);
+    if exist(libfile)
+      disp(sprintf('  - Found %s', libfile));
+    else
+      lib = 'unfound';
+    end;
+
+    include = parent;
+    if exist(include)
+      disp(sprintf('  - Root of includes is %s', include));
+    else
+      error_incorrect_dir('matlab');
+    end;
+  else
+    % location is 'installed'
+    [parent, here] = fileparts(pwd);     % ..
+    [parent, here] = fileparts(parent);  % ..
+    [parent, here] = fileparts(parent);  % ..
+    lib = fullfile(parent, 'lib');
+    libfile = fullfile(lib, libname);
+    if exist(libfile)
+      disp(sprintf('  - Found %s', libfile));
+    else
+      if bit64 == 64
+        % Try one more common alternative.
+        lib = fullfile(parent, 'lib64');
+        libfile = fullfile(lib, libname);
+        if exist(libfile)
+          disp(sprintf('  - Found %s', libfile));
+        else
+          lib = 'unfound';
+        end;
+      end;
+    end;
+
+    % In the installed target directory, include will be something
+    % like /usr/local/include
+    %
+    include = fullfile(parent, 'include');
+    if exist(include)
+      disp(sprintf('  - Root of includes is %s', include));
+    else
+      error_incorrect_dir('matlab');
+    end;
+  end;
+
+
+%
+% we on occasion allow the user to supply arguments for the directories
+% Check include and library dirs (Linux & Mac case) supplied exist
+% -------------------------------------------------------------------------
+function y = checkSuppliedArguments(include_supplied, lib_supplied)
+  disp('* Checking for libSBML library and include files ...');
+
+  % assume we find them
+  y = 1;
+
+  % check the include directory supplied exists
+  if exist(include_supplied)
+    disp(sprintf('  - Root of includes found at %s', include_supplied));
+  else
+    disp(sprintf('  - Root of includes NOT found at %s', include_supplied));
+    y = 0;
+  end;
+
+  % check that the correct library is found
+  if ismac()
+    libname = 'libsbml.dylib';
+  else
+    libname = 'libsbml.so';
+  end;
+
+  libfile = fullfile(lib_supplied, libname);
+  if exist(libfile)
+    disp(sprintf('  - Found %s', libfile));
+  else
+    disp(sprintf('  - NOT found %s', libfile));
+    y = 0;
+  end;
+
+
+%
+% Drive the build process (Windows version).
+% -------------------------------------------------------------------------
+function build_win(matlab_octave, root, writeAccess, bit64, in_installer)
+
+  disp('Phase 2: tests for libraries and other dependencies ...');
+  [include_dir, lib] = find_win_dirs(root, bit64, in_installer);
+
+  % check that the libraries can all be found
+  found = 1;
+  for i = 1:length(lib)
+    if (exist(lib{i}) ~= 0)
+      disp(sprintf('%s found', lib{i}));
+    else
+      disp(sprintf('%s not found', lib{i}));
+      found = 0;
+    end;
+  end;
+
+  if (found == 0)
+    error (sprintf('Not all dependencies could be found\n%s%s', ...
+    'expected the dependencies to be in ', fileparts(lib{1})));
+  else
+    disp('  - All dependencies found.  Good.');
+  end;
+
+
+  % if we do not have write access need to find somewhere else to build
+  if (writeAccess == 0)% must be 0; 1 is for testing
+    % create a new dir in the users path
+    this_dir = pwd;
+    if (matlab_octave == 'MATLAB')
+      user_dir = userpath;
+      user_dir = user_dir(1:length(user_dir)-1);
+    else
+      % This is Octave.  Octave doesn't have 'userpath'.
+      user_dir = tempdir;
+    end;
+    disp(sprintf('  - Copying library files to %s ...', user_dir));
+    if (copyLibraries(this_dir, user_dir, lib) == 1)
+      disp('  - Copying of library files successful.');
+    else
+      error('Cannot copy library files on this system');
+    end;
+    disp(sprintf('  - Copying MATLAB binding files to %s ...', user_dir));
+    if (copyMatlabDir(this_dir, user_dir) == 1)
+      disp('- Copying of MATLAB binding files successful');
+    else
+      error('Cannot copy matlab binding files on this system');
+    end;
+  else
+    this_dir = pwd;
+    user_dir = pwd;
+    % copy the library files to here
+    disp(sprintf('  - Copying library files to %s ...', user_dir));
+    if (copyLibraries(this_dir, user_dir, lib) == 1)
+      disp('  - Copying of library files successful');
+    else
+      error('Cannot copy library files on this system');
+    end;
+  end;
+
+  % build the files
+  compile_mex(include_dir, lib{1}, matlab_octave);
+
+%
+% Find include and library dirs (windows case).
+% -------------------------------------------------------------------------
+% Return values:
+%   INCLUDE -> the full path to the include directory
+%   LIB     -> an array of the libsbml dependency libraries
+%
+function [include, lib] = find_win_dirs(root, bit64, in_installer)
+  disp('* Locating libSBML library and include files ...');
+
+  % in the src tree we expect all lib dlls to be in root/win/bin
+  %                 and the include dir to be root/src
+  % in the installer the lib will be in root/win32/lib
+  %                  the dll will be in root/win32/bin
+  %                 and the include dir to be root/win32/include
+  % and for 64 bits the win32 will be win64
+  if (in_installer == 0)
+    bin_dir = [root, filesep, 'win', filesep, 'bin'];
+    lib_dir = [root, filesep, 'win', filesep, 'bin'];
+    include = [root, filesep, 'src'];
+  else
+    if (bit64 == 32)
+      bin_dir = [root, filesep, 'win32', filesep, 'bin'];
+      lib_dir = [root, filesep, 'win32', filesep, 'lib'];
+      include = [root, filesep, 'win32', filesep, 'include'];
+    else
+      bin_dir = [root, filesep, 'win64', filesep, 'bin'];
+      lib_dir = [root, filesep, 'win64', filesep, 'lib'];
+      include = [root, filesep, 'win64', filesep, 'include'];
+    end;
+  end;
+
+  disp(sprintf('  - Checking for the existence of the %s directory ...\n', bin_dir));
+  % and are the libraries in this directory
+  if ((exist(bin_dir, 'dir') ~= 7) || (exist([bin_dir, filesep, 'libsbml.dll']) == 0))
+      disp(sprintf('%s directory could not be found\n\n%s\n%s %s', bin_dir, ...
+          'The build process assumes that the libsbml binaries', ...
+          'exist at', bin_dir));
+      message = sprintf('\n%s\n%s', ...
+          'if they are in another directory please enter the ', ...
+          'full path to reach the directory from this directory: ');
+      new_bin_dir = input(message, 's');
+
+      if (exist(new_bin_dir, 'dir') == 0)
+          error('libraries could not be found');
+      else
+        bin_dir = new_bin_dir;
+        if (in_installer == 0)
+          lib_dir = bin_dir;
+        end;
+      end;
+  end;
+
+  if (~strcmp(bin_dir, lib_dir))
+    disp(sprintf('  - Checking for the existence of the %s directory ...\n', lib_dir));
+    if (exist(lib_dir, 'dir') ~= 7)
+        disp(sprintf('%s directory could not be found\n\n%s\n%s %s', lib_dir, ...
+            'The build process assumes that the libsbml binaries', ...
+            'exist at', lib_dir));
+        message = sprintf('\n%s\n%s', ...
+            'if they are in another directory please enter the ', ...
+            'full path to reach the directory from this directory: ');
+        new_lib_dir = input(message, 's');
+
+        if (exist(new_lib_dir, 'dir') == 0)
+            error('libraries could not be found');
+        else
+          lib_dir = new_lib_dir;
+        end;
+    end;
+  end;
+
+
+% check that the include directory exists
+  disp(sprintf('  - Checking for the existence of the %s directory ...\n', include));
+  if (exist(include, 'dir') ~= 7)
+      disp(sprintf('%s directory could not be found\n\n%s\n%s %s', include, ...
+          'The build process assumes that the libsbml include files', ...
+          'exist at', include));
+      message = sprintf('\n%s\n%s', ...
+          'if they are in another directory please enter the ', ...
+          'full path to reach the directory from this directory: ');
+      new_inc_dir = input(message, 's');
+
+      if (exist(new_inc_dir, 'dir') == 0)
+          error('include files could not be found');
+      else
+        include = new_inc_dir;
+      end;
+  end;
+
+  % create the array of library files
+  if (bit64 == 32)
+    if (in_installer == 0)
+      lib{1} = [bin_dir, filesep, 'libsbml.lib'];
+      lib{2} = [bin_dir, filesep, 'libsbml.dll'];
+      lib{3} = [bin_dir, filesep, 'libxml2.lib'];
+      lib{4} = [bin_dir, filesep, 'libxml2.dll'];
+      lib{5} = [bin_dir, filesep, 'iconv.lib'];
+      lib{6} = [bin_dir, filesep, 'iconv.dll'];
+      lib{7} = [bin_dir, filesep, 'bzip2.lib'];
+      lib{8} = [bin_dir, filesep, 'bzip2.dll'];
+      lib{9} = [bin_dir, filesep, 'zdll.lib'];
+      lib{10} = [bin_dir, filesep, 'zlib1.dll'];
+    else
+      lib{1} = [lib_dir, filesep, 'libsbml.lib'];
+      lib{2} = [bin_dir, filesep, 'libsbml.dll'];
+      lib{3} = [lib_dir, filesep, 'libxml2.lib'];
+      lib{4} = [bin_dir, filesep, 'libxml2.dll'];
+      lib{5} = [lib_dir, filesep, 'iconv.lib'];
+      lib{6} = [bin_dir, filesep, 'iconv.dll'];
+      lib{7} = [lib_dir, filesep, 'bzip2.lib'];
+      lib{8} = [bin_dir, filesep, 'bzip2.dll'];
+      lib{9} = [lib_dir, filesep, 'zdll.lib'];
+      lib{10} = [bin_dir, filesep, 'zlib1.dll'];
+    end;
+  else
+    if (in_installer == 0)
+      lib{1} = [bin_dir, filesep, 'libsbml.lib'];
+      lib{2} = [bin_dir, filesep, 'libsbml.dll'];
+      lib{3} = [bin_dir, filesep, 'libxml2.lib'];
+      lib{4} = [bin_dir, filesep, 'libxml2.dll'];
+      lib{5} = [bin_dir, filesep, 'libiconv.lib'];
+      lib{6} = [bin_dir, filesep, 'libiconv.dll'];
+      lib{7} = [bin_dir, filesep, 'bzip2.lib'];
+      lib{8} = [bin_dir, filesep, 'libbz2.dll'];
+      lib{9} = [bin_dir, filesep, 'zdll.lib'];
+      lib{10} = [bin_dir, filesep, 'zlib1.dll'];
+    else
+      lib{1} = [lib_dir, filesep, 'libsbml.lib'];
+      lib{2} = [bin_dir, filesep, 'libsbml.dll'];
+      lib{3} = [lib_dir, filesep, 'libxml2.lib'];
+      lib{4} = [bin_dir, filesep, 'libxml2.dll'];
+      lib{5} = [lib_dir, filesep, 'libiconv.lib'];
+      lib{6} = [bin_dir, filesep, 'libiconv.dll'];
+      lib{7} = [lib_dir, filesep, 'bzip2.lib'];
+      lib{8} = [bin_dir, filesep, 'libbz2.dll'];
+      lib{9} = [lib_dir, filesep, 'zdll.lib'];
+      lib{10} = [bin_dir, filesep, 'zlib1.dll'];
+    end;
+  end;
+
+
+%
+% Drive the build process (Mac and Linux version).
+% -------------------------------------------------------------------------
+function build_unix(varargin)
+
+  matlab_octave = varargin{1};
+  location = varargin{2};
+  writeAccess = varargin{3};
+  bit64 = varargin{4};
+
+  if (nargin == 4)
+    [include, lib] = find_unix_dirs(location, bit64);
+  else
+    include = varargin{5};
+    lib = varargin{6};
+  end;
+
+  if writeAccess == 1
+    % We can write to the current directory.  Our job is easy-peasy.
+    %
+    compile_mex(include, lib, matlab_octave);
+  else
+    % We don't have write access to this directory.  Copy the files
+    % somewhere else, relocate to there, and then try building.
+    %
+    working_dir = find_working_dir(matlab_octave);
+    current_dir = pwd;
+    copy_matlab_dir(current_dir, working_dir);
+    cd(working_dir);
+    compile_mex(include, lib, matlab_octave);
+    cd(current_dir);
+  end;
+
+
+%
+% Run mex/mkoctfile.
+% -------------------------------------------------------------------------
+function compile_mex(include_dir, library_dir, matlab_octave)
+  disp(sprintf('* Creating mex files in %s', pwd));
+
+  % list the possible opts files to be tried
+  optsfiles = {'', './mexopts-osx109.sh', './mexopts-osx108.sh', './mexopts-lion.sh', './mexopts-xcode43.sh', './mexopts-xcode45.sh', './mexopts-R2009-R2010.sh', './mexopts-R2008.sh', './mexopts-R2007.sh'};
+
+  success = 0;
+  n = 1;
+
+  if strcmpi(matlab_octave, 'matlab')
+    while(~success && n < length(optsfiles))
+        try
+          if ~isempty(optsfiles{n})
+              disp(sprintf('* Trying to compile with mexopts file: %s', optsfiles{n}));
+          end;
+          success = do_compile_mex(include_dir, library_dir, matlab_octave, optsfiles{n});
+        catch err
+          disp(' ==> The last attempt to build the Matlab bindings failed. We will try again with a different mexopts file');
+        end;
+      n = n + 1;
+    end;
+  else
+    success = do_compile_mex(include_dir, library_dir, matlab_octave, optsfiles{n});
+  end;
+
+  if ~success
+    error('Build failed');
+  end;
+
+function success = do_compile_mex(include_dir, library_dir, matlab_octave, altoptions)
+
+   inc_arg    = ['-I', include_dir];
+   inc_arg2   = ['-I', library_dir];
+  lib_arg    = ['-L', library_dir];
+  added_args = [' '];
+
+  if ismac() || isunix()
+    added_args = ['-lsbml'];
+  end;
+
+  % The messy file handle stuff is because this seems to be the best way to
+  % be able to pass arguments to the feval function.
+
+  if strcmpi(matlab_octave, 'matlab')
+    % on windows the command needs to be different
+    if isWindows()
+      fhandle = @mex;
+      disp('  - Building TranslateSBML ...');
+      feval(fhandle, 'TranslateSBML.c', inc_arg, inc_arg2, library_dir, '-DWIN32');
+      disp('  - Building OutputSBML ...');
+      feval(fhandle, 'OutputSBML.c', inc_arg, inc_arg2, library_dir, '-DWIN32');
+    else
+      fhandle = @mex;
+      disp('  - Building TranslateSBML ...');
+      if ~isempty(altoptions)
+        feval(fhandle, 'TranslateSBML.c', '-f', altoptions, inc_arg, inc_arg2, lib_arg, added_args);
+      else
+        feval(fhandle, 'TranslateSBML.c', inc_arg, inc_arg2, lib_arg, added_args);
+      end;
+      disp('  - Building OutputSBML ...');
+      if ~isempty(altoptions)
+        feval(fhandle, 'OutputSBML.c', '-f', altoptions, inc_arg, inc_arg2, lib_arg, added_args);
+      else
+        feval(fhandle, 'OutputSBML.c', inc_arg, inc_arg2, lib_arg, added_args);
+      end;
+    end;
+  else
+    if isWindows()
+      fhandle = @mkoctfile;
+      disp('  - Building TranslateSBML ...');
+      feval(fhandle, '--mex', 'TranslateSBML.c', '-DUSE_OCTAVE', inc_arg, inc_arg2, ...
+            '-lbz2', '-lz', library_dir);
+      disp('  - Building OutputSBML ...');
+      feval(fhandle, '--mex', 'OutputSBML.c', '-DUSE_OCTAVE', inc_arg, inc_arg2, ...
+            '-lbz2', '-lz', library_dir);
+    else
+      fhandle = @mkoctfile;
+      disp('  - Building TranslateSBML ...');
+      feval(fhandle, '--mex', 'TranslateSBML.c', '-DUSE_OCTAVE', inc_arg, inc_arg2, ...
+            '-lbz2', '-lz', lib_arg, added_args);
+      disp('  - Building OutputSBML ...');
+      feval(fhandle, '--mex', 'OutputSBML.c', '-DUSE_OCTAVE', inc_arg, inc_arg2, ...
+            '-lbz2', '-lz', lib_arg, added_args);
+    end;
+%   mkoctfile --mex TranslateSBML.c -DUSE_OCTAVE inc_arg inc_arg2 -lbz2 -lz lib_arg;
+  end;
+
+  transFile = strcat('TranslateSBML.', mexext());
+  outFile = strcat('OutputSBML.', mexext());
+  if ~exist(transFile) || ~exist(outFile)
+    success = 0;
+  else
+    success = 1;
+  end;
+
+
+
+%
+% Find a directory where we can copy our files (Linux & Mac version).
+%
+% -------------------------------------------------------------------------
+function working_dir = find_working_dir(matlab_octave)
+  if strcmpi(matlab_octave, 'matlab')
+    user_dir = userpath;
+    user_dir = user_dir(1:length(user_dir)-1);
+  else
+    % This is Octave.  Octave doesn't have 'userpath'.
+    user_dir = tempdir;
+  end;
+
+  working_dir = fullfile(user_dir, 'libsbml');
+
+  if ~exist(working_dir, 'dir')
+    [success, msg, msgid] = mkdir(working_dir);
+    if ~success
+      error(sprintf('\n%s\n%s\n', msg, 'Build failed.'));
+    end;
+  end;
+
+
+%
+% Copy the matlab binding directory, with tests.
+%
+% This also creates the necessary directories and subdirectories.
+% -------------------------------------------------------------------------
+function copy_matlab_dir(orig_dir, working_dir)
+  disp(sprintf('  - Copying files to %s', working_dir));
+
+  % Copy files from src/bindings/matlab.
+
+  [success, msg, msgid] = copyfile('TranslateSBML.c', working_dir);
+  if ~success
+    error(sprintf('\n%s\n%s\n', msg, 'Build failed.'));
+  end;
+
+  [success, msg, msgid] = copyfile('OutputSBML.c', working_dir);
+  if ~success
+    error(sprintf('\n%s\n%s\n', msg, 'Build failed.'));
+  end;
+
+  [success, msg, msgid] = copyfile('*.m', working_dir);
+  if ~success
+    error(sprintf('\n%s\n%s\n', msg, 'Build failed.'));
+  end;
+
+  [success, msg, msgid] = copyfile('*.xml', working_dir);
+  if ~success
+    error(sprintf('\n%s\n%s\n', msg, 'Build failed.'));
+  end;
+
+  % Copy files from src/bindings/matlab/test.
+
+  test_subdir = fullfile(working_dir, 'test');
+
+  if ~exist(test_subdir, 'dir')
+    [success, msg, msgid] = mkdir(test_subdir);
+    if ~success
+      error(sprintf('\n%s\n%s\n', msg, 'Build failed.'));
+    end;
+  end;
+
+  cd 'test';
+
+  [success, msg, msgid] = copyfile('*.m', test_subdir);
+  if ~success
+    error(sprintf('\n%s\n%s\n', msg, 'Build failed.'));
+  end;
+
+  % Copy files from src/bindings/matlab/test/test-data/.
+
+  test_data_subdir = fullfile(test_subdir, 'test-data');
+
+  if ~exist(test_data_subdir, 'dir')
+    [success, msg, msgid] = mkdir(test_data_subdir);
+    if ~success
+      error(sprintf('\n%s\n%s\n', msg, 'Build failed.'));
+    end;
+  end;
+
+  cd 'test-data';
+
+  [success, msg, msgid] = copyfile('*.xml', test_data_subdir);
+  if ~success
+    error(sprintf('\n%s\n%s\n', msg, 'Build failed.'));
+  end;
+
+
+%
+% Print error about being in the wrong location.
+% -------------------------------------------------------------------------
+function error_incorrect_dir(expected)
+  message = sprintf('\n%s\n%s%s%s\n%s\n%s%s%s\n%s\n', ...
+      'This script needs to be invoked from the libSBML subdirectory ', ...
+      'ending in "', expected, '". However, it is being invoked', ...
+      'from the directory', '   "', pwd, '"', ...
+      'instead.  Please change your working directory and re-run this script.');
+  error(message);
+
+
+
+%
+% Copy library files to the given directory on windows
+% -------------------------------------------------------------------------
+function copied = copyLibraries(orig_dir, target_dir, lib)
+
+  copied = 0;
+  cd (target_dir);
+
+  % if we moving to another location create a libsbml directory
+  % if we are staying in src/matlab/bindings copy here
+  if (~strcmp(orig_dir, target_dir))
+    if (exist('libsbml', 'dir') == 0)
+      mkdir('libsbml');
+    end;
+    cd libsbml;
+  end;
+  new_dir = pwd;
+  % copy the necessary files
+  for i = 1:length(lib)
+    copyfile(lib{i}, new_dir);
+  end;
+  cd(orig_dir);
+
+  copied = 1;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  % creates a copy of the matlab binding directory with tests
+  function copied = copyMatlabDir(orig_dir, target_dir)
+
+    copied = 0;
+    cd (target_dir);
+    % create libsbml dir
+    if (exist('libsbml', 'dir') == 0)
+      mkdir('libsbml');
+    end;
+    cd libsbml;
+    new_dir = pwd;
+
+    %copy files to libsbml
+    cd(orig_dir);
+    copyfile('TranslateSBML.c', new_dir);
+    copyfile('OutputSBML.c', new_dir);
+    copyfile('*.m', new_dir);
+    copyfile('*.xml', new_dir);
+    cd(new_dir);
+%     delete ('buildLibSBML.m');
+
+    % create test dir
+    testdir = fullfile(pwd, 'test');
+    if (exist(testdir, 'dir') == 0)
+      mkdir('test');
+    end;
+    cd('test');
+    new_dir = pwd;
+
+    %copy test files
+    cd(orig_dir);
+    cd('test');
+    copyfile('*.m', new_dir);
+
+    % create test-data dir
+    cd(new_dir);
+    testdir = fullfile(pwd, 'test-data');
+    if (exist(testdir, 'dir') == 0)
+      mkdir('test-data');
+    end;
+    cd('test-data');
+    new_dir = pwd;
+
+    %copy test-data files
+    cd(orig_dir);
+    cd ('test');
+    cd ('test-data');
+    copyfile('*.xml', new_dir);
+
+    %navigate to new libsbml directory
+    cd(new_dir);
+    cd ..;
+    cd ..;
+
+    % put in some tests here
+    copied = 1;
+
+
+% =========================================================================
+% The end.
+%
+% Please leave the following for [X]Emacs users:
+% Local Variables:
+% matlab-indent-level: 2
+% fill-column: 72
+% End:
+% =========================================================================
+
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/THIRD_PARTY_SOFTWARE/SBMLimportExport/auxiliary/installSBML.m b/IQMtools V1.2.2.2/IQMlite/auxiliary/THIRD_PARTY_SOFTWARE/SBMLimportExport/auxiliary/installSBML.m
new file mode 100644
index 0000000000000000000000000000000000000000..6d3a2355d14437285dd9010f4c8d7742fcc26690
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/THIRD_PARTY_SOFTWARE/SBMLimportExport/auxiliary/installSBML.m	
@@ -0,0 +1,430 @@
+function installSBML(varargin)
+% Installs the MATLAB language interface for libSBML.
+%
+% This script assumes that the libsbml matlab binding executables files already
+% exist; either because the user has built them using buildSBML (only
+% in the src release) or the binding is being installed from an installer.
+%
+% Currently prebuilt executables are only available in the windows installers
+% of libSBML.
+%
+% For Linux or Mac users this means that you need to build libsbml and then
+% run the buildSBML script.
+
+
+% Filename    : installSBML.m
+% Description : install matlab binding
+% Author(s)   : SBML Team <sbml-team@caltech.edu>
+% Organization: EMBL-EBI
+% 
+% This file is part of libSBML.  Please visit http://sbml.org for more
+% information about SBML, and the latest version of libSBML.
+%
+% Copyright (C) 2013-2014 jointly by the following organizations:
+%     1. California Institute of Technology, Pasadena, CA, USA
+%     2. EMBL European Bioinformatics Institute (EMBL-EBI), Hinxton, UK
+%     3. University of Heidelberg, Heidelberg, Germany
+%
+% Copyright (C) 2009-2013 jointly by the following organizations: 
+%     1. California Institute of Technology, Pasadena, CA, USA
+%     2. EMBL European Bioinformatics Institute (EMBL-EBI), Hinxton, UK
+%  
+% Copyright (C) 2006-2008 by the California Institute of Technology,
+%     Pasadena, CA, USA 
+%  
+% Copyright (C) 2002-2005 jointly by the following organizations: 
+%     1. California Institute of Technology, Pasadena, CA, USA
+%     2. Japan Science and Technology Agency, Japan
+% 
+% This library is free software; you can redistribute it and/or modify it
+% under the terms of the GNU Lesser General Public License as published by
+% the Free Software Foundation.  A copy of the license agreement is provided
+% in the file named "LICENSE.txt" included with this software distribution
+% and also available online as http://sbml.org/software/libsbml/license.html
+%
+
+% =========================================================================
+% Main loop.
+% =========================================================================
+
+% look at input arguments
+
+  [verbose, directory] = checkInputArguments(varargin);
+      
+  myDisp({'Installing the libSBML interface.'},  verbose);
+
+ [matlab_octave]  = check_system(verbose);
+ 
+ [functioning, located] = checkForExecutables(matlab_octave, directory, verbose);
+ 
+ if (functioning == 0)
+   if (located == 0)
+     % we didnt find executables where we first looked
+     % try again with a different directory
+     if (isWindows() == 0)
+       if (strcmp(directory, '/usr/local/lib') == 0)
+         directory = '/usr/local/lib';
+         functioning = checkForExecutables(matlab_octave, directory, verbose);
+       end;
+     else
+       if (strcmp(directory, pwd) == 0)
+         directory = pwd;
+         functioning = checkForExecutables(matlab_octave, directory, verbose);
+       end;
+     end;
+   else
+     % we found executables but they did not work
+     error('%s%s%s\n%s%s', ...
+       'Executables were located at ', directory, ' but failed to execute', ...
+       'Please contact the libSBML team libsbml-team@caltech.edu ', ...
+       'for further assistance');
+   end;
+ end;
+
+ if (functioning == 1)
+   myDisp({'Installation successful'}, verbose);
+ end;
+end
+  
+  
+  
+% =========================================================================
+% Helper functions
+% =========================================================================
+
+% check any input arguments
+%--------------------------------------------------------------------------
+function [verbose, directory] = checkInputArguments(input)
+
+  numArgs = length(input);
+  
+  if (numArgs > 2)
+    reportInputArgumentError('Too many arguments to installSBML');
+  end;
+  
+  if (numArgs == 0)
+    verbose = 1;
+    if (isWindows() == 1)
+      directory = pwd;
+    else
+      directory = '/usr/local/lib';
+    end;
+  elseif (numArgs == 1)
+    directory = input{1};
+    verbose = 1;
+  else
+    directory = input{1};
+    verbose = input{2};
+  end;
+ 
+  if (verbose ~= 0 && verbose ~= 1)
+    reportInputArgumentError('Incorrect value for verbose flag');
+  end;
+  
+  if (ischar(directory) ~= 1)
+    reportInputArgumentError('Directory value should be a string');
+  elseif(exist(directory, 'dir') ~= 7)
+    reportInputArgumentError('Directory value should be a directory');
+  end;
+
+end
+% display error message relating to input arguments
+%---------------------------------------------------
+function reportInputArgumentError(message)
+
+    error('%s\n%s\n\t%s%s\n\t%s%s\n\t\t%s', message, ...
+      'Arguments are optional but if present:', ...
+      'the first should be a string representing the directory containing ', ...
+      'the executables', 'the second should be a flag (0 or 1) indicating ', ...
+      'whether messages should be displayed ', ...
+      '0 - no messages; 1 - display messages');
+end
+      
+
+
+% display error messages iff verbose = 1
+%-----------------------------------------
+function myDisp(message, verbose)
+
+  outputStr = '';
+
+  if (verbose == 1)
+    for i=1:length(message)
+      outputStr = sprintf('%s\n%s', outputStr, message{i});
+    end;
+  end;
+ 
+  disp(outputStr);
+end
+
+%
+%
+% Is this windows
+% Mac OS X 10.7 Lion returns true for a call to ispc()
+% since we were using that to distinguish between windows and macs we need
+% to catch this
+% ------------------------------------------------------------------------
+function y = isWindows()
+
+  y = 1;
+  
+  if isunix()
+    y = 0;
+    return;
+  end;
+  
+  if ismac()
+    y = 0;
+    return;
+  end;
+  
+  if ~ispc()
+    error('\n%s\n%s\n', ...
+      'Unable to determine the type of operating system in use.', ...
+      'Please contact libsbml-team@caltech.edu to help resolve this problem.');
+  end;
+end   
+
+% 
+% Assess our computing environment.
+% -------------------------------------------------------------------------
+function [matlab_octave] = check_system(verbose)
+ message{1} = '* Doing preliminary checks of runtime environment ...';
+
+  if (strcmp(isoctave(), '0'))
+    matlab_octave = 'MATLAB';
+    message{2} = '  - This appears to be MATLAB and not Octave.';
+  else
+    matlab_octave = 'Octave';
+    message{2} = '  - This appears to be Octave and not MATLAB.';
+  end;
+  
+  myDisp(message, verbose);
+end
+
+%
+% check for executables and that they are right ones
+% -------------------------------------------------------------------------
+function [success, located] = checkForExecutables(matlab_octave, directory, verbose)  
+  message{1} = 'Checking for executables in ';
+  message{2} = sprintf('\t%s', directory);
+  
+  transFile = strcat('TranslateSBML.', mexext());
+  outFile = strcat('OutputSBML.', mexext());
+  
+  thisDirTFile = fullfile(pwd(), transFile);
+  thisDirOFile = fullfile(pwd(), outFile);
+
+  success = 0;
+  located = 0;
+  
+  if strcmpi(matlab_octave, 'matlab')
+    if (~(exist([directory, filesep, transFile], 'file') ~= 0 ...
+        && exist([directory, filesep, outFile], 'file') ~= 0))
+      located = 0;
+    else 
+      located = 1;
+    end;
+  else
+    % octave is much more picky about whether the files exist
+  	% it wants to find the libraries at the same time
+  	% exist throws an exception if it cannot find them
+    if (~(myExist(directory, transFile) ~= 0 ...
+        && myExist(directory, outFile) ~= 0))
+      located = 0;
+    else 
+      located = 1;
+    end;
+  end;
+
+  if (located == 1)
+    % we have found the executables where the user says but 
+    % need to check that there are not other files on the path
+    t = which(transFile);
+    o = which(outFile);
+      
+    % exclude the current dir
+    currentT = strcmp(t, thisDirTFile);
+    currentO = strcmp(t, thisDirOFile);
+    found = 0;
+    if (currentT == 1 && currentO == 1)
+      t_found = 0;
+      if (isempty(t) == 0 && strcmp(t, [directory, filesep, transFile]) == 0)
+        found = 1;
+        t_found = 1;
+      elseif (isempty(o) == 0 && strcmp(o, [directory, filesep, outFile]) == 0)
+        found = 1;
+      end;
+    end;
+    if (found == 1)  
+      if (t_found == 1)
+        pathDir = t;
+      else
+        pathDir = o;
+      end;
+      error('%s\n%s\n%s', 'Other libsbml executables found on the path at:', ... 
+        pathDir, ...
+      'Please uninstall these before attempting to install again');
+    end;
+  end;
+
+
+  if (located == 1)
+    message{3} = 'Executables found';
+  else
+    message{3} = 'Executables not found';
+  end;
+
+  
+  myDisp(message, verbose);
+  
+  if (located == 1)
+    % we have found the executables
+    % add the directory to the matlab path
+    added = addDir(directory, verbose);
+    
+    % if addDir returns 0 this may be that the user does not have
+    % permission to add to the path
+    if (added == 0)
+      error('%s%s%s%s\n%s%s', ...
+        'The directory containing the executables could not ', ...
+        'be added to the ', matlab_octave, ' path', ... 
+        'You may need to run in administrator mode or contact your ', ...
+        'network manager if running from a network');
+    elseif (added == 1)
+      % to test the actual files we need to be in the directory
+      % if we happen to be in the src tree where the .m helps files
+      % exist these will get picked up first by the function calls
+      % according to mathworks the only way to avoid this is to cd to the 
+      % right dir 
+      currentDir = pwd();
+      cd(directory);
+      success = doesItRun(matlab_octave, verbose, currentDir);
+      cd (currentDir);
+    end;
+    
+    % at this point if success = 0 it means there was an error running
+    % the files - take the directory out of the path
+    if (success == 0 && added == 1)
+      removeDir(directory, verbose);
+    end;
+  end;
+end
+
+% test the installation
+% -------------------------------------------------------------------------
+function success = doesItRun(matlab_octave, verbose, dirForTest)
+    
+  success = 1;
+  
+  message{1} = 'Attempting to execute functions';
+  myDisp(message, verbose);
+    
+  testFile = fullfile(dirForTest, 'test.xml');
+  
+  if strcmpi(matlab_octave, 'matlab')
+    try
+      M = TranslateSBML(testFile);
+      message{1} = 'TranslateSBML successful';
+    catch ME
+      success = 0;
+      message{1} = sprintf('%s\n%s', 'TranslateSBML failed', ME.message);
+    end;
+  else
+    try
+      M = TranslateSBML(testFile);
+      message{1} = 'TranslateSBML successful';
+    catch
+      success = 0;
+      message{1} = 'TranslateSBML failed';
+    end;
+  end;
+
+  if strcmpi(matlab_octave, 'matlab')
+    outFile = [tempdir, filesep, 'test-out.xml'];
+  else
+    if isWindows()
+      outFile = [tempdir, 'temp', filesep, 'test-out.xml'];
+    else
+      outFile = [tempdir, 'test-out.xml'];
+    end;
+  end;
+      
+  if (success == 1)
+    if strcmpi(matlab_octave, 'matlab')
+      try
+        if (verbose == 1)
+          OutputSBML(M, outFile);
+        else
+          OutputSBML(M, outFile, verbose, verbose);
+        end;
+        message{2} = 'OutputSBML successful';
+      catch ME
+        success = 0;
+        message{2} = sprintf('%s\n%s', 'OutputSBML failed', ME.message);
+      end;
+    else
+      try
+        if (verbose == 1)
+          OutputSBML(M, outFile);
+        else
+          OutputSBML(M, outFile, verbose, verbose);
+        end;
+        message{2} = 'OutputSBML successful';
+      catch
+        success = 0;
+        message{2} = 'OutputSBML failed';
+      end;
+    end;
+  end;
+  
+  myDisp(message, verbose);
+end
+ 
+% add directory to the matlab path
+% -------------------------------------------------------------------------
+function added = addDir(name, verbose)
+
+  added = 0;
+  addpath(name);
+  if (savepath ~= 0)
+    message{1} = sprintf('Adding %s to path ...\nFailed', name);
+  else
+    message{1} = sprintf('Adding %s to path ...\nSuccess', name);
+    added = 1;
+  end;
+  
+  myDisp(message, verbose);
+end
+  
+% remove directory to the matlab path
+% -------------------------------------------------------------------------
+function added = removeDir(name, verbose)
+
+  added = 0;
+  rmpath(name);
+  if (savepath ~= 0)
+    message{1} = sprintf('Removing %s from path ...\nFailed', name);
+  else
+    message{1} = sprintf('Removing %s from path ...\nSuccess', name);
+    added = 1;
+  end;
+  
+  myDisp(message, verbose);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function found = myExist(directory, filename)
+
+
+found = 0;
+dirnames = dir(directory);
+i = 1;
+while (found == 0 && i <= length(dirnames))
+  if (dirnames(i).isdir == 0)
+	  found = strcmp(dirnames(i).name, filename);
+	end;
+	i = i+1;
+end;
+  
+end
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/THIRD_PARTY_SOFTWARE/SBMLimportExport/auxiliary/isFbcEnabled.m b/IQMtools V1.2.2.2/IQMlite/auxiliary/THIRD_PARTY_SOFTWARE/SBMLimportExport/auxiliary/isFbcEnabled.m
new file mode 100644
index 0000000000000000000000000000000000000000..578f8a1efc86f5fcac6f20bec56fd6a173054631
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/THIRD_PARTY_SOFTWARE/SBMLimportExport/auxiliary/isFbcEnabled.m	
@@ -0,0 +1,76 @@
+function fbcEnabled = isFbcEnabled()
+% Checks whether the version of libSBML has been built with 
+% the FBC package extension enabled
+
+% Filename    : isFbcEnabled.m
+% Description : check fbc status
+% Author(s)   : SBML Team <sbml-team@caltech.edu>
+% Organization: EMBL-EBI, Caltech
+% Created     : 2011-02-08
+%
+% This file is part of libSBML.  Please visit http://sbml.org for more
+% information about SBML, and the latest version of libSBML.
+%
+% Copyright (C) 2013-2014 jointly by the following organizations:
+%     1. California Institute of Technology, Pasadena, CA, USA
+%     2. EMBL European Bioinformatics Institute (EMBL-EBI), Hinxton, UK
+%     3. University of Heidelberg, Heidelberg, Germany
+%
+% Copyright (C) 2009-2011 jointly by the following organizations: 
+%     1. California Institute of Technology, Pasadena, CA, USA
+%     2. EMBL European Bioinformatics Institute (EMBL-EBI), Hinxton, UK
+%  
+% Copyright (C) 2006-2008 by the California Institute of Technology,
+%     Pasadena, CA, USA 
+%  
+% Copyright (C) 2002-2005 jointly by the following organizations: 
+%     1. California Institute of Technology, Pasadena, CA, USA
+%     2. Japan Science and Technology Agency, Japan
+% 
+% This library is free software; you can redistribute it and/or modify
+% it under the terms of the GNU Lesser General Public License as
+% published by the Free Software Foundation.  A copy of the license
+% agreement is provided in the file named "LICENSE.txt" included with
+% this software distribution and also available online as
+% http://sbml.org/software/libsbml/license.html
+
+% assume not enabled
+fbcEnabled = 0;
+
+if (isoctave() == '0')
+  filename = fullfile(tempdir, 'fbc.xml');
+else
+  filename = fullfile(pwd, 'fbc.xml');
+end;
+writeTempFile(filename);
+
+try
+  [m, e] = TranslateSBML(filename, 1, 0);
+
+  if (length(e) == 0 && isfield(m, 'fbc_version') == 1 )
+    fbcEnabled = 1;
+  end;
+  
+  delete(filename);
+  
+catch
+  
+  delete(filename);
+  
+  return
+end;
+
+
+
+
+function writeTempFile(filename)
+
+fout = fopen(filename, 'w');
+
+fprintf(fout, '<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n');
+fprintf(fout, '<sbml xmlns=\"http://www.sbml.org/sbml/level3/version1/core\" ');
+fprintf(fout, 'xmlns:fbc=\"http://www.sbml.org/sbml/level3/version1/fbc/version1\" ');
+fprintf(fout, 'level=\"3\" version=\"1\" fbc:required=\"false\">\n');
+fprintf(fout, '  <model/>\n</sbml>\n');
+
+fclose(fout);
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/THIRD_PARTY_SOFTWARE/SBMLimportExport/auxiliary/isSBML_Model.m b/IQMtools V1.2.2.2/IQMlite/auxiliary/THIRD_PARTY_SOFTWARE/SBMLimportExport/auxiliary/isSBML_Model.m
new file mode 100644
index 0000000000000000000000000000000000000000..757342bec6e82d7b07f2df92170e9edc1c23c578
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/THIRD_PARTY_SOFTWARE/SBMLimportExport/auxiliary/isSBML_Model.m	
@@ -0,0 +1,3709 @@
+function [valid, message] = isSBML_Model(varargin)
+% [valid, message] = isSBML_Model(SBMLModel)
+%
+% Takes
+%
+% 1. SBMLModel, an SBML Model structure
+% 2. extensions_allowed (optional) =
+%   - 0, structures should contain ONLY required fields
+%   - 1, structures may contain additional fields (default)
+%
+% Returns
+%
+% 1. valid = 
+%   - 1, if the structure represents
+%        a MATLAB_SBML Model structure of the appropriate
+%        level and version
+%   - 0, otherwise
+% 2. a message explaining any failure
+%
+
+%<!---------------------------------------------------------------------------
+% This file is part of libSBML.  Please visit http://sbml.org for more
+% information about SBML, and the latest version of libSBML.
+%
+% Copyright (C) 2013-2014 jointly by the following organizations:
+%     1. California Institute of Technology, Pasadena, CA, USA
+%     2. EMBL European Bioinformatics Institute (EMBL-EBI), Hinxton, UK
+%     3. University of Heidelberg, Heidelberg, Germany
+%
+% Copyright (C) 2009-2013 jointly by the following organizations: 
+%     1. California Institute of Technology, Pasadena, CA, USA
+%     2. EMBL European Bioinformatics Institute (EMBL-EBI), Hinxton, UK
+%  
+% Copyright (C) 2006-2008 by the California Institute of Technology,
+%     Pasadena, CA, USA 
+%  
+% Copyright (C) 2002-2005 jointly by the following organizations: 
+%     1. California Institute of Technology, Pasadena, CA, USA
+%     2. Japan Science and Technology Agency, Japan
+% 
+% This library is free software; you can redistribute it and/or modify
+% it under the terms of the GNU Lesser General Public License as
+% published by the Free Software Foundation.  A copy of the license
+% agreement is provided in the file named "LICENSE.txt" included with
+% this software distribution and also available online as
+% http://sbml.org/software/libsbml/license.html
+%----------------------------------------------------------------------- -->
+
+
+%check the input arguments are appropriate
+if (nargin < 1)
+  error('isSBML_Model needs at least one argument');
+elseif (nargin == 1)
+  SBMLStructure = varargin{1};
+  extensions_allowed = 1;
+elseif (nargin == 2)
+  SBMLStructure = varargin{1};
+  extensions_allowed = varargin{2};
+else
+  error('too many arguments to isSBML_Model');
+end;
+     
+if (isfield(SBMLStructure, 'fbc_version') && isFbcEnabled() == 1)
+  if isfield(SBMLStructure, 'SBML_level') && isfield(SBMLStructure, 'SBML_version')
+    [valid, message] = isSBML_FBC_Model(SBMLStructure, SBMLStructure.SBML_level, ...
+      SBMLStructure.SBML_version, SBMLStructure.fbc_version, extensions_allowed);
+  else
+    [valid, message] = isValidSBML_Model(SBMLStructure, extensions_allowed, 0);
+  end;
+else
+  [valid, message] = isValidSBML_Model(SBMLStructure, extensions_allowed, 0);
+end;  
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function [valid, message] = isValidSBML_Model(SBMLStructure, ...
+                                        extensions_allowed, in_fbc)
+
+
+%check the input arguments are appropriate
+
+if (length(SBMLStructure) > 1)
+  valid = 0;
+  message = 'cannot deal with arrays of structures';
+  return;
+end;
+
+if ~isempty(SBMLStructure)
+  if isfield(SBMLStructure, 'SBML_level')
+    level = SBMLStructure.SBML_level;
+  else
+    level = 3;
+  end;
+  if isfield(SBMLStructure, 'SBML_version')
+    version = SBMLStructure.SBML_version;
+  else
+    version = 1;
+  end;
+else
+  level = 3;
+  version = 1;
+end;
+
+isValidLevelVersionCombination(level, version);
+
+message = '';
+
+% check that argument is a structure
+valid = isstruct(SBMLStructure);
+
+% check the typecode
+typecode = 'SBML_MODEL';
+if (valid == 1 && ~isempty(SBMLStructure))
+  if isfield(SBMLStructure, 'typecode')
+    if (strcmp(typecode, SBMLStructure.typecode) ~= 1)
+      valid = 0;
+      message = 'typecode mismatch';
+      return;
+    end;
+  else
+    valid = 0;
+    message = 'missing typecode field';
+    return;
+  end;
+end;
+
+
+% check that structure contains all the necessary fields
+[SBMLfieldnames, numFields] = getFieldnames('SBML_MODEL', level, version);
+
+if (numFields ==0)
+	valid = 0;
+	message = 'invalid level/version';
+end;
+
+index = 1;
+while (valid == 1 && index <= numFields)
+	valid = isfield(SBMLStructure, char(SBMLfieldnames(index)));
+	if (valid == 0);
+		message = sprintf('%s field missing', char(SBMLfieldnames(index)));
+	end;
+	index = index + 1;
+end;
+
+%check that any nested structures are appropriate
+
+% functionDefinitions
+if (valid == 1 && level > 1)
+  index = 1;
+  while (valid == 1 && index <= length(SBMLStructure.functionDefinition))
+    [valid, message] = isSBML_Struct('SBML_FUNCTION_DEFINITION', ...
+                                  SBMLStructure.functionDefinition(index), ...
+                                  level, version, extensions_allowed);
+    index = index + 1;
+  end;
+end;
+
+% unitDefinitions
+if (valid == 1)
+  index = 1;
+  while (valid == 1 && index <= length(SBMLStructure.unitDefinition))
+    [valid, message] = isSBML_Struct('SBML_UNIT_DEFINITION', ...
+                                  SBMLStructure.unitDefinition(index), ...
+                                  level, version, extensions_allowed);
+    index = index + 1;
+  end;
+end;
+
+% compartments
+if (valid == 1)
+  index = 1;
+  while (valid == 1 && index <= length(SBMLStructure.compartment))
+    [valid, message] = isSBML_Struct('SBML_COMPARTMENT', ...
+                                  SBMLStructure.compartment(index), ...
+                                  level, version, extensions_allowed);
+    index = index + 1;
+  end;
+end;
+
+% species
+if (valid == 1 && in_fbc == 0)
+  index = 1;
+  while (valid == 1 && index <= length(SBMLStructure.species))
+    [valid, message] = isSBML_Struct('SBML_SPECIES', ...
+                                  SBMLStructure.species(index), ...
+                                  level, version, extensions_allowed);
+    index = index + 1;
+  end;
+end;
+
+% compartmentTypes
+if (valid == 1 && level == 2 && version > 1)
+  index = 1;
+  while (valid == 1 && index <= length(SBMLStructure.compartmentType))
+    [valid, message] = isSBML_Struct('SBML_COMPARTMENT_TYPE', ...
+                                  SBMLStructure.compartmentType(index), ...
+                                  level, version, extensions_allowed);
+    index = index + 1;
+  end;
+end;
+
+% speciesTypes
+if (valid == 1 && level == 2 && version > 1)
+  index = 1;
+  while (valid == 1 && index <= length(SBMLStructure.speciesType))
+    [valid, message] = isSBML_Struct('SBML_SPECIES_TYPE', ...
+                                  SBMLStructure.speciesType(index), ...
+                                  level, version, extensions_allowed);
+    index = index + 1;
+  end;
+end;
+
+% parameter
+if (valid == 1)
+  index = 1;
+  while (valid == 1 && index <= length(SBMLStructure.parameter))
+    [valid, message] = isSBML_Struct('SBML_PARAMETER', ...
+                                  SBMLStructure.parameter(index), ...
+                                  level, version, extensions_allowed);
+    index = index + 1;
+  end;
+end;
+
+% initialAssignment
+if (valid == 1 && (level > 2 || (level == 2 && version > 1)))
+  index = 1;
+  while (valid == 1 && index <= length(SBMLStructure.initialAssignment))
+    [valid, message] = isSBML_Struct('SBML_INITIAL_ASSIGNMENT', ...
+                                  SBMLStructure.initialAssignment(index), ...
+                                  level, version, extensions_allowed);
+    index = index + 1;
+  end;
+end;
+
+% rule
+if (valid == 1)
+  index = 1;
+  while (valid == 1 && index <= length(SBMLStructure.rule))
+    [valid, message] = isSBML_Rule(SBMLStructure.rule(index), ...
+                                  level, version, extensions_allowed);
+    index = index + 1;
+  end;
+end;
+
+% constraints
+if (valid == 1 && (level > 2 || (level == 2 && version > 1)))
+  index = 1;
+  while (valid == 1 && index <= length(SBMLStructure.constraint))
+    [valid, message] = isSBML_Struct('SBML_CONSTRAINT', ...
+                                  SBMLStructure.constraint(index), ...
+                                  level, version, extensions_allowed);
+    index = index + 1;
+  end;
+end;
+
+% reaction
+if (valid == 1)
+  index = 1;
+  while (valid == 1 && index <= length(SBMLStructure.reaction))
+    [valid, message] = isSBML_Struct('SBML_REACTION', ...
+                                  SBMLStructure.reaction(index), ...
+                                  level, version, extensions_allowed);
+    index = index + 1;
+  end;
+end;
+
+% event
+if (valid == 1 && level > 1)
+  index = 1;
+  while (valid == 1 && index <= length(SBMLStructure.event))
+    [valid, message] = isSBML_Struct('SBML_EVENT', ...
+                                  SBMLStructure.event(index), ...
+                                  level, version, extensions_allowed);
+    index = index + 1;
+  end;
+end;
+
+
+% report failure
+if (valid == 0)
+	message = sprintf('Invalid Model structure\n%s\n', message);
+end;
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function [valid, message] = isSBML_Struct(typecode, SBMLStructure, level, version, extensions_allowed)
+
+
+
+
+if (length(SBMLStructure) > 1)
+  valid = 0;
+  message = 'cannot deal with arrays of structures';
+  return;
+end;
+
+isValidLevelVersionCombination(level, version);
+
+message = '';
+
+% check that argument is a structure
+valid = isstruct(SBMLStructure);
+
+% check the typecode
+if (valid == 1 && ~isempty(SBMLStructure))
+  if isfield(SBMLStructure, 'typecode')
+    if (strcmp(typecode, SBMLStructure.typecode) ~= 1)
+      valid = 0;
+      message = 'typecode mismatch';
+      return;
+    end;
+  else
+    valid = 0;
+    message = 'missing typecode field';
+    return;
+  end;
+end;
+
+% if the level and version fields exist they must match
+if (valid == 1 && isfield(SBMLStructure, 'level') && ~isempty(SBMLStructure))
+	if ~isequal(level, SBMLStructure.level)
+		valid = 0;
+		message = 'level mismatch';
+	end;
+end;
+if (valid == 1 && isfield(SBMLStructure, 'version') && ~isempty(SBMLStructure))
+	if ~isequal(version, SBMLStructure.version)
+		valid = 0;
+		message = 'version mismatch';
+	end;
+end;
+
+% check that structure contains all the necessary fields
+[SBMLfieldnames, numFields] = getFieldnames(typecode, level, version);
+
+if (numFields ==0)
+	valid = 0;
+	message = 'invalid level/version';
+end;
+
+index = 1;
+while (valid == 1 && index <= numFields)
+	valid = isfield(SBMLStructure, char(SBMLfieldnames(index)));
+	if (valid == 0);
+		message = sprintf('%s field missing', char(SBMLfieldnames(index)));
+	end;
+	index = index + 1;
+end;
+
+if (extensions_allowed == 0)
+  % check that the structure contains ONLY the expected fields
+  if (valid == 1)
+    if (numFields ~= length(fieldnames(SBMLStructure))-2)
+      valid = 0;
+      message = sprintf('Unexpected field detected');
+    end;
+  end;
+end;
+
+% some structures have child structures
+switch (typecode)
+  case 'SBML_EVENT'
+    % eventAssignments
+    if (valid == 1)
+      index = 1;
+      while (valid == 1 && index <= length(SBMLStructure.eventAssignment))
+        [valid, message] = isSBML_Struct('SBML_EVENT_ASSIGNMENT', ...
+                                      SBMLStructure.eventAssignment(index), ...
+                                      level, version, extensions_allowed);
+        index = index + 1;
+      end;
+    end;
+
+    % trigger/delay/priority
+    % these are level and version dependent
+    if (valid == 1)
+      if (level == 2 && version > 2)
+        if (length(SBMLStructure.trigger) > 1)
+          valid = 0;
+          message = 'multiple trigger elements encountered';
+        elseif (length(SBMLStructure.delay) > 1)
+          valid = 0;
+          message = 'multiple delay elements encountered';
+        end;
+        if (valid == 1 && length(SBMLStructure.trigger) == 1)
+          [valid, message] = isSBML_Struct('SBML_TRIGGER', ...
+                                            SBMLStructure.trigger, ...
+                                            level, version, extensions_allowed);
+        end;
+        if (valid == 1 && length(SBMLStructure.delay) == 1)
+          [valid, message] = isSBML_Struct('SBML_DELAY', ...
+                                            SBMLStructure.delay, ...
+                                            level, version, extensions_allowed);
+       end;
+      elseif (level > 2)
+        if (length(SBMLStructure.trigger) > 1)
+          valid = 0;
+          message = 'multiple trigger elements encountered';
+        elseif (length(SBMLStructure.delay) > 1)
+          valid = 0;
+          message = 'multiple delay elements encountered';
+        elseif (length(SBMLStructure.priority) > 1)
+          valid = 0;
+          message = 'multiple priority elements encountered';
+        end;
+        if (valid == 1 && length(SBMLStructure.trigger) == 1)
+          [valid, message] = isSBML_Struct('SBML_TRIGGER', ...
+                                            SBMLStructure.trigger, ...
+                                            level, version, extensions_allowed);
+        end;
+        if (valid == 1 && length(SBMLStructure.delay) == 1)
+          [valid, message] = isSBML_Struct('SBML_DELAY', ...
+                                            SBMLStructure.delay, ...
+                                            level, version, extensions_allowed);
+        end;
+        if (valid == 1 && length(SBMLStructure.priority) == 1)
+          [valid, message] = isSBML_Struct('SBML_PRIORITY', ...
+                                            SBMLStructure.priority, ...
+                                            level, version, extensions_allowed);
+        end;
+      end;
+    end;
+
+  case 'SBML_KINETIC_LAW'
+    % parameters
+    if (valid == 1 && level < 3)
+      index = 1;
+      while (valid == 1 && index <= length(SBMLStructure.parameter))
+        [valid, message] = isSBML_Struct('SBML_PARAMETER', ...
+                                      SBMLStructure.parameter(index), ...
+                                      level, version, extensions_allowed);
+        index = index + 1;
+      end;
+    end;
+
+    %check that any nested structures are appropriate
+
+    % localParameters
+    if (valid == 1 && level > 2)
+      index = 1;
+      while (valid == 1 && index <= length(SBMLStructure.localParameter))
+        [valid, message] = isSBML_Struct('SBML_LOCAL_PARAMETER', ...
+                                      SBMLStructure.localParameter(index), ...
+                                      level, version, extensions_allowed);
+        index = index + 1;
+      end;
+    end;
+
+  case 'SBML_REACTION'
+    % reactants
+    if (valid == 1)
+      index = 1;
+      while (valid == 1 && index <= length(SBMLStructure.reactant))
+        [valid, message] = isSBML_Struct('SBML_SPECIES_REFERENCE', ...
+                                      SBMLStructure.reactant(index), ...
+                                      level, version, extensions_allowed);
+        index = index + 1;
+      end;
+    end;
+
+    % products
+    if (valid == 1)
+      index = 1;
+      while (valid == 1 && index <= length(SBMLStructure.product))
+        [valid, message] = isSBML_Struct('SBML_SPECIES_REFERENCE', ...
+                                      SBMLStructure.product(index), ...
+                                      level, version, extensions_allowed);
+        index = index + 1;
+      end;
+    end;
+
+    % modifiers
+    if (valid == 1 && level > 1)
+      index = 1;
+      while (valid == 1 && index <= length(SBMLStructure.modifier))
+        [valid, message] = isSBML_Struct('SBML_MODIFIER_SPECIES_REFERENCE', ...
+                                      SBMLStructure.modifier(index), ...
+                                      level, version, extensions_allowed);
+        index = index + 1;
+      end;
+    end;
+
+    % kineticLaw
+    if (valid == 1 && length(SBMLStructure.kineticLaw) == 1)
+      [valid, message] = isSBML_Struct('SBML_KINETIC_LAW', ...
+                                    SBMLStructure.kineticLaw, level, version, extensions_allowed);
+    end;
+
+  case 'SBML_UNIT_DEFINITION'
+    % unit
+    if (valid == 1)
+      index = 1;
+      while (valid == 1 && index <= length(SBMLStructure.unit))
+        [valid, message] = isSBML_Struct('SBML_UNIT', ...
+                                      SBMLStructure.unit(index), ...
+                                      level, version, extensions_allowed);
+        index = index + 1;
+      end;
+    end;
+
+  case 'SBML_SPECIES_REFERENCE'
+    % stoichiometryMath
+    if (level == 2 && version > 2)
+      if (valid == 1 && length(SBMLStructure.stoichiometryMath) == 1)
+        [valid, message] = isSBML_Struct('SBML_STOICHIOMETRY_MATH', ...
+                                      SBMLStructure.stoichiometryMath, ...
+                                      level, version, extensions_allowed);
+      end;
+    end;
+      
+end;
+
+% report failure
+if (valid == 0)
+	message = sprintf('Invalid %s\n%s\n', typecode, message);
+end;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function [valid, message] = isSBML_Rule(SBMLStructure, ...
+                                  level, version, extensions_allowed)
+
+
+
+
+if (length(SBMLStructure) > 1)
+  valid = 0;
+  message = 'cannot deal with arrays of structures';
+  return;
+end;
+
+isValidLevelVersionCombination(level, version);
+
+message = '';
+
+if ~isempty(SBMLStructure)
+  if isfield(SBMLStructure, 'typecode')
+    typecode = SBMLStructure.typecode;
+  else
+    valid = 0;
+    message = 'missing typecode';
+    return;
+  end;
+else
+  typecode = 'SBML_ASSIGNMENT_RULE';
+end;
+
+switch (typecode)
+  case {'SBML_ALGEBRAIC_RULE', 'SBML_ASSIGNMENT_RULE', ...
+      'SBML_COMPARTMENT_VOLUME_RULE', 'SBML_PARAMETER_RULE', ...
+      'SBML_RATE_RULE', 'SBML_SPECIES_CONCENTRATION_RULE'}
+    [valid, message] = isSBML_Struct(typecode, SBMLStructure, level, version, extensions_allowed);
+  case 'SBML_RULE'
+    [valid, message] = checkRule(SBMLStructure, level, version, extensions_allowed);
+  otherwise
+    valid = 0;
+    message = 'Incorrect rule typecode';
+ end;
+ 
+
+function [valid, message] = checkRule(SBMLStructure, level, version, extensions_allowed)
+
+
+message = '';
+
+% check that argument is a structure
+valid = isstruct(SBMLStructure);
+
+% check the typecode
+typecode = 'SBML_RULE';
+if (valid == 1 && ~isempty(SBMLStructure))
+  if (strcmp(typecode, SBMLStructure.typecode) ~= 1)
+    valid = 0;
+    message = 'typecode mismatch';
+  end;
+end;
+
+% if the level and version fields exist they must match
+if (valid == 1 && isfield(SBMLStructure, 'level') && ~isempty(SBMLStructure))
+	if ~isequal(level, SBMLStructure.level)
+		valid = 0;
+		message = 'level mismatch';
+	end;
+end;
+if (valid == 1 && isfield(SBMLStructure, 'version') && ~isempty(SBMLStructure))
+	if ~isequal(version, SBMLStructure.version)
+		valid = 0;
+		message = 'version mismatch';
+	end;
+end;
+
+% check that structure contains all the necessary fields
+[SBMLfieldnames, numFields] = getAlgebraicRuleFieldnames(level, version);
+
+if (numFields ==0)
+	valid = 0;
+	message = 'invalid level/version';
+end;
+
+index = 1;
+while (valid == 1 && index <= numFields)
+	valid = isfield(SBMLStructure, char(SBMLfieldnames(index)));
+	if (valid == 0);
+		message = sprintf('%s field missing', char(SBMLfieldnames(index)));
+	end;
+	index = index + 1;
+end;
+
+if (extensions_allowed == 0)
+  % check that the structure contains ONLY the expected fields
+  if (valid == 1)
+    if (numFields ~= length(fieldnames(SBMLStructure))-2)
+      valid = 0;
+      message = sprintf('Unexpected field detected');
+    end;
+  end;
+end;
+
+% report failure
+if (valid == 0)
+	message = sprintf('Invalid Rule\n%s\n', message);
+end;
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function [valid, message] = isSBML_FBCStruct(typecode, SBMLStructure, level, ...
+  version, pkgVersion, extensions_allowed)
+
+
+
+
+if (length(SBMLStructure) > 1)
+  valid = 0;
+  message = 'cannot deal with arrays of structures';
+  return;
+end;
+
+isValidLevelVersionCombination(level, version);
+
+message = '';
+
+% check that argument is a structure
+valid = isstruct(SBMLStructure);
+
+% check the typecode
+if (valid == 1 && ~isempty(SBMLStructure))
+  if isfield(SBMLStructure, 'typecode')
+    if (strcmp(typecode, SBMLStructure.typecode) ~= 1)
+      valid = 0;
+      message = 'typecode mismatch';
+      return;
+    end;
+  else
+    valid = 0;
+    message = 'missing typecode field';
+    return;
+  end;
+end;
+
+% if the level and version fields exist they must match
+if (valid == 1 && isfield(SBMLStructure, 'level') && ~isempty(SBMLStructure))
+	if ~isequal(level, SBMLStructure.level)
+		valid = 0;
+		message = 'level mismatch';
+	end;
+end;
+if (valid == 1 && isfield(SBMLStructure, 'version') && ~isempty(SBMLStructure))
+	if ~isequal(version, SBMLStructure.version)
+		valid = 0;
+		message = 'version mismatch';
+	end;
+end;
+
+if (valid == 1 && isfield(SBMLStructure, 'fbc_version') && ~isempty(SBMLStructure))
+	if ~isequal(pkgVersion, SBMLStructure.fbc_version)
+		valid = 0;
+		message = 'fbc version mismatch';
+	end;
+end;
+
+
+% check that structure contains all the necessary fields
+[SBMLfieldnames, numFields] = getFieldnames(typecode, level, version, pkgVersion);
+
+if (numFields ==0)
+	valid = 0;
+	message = 'invalid level/version';
+end;
+
+index = 1;
+while (valid == 1 && index <= numFields)
+	valid = isfield(SBMLStructure, char(SBMLfieldnames(index)));
+	if (valid == 0);
+		message = sprintf('%s field missing', char(SBMLfieldnames(index)));
+	end;
+	index = index + 1;
+end;
+
+if (extensions_allowed == 0)
+  % check that the structure contains ONLY the expected fields
+  if (valid == 1)
+    if (numFields ~= length(fieldnames(SBMLStructure)))
+      valid = 0;
+      message = sprintf('Unexpected field detected');
+    end;
+  end;
+end;
+
+% some structures have child structures
+switch (typecode)
+  case 'SBML_FBC_OBJECTIVE'
+    % eventAssignments
+    if (valid == 1)
+      index = 1;
+      while (valid == 1 && index <= length(SBMLStructure.fbc_fluxObjective))
+        [valid, message] = isSBML_FBCStruct('SBML_FBC_FLUXOBJECTIVE', ...
+                                      SBMLStructure.fbc_fluxObjective(index), ...
+                                      level, version, pkgVersion, extensions_allowed);
+        index = index + 1;
+      end;
+    end;
+end;
+
+% report failure
+if (valid == 0)
+	message = sprintf('Invalid %s\n%s\n', typecode, message);
+end;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+function [valid, message] = isSBML_FBC_Model(SBMLStructure, level, version, ...
+             pkgVersion, extensions_allowed)
+% [valid, message] = isSBML_FBC_Model(SBMLFBCModel, level, version, pkgVersion)
+
+
+if (length(SBMLStructure) > 1)
+	message = 'cannot deal with arrays of structures';
+  valid = 0;
+  return;
+end;
+
+isValidLevelVersionCombination(level, version);
+
+message = '';
+
+% check that argument is a structure
+valid = isstruct(SBMLStructure);
+
+% check the typecode
+typecode = 'SBML_MODEL';
+if (valid == 1 && ~isempty(SBMLStructure))
+  if isfield(SBMLStructure, 'typecode')
+    if (strcmp(typecode, SBMLStructure.typecode) ~= 1)
+      valid = 0;
+      message = 'typecode mismatch';
+      return;
+    end;
+  else
+    valid = 0;
+    message = 'typecode field missing';
+    return;
+  end;
+end;
+
+% if the level and version fields exist they must match
+if (valid == 1 && isfield(SBMLStructure, 'SBML_level') && ~isempty(SBMLStructure))
+	if ~isequal(level, SBMLStructure.SBML_level)
+		valid = 0;
+		message = 'level mismatch';
+	end;
+end;
+if (valid == 1 && isfield(SBMLStructure, 'SBML_version') && ~isempty(SBMLStructure))
+	if ~isequal(version, SBMLStructure.SBML_version)
+		valid = 0;
+		message = 'version mismatch';
+	end;
+end;
+if (valid == 1 && isfield(SBMLStructure, 'fbc_version') && ~isempty(SBMLStructure))
+	if ~isequal(pkgVersion, SBMLStructure.fbc_version)
+		valid = 0;
+		message = 'FBC version mismatch';
+	end;
+end;
+
+if (valid == 1)
+  % do not worry about extra fields at this point
+  % we know we are in an fbc model
+  [valid, message] = isValidSBML_Model(SBMLStructure, extensions_allowed, 1);
+end;
+
+% check that structure contains all the fbc fields
+if (valid == 1)
+  [SBMLfieldnames, numFields] = getFieldnames('SBML_FBC_MODEL', level, ...
+                                                version, pkgVersion);
+
+  if (numFields ==0)
+    valid = 0;
+    message = 'invalid level/version';
+  end;
+
+  index = 1;
+  while (valid == 1 && index <= numFields)
+    valid = isfield(SBMLStructure, char(SBMLfieldnames(index)));
+    if (valid == 0);
+      message = sprintf('%s field missing', char(SBMLfieldnames(index)));
+    end;
+    index = index + 1;
+  end;
+
+  %check that any nested structures are appropriate
+
+
+  % fluxBound
+  if (valid == 1)
+    index = 1;
+    while (valid == 1 && index <= length(SBMLStructure.fbc_fluxBound))
+      [valid, message] = isSBML_FBCStruct('SBML_FBC_FLUXBOUND', ...
+                                    SBMLStructure.fbc_fluxBound(index), ...
+                                    level, version, pkgVersion, extensions_allowed);
+      index = index + 1;
+    end;
+  end;
+
+  % objective
+  if (valid == 1)
+    index = 1;
+    while (valid == 1 && index <= length(SBMLStructure.fbc_objective))
+      [valid, message] = isSBML_FBCStruct('SBML_FBC_OBJECTIVE', ...
+                                    SBMLStructure.fbc_objective(index), ...
+                                    level, version, pkgVersion, extensions_allowed);
+      index = index + 1;
+    end;
+  end;
+  
+  %species
+  if (valid == 1)
+    index = 1;
+    while (valid == 1 && index <= length(SBMLStructure.species))
+      [valid, message] = isSBML_FBC_Species('SBML_FBC_SPECIES', ...
+                                    SBMLStructure.species(index), ...
+                                    level, version, pkgVersion, extensions_allowed);
+      index = index + 1;
+    end;
+  end;
+  
+
+end;
+
+% report failure
+if (valid == 0)
+	message = sprintf('Invalid FBC Model\n%s\n', message);
+end;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function [valid, message] = isSBML_FBC_Species(typecode, SBMLStructure, ...
+                                    level, version, pkgVersion, extensions_allowed)
+
+if (length(SBMLStructure) > 1)
+	message = 'cannot deal with arrays of structures';
+  valid = 0;
+  return;
+end;
+
+isValidLevelVersionCombination(level, version);
+
+message = '';
+
+% check that argument is a structure
+valid = isstruct(SBMLStructure);
+
+% check the typecode
+typecode = 'SBML_SPECIES';
+if (valid == 1 && ~isempty(SBMLStructure))
+  if isfield(SBMLStructure, 'typecode')
+    if (strcmp(typecode, SBMLStructure.typecode) ~= 1)
+      valid = 0;
+      message = 'typecode mismatch';
+      return;
+    end;
+  else
+    valid = 0;
+    message = 'typecode field missing';
+    return;
+  end;
+end;
+
+% if the level and version fields exist they must match
+if (valid == 1 && isfield(SBMLStructure, 'level') && ~isempty(SBMLStructure))
+	if ~isequal(level, SBMLStructure.level)
+		valid = 0;
+		message = 'level mismatch';
+	end;
+end;
+if (valid == 1 && isfield(SBMLStructure, 'version') && ~isempty(SBMLStructure))
+	if ~isequal(version, SBMLStructure.version)
+		valid = 0;
+		message = 'version mismatch';
+	end;
+end;
+if (valid == 1 && isfield(SBMLStructure, 'fbc_version') && ~isempty(SBMLStructure))
+	if ~isequal(pkgVersion, SBMLStructure.fbc_version)
+		valid = 0;
+		message = 'FBC version mismatch';
+	end;
+end;
+
+if (valid == 1)
+  [valid, message] = isSBML_Struct('SBML_SPECIES', SBMLStructure, level, ...
+                                             version, 1);
+end;
+
+% check that structure contains all the fbc fields
+if (valid == 1)
+  [SBMLfieldnames, numFields] = getFieldnames('SBML_FBC_SPECIES', level, ...
+                                                version);
+
+  if (numFields ==0)
+    valid = 0;
+    message = 'invalid level/version';
+  end;
+
+  index = 1;
+  while (valid == 1 && index <= numFields)
+    valid = isfield(SBMLStructure, char(SBMLfieldnames(index)));
+    if (valid == 0);
+      message = sprintf('%s field missing', char(SBMLfieldnames(index)));
+    end;
+    index = index + 1;
+  end;
+
+  if (extensions_allowed == 0)
+    % check that the structure contains ONLY the expected fields
+    if (valid == 1)
+      if (numFields ~= length(fieldnames(SBMLStructure))-19)
+        valid = 0;
+        message = sprintf('Unexpected field detected');
+      end;
+    end;
+  end;
+
+
+end;
+
+% report failure
+if (valid == 0)
+	message = sprintf('Invalid FBC Species\n%s\n', message);
+end;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function valid = isValidLevelVersionCombination(level, version)
+
+
+
+
+
+
+
+
+
+
+valid = 1;
+
+if ~isIntegralNumber(level)
+	error('level must be an integer');
+elseif ~isIntegralNumber(version)
+	error('version must be an integer');
+end;
+
+if (level < 1 || level > 3)
+	error('current SBML levels are 1, 2 or 3');
+end;
+
+if (level == 1)
+	if (version < 1 || version > 2)
+		error('SBMLToolbox supports versions 1-2 of SBML Level 1');
+	end;
+
+elseif (level == 2)
+	if (version < 1 || version > 4)
+		error('SBMLToolbox supports versions 1-4 of SBML Level 2');
+	end;
+
+elseif (level == 3)
+	if (version ~= 1)
+		error('SBMLToolbox supports only version 1 of SBML Level 3');
+	end;
+
+end;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function value = isIntegralNumber(number)
+
+
+value = 0;
+
+integerClasses = {'int8', 'uint8', 'int16', 'uint16', 'int32', 'uint32', 'int64', 'uint64'};
+
+% since the function isinteger does not exist in MATLAB Rel 13
+% this is not used
+%if (isinteger(number))
+if (ismember(class(number), integerClasses))
+    value = 1;
+elseif (isnumeric(number))
+    % if it is an integer 
+    if (number == fix(number))
+        value = 1;
+    end;
+end;
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function [SBMLfieldnames, nNumberFields] = getAlgebraicRuleFieldnames(level, ...
+                                                             version)
+
+
+
+
+
+
+
+
+
+if (~isValidLevelVersionCombination(level, version))
+  error ('invalid level/version combination');
+end;
+
+if (level == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'type', ...
+		                   'formula', ...
+		                   'variable', ...
+		                   'species', ...
+		                   'compartment', ...
+		                   'name', ...
+		                   'units', ...
+		                 };
+		nNumberFields = 10;
+elseif (level == 2)
+	if (version == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'formula', ...
+		                   'variable', ...
+		                   'species', ...
+		                   'compartment', ...
+		                   'name', ...
+		                   'units', ...
+		                 };
+		nNumberFields = 10;
+	elseif (version == 2)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'formula', ...
+		                   'variable', ...
+		                   'species', ...
+		                   'compartment', ...
+		                   'name', ...
+		                   'units', ...
+		                 };
+		nNumberFields = 11;
+	elseif (version == 3)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'formula', ...
+		                   'variable', ...
+		                   'species', ...
+		                   'compartment', ...
+		                   'name', ...
+		                   'units', ...
+		                 };
+		nNumberFields = 11;
+	elseif (version == 4)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'formula', ...
+		                   'variable', ...
+		                   'species', ...
+		                   'compartment', ...
+		                   'name', ...
+		                   'units', ...
+		                 };
+		nNumberFields = 11;
+	end;
+elseif (level == 3)
+	if (version == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'formula', ...
+		                   'variable', ...
+		                   'species', ...
+		                   'compartment', ...
+		                   'name', ...
+		                   'units', ...
+		                 };
+		nNumberFields = 11;
+	end;
+end;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function [SBMLfieldnames, nNumberFields] = getAssignmentRuleFieldnames(level, ...
+                                                             version)
+
+
+
+
+
+
+
+
+
+
+if (~isValidLevelVersionCombination(level, version))
+  error ('invalid level/version combination');
+end;
+
+if (level == 1)
+		SBMLfieldnames = [];
+		nNumberFields = 0;
+elseif (level == 2)
+	if (version == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'formula', ...
+		                   'variable', ...
+		                   'species', ...
+		                   'compartment', ...
+		                   'name', ...
+		                   'units', ...
+		                 };
+		nNumberFields = 10;
+	elseif (version == 2)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'formula', ...
+		                   'variable', ...
+		                   'species', ...
+		                   'compartment', ...
+		                   'name', ...
+		                   'units', ...
+		                 };
+		nNumberFields = 11;
+	elseif (version == 3)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'formula', ...
+		                   'variable', ...
+		                   'species', ...
+		                   'compartment', ...
+		                   'name', ...
+		                   'units', ...
+		                 };
+		nNumberFields = 11;
+	elseif (version == 4)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'formula', ...
+		                   'variable', ...
+		                   'species', ...
+		                   'compartment', ...
+		                   'name', ...
+		                   'units', ...
+		                 };
+		nNumberFields = 11;
+	end;
+elseif (level == 3)
+	if (version == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'formula', ...
+		                   'variable', ...
+		                   'species', ...
+		                   'compartment', ...
+		                   'name', ...
+		                   'units', ...
+		                 };
+		nNumberFields = 11;
+	end;
+end;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function [SBMLfieldnames, nNumberFields] = getCompartmentFieldnames(level, ...
+                                                                    version)
+
+
+
+
+
+
+
+
+
+
+if (~isValidLevelVersionCombination(level, version))
+  error ('invalid level/version combination');
+end;
+
+if (level == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'name', ...
+		                   'volume', ...
+		                   'units', ...
+		                   'outside', ...
+		                   'isSetVolume', ...
+		                 };
+		nNumberFields = 8;
+elseif (level == 2)
+	if (version == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'name', ...
+		                   'id', ...
+		                   'spatialDimensions', ...
+		                   'size', ...
+		                   'units', ...
+		                   'outside', ...
+		                   'constant', ...
+		                   'isSetSize', ...
+		                   'isSetVolume', ...
+		                 };
+		nNumberFields = 13;
+	elseif (version == 2)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'name', ...
+		                   'id', ...
+		                   'compartmentType', ...
+		                   'spatialDimensions', ...
+		                   'size', ...
+		                   'units', ...
+		                   'outside', ...
+		                   'constant', ...
+		                   'isSetSize', ...
+		                   'isSetVolume', ...
+		                 };
+		nNumberFields = 14;
+	elseif (version == 3)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'name', ...
+		                   'id', ...
+		                   'compartmentType', ...
+		                   'spatialDimensions', ...
+		                   'size', ...
+		                   'units', ...
+		                   'outside', ...
+		                   'constant', ...
+		                   'isSetSize', ...
+		                   'isSetVolume', ...
+		                 };
+		nNumberFields = 15;
+	elseif (version == 4)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'name', ...
+		                   'id', ...
+		                   'compartmentType', ...
+		                   'spatialDimensions', ...
+		                   'size', ...
+		                   'units', ...
+		                   'outside', ...
+		                   'constant', ...
+		                   'isSetSize', ...
+		                   'isSetVolume', ...
+		                 };
+		nNumberFields = 15;
+	end;
+elseif (level == 3)
+	if (version == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'name', ...
+		                   'id', ...
+		                   'spatialDimensions', ...
+		                   'size', ...
+		                   'units', ...
+		                   'constant', ...
+		                   'isSetSize', ...
+		                   'isSetSpatialDimensions', ...
+		                 };
+		nNumberFields = 13;
+	end;
+end;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function [SBMLfieldnames, nNumberFields] = getCompartmentTypeFieldnames(level, ...
+                                                                        version)
+
+
+
+
+
+
+
+
+
+
+if (~isValidLevelVersionCombination(level, version))
+  error ('invalid level/version combination');
+end;
+
+if (level == 1)
+	SBMLfieldnames = [];
+	nNumberFields = 0;
+elseif (level == 2)
+	if (version == 1)
+		SBMLfieldnames = [];
+		nNumberFields = 0;
+	elseif (version == 2)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'name', ...
+		                   'id', ...
+		                 };
+		nNumberFields = 6;
+	elseif (version == 3)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'name', ...
+		                   'id', ...
+		                 };
+		nNumberFields = 7;
+	elseif (version == 4)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'name', ...
+		                   'id', ...
+		                 };
+		nNumberFields = 7;
+	end;
+elseif (level == 3)
+	if (version == 1)
+		SBMLfieldnames = [];
+		nNumberFields = 0;
+	end;
+end;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function [SBMLfieldnames, nNumberFields] = getCompartmentVolumeRuleFieldnames(level, ...
+                                                             version)
+
+
+
+
+
+
+
+
+
+
+if (~isValidLevelVersionCombination(level, version))
+  error ('invalid level/version combination');
+end;
+
+if (level == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'type', ...
+		                   'formula', ...
+		                   'variable', ...
+		                   'species', ...
+		                   'compartment', ...
+		                   'name', ...
+		                   'units', ...
+		                 };
+		nNumberFields = 10;
+elseif (level == 2)
+	if (version == 1)
+		SBMLfieldnames = [];
+		nNumberFields = 0;
+	elseif (version == 2)
+		SBMLfieldnames = [];
+		nNumberFields = 0;
+	elseif (version == 3)
+		SBMLfieldnames = [];
+		nNumberFields = 0;
+	elseif (version == 4)
+		SBMLfieldnames = [];
+		nNumberFields = 0;
+	end;
+elseif (level == 3)
+	if (version == 1)
+		SBMLfieldnames = [];
+		nNumberFields = 0;
+	end;
+end;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function [SBMLfieldnames, nNumberFields] = getConstraintFieldnames(level, ...
+                                                                   version)
+
+
+
+
+
+
+
+
+
+
+if (~isValidLevelVersionCombination(level, version))
+  error ('invalid level/version combination');
+end;
+
+if (level == 1)
+	SBMLfieldnames = [];
+	nNumberFields = 0;
+elseif (level == 2)
+	if (version == 1)
+		SBMLfieldnames = [];
+		nNumberFields = 0;
+	elseif (version == 2)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'math', ...
+		                   'message', ...
+		                 };
+		nNumberFields = 7;
+	elseif (version == 3)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'math', ...
+		                   'message', ...
+		                 };
+		nNumberFields = 7;
+	elseif (version == 4)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'math', ...
+		                   'message', ...
+		                 };
+		nNumberFields = 7;
+	end;
+elseif (level == 3)
+	if (version == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'math', ...
+		                   'message', ...
+		                 };
+		nNumberFields = 7;
+	end;
+end;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function [SBMLfieldnames, nNumberFields] = getDelayFieldnames(level, ...
+                                                              version)
+
+
+
+
+
+
+
+
+
+
+if (~isValidLevelVersionCombination(level, version))
+  error ('invalid level/version combination');
+end;
+
+if (level == 1)
+	SBMLfieldnames = [];
+	nNumberFields = 0;
+elseif (level == 2)
+	if (version == 1)
+		SBMLfieldnames = [];
+		nNumberFields = 0;
+	elseif (version == 2)
+		SBMLfieldnames = [];
+		nNumberFields = 0;
+	elseif (version == 3)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'math', ...
+		                 };
+		nNumberFields = 6;
+	elseif (version == 4)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'math', ...
+		                 };
+		nNumberFields = 6;
+	end;
+elseif (level == 3)
+	if (version == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'math', ...
+		                 };
+		nNumberFields = 6;
+	end;
+end;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function [SBMLfieldnames, nNumberFields] = getEventAssignmentFieldnames(level, ...
+                                                                        version)
+
+
+
+
+
+
+
+
+
+
+if (~isValidLevelVersionCombination(level, version))
+  error ('invalid level/version combination');
+end;
+
+if (level == 1)
+	SBMLfieldnames = [];
+	nNumberFields = 0;
+elseif (level == 2)
+	if (version == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'variable', ...
+		                   'math', ...
+		                 };
+		nNumberFields = 6;
+	elseif (version == 2)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'variable', ...
+		                   'sboTerm', ...
+		                   'math', ...
+		                 };
+		nNumberFields = 7;
+	elseif (version == 3)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'variable', ...
+		                   'math', ...
+		                 };
+		nNumberFields = 7;
+	elseif (version == 4)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'variable', ...
+		                   'math', ...
+		                 };
+		nNumberFields = 7;
+	end;
+elseif (level == 3)
+	if (version == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'variable', ...
+		                   'math', ...
+		                 };
+		nNumberFields = 7;
+	end;
+end;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function [SBMLfieldnames, nNumberFields] = getEventFieldnames(level, ...
+                                                              version)
+
+
+
+
+
+
+
+
+
+
+if (~isValidLevelVersionCombination(level, version))
+  error ('invalid level/version combination');
+end;
+
+if (level == 1)
+	SBMLfieldnames = [];
+	nNumberFields = 0;
+elseif (level == 2)
+	if (version == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'name', ...
+		                   'id', ...
+		                   'trigger', ...
+		                   'delay', ...
+		                   'timeUnits', ...
+		                   'eventAssignment', ...
+		                 };
+		nNumberFields = 10;
+	elseif (version == 2)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'name', ...
+		                   'id', ...
+		                   'trigger', ...
+		                   'delay', ...
+		                   'timeUnits', ...
+		                   'sboTerm', ...
+		                   'eventAssignment', ...
+		                 };
+		nNumberFields = 11;
+	elseif (version == 3)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'name', ...
+		                   'id', ...
+		                   'trigger', ...
+		                   'delay', ...
+		                   'eventAssignment', ...
+		                 };
+		nNumberFields = 10;
+	elseif (version == 4)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'name', ...
+		                   'id', ...
+		                   'useValuesFromTriggerTime', ...
+		                   'trigger', ...
+		                   'delay', ...
+		                   'eventAssignment', ...
+		                 };
+		nNumberFields = 11;
+	end;
+elseif (level == 3)
+	if (version == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'name', ...
+		                   'id', ...
+		                   'useValuesFromTriggerTime', ...
+		                   'trigger', ...
+		                   'delay', ...
+		                   'priority', ...
+		                   'eventAssignment', ...
+		                 };
+		nNumberFields = 12;
+	end;
+end;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function [SBMLfieldnames, nNumberFields] = getFieldnames(varargin)
+
+if (nargin < 3)
+  error('getFieldnames requires 3 arguments');
+end;
+
+typecode = varargin{1};
+level = varargin{2};
+version = varargin{3};
+if nargin == 4
+  pkgVersion = varargin{4};
+else
+  pkgVersion = 1;
+end;
+
+done = 1;
+
+
+switch (typecode)
+  case {'SBML_ALGEBRAIC_RULE', 'AlgebraicRule', 'algebraicRule'}
+    [SBMLfieldnames, nNumberFields] = getAlgebraicRuleFieldnames(level, version);
+  case {'SBML_ASSIGNMENT_RULE', 'AssignmentRule', 'assignmentRule'}
+    [SBMLfieldnames, nNumberFields] = getAssignmentRuleFieldnames(level, version);
+  case {'SBML_COMPARTMENT', 'Compartment', 'compartment'}
+    [SBMLfieldnames, nNumberFields] = getCompartmentFieldnames(level, version);
+  case {'SBML_COMPARTMENT_TYPE', 'CompartmentType', 'compartmentType'}
+    [SBMLfieldnames, nNumberFields] = getCompartmentTypeFieldnames(level, version);
+  case {'SBML_COMPARTMENT_VOLUME_RULE', 'CompartmentVolumeRule', 'compartmentVolumeRule'}
+    [SBMLfieldnames, nNumberFields] = getCompartmentVolumeRuleFieldnames(level, version);
+  case {'SBML_CONSTRAINT', 'Constraint', 'constraint'}
+    [SBMLfieldnames, nNumberFields] = getConstraintFieldnames(level, version);
+  case {'SBML_DELAY', 'Delay', 'delay'}
+    [SBMLfieldnames, nNumberFields] = getDelayFieldnames(level, version);
+  case {'SBML_EVENT', 'Event', 'event'}
+    [SBMLfieldnames, nNumberFields] = getEventFieldnames(level, version);
+  case {'SBML_EVENT_ASSIGNMENT', 'EventAssignment', 'eventAssignment'}
+    [SBMLfieldnames, nNumberFields] = getEventAssignmentFieldnames(level, version);
+  case {'SBML_FUNCTION_DEFINITION', 'FunctionDefinition', 'functionDefinition'}
+    [SBMLfieldnames, nNumberFields] = getFunctionDefinitionFieldnames(level, version);
+  case {'SBML_INITIAL_ASSIGNMENT', 'InitialAssignment', 'initialAssignment'}
+    [SBMLfieldnames, nNumberFields] = getInitialAssignmentFieldnames(level, version);
+  case {'SBML_KINETIC_LAW', 'KineticLaw', 'kineticLaw'}
+    [SBMLfieldnames, nNumberFields] = getKineticLawFieldnames(level, version);
+  case {'SBML_LOCAL_PARAMETER', 'LocalParameter', 'localParameter'}
+    [SBMLfieldnames, nNumberFields] = getLocalParameterFieldnames(level, version);
+  case {'SBML_MODEL', 'Model', 'model'}
+    [SBMLfieldnames, nNumberFields] = getModelFieldnames(level, version);
+  case {'SBML_MODIFIER_SPECIES_REFERENCE', 'ModifierSpeciesReference', 'modifierSpeciesReference'}
+    [SBMLfieldnames, nNumberFields] = getModifierSpeciesReferenceFieldnames(level, version);
+  case {'SBML_PARAMETER', 'Parameter', 'parameter'}
+    [SBMLfieldnames, nNumberFields] = getParameterFieldnames(level, version);
+  case {'SBML_PARAMETER_RULE', 'ParameterRule', 'parameterRule'}
+    [SBMLfieldnames, nNumberFields] = getParameterRuleFieldnames(level, version);
+  case {'SBML_PRIORITY', 'Priority', 'priority'}
+    [SBMLfieldnames, nNumberFields] = getPriorityFieldnames(level, version);
+  case {'SBML_RATE_RULE', 'RateRule', 'ruleRule'}
+    [SBMLfieldnames, nNumberFields] = getRateRuleFieldnames(level, version);
+  case {'SBML_REACTION', 'Reaction', 'reaction'}
+    [SBMLfieldnames, nNumberFields] = getReactionFieldnames(level, version);
+  case {'SBML_SPECIES', 'Species', 'species'}
+    [SBMLfieldnames, nNumberFields] = getSpeciesFieldnames(level, version);
+  case {'SBML_SPECIES_CONCENTRATION_RULE', 'SpeciesConcentrationRule', 'speciesConcentrationRule'}
+    [SBMLfieldnames, nNumberFields] = getSpeciesConcentrationRuleFieldnames(level, version);
+  case {'SBML_SPECIES_REFERENCE', 'SpeciesReference', 'speciesReference'}
+    [SBMLfieldnames, nNumberFields] = getSpeciesReferenceFieldnames(level, version);
+  case {'SBML_SPECIES_TYPE', 'SpeciesType', 'speciesType'}
+    [SBMLfieldnames, nNumberFields] = getSpeciesTypeFieldnames(level, version);
+  case {'SBML_STOICHIOMETRY_MATH', 'StoichiometryMath', 'stoichiometryMath'}
+    [SBMLfieldnames, nNumberFields] = getStoichiometryMathFieldnames(level, version);
+  case {'SBML_TRIGGER', 'Trigger', 'trigger'}
+    [SBMLfieldnames, nNumberFields] = getTriggerFieldnames(level, version);
+  case {'SBML_UNIT', 'Unit', 'unit'}
+    [SBMLfieldnames, nNumberFields] = getUnitFieldnames(level, version);
+  case {'SBML_UNIT_DEFINITION', 'UnitDefinition', 'unitDefinition'}
+    [SBMLfieldnames, nNumberFields] = getUnitDefinitionFieldnames(level, version);
+  otherwise
+    done = 0;  
+end;
+
+if done == 0
+  switch (typecode)
+    case {'SBML_FBC_FLUXBOUND', 'FluxBound', 'fluxBound'}
+     [SBMLfieldnames, nNumberFields] = getFluxBoundFieldnames(level, version, pkgVersion);
+    case {'SBML_FBC_FLUXOBJECTIVE', 'FluxObjective', 'fluxObjective'}
+     [SBMLfieldnames, nNumberFields] = getFluxObjectiveFieldnames(level, version, pkgVersion);
+    case {'SBML_FBC_OBJECTIVE', 'Objective', 'objective'}
+     [SBMLfieldnames, nNumberFields] = getObjectiveFieldnames(level, version, pkgVersion);
+    case {'SBML_FBC_MODEL', 'FBCModel'}
+     [SBMLfieldnames, nNumberFields] = getFBCModelFieldnames(level, version, pkgVersion);
+    case {'SBML_FBC_SPECIES', 'FBCSpecies'}
+     [SBMLfieldnames, nNumberFields] = getFBCSpeciesFieldnames(level, version, pkgVersion);
+    otherwise
+      error('%s\n%s', ...
+        'getFieldnames(typecode, level, version', ...
+        'typecode not recognised');    
+  end;
+end;
+ 
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function [SBMLfieldnames, nNumberFields] = getFunctionDefinitionFieldnames(level, ...
+                                                                           version)
+
+
+
+
+
+
+
+
+
+
+if (~isValidLevelVersionCombination(level, version))
+  error ('invalid level/version combination');
+end;
+
+if (level == 1)
+	SBMLfieldnames = [];
+	nNumberFields = 0;
+elseif (level == 2)
+	if (version == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'name', ...
+		                   'id', ...
+		                   'math', ...
+		                 };
+		nNumberFields = 7;
+	elseif (version == 2)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'name', ...
+		                   'id', ...
+		                   'math', ...
+		                 };
+		nNumberFields = 8;
+	elseif (version == 3)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'name', ...
+		                   'id', ...
+		                   'math', ...
+		                 };
+		nNumberFields = 8;
+	elseif (version == 4)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'name', ...
+		                   'id', ...
+		                   'math', ...
+		                 };
+		nNumberFields = 8;
+	end;
+elseif (level == 3)
+	if (version == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'name', ...
+		                   'id', ...
+		                   'math', ...
+		                 };
+		nNumberFields = 8;
+	end;
+end;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function [SBMLfieldnames, nNumberFields] = getInitialAssignmentFieldnames(level, ...
+                                                                          version)
+
+
+
+
+
+
+
+
+
+
+if (~isValidLevelVersionCombination(level, version))
+  error ('invalid level/version combination');
+end;
+
+if (level == 1)
+	SBMLfieldnames = [];
+	nNumberFields = 0;
+elseif (level == 2)
+	if (version == 1)
+		SBMLfieldnames = [];
+		nNumberFields = 0;
+	elseif (version == 2)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'symbol', ...
+		                   'math', ...
+		                 };
+		nNumberFields = 7;
+	elseif (version == 3)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'symbol', ...
+		                   'math', ...
+		                 };
+		nNumberFields = 7;
+	elseif (version == 4)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'symbol', ...
+		                   'math', ...
+		                 };
+		nNumberFields = 7;
+	end;
+elseif (level == 3)
+	if (version == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'symbol', ...
+		                   'math', ...
+		                 };
+		nNumberFields = 7;
+	end;
+end;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function [SBMLfieldnames, nNumberFields] = getKineticLawFieldnames(level, ...
+                                                                   version)
+
+
+
+
+
+
+
+
+
+
+if (~isValidLevelVersionCombination(level, version))
+  error ('invalid level/version combination');
+end;
+
+if (level == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'formula', ...
+		                   'parameter', ...
+		                   'timeUnits', ...
+		                   'substanceUnits', ...
+		                 };
+		nNumberFields = 7;
+elseif (level == 2)
+	if (version == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'formula', ...
+		                   'math', ...
+		                   'parameter', ...
+		                   'timeUnits', ...
+		                   'substanceUnits', ...
+		                 };
+		nNumberFields = 9;
+	elseif (version == 2)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'formula', ...
+		                   'math', ...
+		                   'parameter', ...
+		                   'sboTerm', ...
+		                 };
+		nNumberFields = 8;
+	elseif (version == 3)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'formula', ...
+		                   'math', ...
+		                   'parameter', ...
+		                 };
+		nNumberFields = 8;
+	elseif (version == 4)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'formula', ...
+		                   'math', ...
+		                   'parameter', ...
+		                 };
+		nNumberFields = 8;
+	end;
+elseif (level == 3)
+	if (version == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'math', ...
+		                   'localParameter', ...
+		                 };
+		nNumberFields = 7;
+	end;
+end;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function [SBMLfieldnames, nNumberFields] = getLocalParameterFieldnames(level, ...
+                                                                       version)
+
+
+
+
+
+
+
+
+
+
+if (~isValidLevelVersionCombination(level, version))
+  error ('invalid level/version combination');
+end;
+
+if (level == 1)
+	SBMLfieldnames = [];
+	nNumberFields = 0;
+elseif (level == 2)
+	SBMLfieldnames = [];
+	nNumberFields = 0;
+elseif (level == 3)
+	if (version == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'name', ...
+		                   'id', ...
+		                   'value', ...
+		                   'units', ...
+		                   'isSetValue', ...
+		                 };
+		nNumberFields = 10;
+  end;
+end;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function [SBMLfieldnames, nNumberFields] = getModelFieldnames(level, ...
+                                                              version)
+
+
+
+
+
+
+
+
+
+
+if (~isValidLevelVersionCombination(level, version))
+  error ('invalid level/version combination');
+end;
+
+if (level == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'SBML_level', ...
+		                   'SBML_version', ...
+		                   'name', ...
+		                   'unitDefinition', ...
+		                   'compartment', ...
+		                   'species', ...
+		                   'parameter', ...
+		                   'rule', ...
+		                   'reaction', ...
+		                 };
+		nNumberFields = 12;
+elseif (level == 2)
+	if (version == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'SBML_level', ...
+		                   'SBML_version', ...
+		                   'name', ...
+		                   'id', ...
+		                   'functionDefinition', ...
+		                   'unitDefinition', ...
+		                   'compartment', ...
+		                   'species', ...
+		                   'parameter', ...
+		                   'rule', ...
+		                   'reaction', ...
+		                   'event', ...
+		                 };
+		nNumberFields = 16;
+	elseif (version == 2)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'SBML_level', ...
+		                   'SBML_version', ...
+		                   'name', ...
+		                   'id', ...
+		                   'sboTerm', ...
+		                   'functionDefinition', ...
+		                   'unitDefinition', ...
+		                   'compartmentType', ...
+		                   'speciesType', ...
+		                   'compartment', ...
+		                   'species', ...
+		                   'parameter', ...
+		                   'initialAssignment', ...
+		                   'rule', ...
+		                   'constraint', ...
+		                   'reaction', ...
+		                   'event', ...
+		                 };
+		nNumberFields = 21;
+	elseif (version == 3)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'SBML_level', ...
+		                   'SBML_version', ...
+		                   'name', ...
+		                   'id', ...
+		                   'sboTerm', ...
+		                   'functionDefinition', ...
+		                   'unitDefinition', ...
+		                   'compartmentType', ...
+		                   'speciesType', ...
+		                   'compartment', ...
+		                   'species', ...
+		                   'parameter', ...
+		                   'initialAssignment', ...
+		                   'rule', ...
+		                   'constraint', ...
+		                   'reaction', ...
+		                   'event', ...
+		                 };
+		nNumberFields = 21;
+	elseif (version == 4)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'SBML_level', ...
+		                   'SBML_version', ...
+		                   'name', ...
+		                   'id', ...
+		                   'sboTerm', ...
+		                   'functionDefinition', ...
+		                   'unitDefinition', ...
+		                   'compartmentType', ...
+		                   'speciesType', ...
+		                   'compartment', ...
+		                   'species', ...
+		                   'parameter', ...
+		                   'initialAssignment', ...
+		                   'rule', ...
+		                   'constraint', ...
+		                   'reaction', ...
+		                   'event', ...
+		                 };
+		nNumberFields = 21;
+	end;
+elseif (level == 3)
+	if (version == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'SBML_level', ...
+		                   'SBML_version', ...
+		                   'name', ...
+		                   'id', ...
+		                   'sboTerm', ...
+		                   'functionDefinition', ...
+		                   'unitDefinition', ...
+		                   'compartment', ...
+		                   'species', ...
+		                   'parameter', ...
+		                   'initialAssignment', ...
+		                   'rule', ...
+		                   'constraint', ...
+		                   'reaction', ...
+		                   'event', ...
+		                   'substanceUnits', ...
+		                   'timeUnits', ...
+		                   'lengthUnits', ...
+		                   'areaUnits', ...
+		                   'volumeUnits', ...
+		                   'extentUnits', ...
+		                   'conversionFactor', ...
+		                 };
+		nNumberFields = 26;
+	end;
+end;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function [SBMLfieldnames, nNumberFields] = getModifierSpeciesReferenceFieldnames(level, ...
+                                                                                 version)
+
+
+
+
+
+
+
+
+
+
+if (~isValidLevelVersionCombination(level, version))
+  error ('invalid level/version combination');
+end;
+
+if (level == 1)
+	SBMLfieldnames = [];
+	nNumberFields = 0;
+elseif (level == 2)
+	if (version == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'species', ...
+		                 };
+		nNumberFields = 5;
+	elseif (version == 2)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'species', ...
+		                   'id', ...
+		                   'name', ...
+		                   'sboTerm', ...
+		                 };
+		nNumberFields = 8;
+	elseif (version == 3)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'species', ...
+		                   'id', ...
+		                   'name', ...
+		                 };
+		nNumberFields = 8;
+	elseif (version == 4)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'species', ...
+		                   'id', ...
+		                   'name', ...
+		                 };
+		nNumberFields = 8;
+	end;
+elseif (level == 3)
+	if (version == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'species', ...
+		                   'id', ...
+		                   'name', ...
+		                 };
+		nNumberFields = 8;
+	end;
+end;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function [SBMLfieldnames, nNumberFields] = getParameterFieldnames(level, ...
+                                                                  version)
+
+
+
+
+
+
+
+
+
+
+if (~isValidLevelVersionCombination(level, version))
+  error ('invalid level/version combination');
+end;
+
+if (level == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'name', ...
+		                   'value', ...
+		                   'units', ...
+		                   'isSetValue', ...
+		                 };
+		nNumberFields = 7;
+elseif (level == 2)
+	if (version == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'name', ...
+		                   'id', ...
+		                   'value', ...
+		                   'units', ...
+		                   'constant', ...
+		                   'isSetValue', ...
+		                 };
+		nNumberFields = 10;
+	elseif (version == 2)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'name', ...
+		                   'id', ...
+		                   'value', ...
+		                   'units', ...
+		                   'constant', ...
+		                   'sboTerm', ...
+		                   'isSetValue', ...
+		                 };
+		nNumberFields = 11;
+	elseif (version == 3)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'name', ...
+		                   'id', ...
+		                   'value', ...
+		                   'units', ...
+		                   'constant', ...
+		                   'isSetValue', ...
+		                 };
+		nNumberFields = 11;
+	elseif (version == 4)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'name', ...
+		                   'id', ...
+		                   'value', ...
+		                   'units', ...
+		                   'constant', ...
+		                   'isSetValue', ...
+		                 };
+		nNumberFields = 11;
+	end;
+elseif (level == 3)
+	if (version == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'name', ...
+		                   'id', ...
+		                   'value', ...
+		                   'units', ...
+		                   'constant', ...
+		                   'isSetValue', ...
+		                 };
+		nNumberFields = 11;
+	end;
+end;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function [SBMLfieldnames, nNumberFields] = getParameterRuleFieldnames(level, ...
+                                                             version)
+
+
+
+
+
+
+
+
+
+
+if (~isValidLevelVersionCombination(level, version))
+  error ('invalid level/version combination');
+end;
+
+if (level == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'type', ...
+		                   'formula', ...
+		                   'variable', ...
+		                   'species', ...
+		                   'compartment', ...
+		                   'name', ...
+		                   'units', ...
+		                 };
+		nNumberFields = 10;
+elseif (level == 2)
+	if (version == 1)
+		SBMLfieldnames = [];
+		nNumberFields = 0;
+	elseif (version == 2)
+		SBMLfieldnames = [];
+		nNumberFields = 0;
+	elseif (version == 3)
+		SBMLfieldnames = [];
+		nNumberFields = 0;
+	elseif (version == 4)
+		SBMLfieldnames = [];
+		nNumberFields = 0;
+	end;
+elseif (level == 3)
+	if (version == 1)
+		SBMLfieldnames = [];
+		nNumberFields = 0;
+	end;
+end;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function [SBMLfieldnames, nNumberFields] = getPriorityFieldnames(level, ...
+                                                                 version)
+
+
+
+
+
+
+
+
+
+
+if (~isValidLevelVersionCombination(level, version))
+  error ('invalid level/version combination');
+end;
+
+if (level == 1)
+	SBMLfieldnames = [];
+	nNumberFields = 0;
+elseif (level == 2)
+	SBMLfieldnames = [];
+	nNumberFields = 0;
+elseif (level == 3)
+	if (version == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'math', ...
+		                 };
+		nNumberFields = 6;
+  end;
+end;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function [SBMLfieldnames, nNumberFields] = getRateRuleFieldnames(level, ...
+                                                             version)
+
+
+
+
+
+
+
+
+
+
+if (~isValidLevelVersionCombination(level, version))
+  error ('invalid level/version combination');
+end;
+
+if (level == 1)
+		SBMLfieldnames = [];
+		nNumberFields = 0;
+elseif (level == 2)
+	if (version == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'formula', ...
+		                   'variable', ...
+		                   'species', ...
+		                   'compartment', ...
+		                   'name', ...
+		                   'units', ...
+		                 };
+		nNumberFields = 10;
+	elseif (version == 2)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'formula', ...
+		                   'variable', ...
+		                   'species', ...
+		                   'compartment', ...
+		                   'name', ...
+		                   'units', ...
+		                 };
+		nNumberFields = 11;
+	elseif (version == 3)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'formula', ...
+		                   'variable', ...
+		                   'species', ...
+		                   'compartment', ...
+		                   'name', ...
+		                   'units', ...
+		                 };
+		nNumberFields = 11;
+	elseif (version == 4)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'formula', ...
+		                   'variable', ...
+		                   'species', ...
+		                   'compartment', ...
+		                   'name', ...
+		                   'units', ...
+		                 };
+		nNumberFields = 11;
+	end;
+elseif (level == 3)
+	if (version == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'formula', ...
+		                   'variable', ...
+		                   'species', ...
+		                   'compartment', ...
+		                   'name', ...
+		                   'units', ...
+		                 };
+		nNumberFields = 11;
+	end;
+end;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function [SBMLfieldnames, nNumberFields] = getReactionFieldnames(level, ...
+                                                                 version)
+
+
+
+
+
+
+
+
+
+
+if (~isValidLevelVersionCombination(level, version))
+  error ('invalid level/version combination');
+end;
+
+if (level == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'name', ...
+		                   'reactant', ...
+		                   'product', ...
+		                   'kineticLaw', ...
+		                   'reversible', ...
+		                   'fast', ...
+		                 };
+		nNumberFields = 9;
+elseif (level == 2)
+	if (version == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'name', ...
+		                   'id', ...
+		                   'reactant', ...
+		                   'product', ...
+		                   'modifier', ...
+		                   'kineticLaw', ...
+		                   'reversible', ...
+		                   'fast', ...
+		                   'isSetFast', ...
+		                 };
+		nNumberFields = 13;
+	elseif (version == 2)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'name', ...
+		                   'id', ...
+		                   'reactant', ...
+		                   'product', ...
+		                   'modifier', ...
+		                   'kineticLaw', ...
+		                   'reversible', ...
+		                   'fast', ...
+		                   'sboTerm', ...
+		                   'isSetFast', ...
+		                 };
+		nNumberFields = 14;
+	elseif (version == 3)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'name', ...
+		                   'id', ...
+		                   'reactant', ...
+		                   'product', ...
+		                   'modifier', ...
+		                   'kineticLaw', ...
+		                   'reversible', ...
+		                   'fast', ...
+		                   'isSetFast', ...
+		                 };
+		nNumberFields = 14;
+	elseif (version == 4)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'name', ...
+		                   'id', ...
+		                   'reactant', ...
+		                   'product', ...
+		                   'modifier', ...
+		                   'kineticLaw', ...
+		                   'reversible', ...
+		                   'fast', ...
+		                   'isSetFast', ...
+		                 };
+		nNumberFields = 14;
+	end;
+elseif (level == 3)
+	if (version == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'name', ...
+		                   'id', ...
+		                   'reactant', ...
+		                   'product', ...
+		                   'modifier', ...
+		                   'kineticLaw', ...
+		                   'reversible', ...
+		                   'fast', ...
+		                   'isSetFast', ...
+		                   'compartment', ...
+		                 };
+		nNumberFields = 15;
+	end;
+end;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function [SBMLfieldnames, nNumberFields] = getRuleFieldnames(level, ...
+                                                             version)
+
+
+
+
+
+
+
+
+
+
+if (~isValidLevelVersionCombination(level, version))
+  error ('invalid level/version combination');
+end;
+
+if (level == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'type', ...
+		                   'formula', ...
+		                   'variable', ...
+		                   'species', ...
+		                   'compartment', ...
+		                   'name', ...
+		                   'units', ...
+		                 };
+		nNumberFields = 10;
+elseif (level == 2)
+	if (version == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'formula', ...
+		                   'variable', ...
+		                   'species', ...
+		                   'compartment', ...
+		                   'name', ...
+		                   'units', ...
+		                 };
+		nNumberFields = 10;
+	elseif (version == 2)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'formula', ...
+		                   'variable', ...
+		                   'species', ...
+		                   'compartment', ...
+		                   'name', ...
+		                   'units', ...
+		                 };
+		nNumberFields = 11;
+	elseif (version == 3)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'formula', ...
+		                   'variable', ...
+		                   'species', ...
+		                   'compartment', ...
+		                   'name', ...
+		                   'units', ...
+		                 };
+		nNumberFields = 11;
+	elseif (version == 4)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'formula', ...
+		                   'variable', ...
+		                   'species', ...
+		                   'compartment', ...
+		                   'name', ...
+		                   'units', ...
+		                 };
+		nNumberFields = 11;
+	end;
+elseif (level == 3)
+	if (version == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'formula', ...
+		                   'variable', ...
+		                   'species', ...
+		                   'compartment', ...
+		                   'name', ...
+		                   'units', ...
+		                 };
+		nNumberFields = 11;
+	end;
+end;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function [SBMLfieldnames, nNumberFields] = getSpeciesConcentrationRuleFieldnames(level, ...
+                                                             version)
+
+
+
+
+
+
+
+
+
+
+if (~isValidLevelVersionCombination(level, version))
+  error ('invalid level/version combination');
+end;
+
+if (level == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'type', ...
+		                   'formula', ...
+		                   'variable', ...
+		                   'species', ...
+		                   'compartment', ...
+		                   'name', ...
+		                   'units', ...
+		                 };
+		nNumberFields = 10;
+elseif (level == 2)
+	if (version == 1)
+		SBMLfieldnames = [];
+		nNumberFields = 0;
+	elseif (version == 2)
+		SBMLfieldnames = [];
+		nNumberFields = 0;
+	elseif (version == 3)
+		SBMLfieldnames = [];
+		nNumberFields = 0;
+	elseif (version == 4)
+		SBMLfieldnames = [];
+		nNumberFields = 0;
+	end;
+elseif (level == 3)
+	if (version == 1)
+		SBMLfieldnames = [];
+		nNumberFields = 0;
+	end;
+end;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function [SBMLfieldnames, nNumberFields] = getSpeciesFieldnames(level, ...
+                                                                version)
+
+
+
+
+
+
+
+
+
+
+if (~isValidLevelVersionCombination(level, version))
+  error ('invalid level/version combination');
+end;
+
+if (level == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'name', ...
+		                   'compartment', ...
+		                   'initialAmount', ...
+		                   'units', ...
+		                   'boundaryCondition', ...
+		                   'charge', ...
+		                   'isSetInitialAmount', ...
+		                   'isSetCharge', ...
+		                 };
+		nNumberFields = 11;
+elseif (level == 2)
+	if (version == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'name', ...
+		                   'id', ...
+		                   'compartment', ...
+		                   'initialAmount', ...
+		                   'initialConcentration', ...
+		                   'substanceUnits', ...
+		                   'spatialSizeUnits', ...
+		                   'hasOnlySubstanceUnits', ...
+		                   'boundaryCondition', ...
+		                   'charge', ...
+		                   'constant', ...
+		                   'isSetInitialAmount', ...
+		                   'isSetInitialConcentration', ...
+		                   'isSetCharge', ...
+		                 };
+		nNumberFields = 18;
+	elseif (version == 2)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'name', ...
+		                   'id', ...
+		                   'speciesType', ...
+		                   'compartment', ...
+		                   'initialAmount', ...
+		                   'initialConcentration', ...
+		                   'substanceUnits', ...
+		                   'spatialSizeUnits', ...
+		                   'hasOnlySubstanceUnits', ...
+		                   'boundaryCondition', ...
+		                   'charge', ...
+		                   'constant', ...
+		                   'isSetInitialAmount', ...
+		                   'isSetInitialConcentration', ...
+		                   'isSetCharge', ...
+		                 };
+		nNumberFields = 19;
+	elseif (version == 3)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'name', ...
+		                   'id', ...
+		                   'speciesType', ...
+		                   'compartment', ...
+		                   'initialAmount', ...
+		                   'initialConcentration', ...
+		                   'substanceUnits', ...
+		                   'hasOnlySubstanceUnits', ...
+		                   'boundaryCondition', ...
+		                   'charge', ...
+		                   'constant', ...
+		                   'isSetInitialAmount', ...
+		                   'isSetInitialConcentration', ...
+		                   'isSetCharge', ...
+		                 };
+		nNumberFields = 19;
+	elseif (version == 4)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'name', ...
+		                   'id', ...
+		                   'speciesType', ...
+		                   'compartment', ...
+		                   'initialAmount', ...
+		                   'initialConcentration', ...
+		                   'substanceUnits', ...
+		                   'hasOnlySubstanceUnits', ...
+		                   'boundaryCondition', ...
+		                   'charge', ...
+		                   'constant', ...
+		                   'isSetInitialAmount', ...
+		                   'isSetInitialConcentration', ...
+		                   'isSetCharge', ...
+		                 };
+		nNumberFields = 19;
+	end;
+elseif (level == 3)
+	if (version == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'name', ...
+		                   'id', ...
+		                   'compartment', ...
+		                   'initialAmount', ...
+		                   'initialConcentration', ...
+		                   'substanceUnits', ...
+		                   'hasOnlySubstanceUnits', ...
+		                   'boundaryCondition', ...
+		                   'constant', ...
+		                   'isSetInitialAmount', ...
+		                   'isSetInitialConcentration', ...
+		                   'conversionFactor', ...
+		                 };
+		nNumberFields = 17;
+	end;
+end;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function [SBMLfieldnames, nNumberFields] = getSpeciesReferenceFieldnames(level, ...
+                                                                         version)
+
+
+
+
+
+
+
+
+
+
+if (~isValidLevelVersionCombination(level, version))
+  error ('invalid level/version combination');
+end;
+
+if (level == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'species', ...
+		                   'stoichiometry', ...
+		                   'denominator', ...
+		                 };
+		nNumberFields = 6;
+elseif (level == 2)
+	if (version == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'species', ...
+		                   'stoichiometry', ...
+		                   'denominator', ...
+		                   'stoichiometryMath', ...
+		                 };
+		nNumberFields = 8;
+	elseif (version == 2)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'species', ...
+		                   'id', ...
+		                   'name', ...
+		                   'sboTerm', ...
+		                   'stoichiometry', ...
+		                   'stoichiometryMath', ...
+		                 };
+		nNumberFields = 10;
+	elseif (version == 3)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'species', ...
+		                   'id', ...
+		                   'name', ...
+		                   'stoichiometry', ...
+		                   'stoichiometryMath', ...
+		                 };
+		nNumberFields = 10;
+	elseif (version == 4)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'species', ...
+		                   'id', ...
+		                   'name', ...
+		                   'stoichiometry', ...
+		                   'stoichiometryMath', ...
+		                 };
+		nNumberFields = 10;
+	end;
+elseif (level == 3)
+	if (version == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'species', ...
+		                   'id', ...
+		                   'name', ...
+		                   'stoichiometry', ...
+		                   'constant', ...
+		                   'isSetStoichiometry', ...
+		                 };
+		nNumberFields = 11;
+	end;
+end;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function [SBMLfieldnames, nNumberFields] = getSpeciesTypeFieldnames(level, ...
+                                                                    version)
+
+
+
+
+
+
+
+
+
+
+if (~isValidLevelVersionCombination(level, version))
+  error ('invalid level/version combination');
+end;
+
+if (level == 1)
+	SBMLfieldnames = [];
+	nNumberFields = 0;
+elseif (level == 2)
+	if (version == 1)
+		SBMLfieldnames = [];
+		nNumberFields = 0;
+	elseif (version == 2)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'name', ...
+		                   'id', ...
+		                 };
+		nNumberFields = 6;
+	elseif (version == 3)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'name', ...
+		                   'id', ...
+		                 };
+		nNumberFields = 7;
+	elseif (version == 4)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'name', ...
+		                   'id', ...
+		                 };
+		nNumberFields = 7;
+	end;
+elseif (level == 3)
+	if (version == 1)
+		SBMLfieldnames = [];
+		nNumberFields = 0;
+	end;
+end;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function [SBMLfieldnames, nNumberFields] = getStoichiometryMathFieldnames(level, ...
+                                                                          version)
+
+
+
+
+
+
+
+
+
+
+if (~isValidLevelVersionCombination(level, version))
+  error ('invalid level/version combination');
+end;
+
+if (level == 1)
+	SBMLfieldnames = [];
+	nNumberFields = 0;
+elseif (level == 2)
+	if (version == 1)
+		SBMLfieldnames = [];
+		nNumberFields = 0;
+	elseif (version == 2)
+		SBMLfieldnames = [];
+		nNumberFields = 0;
+	elseif (version == 3)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'math', ...
+		                 };
+		nNumberFields = 6;
+	elseif (version == 4)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'math', ...
+		                 };
+		nNumberFields = 6;
+	end;
+elseif (level == 3)
+	if (version == 1)
+		SBMLfieldnames = [];
+		nNumberFields = 0;
+	end;
+end;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function [SBMLfieldnames, nNumberFields] = getTriggerFieldnames(level, ...
+                                                                version)
+
+
+
+
+
+
+
+
+
+
+if (~isValidLevelVersionCombination(level, version))
+  error ('invalid level/version combination');
+end;
+
+if (level == 1)
+	SBMLfieldnames = [];
+	nNumberFields = 0;
+elseif (level == 2)
+	if (version == 1)
+		SBMLfieldnames = [];
+		nNumberFields = 0;
+	elseif (version == 2)
+		SBMLfieldnames = [];
+		nNumberFields = 0;
+	elseif (version == 3)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'math', ...
+		                 };
+		nNumberFields = 6;
+	elseif (version == 4)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'math', ...
+		                 };
+		nNumberFields = 6;
+	end;
+elseif (level == 3)
+	if (version == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'persistent', ...
+		                   'initialValue', ...
+		                   'math', ...
+		                 };
+		nNumberFields = 8;
+	end;
+end;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function [SBMLfieldnames, nNumberFields] = getUnitDefinitionFieldnames(level, ...
+                                                                       version)
+
+
+
+
+
+
+
+
+
+
+if (~isValidLevelVersionCombination(level, version))
+  error ('invalid level/version combination');
+end;
+
+if (level == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'name', ...
+		                   'unit', ...
+		                 };
+		nNumberFields = 5;
+elseif (level == 2)
+	if (version == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'name', ...
+		                   'id', ...
+		                   'unit', ...
+		                 };
+		nNumberFields = 7;
+	elseif (version == 2)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'name', ...
+		                   'id', ...
+		                   'unit', ...
+		                 };
+		nNumberFields = 7;
+	elseif (version == 3)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'name', ...
+		                   'id', ...
+		                   'unit', ...
+		                 };
+		nNumberFields = 8;
+	elseif (version == 4)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'name', ...
+		                   'id', ...
+		                   'unit', ...
+		                 };
+		nNumberFields = 8;
+	end;
+elseif (level == 3)
+	if (version == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'name', ...
+		                   'id', ...
+		                   'unit', ...
+		                 };
+		nNumberFields = 8;
+	end;
+end;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function [SBMLfieldnames, nNumberFields] = getUnitFieldnames(level, ...
+                                                             version)
+
+
+
+
+
+
+
+
+
+
+if (~isValidLevelVersionCombination(level, version))
+  error ('invalid level/version combination');
+end;
+
+if (level == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'kind', ...
+		                   'exponent', ...
+		                   'scale', ...
+		                 };
+		nNumberFields = 6;
+elseif (level == 2)
+	if (version == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'kind', ...
+		                   'exponent', ...
+		                   'scale', ...
+		                   'multiplier', ...
+		                   'offset', ...
+		                 };
+		nNumberFields = 9;
+	elseif (version == 2)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'kind', ...
+		                   'exponent', ...
+		                   'scale', ...
+		                   'multiplier', ...
+		                 };
+		nNumberFields = 8;
+	elseif (version == 3)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'kind', ...
+		                   'exponent', ...
+		                   'scale', ...
+		                   'multiplier', ...
+		                 };
+		nNumberFields = 9;
+	elseif (version == 4)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'kind', ...
+		                   'exponent', ...
+		                   'scale', ...
+		                   'multiplier', ...
+		                 };
+		nNumberFields = 9;
+	end;
+elseif (level == 3)
+	if (version == 1)
+		SBMLfieldnames = { 'typecode', ...
+		                   'metaid', ...
+		                   'notes', ...
+		                   'annotation', ...
+		                   'sboTerm', ...
+		                   'kind', ...
+		                   'exponent', ...
+		                   'scale', ...
+		                   'multiplier', ...
+		                 };
+		nNumberFields = 9;
+	end;
+end;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function [SBMLfieldnames, nNumberFields] = getFBCModelFieldnames(level, ...
+                                                         version, pkgVersion)
+if (~isValidLevelVersionCombination(level, version))
+  error ('invalid level/version combination');
+end;
+
+% need a check on package version
+
+if (level == 1)
+	SBMLfieldnames = [];
+	nNumberFields = 0;
+elseif (level == 2)
+	SBMLfieldnames = [];
+	nNumberFields = 0;
+elseif (level == 3)
+	if (version == 1)
+    if (pkgVersion == 1)
+      SBMLfieldnames = { 'fbc_version', ...
+                         'fbc_fluxBound', ...
+                         'fbc_objective', ...
+                         'fbc_activeObjective', ...
+                       };
+      nNumberFields = 4;
+    end;
+	end;
+end;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function [SBMLfieldnames, nNumberFields] = getFBCSpeciesFieldnames(level, ...
+                                                         version, pkgVersion)
+
+if (~isValidLevelVersionCombination(level, version))
+  error ('invalid level/version combination');
+end;
+
+% need a check on package version
+
+if (level == 1)
+	SBMLfieldnames = [];
+	nNumberFields = 0;
+elseif (level == 2)
+	SBMLfieldnames = [];
+	nNumberFields = 0;
+elseif (level == 3)
+	if (version == 1)
+    if (pkgVersion == 1)
+      SBMLfieldnames = { 'fbc_charge', ...
+                         'isSetfbc_charge', ...
+                         'fbc_chemicalFormula', ...
+                         'fbc_version', ...
+                       };
+      nNumberFields = 4;
+    end;
+	end;
+end;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function [SBMLfieldnames, nNumberFields] = getFluxBoundFieldnames(level, ...
+                                                         version, pkgVersion)
+
+if (~isValidLevelVersionCombination(level, version))
+  error ('invalid level/version combination');
+end;
+
+% need a check on package version
+
+if (level == 1)
+	SBMLfieldnames = [];
+	nNumberFields = 0;
+elseif (level == 2)
+	SBMLfieldnames = [];
+	nNumberFields = 0;
+elseif (level == 3)
+	if (version == 1)
+    if (pkgVersion == 1)
+      SBMLfieldnames = { 'typecode', ...
+                         'metaid', ...
+                         'notes', ...
+                         'annotation', ...
+                         'sboTerm', ...
+                         'fbc_id', ...
+                         'fbc_reaction', ...
+                         'fbc_operation', ...
+                         'fbc_value', ...
+                         'isSetfbc_value', ...
+                         'level', ...
+                         'version', ...
+                         'fbc_version', ...
+                       };
+      nNumberFields = 13;
+    end;
+	end;
+end;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function [SBMLfieldnames, nNumberFields] = getFluxObjectiveFieldnames(level, ...
+                                                         version, pkgVersion)
+
+if (~isValidLevelVersionCombination(level, version))
+  error ('invalid level/version combination');
+end;
+
+% need a check on package version
+
+if (level == 1)
+	SBMLfieldnames = [];
+	nNumberFields = 0;
+elseif (level == 2)
+	SBMLfieldnames = [];
+	nNumberFields = 0;
+elseif (level == 3)
+	if (version == 1)
+    if (pkgVersion == 1)
+      SBMLfieldnames = { 'typecode', ...
+                         'metaid', ...
+                         'notes', ...
+                         'annotation', ...
+                         'sboTerm', ...
+                         'fbc_reaction', ...
+                         'fbc_coefficient', ...
+                         'isSetfbc_coefficient', ...
+                         'level', ...
+                         'version', ...
+                         'fbc_version', ...
+                       };
+      nNumberFields = 11;
+    end;
+	end;
+end;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function [SBMLfieldnames, nNumberFields] = getObjectiveFieldnames(level, ...
+                                                         version, pkgVersion)
+
+if (~isValidLevelVersionCombination(level, version))
+  error ('invalid level/version combination');
+end;
+
+% need a check on package version
+
+if (level == 1)
+	SBMLfieldnames = [];
+	nNumberFields = 0;
+elseif (level == 2)
+	SBMLfieldnames = [];
+	nNumberFields = 0;
+elseif (level == 3)
+	if (version == 1)
+    if (pkgVersion == 1)
+      SBMLfieldnames = { 'typecode', ...
+                         'metaid', ...
+                         'notes', ...
+                         'annotation', ...
+                         'sboTerm', ...
+                         'fbc_id', ...
+                         'fbc_type', ...
+                         'fbc_fluxObjective', ...
+                         'level', ...
+                         'version', ...
+                         'fbc_version', ...
+                       };
+      nNumberFields = 11;
+    end;
+	end;
+end;
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/THIRD_PARTY_SOFTWARE/SBMLimportExport/auxiliary/isoctave.m b/IQMtools V1.2.2.2/IQMlite/auxiliary/THIRD_PARTY_SOFTWARE/SBMLimportExport/auxiliary/isoctave.m
new file mode 100644
index 0000000000000000000000000000000000000000..fadef931834e2e09e433078c1e61e2e5d7fa1ae0
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/THIRD_PARTY_SOFTWARE/SBMLimportExport/auxiliary/isoctave.m	
@@ -0,0 +1,27 @@
+function t=isoctave()
+%ISOCTAVE  True if the operating environment is octave.
+%   Usage: t=isoctave();
+%
+%   Returns 1 if the operating environment is octave, otherwise
+%   0 (Matlab)
+
+% @file    isoctave.m
+% @brief   Returns true if using octave
+% @author  Sarah Keating
+% 
+%
+% ISOCTAVE.M
+%
+% COPYRIGHT : (c) NUHAG, Dept.Math., University of Vienna, AUSTRIA
+%             http://nuhag.eu/
+%             Permission is granted to modify and re-distribute this
+%             code in any manner as long as this notice is preserved.
+%             All standard disclaimers apply.
+%
+
+if exist('OCTAVE_VERSION')
+  % Only Octave has this variable.
+  t='1';
+else
+  t='0';
+end;
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/compareFilesEqualIQM.m b/IQMtools V1.2.2.2/IQMlite/auxiliary/compareFilesEqualIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..40825420be4db6bff6a0c826c9d19a65630bd137
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/compareFilesEqualIQM.m	
@@ -0,0 +1,18 @@
+function [result] = compareFilesEqualIQM(A,B,line)
+% Compares if two text files have equal content. 
+% A and B are paths to the files to be compared.
+% line indicates the number of the line from which the comparison should
+% start. As line separator char(10) is assumed.
+
+    Ax = fileread(A);
+    Bx = fileread(B);
+    
+    % Get from line-th line
+    if line>1,
+        ix = find(Ax==char(10)); Ax = Ax(ix(line-1)+1:end);
+        ix = find(Bx==char(10)); Bx = Bx(ix(line-1)+1:end);
+    end
+    
+    % Compare
+    result = strcmp(Ax,Bx);
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/compatibility/mat2datasetIQM.m b/IQMtools V1.2.2.2/IQMlite/auxiliary/compatibility/mat2datasetIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..5866c7362375028432ca605c5a15cac83b31f0b6
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/compatibility/mat2datasetIQM.m	
@@ -0,0 +1,29 @@
+function [output] = mat2datasetIQM(x,colNames)
+% mat2datasetIQM: converts a double matrix to a dataset
+% Function required to allow compatibility with pre R2013 versions of MATLAB
+%
+%   d = mat2datasetIQM(x)
+%   d = mat2datasetIQM(x,colNames)
+%
+% x:        matlab matrix
+% colNames: cell-array with columnnames
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+if nargin == 1,
+    colNames = {};
+    for k=1:size(x,2),
+        colNames{k} = sprintf('x%d',k);
+    end
+end
+
+if length(colNames) ~= size(x,2),
+    error('Incorrect number of column names.');
+end
+
+output = table();
+for k=1:size(x,2),
+    output.(colNames{k}) = x(:,k);
+end
+
+    
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/compatibility/strmatchIQM.m b/IQMtools V1.2.2.2/IQMlite/auxiliary/compatibility/strmatchIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..27b34f2819da48d98016578241f4711ceb18c5c5
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/compatibility/strmatchIQM.m	
@@ -0,0 +1,48 @@
+function [I] = strmatchIQM(str,strarray,varargin)
+% strmatchIQM: emulates the functionality of strmatch. strmatch will be
+% removed from standard matlab soon (currently R2012a).
+%
+% I = strmatchIQM(STR, STRARRAY) looks through the rows of the character
+% array or cell array of strings STRARRAY to find strings that begin
+% with the string contained in STR, and returns the matching row indices.
+% Any trailing space characters in STR or STRARRAY are ignored when
+% matching. strmatch is fastest when STRARRAY is a character array.
+% 
+% I = strmatchIQM(STR, STRARRAY, 'exact') compares STR with each row of
+% STRARRAY, looking for an exact match of the entire strings. Any
+% trailing space characters in STR or STRARRAY are ignored when matching.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+% if verLessThan('matlab', '7.14'),
+%     % strmatch exists
+%     I = strmatch(str,strarray,varargin{:}); %#ok<*MATCH3>
+% else
+    % In newer versions "strmatch" might not exist - use a workaround instead
+
+    % Check if strarray is a string array and if yes, convert to cell-array
+    if ischar(strarray),
+        strarraynew = {};
+        for k=1:size(strarray,1),
+            strarraynew{k} = strarray(k,:);
+        end
+        strarray = strarraynew;
+    end
+    
+    if nargin==3,
+        if strcmp(varargin{1},'exact'),
+            I = find(strcmp(str,strarray));
+            I = I(:);
+        else
+            error('Third input argument to strmatchIQM needs to be "exact" or not specified.');
+        end
+    else
+        I = find(strncmp(str,strarray,length(str)));
+        I = I(:);
+    end
+% end
+        
+if isempty(I),
+    I = [];
+end
+
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/compliance/IQMconvertCellTable2ReportTable.m b/IQMtools V1.2.2.2/IQMlite/auxiliary/compliance/IQMconvertCellTable2ReportTable.m
new file mode 100644
index 0000000000000000000000000000000000000000..0c01af0f4e29f96430358bbfa92d3c64d4da52dd
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/compliance/IQMconvertCellTable2ReportTable.m	
@@ -0,0 +1,214 @@
+function [text] = IQMconvertCellTable2ReportTable(cellTable,format,filename)
+% This function allows to generate tables for display in the command window
+% and also allows to write them out to a text file - both humanly readable
+% and parse-able to subsequently reformat them for inclusion into a report.
+%
+% The input argument "cellTable" is a MATLAB cell-matrix that is allowed to
+% use a certain syntax, defined below:
+% 
+% The first column of the cell-matrix can be used as a "control-column"
+% and the first element in each row can contain any of the following <xy> tags:
+%   <TT>: Table title (only first element of cellTable written out across whole table width)
+%   <TH>: Table header (each cell of cellTable considered a table header element)
+%   <TR>: Table row (each cell of cellTable considered a table data element)
+%   <TF>: Table footer (only first element of cellTable written out across whole table width)
+%   <HR>: Table separator (no content expected. Just introducing a break (e.g., horizontal line))
+%   <TI>: Table information (only first element written out across the whole line. No separators top and bottom)
+% 
+% This control column can be missing and in this case the cellTable is just
+% written out, considering each cell a cell in the table <TR>.
+%
+% Several tables can be present in the same cellTable. Each starts with
+% <TT> or <TH>.
+%
+% Additional formatting in table cells:
+% -------------------------------------
+% * Line breaks ('\n') can be used in cell elements. For text output they
+%   are replace by spaces (' '). For report outputs they are replace by
+%   HTML tag '<br>'.
+%
+% [SYNTAX]
+% [text] = IQMconvertCellTable2ReportTable(cellTable)
+% [text] = IQMconvertCellTable2ReportTable(cellTable,format)
+% [text] = IQMconvertCellTable2ReportTable(cellTable,format,filename)
+%
+% [INPUT]
+% cellTable:    Cell-matrix with string and/or numeric entries and
+%               potentially the control column for formatting 
+% format:   	Control of output format
+%           "text":     Will convert to text only without control tags.
+%                       This can be used if information shoudl just be
+%                       displayed to the user in the command window or exported
+%                       to a file that will not be part of a report.
+%           "report":   This will convert the table to text as well but
+%                       additionally add some formatting that is needed to
+%                       parse this table from a text file for later
+%                       formatting into a report. (default).
+% filename:     If a filename is provided then the table is exported to
+%               filename.txt. (default: '');
+%
+% [OUTPUT]
+% text:         Formatted string table output
+% The text might also be written to a file.              
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+% Handle variable input arguments
+if nargin<2,
+    format = 'report';
+end
+if nargin<3.
+    filename = '';
+end
+format = lower(format);
+
+% Check things
+if isempty(strmatchIQM(format,{'report','text'},'exact')),
+    error('Input argument "format" wrongly defined.');
+end
+
+% Convert all elements in cellTable to char 
+for k=1:size(cellTable,1),
+    for k2=1:size(cellTable,2),
+        if isempty(cellTable{k,k2}),
+            cellTable{k,k2} = '';
+        end
+        if isnumeric(cellTable{k,k2}),
+            cellTable{k,k2} = num2str(cellTable{k,k2});
+        end
+    end
+end
+
+% Check line breaks in cellTable and replace by '<br>'
+for k=1:size(cellTable,1),
+    for k2=1:size(cellTable,2),
+        cellTable{k,k2} = regexprep(cellTable{k,k2},'\n','<br>');
+    end
+end
+
+
+% Check if control column present
+CONTROL = 1;
+if isnumeric(cellTable{1,1}),
+    CONTROL = 0;
+end
+if isempty(intersect({'<TT>','<TH>','<TR>','<TF>','<HR>'},cellTable(:,1))),
+    CONTROL = 0;
+end
+
+% If no control column then treat all rows as <TR>
+if CONTROL,
+    control_column = upper(cellTable(:,1));
+    cellTable2     = cellTable(:,2:end);
+else
+    control_column = cell(size(cellTable,1),1);
+    control_column(1:end) = {'<TR>'};
+    cellTable2     = cellTable;
+end
+    
+% Find maxcellTable lengths of strings in each <TR> and <TH> column
+length_column_string = -Inf(1,size(cellTable2,2));
+for k=1:size(cellTable2,2),
+    for k2=1:size(cellTable2,1),
+        if strcmp(control_column{k2},'<TR>') || strcmp(control_column{k2},'<TH>'),
+            if length(cellTable2{k2,k}) > length_column_string(k),
+                length_column_string(k) = length(cellTable2{k2,k});
+            end
+        end
+    end
+end
+
+% Update table entries by postpadding with spaces to match
+% length_column_string - do not postpad last column. 
+for k=1:size(cellTable2,1),
+    for k2=1:size(cellTable2,2),
+        cellTable2{k,k2} = postFillCharIQM(cellTable2{k,k2},length_column_string(k2),' ');
+    end
+end
+
+% Add separator in all but last column for <TH> and <TR> cells.
+% Spaces in case of "text" and ' | in case of "report".
+for k=1:size(cellTable2,1),
+    if strcmp(control_column{k},'<TR>') || strcmp(control_column{k},'<TH>'),
+        for k2=1:size(cellTable2,2)-1,
+            if strcmp(format,'report'), separator = ' | '; else separator = ' | '; end
+            cellTable2{k,k2} = [cellTable2{k,k2} separator];
+        end
+    end
+end
+
+% Get complete table width
+WIDTH_TABLE = length(sprintf('%s',cellTable2{1,:}));
+if strcmp(control_column{1,1},'<TT>'),
+    WIDTH_TABLE = WIDTH_TABLE+3;
+end
+
+% If report then add control chars to first column in tabe
+if strcmp(format,'report'),
+    for k=1:size(cellTable2,1),
+        cellTable2{k,1} = [control_column{k} '   ' cellTable2{k,1}];
+    end
+    addSpaces = '       ';
+    addSpacesHR = '   ';
+else
+    addSpaces = '';
+    addSpacesHR = '';
+end    
+
+% Convert to formatted text
+text = '';
+lengthTHRrow = 10;
+for k=1:size(cellTable2,1),
+    textadd = '';
+    % Handle <TT>
+    if strcmp(control_column{k},'<TT>'),
+        if k>1,
+            textadd = sprintf('\n\n%s\n%s%s\n\n',cellTable2{k,1},addSpaces,postFillCharIQM('',WIDTH_TABLE,'='));      
+        else
+            textadd = sprintf('%s\n%s%s\n\n',cellTable2{k,1},addSpaces,postFillCharIQM('',WIDTH_TABLE,'='));
+        end
+    end
+    % Handle <TH>
+    if strcmp(control_column{k},'<TH>'),
+        textadd = '';
+        for k2=1:size(cellTable2,2),
+            textadd = sprintf('%s%s',textadd,cellTable2{k,k2});
+        end
+        lengthTHRrow = length(textadd)-length(addSpaces);
+        textadd = sprintf('%s\n%s%s\n',textadd,addSpaces,postFillCharIQM('',lengthTHRrow,'-'));
+    end
+    % Handle <TR>
+    if strcmp(control_column{k},'<TR>'),
+        textadd = '';
+        for k2=1:size(cellTable2,2),
+            textadd = sprintf('%s%s',textadd,cellTable2{k,k2});
+        end
+        lengthTHRrow = length(textadd)-length(addSpaces);
+        textadd = sprintf('%s\n',textadd);
+    end
+    % Handle <TF>
+    if strcmp(control_column{k},'<TF>'),
+        textadd = sprintf('%s%s\n%s\n',addSpaces,postFillCharIQM('',lengthTHRrow,'-'),cellTable2{k,1});
+    end
+    % Handle <HR>
+    if strcmp(control_column{k},'<HR>'),
+        textadd = sprintf('%s%s%s\n',strtrim(cellTable2{k,1}),addSpacesHR,postFillCharIQM('',lengthTHRrow,'-'));
+    end
+    % Handle <TI>
+    if strcmp(control_column{k},'<TI>'),
+        textadd = sprintf('%s\n',cellTable2{k,1});
+    end
+    
+    % Combine text
+    text = [text textadd];
+end
+
+% Remove tags if "format" is "text"
+if strcmp(format,'text'),
+    text = strrep(text,'<br>','    ');
+    text = strrep(text,'<BR>','    ');
+end
+
+% Export results to file if filename defined
+IQMwriteText2File(text,[strrep(filename,'.txt','') '.txt']);
+
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/compliance/IQMinitializeCompliance.m b/IQMtools V1.2.2.2/IQMlite/auxiliary/compliance/IQMinitializeCompliance.m
new file mode 100644
index 0000000000000000000000000000000000000000..fbfda68b9992f51bf4e1cc906876808d42d5f357
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/compliance/IQMinitializeCompliance.m	
@@ -0,0 +1,60 @@
+function [] = IQMinitializeCompliance(ScriptName)
+% This function initializes the compliance check. Basically, it sets a
+% global variable (Current_ROOT_file_IQMtools_compliance) to a value of
+% "ScriptName". Additionally, this function sets the sed for random
+% generators in MATLAB, to ensure that rerunning the same script leads to
+% the same results.
+%
+% When the compliance mode is checked each analysis script needs to make a
+% call to "IQMinitializeCompliance(ScriptName)" at the beginning of the
+% script. The input argument needs to be the filename of the analysis
+% script. This can include the absolute path or just be the filename.
+%
+% [SYNTAX]
+% [] = IQMinitializeCompliance(ScriptName)
+%
+% [INPUT]
+% ScriptName:   Filename (with or without path) to the analysis script.
+%
+% [OUTPUT]
+% None
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Clear global variable 
+clear global Current_ROOT_file_IQMtools_compliance
+
+% Initialize the global variable
+global Current_ROOT_file_IQMtools_compliance
+
+% Set its value
+Current_ROOT_file_IQMtools_compliance = ScriptName;
+
+% Remove extension (.m) if present 
+Current_ROOT_file_IQMtools_compliance = strrep(Current_ROOT_file_IQMtools_compliance,'.m','');
+
+% Check if a function above IQMinitializeCompliance is stored in dbstack
+% ... if yes then assume this is the "root" script.
+x           = dbstack();
+rootFile    = strrep(x(end).file,'.m','');
+
+if ~strcmp(rootFile,'IQMinitializeCompliance'),
+    % There is at least one parent function to IQMinitializeCompliance
+    % Check if Current_ROOT_file_IQMtools_compliance is the parent function of IQMinitializeCompliance 
+    
+    names       = {x.name};
+    ix          = strmatchIQM('IQMinitializeCompliance',names,'exact');
+    checkFile   = names{ix+1};
+    
+    [p,f,e] = fileparts(Current_ROOT_file_IQMtools_compliance);
+    if ~strcmp(f,checkFile),
+        error('Input argument to "IQMinitializeCompliance" does not match the filename of this script in which this command is run.');
+    end
+end
+
+% Set seed
+setseedIQM(123456)
+
+
+
+
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/compliance/IQMoutputTable.m b/IQMtools V1.2.2.2/IQMlite/auxiliary/compliance/IQMoutputTable.m
new file mode 100644
index 0000000000000000000000000000000000000000..4fbd284b7b9c601306b385c84db777e09822001d
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/compliance/IQMoutputTable.m	
@@ -0,0 +1,61 @@
+function [text] = IQMoutputTable(xtable,xtitle,xfooter,filename)
+% This function allows to convert a MATLAB table to a report table
+% formatted to be compatible with IQReport.
+%
+% [SYNTAX]
+% [text] = IQMoutputTable(xtable,xtitle,xfooter,filename)
+%
+% [INPUT]
+% xtable:       MATLAB table
+% xtitle:       String with the table caption (default: '')
+% xfooter:      String with the table footer (default: '')
+% filename:     If a filename is provided then the table is exported to
+%               filename.txt. (default: '');
+%
+% [OUTPUT]
+% The text is written to a file.              
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+% Handle variable input arguments
+if nargin<4,
+    error('Please provide all input arguments.');
+end
+
+% Check table
+if ~istable(xtable),
+    error('First input argument is not a MATLAB table.');
+end
+
+% Get info
+Ncols               = size(xtable,2)+1;
+headerNames         = xtable.Properties.VariableNames;
+
+% Generate table-content as cell-array
+tableCells          = table2cell(xtable);
+
+% Add <TR> info
+tableRows           = cell(size(tableCells,1),1); 
+tableRows(1:end)    = {'<TR>'};
+tableCells          = [tableRows tableCells];
+
+% Add <TH> info
+tableCells          = [ [{'<TH>'} headerNames]; tableCells];
+
+% Add <TT> info
+tableTitle          = cell(1,Ncols);
+tableTitle{1}       = '<TT>';
+tableTitle{2}       = xtitle;
+tableCells          = [tableTitle; tableCells];
+
+% Add <TF> info
+if ~isempty(xfooter),
+    tableFooter         = cell(1,Ncols);
+    tableFooter{1}      = '<TF>';
+    tableFooter{2}      = xfooter;
+    tableCells          = [tableCells; tableFooter];
+end
+
+% Convert to report table
+IQMconvertCellTable2ReportTable(tableCells,'report',filename);
+
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/compliance/getComplianceModeIQM.m b/IQMtools V1.2.2.2/IQMlite/auxiliary/compliance/getComplianceModeIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..d934b7ac868c296ad0d76caadecb37f441ff8f64
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/compliance/getComplianceModeIQM.m	
@@ -0,0 +1,15 @@
+function [ COMPLIANCE_OUTPUT_MODE ] = getComplianceModeIQM()
+% This function returns value of the setting COMPLIANCE_OUTPUT_MODE in
+% SETUP_PATHS_TOOLS_IQMLITE.   
+%
+% [SYNTAX]
+% [ COMPLIANCE_OUTPUT_MODE ] = getComplianceModeIQM()
+%
+% [INPUT]
+%
+% [OUTPUT]
+% COMPLIANCE_OUTPUT_MODE:     Value of COMPLIANCE_OUTPUT_MODE
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+SETUP_PATHS_TOOLS_IQMLITE
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/compliance/getFunctionCallInformationIQM.m b/IQMtools V1.2.2.2/IQMlite/auxiliary/compliance/getFunctionCallInformationIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..6a7583fe52b985ee16f25553c43dbd93e05850e9
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/compliance/getFunctionCallInformationIQM.m	
@@ -0,0 +1,127 @@
+function [ results ] = getFunctionCallInformationIQM(FlagText,FlagLineNumbers,FlagCompleteNames)
+% This function generates and returns information about the username, the
+% current date and time and the stack of functions that have been called
+% until this function. This function here is not included in the stack.
+%
+% For compliance reasons it is important to have time stamps etc. for all
+% output - especially figures and tables.
+% 
+% This function allows to add this automatically when printing figures to
+% file via IQMprintFigure and writing text to file via IQMwriteText2File.
+%
+% [SYNTAX]
+% [ results ] = getFunctionCallInformationIQM()
+% [ results ] = getFunctionCallInformationIQM(FlagText)
+% [ results ] = getFunctionCallInformationIQM(FlagText,FlagLineNumbers)
+% [ results ] = getFunctionCallInformationIQM(FlagText,FlagLineNumbers,FlagCompleteNames)
+%
+% [INPUT]
+% FlagText:             =0: Return MATLAB structure with the information 
+%                       =1: Return a cell-array with the information - in table format (default)
+% FlagLineNumbers:      =0: Do not include line numbers (default)
+%                       =1: Include line numbers
+% FlagCompleteNames:    =0: Show filenames only (default)
+%                       =1: Show complete filenames with absolute path
+%
+% [OUTPUT]
+% results:  MATLAB structure with the following information:
+%   results.username:           String with username who ran the function
+%   results.data:               String with current date and time
+%   results.callingSequence:    String with function and script names that
+%                               have been called prior to this function.
+%                               this function here is not included. Line
+%                               number is included as well.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+% If COMPLIANCE_OUTPUT_MODE is on then Current_ROOT_file_IQMtools_compliance
+% needs to be set to the name of the script in which the user executes a
+% function that will lead (through several subscripts and functions) to an
+% output by IQMprintFigure or IQMwriteText2File.
+% The check requires global variables that are not accessible in a parfor
+% loop. Thus we need to check if in parallel execution or not. And only if
+% not then do the compliance check
+if ~isInsideParForLoopIQM(),
+    global Current_ROOT_file_IQMtools_compliance
+    if getComplianceModeIQM(),
+        if isempty(Current_ROOT_file_IQMtools_compliance),
+            error(sprintf('Compliance mode is on. Please use the function "IQMinitializeCompliance" at the beginning of each main working script.\nDo not use "clear all" within a script - or rerun the "IQMinitializeCompliance" function after each call to "clear all".'));
+        end
+    end
+else
+    Current_ROOT_file_IQMtools_compliance = 'undefined due to parfor';
+end
+
+% Handle variable input arguments
+if nargin<1,
+    FlagText                = 1;
+end
+if nargin<2,
+    FlagLineNumbers         = 0;
+end
+if nargin<3,
+    FlagCompleteNames       = 0;
+end
+
+% Initialize results variable
+results                     = [];
+
+% Get basic information about user and date and time of function call
+results.username            = usernameIQM();
+results.date                = datestr(now,'yyyy-mmm-DD HH:MM');
+
+% Get information about call sequence
+x                           = dbstack('-completenames');
+
+callingSequence             = {};
+for k=length(x):-1:2,
+    if FlagLineNumbers,
+        callingSequence{end+1} = sprintf('%s (Line: %d)\n',x(k).file,x(k).line);
+    else
+        callingSequence{end+1} = sprintf('%s\n',x(k).file);
+    end
+end
+% Adjust folder separators
+results.callingSequence     = strrep(strtrim(callingSequence),'\','/');
+
+% Check if Current_ROOT_file_IQMtools_compliance contents appear in 
+% results.callingSequence. If not then add it. Only check for filename ...
+% not necessarily with path - but with .m at the end and '/' before.
+if getComplianceModeIQM(),
+    [xp,xf,xe] = fileparts(Current_ROOT_file_IQMtools_compliance);
+    checkName  = ['/' xf '.m'];
+    ROOT_PRESENT = 0;
+    for k=1:length(results.callingSequence),
+        ix = strfind(results.callingSequence{k},checkName);
+        if ~isempty(ix),
+            ROOT_PRESENT = 1;
+        end
+    end
+    if ~ROOT_PRESENT,
+        % Root file defined by Current_ROOT_file_IQMtools_compliance not
+        % present in calling sequence. This is due to manual or execution
+        % of parts of the script only. Need to add the root file name
+        if ~isInsideParForLoopIQM(),
+            results.callingSequence = [{['Main analysis file: "' xf '.m"']} results.callingSequence];
+        else
+            results.callingSequence = [{'Main analysis file undefined due to execution in parfor loop'} results.callingSequence];
+        end
+    end
+end
+
+% Convert to table if desired
+if FlagText,
+    textTable               = {'<TR>' 'Username'            results.username                    };
+    textTable(end+1,:)      = {'<TR>' 'Date of creation'    results.date                        };
+    for k=1:length(results.callingSequence),
+        if k==1,
+                textTable(end+1,:)  = {'<TR>' 'Calling sequence'    results.callingSequence{k} };
+        else
+                textTable(end+1,:)  = {'<TR>' ' '                   results.callingSequence{k} };
+        end
+    end
+    results = textTable;
+end
+
+
+
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/diff/diff.exe b/IQMtools V1.2.2.2/IQMlite/auxiliary/diff/diff.exe
new file mode 100644
index 0000000000000000000000000000000000000000..2797ffd05d13c0cd59d28ab31b5d562f3e3c7987
Binary files /dev/null and b/IQMtools V1.2.2.2/IQMlite/auxiliary/diff/diff.exe differ
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/diff/diffIQM.m b/IQMtools V1.2.2.2/IQMlite/auxiliary/diff/diffIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..c8762c6b33e3d54cc94139955eb6b53f2527f415
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/diff/diffIQM.m	
@@ -0,0 +1,10 @@
+function [status, res] = diffIQM(A,B)
+% Comparison of two files using the diff command. 
+% Wrapper to handle Unix and Windows
+
+if isunix(),
+    eval(sprintf('[status, res] = system(''diff %s %s'');', A,B));
+else
+    diffLocation = which('diff.exe');
+    eval(sprintf('[status, res] = system(''"%s" %s %s'');', diffLocation,A,B))
+end
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/getDefaultIntegratorOptionsIQM.m b/IQMtools V1.2.2.2/IQMlite/auxiliary/getDefaultIntegratorOptionsIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..c680e1b7375b6d96e81432e4d2005f55a37c023d
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/getDefaultIntegratorOptionsIQM.m	
@@ -0,0 +1,15 @@
+function [options_M,options_C] = getDefaultIntegratorOptionsIQM()
+% getDefaultIntegratorOptionsIQM returns structures with default integrator 
+% setting options for both MATLAB and CVODE simulation.
+
+% MATLAB
+options_M                     = odeset();
+options_M.method              = 'ode23s';  
+options_M.AbsTol              = 1e-6;
+options_M.RelTol              = 1e-6;
+
+% CVODE
+options_C.method              = 'stiff';  % 'stiff' or 'nonstiff'
+options_C.abstol              = 1e-6;
+options_C.reltol              = 1e-6;
+options_C.maxnumsteps         = 100000;   % max number of steps between two output points
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/getSAStoolInfoIQM.m b/IQMtools V1.2.2.2/IQMlite/auxiliary/getSAStoolInfoIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..90ec03f633a99e4dae292fffc8aa71e33e8bcc65
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/getSAStoolInfoIQM.m	
@@ -0,0 +1,12 @@
+function [PATH_SAS] = getSAStoolInfoIQM()
+% Function loads and returns the content of SETUP_PATHS_TOOLS_IQMLITE already
+% correct for the system. 
+
+% Run the SETUP_PATHS_TOOLS_IQMLITE script
+SETUP_PATHS_TOOLS_IQMLITE
+
+if isunix,
+    PATH_SAS        = PATH_SYSTEM_SAS_UNIX;
+else
+    PATH_SAS        = PATH_SYSTEM_SAS_WINDOWS;
+end
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/graphics/ps/gs/bin/gsdll32.dll b/IQMtools V1.2.2.2/IQMlite/auxiliary/graphics/ps/gs/bin/gsdll32.dll
new file mode 100644
index 0000000000000000000000000000000000000000..0d900f008bd8f8d7b3037106c51b098540aa60c0
Binary files /dev/null and b/IQMtools V1.2.2.2/IQMlite/auxiliary/graphics/ps/gs/bin/gsdll32.dll differ
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/graphics/ps/gs/bin/gsdll32.lib b/IQMtools V1.2.2.2/IQMlite/auxiliary/graphics/ps/gs/bin/gsdll32.lib
new file mode 100644
index 0000000000000000000000000000000000000000..f1071482a3daecc7409bc5859b0a7341780a79c9
Binary files /dev/null and b/IQMtools V1.2.2.2/IQMlite/auxiliary/graphics/ps/gs/bin/gsdll32.lib differ
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/graphics/ps/gs/bin/gswin32c.exe b/IQMtools V1.2.2.2/IQMlite/auxiliary/graphics/ps/gs/bin/gswin32c.exe
new file mode 100644
index 0000000000000000000000000000000000000000..6b7f4e50d0b5ef30c40f921a87ddce3576574a4e
Binary files /dev/null and b/IQMtools V1.2.2.2/IQMlite/auxiliary/graphics/ps/gs/bin/gswin32c.exe differ
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/graphics/ps/gs/fonts/EMPTY.txt b/IQMtools V1.2.2.2/IQMlite/auxiliary/graphics/ps/gs/fonts/EMPTY.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/graphics/ps/gs/lib/EMPTY.txt b/IQMtools V1.2.2.2/IQMlite/auxiliary/graphics/ps/gs/lib/EMPTY.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/graphics/ps/ps2pdfSB/license.txt b/IQMtools V1.2.2.2/IQMlite/auxiliary/graphics/ps/ps2pdfSB/license.txt
new file mode 100644
index 0000000000000000000000000000000000000000..938125d4137ae513ed6bd9830a941d60c84383e9
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/graphics/ps/ps2pdfSB/license.txt	
@@ -0,0 +1,27 @@
+Copyright (c) 2008-2010, The MathWorks, Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in
+      the documentation and/or other materials provided with the distribution
+    * Neither the name of the The MathWorks, Inc. nor the names
+      of its contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/graphics/ps/ps2pdfSB/ps2pdf.m b/IQMtools V1.2.2.2/IQMlite/auxiliary/graphics/ps/ps2pdfSB/ps2pdf.m
new file mode 100644
index 0000000000000000000000000000000000000000..f2f7318f7305b95cd38ef62655962291e281d60d
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/graphics/ps/ps2pdfSB/ps2pdf.m	
@@ -0,0 +1,393 @@
+function ps2pdfIQM(varargin)
+%ps2pdfIQM Function to convert a PostScript file to PDF using Ghostscript
+%
+%  Converts a postscript file into PDF. The resulting PDF file will contain
+%  one page for each page defined in the postscript files, so a multi-page
+%  postscript file, like those generated by using the '-append' option of 
+%  MATLAB's print command, can be used to generate a multi-page PDF file. 
+%
+%   Ghostscript is a third-party application currently supplied with 
+%   MATLAB. The caller may also specify a different version of Ghostscript
+%   to use.
+%
+%   ps2pdfIQM expects to be called with a set of parameter-value pairs. The
+%   order of these is unimportant, but required parameters MUST be
+%   specified
+%
+%   In the list below, required parameters are marked with an asterisk *
+%        NOTE: ps2pdfIQM can not use MATLAB's version of Ghostscript
+%              in a deployed application; you MUST provide a 
+%              the path to a separate instance of Ghostscript. This 
+%              parameter is marked with a double asterisk **
+%
+%   Parameter:        Value:  
+%   *  psfile         full or relative path to the postscript file to convert
+%
+%   *  pdffile        full or relative path to the pdf file to create
+%
+%   ** gscommand      path to Ghostscript executable to use; this will try
+%                     to default to the version of Ghostscript shipped with 
+%                     MATLAB, if any. If this value is specified you should 
+%                     also specify the gsfontpath and gslibpath values.
+%
+%                     ** See note on deployed applications, above.
+%
+%      gsfontpath     full path to the Ghostscript font files
+%                     If a gscommand is specified then this path should
+%                     also be specified and reference the same Ghostscript
+%                     version
+%
+%      gslibpath      full path to the Ghostscript library (.ps) files. 
+%                     If a gscommand is specified then this path should
+%                     also be specified and reference the same Ghostscript
+%                     version
+%
+%                     If gscommand is NOT specified and we can determine
+%                     the version of Ghostscript, if any, shipped with
+%                     MATLAB, then this value will be overridden to use the
+%                     path that references MATLAB's version of Ghostscript
+%
+%      gspapersize    paper size to use in the created .pdf file. If not 
+%                     specified or the specified value is not recognized 
+%                     it will use whatever default paper size is 
+%                     built into the version of Ghostscript being run
+%
+%                         NOTE: no scaling of the input occurs - it's simply
+%                         placed on a page with the specified paper size. 
+%
+%                         Valid values for gspapersize are: 
+%                              'letter', 'ledger', 'legal', '11x17', 
+%                              'archA', 'archB', 'archC', 'archD', 'archE', 
+%                              'a0', 'a1', 'a2', 'a3','a4', 'a5',
+%                              'a6', 'a7', 'a8', 'a9', 'a10'
+%                         
+%      deletepsfile   0 to keep the input ps file after creating pdf
+%                     non-zero to delete the input ps file after creating pdf
+%                     Default is 0: keep the input ps file (do NOT delete it)
+%                        NOTE: if the pdf creation process fails, the input
+%                        PS file will be kept regardless of this setting
+%
+%      verbose        0 to suppress display of status/progress info; 
+%                     non-zero to allow display of status/progress info
+%                     Default is 0 (no display)
+%
+% Example usage: 
+%    use MATLAB's version of Ghostscript to generate an A4 pdf file
+%      ps2pdfIQM('psfile', 'input.ps', 'pdffile', 'output.pdf', 'gspapersize', 'a4')
+%
+%    use a local copy of Ghostcript to generate a file, and display some 
+%    status/progress info while doing so.
+%      ps2pdfIQM('psfile', '../reports/input.ps', 'pdffile', 'c:\temp\output3.pdf', ...
+%            'gspapersize', 'a4', 'verbose', 1, ...
+%            'gscommand', 'C:\Program Files\GhostScript\bin\gswin32c.exe', ...
+%            'gsfontpath', 'C:\Program Files\GhostScript\fonts', ...
+%            'gslibpath', 'C:\Program Files\GhostScript\lib')
+%
+%    use MATLAB's version of Ghostscript to generate a pdf file and delete
+%    the input.ps file when done 
+%      ps2pdfIQM('psfile', 'input.ps', 'pdffile', 'output.pdf', 'gspapersize', 'a4', 'deletepsfile', 1)
+
+%   Update log: 
+%      Jun 16, 2010: added check for deployed application
+%      May 19, 2010: wrapped filenames sent to Ghostscript in quotes
+%      May 06, 2010: updated how Ghostscript is found, don't rely on MATLAB version #
+%      Aug 15, 2008: fixed bug where embedded space in location of 
+%                    MATLAB's version of Ghostscript caused ps2pdfIQM to fail.
+%      Apr 16, 2008: added deletepsfile option
+
+%   Copyright 2008-2010 The MathWorks, Inc.
+
+   if nargin < 1 
+      error('ps2pdfIQM:parameters', 'No parameters specified. Type ''help ps2pdfIQM'' for details on how to use this function.');
+   end
+
+   % parse input args
+   gsData = LocalParseArgs(varargin{:});
+
+   % setup the file that tells GS what we want it to do
+   gsData = LocalCreateResponseFile(gsData); 
+
+   gsDebug = 0;
+   if gsData.verbose 
+      fprintf('ps2pdfIQM: input settings are:\n');
+      if isfield(gsData, 'paperSizes')
+          gsData = rmfield(gsData, 'paperSizes');
+      end
+      gsData  %#ok<NOPRT>
+      fprintf('ps2pdfIQM: response file for Ghostscript is:\n');
+      type(gsData.responseFile);
+      gsDebug = 1;
+   end
+
+   %to hold results/status from system call
+   s = 0; %#ok<NASGU>
+   r = ''; %#ok<NASGU>
+
+   % run Ghostscript to convert the file
+   if gsData.useBuiltin 
+      [s, r] = gsData.cmd(['@' gsData.responseFile], gsData.psFile, gsDebug);
+   else 
+      [s, r] = system([gsData.cmd ' @"' gsData.responseFile '" "' gsData.psFile '"']);
+   end
+
+   if gsData.verbose
+      disp( ['Ghostscript STDOUT: ' num2str(s) ] );
+      disp( ['Ghostscript STDERR: ' r ] );
+   else
+      delete(gsData.responseFile)
+   end
+
+   if s && ~isempty(r)
+      error('ps2pdfIQM:ghostscript',  ['Problem converting PostScript. System returned error: ' num2str(s) '.' r]) 
+   elseif s
+      error('ps2pdfIQM:ghostscript',  ['Problem calling GhostScript. System returned error: ' num2str(s)]) 
+   end
+
+   %if after all this we still couldn't create the file, report the error
+   fid = fopen( gsData.pdfFile, 'r');
+   if ( fid == -1 )
+      error('ps2pdfIQM:ghostscript', '%s', [ 'Ghostscript could not create ''' gsData.pfdFile '''.' ])
+   else
+      fclose( fid );
+   end
+
+   % if we get here, we successfully created pdf file; delete ps file if
+   % requested to do so
+   if gsData.deletePSFile 
+       delete(gsData.psFile);
+   end
+
+end
+
+%local function to parse arguments and fill in the gsData structure
+%  .psFile - postscript file to convert
+%  .pdfFile - pdf file to create
+%  .cmd     - path/name of Ghostscript command to run or handle to gscript
+%             builtin
+%  .useBuiltin - 1 if using builtin gs command 
+%  .fontPath - path to the Ghostscript fonts, if any
+%  .libPath - path to the Ghostscript libs (Ghostscript .ps files), if any) 
+%  .paperSize - paper size to set for resulting .pdf file 
+%  .deletePSFile - 0 to keep (not delete) the input ps file if pdf created ok
+%  .verbose - if non-zero, display some status/progress info to command window
+function gsData = LocalParseArgs(varargin) 
+    gsData.paperSizes = {'letter', 'ledger', 'legal', '11x17', 'archA', 'archB', ... 
+                   'archC', 'archD', 'archE', 'a0', 'a1', 'a2', 'a3','a4', 'a5', ...
+                   'a6', 'a7', 'a8', 'a9', 'a10'};
+
+    %default values for some settings
+    gsData.verbose      = 0; 
+    gsData.useBuiltin   = 0;
+    gsData.deletePSFile = 0; 
+    
+    for i = 1 : 2 : length(varargin)-1 
+        param_arg = varargin{i};
+        param_value = varargin{i+1};        
+        switch(lower(param_arg)) 
+            % path to ps file to conver
+            case 'psfile'
+               if ~exist(param_value, 'file')
+                  error('print:ghostscript', ...
+                      'Can not find postscript file <%s> to convert', ...
+                      param_value)
+               end
+               gsData.psFile = param_value;
+
+            % path to pdf file to create
+            case 'pdffile'
+                %verify we can create file at that location
+                pdf_fid = fopen(param_value,'w');
+                if pdf_fid < 0 
+                    error('ps2pdfIQM:invalidPDFFIle', ... 
+                        'Can not open <%s> for writing', ...
+                        param_value);
+                end
+                fclose(pdf_fid); 
+                %delete temp file we created
+                delete(param_value); 
+                gsData.pdfFile = param_value;
+
+            % full path to gs executable
+            case 'gscommand' 
+               if ~exist(param_value, 'file')
+                  error('ps2pdfIQM:ghostscriptCommand', ...
+                      'Can not find Ghostscript executable (''gscommand'') <%s>',...
+                      param_value)
+               end
+               if ispc && ~isempty(findstr(param_value, ' '))
+                   param_value = ['"' param_value '"']; %#ok<AGROW>
+               end
+               gsData.cmd = param_value; 
+                
+            % full path to gs font dir
+            case 'gsfontpath' 
+               if ~exist(param_value, 'dir')
+                   error('ps2pdfIQM:ghostscriptFontPath', ...
+                         'Can not find the directory <%s> for Ghostscript fonts (''gsfontpath'')', ...
+                         param_value)
+               end
+               gsData.fontPath = param_value;
+
+            % full path to gs lib dir
+            case 'gslibpath' 
+               if ~exist(param_value, 'dir')
+                   error('ps2pdfIQM:ghostscriptLibPath', ...
+                         'Can not find the directory <%s> for Ghostscript library files (''gslibpath'')', ...
+                         param_value)
+               end
+               gsData.libPath = param_value;
+                
+            % paper size 
+            case 'gspapersize'
+               idx = strcmpi(param_value, gsData.paperSizes);
+               if ~any(idx)
+                  warning('ps2pdfIQM:papersize', ...
+                        '''gspapersize'' value <%s> not found in the list of known sizes, ignoring it.', param_value);
+               else
+                  gsData.paperSize = gsData.paperSizes{idx};
+               end
+
+            % deletePSFile
+            case 'deletepsfile'
+               if isnumeric(param_value) 
+                  gsData.deletePSFile = param_value; 
+               else
+                   warning('ps2pdfIQM:deletepsfile', ...
+                         '''deletepsfile'' value <%s> class <%s> should be numeric, defaulting to 0', ...
+                         param_value, class(param_value));
+               end
+               
+            % verbose
+            case 'verbose'
+               if isnumeric(param_value) 
+                  gsData.verbose = param_value; 
+               else
+                   warning('ps2pdfIQM:verbose', ...
+                         '''verbose'' value <%s> class <%s> should be numeric, defaulting to 0', ...
+                         param_value, class(param_value));
+               end
+               
+            otherwise
+               if isnumeric(param_value)
+                   param_value = num2str(param_value);
+               end
+                  warning('ps2pdfIQM:unknown', ...
+                     'ignoring unknown parameter <%s> with value <%s>.', param_arg, param_value);
+        end
+    end    
+
+    if ~isfield(gsData, 'psFile') 
+        error('ps2pdfIQM:noInputFile', ...
+               'No input (psfile) file specified');
+    end
+    
+    if ~isfield(gsData, 'pdfFile') 
+        error('ps2pdfIQM:noOutputFile', ...
+               'No output (pdffile) file specified');
+    end
+    
+    if ~isfield(gsData, 'cmd') 
+        if isdeployed
+            error('ps2pdfIQM:deployedNeedsGhostscript', ...
+                  'In order to use ''ps2pdfIQM'' in a deployed application you must provide the path to a separate instance of Ghostscript.');
+        end
+
+        % updated code to find ghostscript - look for gs8x first, 
+        % then try old location. Don't depend on MATLAB version #
+        ghostDir = fullfile( matlabroot, 'sys', 'gs8x' );
+        if ~exist(ghostDir, 'dir')
+            [gsCmd, ghostDir] = Local_GetOldGhostscript();
+            gsData.cmd = gsCmd;
+        else
+           gsData.cmd = Local_GetGscriptFcnHandle;
+           if ~isempty(gsData.cmd)
+              gsData.useBuiltin = 1; % use builtin Ghostscript
+           end
+        end
+        if ~exist(ghostDir, 'dir')
+           error('ps2pdfIQM:ghostscriptCommand', ...
+                 'Can not find Ghostscript installed with MATLAB in <%s>',...
+                 ghostDir);
+        end
+
+        if ~isempty(gsData.cmd)
+           % if using MATLAB's version of GhostScript, use same set of fonts and library files
+           if isfield(gsData, 'fontPath') || isfield(gsData, 'libPath')
+              warning('ps2pdfIQM:ghostscriptPathOverride', ...
+                    'Using MATLAB''s version of Ghostscript; overriding ''gsfontpath'' and ''gslibpath'' to use builtin MATLAB version');
+           end
+           gsData.fontPath = fullfile( ghostDir, 'fonts', '');
+           gsData.libPath = fullfile( ghostDir, 'ps_files', '');
+        else 
+            error('ps2pdfIQM:noGhostscriptCommand', ...
+                  'Can not find Ghostscript program in MATLAB');
+        end
+    else
+        % if gscommandpath was specified, 
+        if ~isfield(gsData, 'fontPath') || ~isfield(gsData, 'libPath')
+           warning('ps2pdfIQM:ghostscriptCommandSuggestion', ...
+                 ['When specifying a Ghostscript executable (''gscommand'') you should also '...
+                 'specify both the ''gsfontpath'' and ''gslibpath'' locations']);
+   
+        end
+    end
+end
+
+%local function to create the input file needed for Ghostscript
+function gsData = LocalCreateResponseFile(gsData) 
+   % open a response file to write out Ghostscript commands
+   rsp_file = [tempname '.rsp'];
+   rsp_fid = fopen (rsp_file, 'w');
+
+   if (rsp_fid < 0)
+      error('ps2pdfIQM:responseFileCreate', 'Unable to create response file')
+   end
+
+   fprintf(rsp_fid, '-dBATCH -dNOPAUSE\n');
+   if ~gsData.verbose
+       fprintf(rsp_fid, '-q\n');
+   end
+   if isfield(gsData, 'libPath')
+      fprintf(rsp_fid, '-I"%s"\n', gsData.libPath);
+   end
+   if isfield(gsData, 'fontPath')
+      fprintf(rsp_fid, '-I"%s"\n', gsData.fontPath);
+   end
+   if isfield(gsData, 'paperSize') 
+      fprintf( rsp_fid, '-sPAPERSIZE=%s\n', gsData.paperSize );
+   end
+   fprintf(rsp_fid, '-sOutputFile="%s"\n', gsData.pdfFile);
+   fprintf(rsp_fid, '-sDEVICE=%s\n', 'pdfwrite');
+   fclose(rsp_fid);
+   gsData.responseFile = rsp_file;
+end
+
+%local function to get a handle to MATLAB's Ghostscript implementation
+%NOTE: this may change or be removed in future releases
+function gs = Local_GetGscriptFcnHandle()
+  gs = '';
+  p = which('-all', 'gscript');
+  if ~isempty(p) 
+      p = p{1};
+      fpath = fileparts(p);
+      olddir = cd(fpath);
+      gs = @gscript;
+      cd(olddir);
+  end
+end
+
+% local function to try and get location of Ghostscript in older MATLAB
+function [gsCmd, ghostDir] = Local_GetOldGhostscript
+   ghostDir = fullfile( matlabroot, 'sys', 'ghostscript' );
+   gsCmd = '';
+   if ispc
+      if exist(fullfile(ghostDir,'bin','win32','gs.exe'), 'file')
+         gsCmd = fullfile(ghostDir,'bin','win32','gs.exe');
+      end
+   else 
+      if exist(fullfile(ghostDir,'bin',lower(computer),'gs'), 'file')
+         gsCmd = fullfile(ghostDir,'bin',lower(computer), 'gs');
+      end
+   end
+   gsCmd = ['"' gsCmd '"'];
+end
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/graphics/ps/ps2pdfSB/ps2pdfIQM.m b/IQMtools V1.2.2.2/IQMlite/auxiliary/graphics/ps/ps2pdfSB/ps2pdfIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..bc9c22cb8778d4a40020efb8226dfe1fb80b04a7
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/graphics/ps/ps2pdfSB/ps2pdfIQM.m	
@@ -0,0 +1,55 @@
+function ps2pdfIQM(psfile,pdffile)
+% Function to convert a PostScript file to PDF using Ghostscript.
+%
+% Converts a postscript file into PDF. The resulting PDF file will contain
+% one page for each page defined in the postscript files, so a multi-page
+% postscript file, like those generated by using the '-append' option of 
+% MATLAB's print command, can be used to generate a multi-page PDF file. 
+%
+% The source PS file is then deleted.
+%
+% [SYNTAX]
+% [] = ps2pdfIQM(psfile,pdffile)
+%
+% [INPUT]
+% psfile:     full or relative path to the postscript file to convert
+% pdffile:    full or relative path to the pdf file to create
+%
+% [OUTPUT]
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+if ~isunix(),
+    % Get root folder for ghostscript
+    gsDir = [fileparts(which('installIQMlite.m')) '/auxiliary/graphics/ps/gs/'];
+    
+    ps2pdf('psfile',psfile,'pdffile',pdffile, ...
+        'deletepsfile',1, ...
+        'gspapersize', 'a4', ...
+        'gscommand', [gsDir 'bin/gswin32c.exe'], ...
+        'gsfontpath', [gsDir 'fonts'], ...
+        'gslibpath', [gsDir 'lib'], ...
+		'verbose',0);
+else
+    if ~ismac,
+        % For Windows ps2pdf is included in IQM Tools
+        % On Unix/Linux it is always present
+        system(sprintf('ps2pdf -dBATCH -dNOPAUSE -sPAPERSIZE=a4 -sDEVICE=pdfwrite -dPDFSETTINGS=/default %s %s',psfile,pdffile));
+        delete(psfile);
+    else
+        % Only Apple requires different handling
+        [~,ps2pdfCmd]   = unix('which ps2pdf');
+        ps2pdfCmd       = strtrim(ps2pdfCmd);
+        if ~isempty(ps2pdfCmd)
+            cmdstr      = sprintf('%s -dBATCH -dNOPAUSE -sPAPERSIZE=a4 -sDEVICE=pdfwrite -dPDFSETTINGS=/default %s %s',ps2pdfCmd,psfile,pdffile);
+            exit_status = unix(cmdstr);
+            if exit_status,
+                warning('ps2pdf failed');
+            else
+                delete(psfile);
+            end
+        else
+            warning('ps2pdf command not found on system - you might want to consider installation of ps2pdf on your Mac.');
+        end
+    end
+end
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/graphics/subaxis/parseArgs.m b/IQMtools V1.2.2.2/IQMlite/auxiliary/graphics/subaxis/parseArgs.m
new file mode 100644
index 0000000000000000000000000000000000000000..b2ff18e2924b83b7d87b6e640a370485edd6c95b
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/graphics/subaxis/parseArgs.m	
@@ -0,0 +1,126 @@
+function ArgStruct=parseArgs(args,ArgStruct,varargin)
+% Helper function for parsing varargin. 
+%
+%
+% ArgStruct=parseArgs(varargin,ArgStruct[,FlagtypeParams[,Aliases]])
+%
+% * ArgStruct is the structure full of named arguments with default values.
+% * Flagtype params is params that don't require a value. (the value will be set to 1 if it is present)
+% * Aliases can be used to map one argument-name to several argstruct fields
+%
+%
+% example usage: 
+% --------------
+% function parseargtest(varargin)
+%
+% %define the acceptable named arguments and assign default values
+% Args=struct('Holdaxis',0, ...
+%        'SpacingVertical',0.05,'SpacingHorizontal',0.05, ...
+%        'PaddingLeft',0,'PaddingRight',0,'PaddingTop',0,'PaddingBottom',0, ...
+%        'MarginLeft',.1,'MarginRight',.1,'MarginTop',.1,'MarginBottom',.1, ...
+%        'rows',[],'cols',[]); 
+%
+% %The capital letters define abrreviations.  
+% %  Eg. parseargtest('spacingvertical',0) is equivalent to  parseargtest('sv',0) 
+%
+% Args=parseArgs(varargin,Args, ... % fill the arg-struct with values entered by the user
+%           {'Holdaxis'}, ... %this argument has no value (flag-type)
+%           {'Spacing' {'sh','sv'}; 'Padding' {'pl','pr','pt','pb'}; 'Margin' {'ml','mr','mt','mb'}});
+%
+% disp(Args)
+%
+%
+%
+%
+% % Aslak Grinsted 2003
+
+Aliases={};
+FlagTypeParams='';
+
+if (length(varargin)>0) 
+    FlagTypeParams=strvcat(varargin{1});
+    if length(varargin)>1
+        Aliases=varargin{2};
+    end
+end
+ 
+
+%---------------Get "numeric" arguments
+NumArgCount=1;
+while (NumArgCount<=size(args,2))&(~ischar(args{NumArgCount}))
+    NumArgCount=NumArgCount+1;
+end
+NumArgCount=NumArgCount-1;
+if (NumArgCount>0)
+    ArgStruct.NumericArguments={args{1:NumArgCount}};
+else
+    ArgStruct.NumericArguments={};
+end 
+
+
+%--------------Make an accepted fieldname matrix (case insensitive)
+Fnames=fieldnames(ArgStruct);
+for i=1:length(Fnames)
+    name=lower(Fnames{i,1});
+    Fnames{i,2}=name; %col2=lower
+    AbbrevIdx=find(Fnames{i,1}~=name);
+    Fnames{i,3}=[name(AbbrevIdx) ' ']; %col3=abreviation letters (those that are uppercase in the ArgStruct) e.g. SpacingHoriz->sh
+    %the space prevents strvcat from removing empty lines
+    Fnames{i,4}=isempty(strmatchIQM(Fnames{i,2},FlagTypeParams)); %Does this parameter have a value? (e.g. not flagtype)
+end
+FnamesFull=strvcat(Fnames{:,2});
+FnamesAbbr=strvcat(Fnames{:,3});
+
+if length(Aliases)>0  
+    for i=1:length(Aliases)
+        name=lower(Aliases{i,1});
+        FieldIdx=strmatchIQM(name,FnamesAbbr,'exact'); %try abbreviations (must be exact)
+        if isempty(FieldIdx) 
+            FieldIdx=strmatchIQM(name,FnamesFull); %&??????? exact or not? 
+        end
+        Aliases{i,2}=FieldIdx;
+        AbbrevIdx=find(Aliases{i,1}~=name);
+        Aliases{i,3}=[name(AbbrevIdx) ' ']; %the space prevents strvcat from removing empty lines
+        Aliases{i,1}=name; %dont need the name in uppercase anymore for aliases
+    end
+    %Append aliases to the end of FnamesFull and FnamesAbbr
+    FnamesFull=strvcat(FnamesFull,strvcat(Aliases{:,1})); 
+    FnamesAbbr=strvcat(FnamesAbbr,strvcat(Aliases{:,3}));
+end
+
+%--------------get parameters--------------------
+l=NumArgCount+1; 
+while (l<=length(args))
+    a=args{l};
+    if ischar(a)
+        paramHasValue=1; % assume that the parameter has is of type 'param',value
+        a=lower(a);
+        FieldIdx=strmatchIQM(a,FnamesAbbr,'exact'); %try abbreviations (must be exact)
+        if isempty(FieldIdx) 
+            FieldIdx=strmatchIQM(a,FnamesFull); 
+        end
+        if (length(FieldIdx)>1) %shortest fieldname should win 
+            [mx,mxi]=max(sum(FnamesFull(FieldIdx,:)==' ',2));
+            FieldIdx=FieldIdx(mxi);
+        end
+        if FieldIdx>length(Fnames) %then it's an alias type.
+            FieldIdx=Aliases{FieldIdx-length(Fnames),2}; 
+        end
+        
+        if isempty(FieldIdx) 
+            error(['Unknown named parameter: ' a])
+        end
+        for curField=FieldIdx' %if it is an alias it could be more than one.
+            if (Fnames{curField,4})
+                val=args{l+1};
+            else
+                val=1; %parameter is of flag type and is set (1=true)....
+            end
+            ArgStruct.(Fnames{curField,1})=val;
+        end
+        l=l+1+Fnames{FieldIdx(1),4}; %if a wildcard matches more than one
+    else
+        error(['Expected a named parameter: ' num2str(a)])
+    end
+end
+
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/graphics/subaxis/subaxis.m b/IQMtools V1.2.2.2/IQMlite/auxiliary/graphics/subaxis/subaxis.m
new file mode 100644
index 0000000000000000000000000000000000000000..34b4cf4eea64c88860b438c705102853be2fd281
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/graphics/subaxis/subaxis.m	
@@ -0,0 +1,100 @@
+function h=subaxis(varargin)
+%SUBAXIS Create axes in tiled positions. (just like subplot)
+%   Usage:
+%      h=subaxis(rows,cols,cellno[,settings])
+%      h=subaxis(rows,cols,cellx,celly[,settings])
+%      h=subaxis(rows,cols,cellx,celly,spanx,spany[,settings])
+%
+% SETTINGS: Spacing,SpacingHoriz,SpacingVert
+%           Padding,PaddingRight,PaddingLeft,PaddingTop,PaddingBottom
+%           Margin,MarginRight,MarginLeft,MarginTop,MarginBottom
+%           Holdaxis
+%
+%           all units are relative (e.g from 0 to 1)
+%
+%           Abbreviations of parameters can be used.. (Eg MR instead of MarginRight)
+%           (holdaxis means that it wont delete any axes below.)
+%
+%
+% Example:
+%
+%   >> subaxis(2,1,1,'SpacingVert',0,'MR',0); 
+%   >> imagesc(magic(3))
+%   >> subaxis(2,'p',.02);
+%   >> imagesc(magic(4))
+%
+% 2001 / Aslak Grinsted  (Feel free to modify this code.)
+f=gcf;
+
+
+Args=[];
+UserDataArgsOK=0;
+Args=get(f,'UserData');
+if isstruct(Args) 
+    UserDataArgsOK=isfield(Args,'SpacingHorizontal')&isfield(Args,'Holdaxis')&isfield(Args,'rows')&isfield(Args,'cols');
+end
+OKToStoreArgs=isempty(Args)|UserDataArgsOK;
+
+if isempty(Args)&(~UserDataArgsOK)
+    Args=struct('Holdaxis',0, ...
+        'SpacingVertical',0.05,'SpacingHorizontal',0.05, ...
+        'PaddingLeft',0,'PaddingRight',0,'PaddingTop',0,'PaddingBottom',0, ...
+        'MarginLeft',.1,'MarginRight',.1,'MarginTop',.1,'MarginBottom',.1, ...
+        'rows',[],'cols',[]); 
+end
+Args=parseArgs(varargin,Args,{'Holdaxis'},{'Spacing' {'sh','sv'}; 'Padding' {'pl','pr','pt','pb'}; 'Margin' {'ml','mr','mt','mb'}});
+
+if (length(Args.NumericArguments)>1)
+    Args.rows=Args.NumericArguments{1};
+    Args.cols=Args.NumericArguments{2};
+%remove these 2 numerical arguments
+    Args.NumericArguments={Args.NumericArguments{3:end}};
+end
+
+if OKToStoreArgs
+    set(f,'UserData',Args);
+end
+
+
+    
+
+switch length(Args.NumericArguments)
+   case 0
+       return % no arguments but rows/cols.... 
+   case 1
+      x1=mod((Args.NumericArguments{1}-1),Args.cols)+1; x2=x1;
+      y1=floor((Args.NumericArguments{1}-1)/Args.cols)+1; y2=y1;
+   case 2
+      x1=Args.NumericArguments{1};x2=x1;
+      y1=Args.NumericArguments{2};y2=y1;
+   case 4
+      x1=Args.NumericArguments{1};x2=x1+Args.NumericArguments{3}-1;
+      y1=Args.NumericArguments{2};y2=y1+Args.NumericArguments{4}-1;
+   otherwise
+      error('subaxis argument error')
+end
+    
+
+cellwidth=((1-Args.MarginLeft-Args.MarginRight)-(Args.cols-1)*Args.SpacingHorizontal)/Args.cols;
+cellheight=((1-Args.MarginTop-Args.MarginBottom)-(Args.rows-1)*Args.SpacingVertical)/Args.rows;
+xpos1=Args.MarginLeft+Args.PaddingLeft+cellwidth*(x1-1)+Args.SpacingHorizontal*(x1-1);
+xpos2=Args.MarginLeft-Args.PaddingRight+cellwidth*x2+Args.SpacingHorizontal*(x2-1);
+ypos1=Args.MarginTop+Args.PaddingTop+cellheight*(y1-1)+Args.SpacingVertical*(y1-1);
+ypos2=Args.MarginTop-Args.PaddingBottom+cellheight*y2+Args.SpacingVertical*(y2-1);
+
+if Args.Holdaxis
+    h=axes('position',[xpos1 1-ypos2 xpos2-xpos1 ypos2-ypos1]);
+else
+    h=subplot('position',[xpos1 1-ypos2 xpos2-xpos1 ypos2-ypos1]);
+end
+
+
+set(h,'box','on');
+%h=axes('position',[x1 1-y2 x2-x1 y2-y1]);
+set(h,'units',get(gcf,'defaultaxesunits'));
+set(h,'tag','subaxis');
+
+
+
+if (nargout==0) clear h; end;
+
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/help/NovakTyson.m b/IQMtools V1.2.2.2/IQMlite/auxiliary/help/NovakTyson.m
new file mode 100644
index 0000000000000000000000000000000000000000..c1a26c82c6e0ed6d42533535734f8d9a203a00ca
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/help/NovakTyson.m	
@@ -0,0 +1,19 @@
+% This script simply loads the novaktysonTestModelIQM.txt model that is included in this folder.
+% The purpose of this is only remote support to allow people to easily generate a model.
+%
+% [SYNTAX]
+% NovakTyson
+%
+% [INPUT]
+% None
+%
+% [OUTPUT]
+% None
+%
+% In the MATLAB workspace the model is made available as variable "iqm".
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+iqm = IQMmodel('novaktysonTestModelIQM.txt')
+
+disp('The Novak Tyson model has been loaded and is available as "iqm" in the MATLAB workspace.');
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/help/novaktysonTestModelIQM.txt b/IQMtools V1.2.2.2/IQMlite/auxiliary/help/novaktysonTestModelIQM.txt
new file mode 100644
index 0000000000000000000000000000000000000000..2c88428a6fbc622b29cd887495c782e5dfe39272
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/help/novaktysonTestModelIQM.txt	
@@ -0,0 +1,94 @@
+********** MODEL NAME
+Novak-Tyson Model
+
+********** MODEL NOTES
+Novak-Tyson cell cycle model, described in J. theor. Biol. (1998) 195, 69-85
+
+Used in IQM Tools just as an example model for quick model generation and testing.
+
+********** MODEL STATES
+d/dt(Cyclin) = R1-R2-R3  
+d/dt(YT) = R4-R5-R6-R7+R8+R3  
+d/dt(PYT) = R5-R8-R9-R10+R11  
+d/dt(PYTP) = R12-R11-R13-R14+R9  
+d/dt(MPF) = R6-R4-R12-R15+R13  
+d/dt(Cdc25P) = R16 
+d/dt(Wee1P) = R17  
+d/dt(IEP) = R18  
+d/dt(APCstar) = R19  
+
+Cyclin(0) = 0.0172
+YT(0) = 0.0116
+PYT(0) = 0.0009
+PYTP(0) = 0.0198
+MPF(0) = 0.073
+Cdc25P(0) = 0.95
+Wee1P(0) = 0.95
+IEP(0) = 0.242
+APCstar(0) = 0.3132
+
+********** MODEL PARAMETERS
+Ka = 0.1
+Kb = 1  
+Kc = 0.01  
+Kd = 1  
+Ke = 0.1
+Kf = 1  
+Kg = 0.01  
+Kh = 0.01  
+k1 = 0.01  
+k3 = 0.5  
+V2p = 0.005
+V2pp = 0.25  
+V25p = 0.017
+V25pp = 0.17  
+Vweep = 0.01  
+Vweepp = 1  
+kcak = 0.64  
+kpp = 0.004  
+kas = 2  
+kbs = 0.1  
+kcs = 0.13  
+kds = 0.13  
+kes = 2  
+kfs = 0.1
+kgs = 2  
+khs = 0.15  
+
+
+********** MODEL VARIABLES
+k2 = V2p+APCstar*(V2pp-V2p)  
+kwee = Vweepp+Wee1P*(Vweep-Vweepp)  
+k25 = V25p+Cdc25P*(V25pp-V25p)  
+
+
+********** MODEL REACTIONS
+R1 = k1 
+R2 = k2*Cyclin 
+R3 = k3*Cyclin 
+R4 = kpp*MPF 
+R5 = kwee*YT 
+R6 = kcak*YT 
+R7 = k2*YT 
+R8 = k25*PYT 
+R9 = kcak*PYT 
+R10 = k2*PYT 
+R11 = kpp*PYTP 
+R12 = kwee*MPF 
+R13 = k25*PYTP 
+R14 = k2*PYTP 
+R15 = k2*MPF 
+R16 = kas*MPF*(1-Cdc25P)/(1+Ka-Cdc25P)-kbs*Cdc25P/(Kb+Cdc25P) 
+R17 = kes*MPF*(1-Wee1P)/(1+Ke-Wee1P)-kfs*Wee1P/(Kf+Wee1P) 
+R18 = kgs*MPF*(1-IEP)/(1+Kg-IEP)-khs*IEP/(Kh+IEP) 
+R19 = kcs*IEP*(1-APCstar)/(1+Kc-APCstar)-kds*APCstar/(Kd+APCstar) 
+
+
+********** MODEL FUNCTIONS
+
+
+********** MODEL EVENTS
+
+
+********** MODEL MATLAB FUNCTIONS
+
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/isIQMproPresent.m b/IQMtools V1.2.2.2/IQMlite/auxiliary/isIQMproPresent.m
new file mode 100644
index 0000000000000000000000000000000000000000..f93068b81ec04558eeb6cc3bcf851d378103b56a
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/isIQMproPresent.m	
@@ -0,0 +1,8 @@
+function [ ispresent ] = isIQMproPresent()
+% isIQMproPresent: Checks if the IQMpro tools are installed. 
+
+ispresent = 1;
+if exist('IQMPsimulate') ~= 2,
+    ispresent = 0;
+end  
+
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/isSymbolicpresentIQM.m b/IQMtools V1.2.2.2/IQMlite/auxiliary/isSymbolicpresentIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..7a7866b933229eb8c278fc065a2f33946989c583
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/isSymbolicpresentIQM.m	
@@ -0,0 +1,17 @@
+function [flag] = isSymbolicpresentIQM()
+% isSymbolicpresentIQM: checks if the symbolic toolbox is present
+%
+% USAGE:
+% ======
+% [flag] = isSymbolicpresentIQM()
+%
+% Output Arguments:
+% =================
+% flag: 1 if present, 0 if not present
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+flag = ~isempty(ver('symbolic'));
+
+
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/lookforIQML.m b/IQMtools V1.2.2.2/IQMlite/auxiliary/lookforIQML.m
new file mode 100644
index 0000000000000000000000000000000000000000..322efe32811c4ff56debc2a02723894a9c47fca2
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/lookforIQML.m	
@@ -0,0 +1,36 @@
+function [] = lookforIQML(text)
+% lookforIQM: searches all m-files in the IQM Lite folder tree for the 
+% text given as argument. It displays the filenames in which the text
+% appears and additionally opens the files in the editor.
+
+old = pwd;
+cd([fileparts(which('installIQMlite')) '/..']);
+try, recurseFolder('IQMlite',text); catch end
+cd(old);
+return
+
+function recurseFolder(folder,text)
+% change folder
+cd(folder);
+% check all m files in folder for the text
+mfiles = dir('*.m');
+for k = 1:length(mfiles),
+    % read file
+    content = fileread(strcat(mfiles(k).name));
+    if strfind(content,text),
+        disp(mfiles(k).name);
+        edit(mfiles(k).name);
+    else
+%        edit(mfiles(k).name);
+    end
+end
+% recurse in all subfolders
+allfiles = dir;
+for k = 1:length(allfiles),
+    if ~strcmp(allfiles(k).name,'..') && ~strcmp(allfiles(k).name,'.') && allfiles(k).isdir == 1,
+        recurseFolder(allfiles(k).name,text);
+    end
+end
+% up we go
+cd ..
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/matrix/makePosSemiDefIQM.m b/IQMtools V1.2.2.2/IQMlite/auxiliary/matrix/makePosSemiDefIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..a4d8cb49f29cd181b124743bd930a2afac4c5f15
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/matrix/makePosSemiDefIQM.m	
@@ -0,0 +1,31 @@
+function [Xout] = makePosSemiDefIQM(X)
+% Enforce matrix X to become a positive semidefinite matrix Xout.
+% This is accomplished by setting the negative eigenvalues to 0.
+% This function is mainly used in ensuring positive-semidefiniteness of
+% covariance matrices. It turned out not to be enough to set the values to
+% 0 so a slightly different approach has been chosen, documented below.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+THRES = 1e-10;
+
+Xout = X;
+try
+    warning off
+    % Make symmetric
+    X                                           = 0.5*(X+X');
+    % Eigenvalue decomposition
+    [V,D]                                       = eig(X);
+    xxx                                         = diag(D);
+    % Set all eigenvalues below THRES to 0
+    xxx(real(xxx)<THRES)                        = 0;
+    % Set all elements of V below THRES (absolute value since it might be complex) to 0
+    V(abs(V)<THRES)                             = 0;
+    % Combine again to matrix and force it to be real
+    D                                           = diag(xxx);
+    Xout                                        = real(V*D*inv(V));
+        
+    warning on
+catch
+    disp('The covariance matrix seems to have an issue.');
+end
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/output/IQMconvert2pdf.m b/IQMtools V1.2.2.2/IQMlite/auxiliary/output/IQMconvert2pdf.m
new file mode 100644
index 0000000000000000000000000000000000000000..030bae451cf708825c1ee20c237d94babfc7d4b5
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/output/IQMconvert2pdf.m	
@@ -0,0 +1,59 @@
+function [] = IQMconvert2pdf(filename)
+% Function converting a PS file to a PDF file.
+% Now just a wrapper for ps2pdfIQM to allow the definition of just one
+% filename.
+%
+% [SYNTAX]
+% [] = IQMconvert2pdf(filename)
+%
+% [INPUT]
+% filename:     filename to be used
+% 
+% [OUTPUT]
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+if isempty(filename),
+    return
+end
+
+% Remove extension from filename
+filename = strrep(filename,'.ps','');
+filename = strrep(filename,'.pdf','');
+filename = strrep(filename,'.PS','');
+filename = strrep(filename,'.PDF','');
+
+if exist([filename '.ps']),
+    ps2pdfIQM([filename '.ps'],[filename '.pdf']);
+    
+    % Generate the log information for PDF file creation (if COMPLIANCE_OUTPUT_MODE on)
+    % ---------------------------------------------------------------------------------
+    
+    if getComplianceModeIQM(),
+        % Get function call information as table
+        results = getFunctionCallInformationIQM(1,1);
+        
+        % Add table title with filename
+        addresults = cell(2,size(results,2));
+        addresults{1,1} = '<TT>';
+        addresults{1,2} = 'PDF file generation log';
+        addresults{2,1} = '<TR>';
+        addresults{2,2} = 'File (relative to calling function)';
+        addresults{2,3} = [filename '.pdf'];
+        results = [addresults; results];
+        
+        % Generate log file
+        logfilename = [filename '.pdf.log'];
+        logtext     = IQMconvertCellTable2ReportTable(results,'report');
+        
+        % Write out the logfile
+        fid = fopen(logfilename,'w');
+        fprintf(fid,'%s',logtext);
+        fclose(fid);
+        
+        % Delete previous .ps.log file
+        warning off
+        delete([filename '.ps.log']);
+        warning on
+    end
+end
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/output/IQMgetcolors.m b/IQMtools V1.2.2.2/IQMlite/auxiliary/output/IQMgetcolors.m
new file mode 100644
index 0000000000000000000000000000000000000000..c9e5d2051d705c244c85e8be576229b3e9c423be
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/output/IQMgetcolors.m	
@@ -0,0 +1,94 @@
+function [colors,lines,dots,bwcolors] = IQMgetcolors()
+% Help function to generate colors for plotting and for black and white
+% plotting also line types.
+%
+% [SYNTAX]
+% [colors,lines,dots,bwcolors] = IQMgetcolors()
+%
+% [INPUT]
+% NONE
+%
+% [OUTPUT]
+% colors: Nx3 matrix with colors to be used (see below in detail)
+% lines:  cell-array with 48 unique line-styles
+% dots:   cell-array with 12 unique dot-styles
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+colors = [
+    0         0.4470    0.7410
+    0.8500    0.3250    0.0980
+    0.9290    0.6940    0.1250
+    0.4940    0.1840    0.5560
+    0.4660    0.6740    0.1880
+    0.3010    0.7450    0.9330
+    0.6350    0.0780    0.1840
+         0    0.2980    0.4940
+    0.5667    0.2167    0.0653
+    0.6193    0.4627    0.0833
+    0.3293    0.1227    0.3707
+    0.3107    0.4493    0.1253
+    0.2007    0.4967    0.6220
+    0.4233    0.0520    0.1227
+    0.25 0.25 0.25
+    0.6 0.2 0
+    0.75 0.75 0
+    0 0.75 0.75
+    0 0.5 0
+    0 0 1
+    0.75 0 0.75
+    1 0 0
+    0.04 0.14 0.42
+    0.31 0.31 0.31
+    0.5 0.5 0.5
+    0 0 0
+    1 0.69 0.39
+    0 1 0
+    0 1 1
+    1 0 1
+    0.7 0.78 1
+    1 1 0
+    0.68 0.92 1
+    0.85 0.7 1
+    1 0.6 0.78
+    ];
+
+
+
+
+% colors = [0.87 0.49 0
+%            0.17 0.51 0.34
+% 		   0.08 0.16 0.55
+% 		   0.48 0.06 0.89
+% 		   0.85 0.16 0
+% 		   0.68 0.47 0
+% 		   0.04 0.52 0.78
+% 		   0.25 0.25 0.25 
+% 		   0.6 0.2 0
+% 		   0.75 0.75 0
+% 		   0 0.75 0.75
+% 		   0 0.5 0
+% 		   0 0 1
+% 		   0.75 0 0.75
+% 		   1 0 0
+% 		   0.04 0.14 0.42
+% 		   0.31 0.31 0.31
+% 		   0.5 0.5 0.5
+% 		   0 0 0
+% 		   1 0.69 0.39
+% 		   0 1 0
+% 		   0 1 1
+% 		   1 0 1
+% 		   0.7 0.78 1
+% 		   1 1 0
+% 		   0.68 0.92 1
+% 		   0.85 0.7 1
+% 		   1 0.6 0.78];
+      
+lines = {'-' '--' ':' '-.' 'o-','x-','+-','*-','s-','d-','v-','^-','<-','>-','p-','h-',       'o--','x--','+--','*--','s--','d--','v--','^--','<--','>--','p--','h--',     'o-.','x-.','+-.','*-.','s-.','d-.','v-.','^-.','<-.','>-.','p-.','h-.',   'o:','x:','+:','*:','s:','d:','v:','^:','<:','>:','p:','h:'   };
+      
+dots = {'o','x','+','*','s','d','v','^','<','>','p','h'};      
+
+bwcolors = [0 0 0; 0.33 0.33 0.33; 0.66 0.66 0.66];
+      
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/output/IQMprintFigure.m b/IQMtools V1.2.2.2/IQMlite/auxiliary/output/IQMprintFigure.m
new file mode 100644
index 0000000000000000000000000000000000000000..a1f7416edf89026740f5d837bb16b6c6d6104c34
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/output/IQMprintFigure.m	
@@ -0,0 +1,128 @@
+function [] = IQMprintFigure(hfig, filename, format)
+% Print figure "hfig" to file "filename". Supported formats: png, ps, jpg,
+% and pdf. "ps" is default. Several figures can be appended in the same
+% file by using format='ps'. Just run the function repeatedly with same
+% filename. If format='png' or 'jpg', figures are not appended, but
+% overwritten. 
+%
+% By default this function generates a .log file with the same name as the
+% file at the same location with information about original text file name,
+% username, date, and scripts and functions that where run to generate the
+% information. The extension for this log file is '.log'
+%
+% Tips when using PS files:
+%   1) If you want a PDF you need to generate it afterwards using the function: 
+%             IQMconvert2pdf.
+%   2) Dont use the PS format if you have transparency in your plots!
+%   3) If you want to start a new file then remove the file first (by default 
+%      plots are appended in PS mode). Files can be removed by: 
+%             IQMstartNewPrintFigure
+%
+% [SYNTAX]
+% [] = IQMprintFigure(hfig, filename)
+% [] = IQMprintFigure(hfig, filename, format)
+%
+% [INPUT]
+% hfig:         handle of figure to be printed
+% filename:     filename to be used 
+% format:       'ps', 'png', 'jpg' (default: 'ps')
+% 
+% [OUTPUT]
+ 
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+% Handle variable input arguments
+if nargin<2,
+    filename = '';
+end
+if nargin<3,
+    format = 'ps';
+end
+
+% Check filename
+if isempty(filename),
+    return
+end
+
+% Change format to lower
+format = lower(format);
+
+% Handle format settings
+if strcmp(format,'ps'),
+    imgformat   = 'psc2';
+    append      = 1;
+elseif strcmp(format,'png'),
+    imgformat   = 'png';
+    append      = 0;
+elseif strcmp(format,'jpg'),
+    imgformat   = 'jpeg95';
+    append      = 0;
+elseif strcmp(format,'pdf'),
+    imgformat   = 'pdf';
+    append      = 0;
+else
+    error('Currently unsupported image format');
+end
+        
+% Setting figure properties for printing
+if strcmp(imgformat,'png'),
+    set(hfig,'PaperOrientation','portrait');
+else
+    set(hfig,'PaperOrientation','landscape');
+end    
+set(hfig,'PaperType','A4');
+set(hfig,'PaperPositionMode', 'manual');
+set(hfig,'PaperUnits', 'centimeters');
+set(hfig,'PaperPosition', [0 0 29.7 21]);
+
+% Determine path file and extension name
+[path,file,ext] = fileparts(filename);
+if isempty(path),
+    path = '.';
+end
+
+% Create folder if not existing
+warning off
+mkdir(path);
+warning on
+
+% Change into path
+oldPath = pwd;
+cd(path);
+
+% Print figure
+if append,
+    print(hfig,['-d',imgformat],file,'-append');
+else
+    print(hfig,['-d',imgformat],file);
+end
+
+% Generate the log information (if COMPLIANCE_OUTPUT_MODE on)
+% -----------------------------------------------------------
+
+if getComplianceModeIQM(),
+    % Get function call information as table
+    results = getFunctionCallInformationIQM(1,1);
+    
+    % Add table title with filename
+    addresults = cell(2,size(results,2));
+    addresults{1,1} = '<TT>';
+    addresults{1,2} = 'Figure file generation log';
+    addresults{2,1} = '<TR>';
+    addresults{2,2} = 'File (relative to calling function)';
+    addresults{2,3} = [path '/' file '.' format];
+    results = [addresults; results];
+    
+    % Generate log file
+    logfilename = [file '.' format '.log'];
+    logtext     = IQMconvertCellTable2ReportTable(results,'report');
+    
+    % Write out the logfile
+    fid = fopen(logfilename,'w');
+    fprintf(fid,'%s',logtext);
+    fclose(fid);
+end
+
+% Return to previous path
+cd(oldPath);
+
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/output/IQMstartNewPrintFigure.m b/IQMtools V1.2.2.2/IQMlite/auxiliary/output/IQMstartNewPrintFigure.m
new file mode 100644
index 0000000000000000000000000000000000000000..b60b6e0223549acf8df88772c93e2c365d558168
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/output/IQMstartNewPrintFigure.m	
@@ -0,0 +1,60 @@
+function [] = IQMstartNewPrintFigure(filename)
+% Function starts a new file in which figures are to be printed.
+% Basically this means, that it is checked if the file exists and if yes it is deleted.
+% The function "IQMprintFigure" can then be used to print a figure into this file.
+% The function "IQMconvert2pdf" can then be used to convert from PS to PDF (only unix).
+% On Unix check is done for .PDF, on windows for .PS
+%
+% [SYNTAX]
+% [] = IQMstartNewPrintFigure(filename)
+%
+% [INPUT]
+% filename:     filename to be used
+% 
+% [OUTPUT]
+ 
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+if isempty(filename),
+    return
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Create folder if it is not existing
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+folder = fileparts(filename);
+if ~isempty(folder),
+    warning off
+    mkdir(folder);
+    warning on
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% If filename exists then delete it
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(filename),
+    [path,file,ext] = fileparts(filename);
+    filename_pdf = fullfile(path,[file '.pdf']);
+    filename_ps  = fullfile(path,[file '.ps']);
+    filename_pdf_log = fullfile(path,[file '.pdf.log']);
+    filename_ps_log  = fullfile(path,[file '.ps.log']);
+
+    warning off;
+    try
+        delete(filename_pdf);
+    end
+    
+    try
+        delete(filename_ps);
+    end
+    
+    try
+        delete(filename_pdf_log);
+    end
+    
+    try
+        delete(filename_ps_log);
+    end
+    
+    warning on;
+end
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/output/IQMwriteText2File.m b/IQMtools V1.2.2.2/IQMlite/auxiliary/output/IQMwriteText2File.m
new file mode 100644
index 0000000000000000000000000000000000000000..fa6e936495f5ebfa4ca1272cb12a214f67b87038
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/output/IQMwriteText2File.m	
@@ -0,0 +1,70 @@
+function [] = IQMwriteText2File(text,filename)
+% This function allows to write a given string (text) to a file (filename)
+% Filename can include a path and all folders will be created if not yet
+% existing.
+% 
+% By default this function generates a .log file with the same name as the
+% file at the same location with information about original text file name,
+% username, date, and scripts and functions that where run to generate the
+% information. The extension for this log file is '.log'.
+%
+% [SYNTAX]
+% [] = IQMwriteText2File(text,filename)
+%
+% [INPUT]
+% text:     String to write to file
+% filename: Filename (with path) to where to write the text
+%
+% [OUTPUT]
+% File "filename" with given "text"
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+% Check filename
+filename = strrep(filename,'\','/');
+[p,f,e] = fileparts(filename);
+if isempty(p),
+    p = '.';
+end
+
+% Only write out if filename defined
+if isempty(f),
+    return
+end
+
+% Create folder if not existing
+warning off
+mkdir(p);
+warning on
+    
+% Write out the file
+fid = fopen(filename,'w');
+fprintf(fid,'%s',text);
+fclose(fid);
+
+% Generate the log information (if COMPLIANCE_OUTPUT_MODE on)
+% -----------------------------------------------------------
+
+if getComplianceModeIQM(),
+    % Get function call information as table
+    results = getFunctionCallInformationIQM(1,1);
+    
+    % Add table title with filename
+    addresults = cell(2,size(results,2));
+    addresults{1,1} = '<TT>';
+    addresults{1,2} = 'Text file generation log';
+    addresults{2,1} = '<TR>';
+    addresults{2,2} = 'File (relative to calling function)';
+    addresults{2,3} = [p '/' f e];
+    results = [addresults; results];
+    
+    % Generate log file
+    logfilename = [p '/' f e '.log'];
+    logtext     = IQMconvertCellTable2ReportTable(results,'report');
+    
+    % Write out the logfile
+    fid = fopen(logfilename,'w');
+    fprintf(fid,'%s',logtext);
+    fclose(fid);
+end
+
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/parallel/isInsideParForLoopIQM.m b/IQMtools V1.2.2.2/IQMlite/auxiliary/parallel/isInsideParForLoopIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..7921ec017d13c11657dd25015dc669693ec28884
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/parallel/isInsideParForLoopIQM.m	
@@ -0,0 +1,22 @@
+function [output] = isInsideParForLoopIQM()
+% This function checks if it is executed within a parfor loop.
+%
+% [SYNTAX]
+% [output] = isInsideParForLoopIQM()
+%
+% [INPUT]
+%
+% [OUTPUT]
+% output:   0 if not called within a parfor loop
+%           1 if called within a parfor loop
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+% Check if parallel toolbox available - if not then simply return 0
+if ~exist('parpool'),
+    output = 0;
+    return
+end
+
+% Check
+output = ~isempty(getCurrentTask());
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/parallel/sizeParallelIQM.m b/IQMtools V1.2.2.2/IQMlite/auxiliary/parallel/sizeParallelIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..a6c6be63a9e5e01fc6e2b8c78acb136f56758e49
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/parallel/sizeParallelIQM.m	
@@ -0,0 +1,25 @@
+function [poolsize] = sizeParallelIQM()
+% This function returns the size of the current pool of parallel
+% processores reserved for MATLAB.
+%
+% [SYNTAX]
+% [poolsize] = sizeParallelIQM()
+%
+% [INPUT]
+%
+% [OUTPUT]
+% poolsize:     Number of parallel processors available
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+if ~exist('parpool'),
+    poolsize = 0;
+    return
+end
+
+poolobj = gcp('nocreate'); % If no pool, do not create new one.
+if isempty(poolobj)
+    poolsize = 0;
+else
+    poolsize = poolobj.NumWorkers;
+end
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/parallel/startParallelIQM.m b/IQMtools V1.2.2.2/IQMlite/auxiliary/parallel/startParallelIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..8df2ba626f7a7e7918d37277f172f6c9e0060d6d
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/parallel/startParallelIQM.m	
@@ -0,0 +1,46 @@
+function [killMATLABpool] = startParallelIQM(NRNODES)
+% This function requests parallel nodes from the MATLAB parallel toolbox.
+%
+% Will only request parallel nodes if NRNODES>1.
+%
+% [SYNTAX]
+% [killMATLABpool] = startParallelIQM()
+% [killMATLABpool] = startParallelIQM(NRNODES)
+%
+% [INPUT]
+% NRNODES:          Number of nodes requested. If not provided, then the
+%                   default number is used, defined in SETUP_PATHS_TOOLS_IQMPRO
+%
+% [OUTPUT]
+% killMATLABpool:   =0 if matlabpool active before call to this function
+%                   =1 if matlabpool not active before call to this function
+%                   Flag can be passed to stopParallelIQM
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+% Check if parallel toolbox available - if not then simply return
+if ~exist('parpool'),
+    killMATLABpool = 0;
+    return
+end
+
+% Evaluate SETUP_PATHS_TOOLS_IQMPRO to get name of MATLABPOOL profile and
+% to obtain default number of nodes to connect to
+SETUP_PATHS_TOOLS_IQMPRO
+
+% Handle optional number of input arguments
+if nargin==0,
+    NRNODES = N_PROCESSORS_PAR;
+end
+
+% Handle the parallel nodes
+killMATLABpool = 0;
+if NRNODES > 1,
+    if sizeParallelIQM() == 0,
+        warning off
+        eval(sprintf('parpool(''%s'',%d);',MATLABPOOL_PROFILE,NRNODES));
+        warning on
+        killMATLABpool = 1;
+    end
+end
+
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/parallel/stopParallelIQM.m b/IQMtools V1.2.2.2/IQMlite/auxiliary/parallel/stopParallelIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..a2e2fe732f5e48f21ca8b8da9ec71dbf468a2fc3
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/parallel/stopParallelIQM.m	
@@ -0,0 +1,29 @@
+function [] = stopParallelIQM(killMATLABpool)
+% This function closes the connection to parallel nodes via the parallel 
+% toolbox in MATLAB
+%
+% [SYNTAX]
+% [] = stopParallelIQM()
+% [] = stopParallelIQM(killMATLABpool)
+%
+% [INPUT]
+% killMATLABpool: if 0 then do not close matlabpool.
+%
+% [OUTPUT]
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+% Check if parallel toolbox available - if not then simply return
+if ~exist('parpool'),
+    return
+end
+
+% Handle variable input arguments
+if nargin==0,
+    killMATLABpool = 1;
+end
+
+% Close connection
+if sizeParallelIQM()>0 && killMATLABpool==1,
+    delete(gcp('nocreate'));
+end
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/setseedIQM.m b/IQMtools V1.2.2.2/IQMlite/auxiliary/setseedIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..73eb7770974c824fba802507d816e119e33ed0d5
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/setseedIQM.m	
@@ -0,0 +1,21 @@
+function [] = setseedIQM(seed)
+% Set the default stream to defaultSeed. 
+%
+% [SYNTAX]
+% [] = setseedIQM(defaultSeed)
+%
+% [INPUT]
+% defaultSeed:   integer between 0 and 2^32.
+%
+% [OUTPUT]
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+% Check that seed is an integer between 0 and 2^32
+if (mod(seed,1)~=0) || seed<0 || seed>2^32,
+    error('Seed must be an integer between 0 and 2^32');
+end
+
+% Get the version release
+s = RandStream.create('mrg32k3a','Seed',seed);
+RandStream.setGlobalStream(s);
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/tempfilehandling/tempdirIQM.m b/IQMtools V1.2.2.2/IQMlite/auxiliary/tempfilehandling/tempdirIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..27b1e5555ae36fc3567928dd51b988adf4198827
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/tempfilehandling/tempdirIQM.m	
@@ -0,0 +1,9 @@
+function [tmpdir] = tempdirIQM()
+% tempdirIQM:    returns the path to the desired temp folder to be used by
+% IQM Tools
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+% just use the systems default temporary folder!
+tmpdir = tempdir;
+
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/tempfilehandling/tempnameIQM.m b/IQMtools V1.2.2.2/IQMlite/auxiliary/tempfilehandling/tempnameIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..a9de6da158a2f052b6e0e09cb79a557cbb35e982
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/tempfilehandling/tempnameIQM.m	
@@ -0,0 +1,8 @@
+function [tmpname] = tempnameIQM( input_args )
+% tempnameIQM does the same as tempname in MATLAB but uses the IQM Tools own
+% TEMP folder.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+[dummy, filename] = fileparts(tempname);
+tmpname = [tempdirIQM,filename];
diff --git a/IQMtools V1.2.2.2/IQMlite/auxiliary/usernameIQM.m b/IQMtools V1.2.2.2/IQMlite/auxiliary/usernameIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..d1d87296b2180e6b80ae0cb81b9697dbbf7acde7
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/auxiliary/usernameIQM.m	
@@ -0,0 +1,11 @@
+function [username] = usernameIQM()
+% usernameIQM: Get the name of the current user
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+if ispc,
+    username = getenv('UserName');
+else
+    username = getenv('USER');
+end
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/classes/@IQMdosing/IQMdosing.m b/IQMtools V1.2.2.2/IQMlite/classes/@IQMdosing/IQMdosing.m
new file mode 100644
index 0000000000000000000000000000000000000000..ff29ff5b440ca8c2a9374ba63e525e3658929574
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classes/@IQMdosing/IQMdosing.m	
@@ -0,0 +1,141 @@
+function [dos] = IQMdosing(varargin)
+% IQMdosing: creates an IQMdosing object defining a dosing schedule
+%
+% USAGE:
+% ======
+% [dos] = IQMdosing()             creates an empty IQMdosing object
+% [dos] = IQMdosing(IQMstructure)  creates an IQMdosing object from a MATLAB
+%                                   structure in the internal IQMdosing format
+% [dos] = IQMdosing(dosin)        construction from a given IQMdosing object (dosin)
+% [dos] = IQMdosing('file.dos')   converting a IQMdosing text description 
+%                                   to an IQMdosing object.
+%
+% Output Arguments:
+% =================
+% dos: IQMdosing object 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK THE TYPE OF THE INPUT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin==0,
+    inputType = 'empty';
+elseif nargin == 1 || nargin == 2,
+    if isIQMdosing(varargin{1}),
+        inputType = 'IQMdosing';
+        dosInput = varargin{1};
+    elseif isstruct(varargin{1}),
+        inputType = 'IQMstructure';
+        IQMstructure = varargin{1};
+    elseif ischar(varargin{1}),
+        % check if '.dos' given as extension. If yes, then import text description
+        filename = varargin{1};
+        if ~isempty(strfind(filename,'.dos')),
+            inputType = 'TextDosFile';
+        elseif strcmp('DosingAsTextString', varargin{2}),
+            inputType = varargin{2};
+        else
+            error('Input argument of unknown type');
+        end
+    else 
+        error('Input argument of unknown type');
+    end
+else
+    error('Wrong number of input arguments.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CONSTRUCT THE IQMdosing OBJECT 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if strcmp('empty',inputType),
+    % Create empty IQMstructure
+    % parameters substructure
+    parametersStruct = struct('name',{},'value',{},'notes',{});
+    % inputs substructure
+    inputsStruct = struct('name',{},'type',{},'time',{},'Tlag',{},'D',{},'parameters',parametersStruct,'TlagNotes',{},'notes',{});
+    % Create IQMstructure
+    IQMstructure = struct('type','IQMdosing','name','unnamed_dosing','notes','no notes','inputs',inputsStruct);
+    % construct the dosing object
+    dos = class(IQMstructure,'IQMdosing');
+elseif strcmp('IQMdosing',inputType),
+    % copy the object
+    dos = dosInput;
+elseif strcmp('IQMstructure',inputType),
+    % check if the given structure is a IQMstructure 
+    if isfield(IQMstructure,'type'),
+        if ~strcmp(IQMstructure.type,'IQMdosing'),
+            error('Given structure is not a valid internal IQMdosing structure.');
+        end
+    else
+        error('Given structure is not a valid internal IQMdosing structure.');
+    end
+    % construct the dosing object
+    dos = class(IQMstructure,'IQMdosing');
+elseif strcmp('TextDosFile',inputType),
+    % check if a file with given filename exists
+    [path,filename,ext] = fileparts(filename);
+    filename = fullfile(path, [filename '.dos']); 
+    if ~exist(filename),
+        error(sprintf('Dosing file, "%s", does not exist.', filename));
+    end
+    % If file exists then first load it
+    dosText = fileread(filename);
+    % then convert it to IQMstructure
+    [IQMstructure, errorMsg] = convertTextToDosIQM(dosText);
+    % Check if error occurred while importing the dosing description
+    if ~isempty(errorMsg),
+        error(errorMsg);
+    end
+    % construct the dosing object
+    dos = class(IQMstructure,'IQMdosing');
+elseif strcmp('DosingAsTextString', inputType),
+    dosText = varargin{1};
+    % then convert text dosing to IQMstructure
+    [IQMstructure, errorMsg] = convertTextToDosIQM(dosText);
+    % Check if error occurred while importing the dosing definition
+    if ~isempty(errorMsg),
+        error(errorMsg);
+    end
+    % construct the dosing object
+    dos = class(IQMstructure,'IQMdosing');
+else
+    error('Wrong input arguments.');
+end
+
+% Cycle through all inputs in the dosing scheme and expand the dose and
+% paramter to time length if needed. but only if dose or parameter is a
+% scalar and time a vector.
+ds = struct(dos);
+for k=1:length(ds.inputs),
+    if ~strcmp(ds.inputs(k).type,'BOLUS'),
+        NTIME = length(ds.inputs(k).time);
+        NDOSE = length(ds.inputs(k).D);
+        NPARA = length(ds.inputs(k).parameters.value);
+        if NDOSE==1 && NTIME>1,
+            ds.inputs(k).D = ds.inputs(k).D*ones(1,NTIME);
+        end
+        if NPARA==1 && NTIME>1,
+            ds.inputs(k).parameters.value = ds.inputs(k).parameters.value*ones(1,NTIME);
+        end
+    end
+end
+
+%% Check
+for k=1:length(ds.inputs),
+    if ~strcmp(ds.inputs(k).type,'BOLUS'),
+        NTIME = length(ds.inputs(k).time);
+        NDOSE = length(ds.inputs(k).D);
+        NPARA = length(ds.inputs(k).parameters.value);
+        if NDOSE ~= NTIME,
+            error('Different lengths of time and dose vector definitions in dosing object. Scalar dose is expanded automatically to length of dose vector.');
+        end
+        if NPARA ~= NTIME,
+            error('Different lengths of time and parameter vector definitions in dosing object. Scalar parameter is expanded automatically to length of dose vector.');
+        end
+    end
+end
+
+%% Create dosing object for output
+dos = class(ds,'IQMdosing');
+
diff --git a/IQMtools V1.2.2.2/IQMlite/classes/@IQMdosing/IQMstruct.m b/IQMtools V1.2.2.2/IQMlite/classes/@IQMdosing/IQMstruct.m
new file mode 100644
index 0000000000000000000000000000000000000000..ff7d17e4ad8c912a8789b1873c828c207a696079
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classes/@IQMdosing/IQMstruct.m	
@@ -0,0 +1,21 @@
+function [IQMstructure] = IQMstruct(dos)
+% IQMstruct: This function returns the internal data structure
+% of an IQMdosing object
+%
+% USAGE:
+% ======
+% [IQMstructure] = IQMstruct(dos) 
+%
+% dos: IQMdosing object 
+%
+% Output Arguments:
+% =================
+% IQMstructure: internal data structure of the IQMdosing object
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% VERY SIMPLE FUNCTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+IQMstructure = struct(dos);
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classes/@IQMdosing/display.m b/IQMtools V1.2.2.2/IQMlite/classes/@IQMdosing/display.m
new file mode 100644
index 0000000000000000000000000000000000000000..ba5b7601b0eb43faa9107462aa217199d56d30e4
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classes/@IQMdosing/display.m	
@@ -0,0 +1,38 @@
+function [] = display(dos)
+% display: Displays information about IQMdosing object. This function is 
+% called by MATLAB whenever an object is the result of a statement that
+% is not terminated by a semicolon. 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% COLLECT INFORMATION ABOUT THE EXPERIMENT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+nrinputs = length(dos.inputs);
+nameinputs = {dos.inputs.name};
+typeinputs = {dos.inputs.type};
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DISPLAY INFORMATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+text = sprintf('\tIQMdosing\n\t===========\n');
+text = sprintf('%s\tName:  %s\n',text,dos.name);
+% text = sprintf('%s\tNotes: %s\n',text,dos.notes);
+text = sprintf('%s\tNumber inputs:     %d',text,nrinputs);
+disp(text);
+for k=1:length(nameinputs),
+    if length(dos.inputs(k).time) > 1,
+        type2 = 'muliple';
+    else 
+        type2 = 'single';
+    end
+    if ~isempty(dos.inputs(k).Tlag),
+        if ischar(dos.inputs(k).Tlag),
+            disp(sprintf('\t\t%s: %s %s\t\t(LAG - NON NUMERIC)',dos.inputs(k).name,type2,dos.inputs(k).type));
+        else
+            disp(sprintf('\t\t%s: %s %s\t\t(LAG - NUMERIC)',dos.inputs(k).name,type2,dos.inputs(k).type));
+        end
+    else
+        disp(sprintf('\t\t%s: %s %s',dos.inputs(k).name,type2,dos.inputs(k).type));
+    end
+end
diff --git a/IQMtools V1.2.2.2/IQMlite/classes/@IQMexperiment/IQMexperiment.m b/IQMtools V1.2.2.2/IQMlite/classes/@IQMexperiment/IQMexperiment.m
new file mode 100644
index 0000000000000000000000000000000000000000..74916ca81c42cc4b00f16b5aca78cbdffa93535c
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classes/@IQMexperiment/IQMexperiment.m	
@@ -0,0 +1,146 @@
+function [exp] = IQMexperiment(varargin)
+% IQMexperiment: creates an experiment object defining experiment settings 
+%
+% USAGE:
+% ======
+% [exp] = IQMexperiment()                creates an empty IQMexperiment object
+% [exp] = IQMexperiment(IQMstructure)     creates an IQMexperiment object from a MATLAB
+%                                       structure in the internal experiment format
+% [exp] = IQMexperiment(expin)           construction from a given IQMexperiment object (expin)
+% [exp] = IQMexperiment('file.exp')      converting a experiment text description 
+%                                       to an IQMexperiment object.
+% [exp] = IQMexperiment('file.exp',path2paramset)  converting a experiment text description 
+%                                       to an IQMexperiment object. When
+%                                       "activeSet" and/or "parameterSet"
+%                                       definitions are used then the path
+%                                       to the root folder of these
+%                                       definitions needs to be provided.
+%                                       Otherwise: ERROR.
+%
+% Output Arguments:
+% =================
+% exp: IQMexperiment object 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+flag = 0;
+path2paramset = '';
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK THE TYPE OF THE INPUT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin==0,
+    inputType = 'empty';
+elseif nargin == 1 || nargin == 2,
+    if strcmp('IQMexperiment',class(varargin{1})),
+        inputType = 'IQMexperiment';
+        expInput = varargin{1};
+    elseif isstruct(varargin{1}),
+        inputType = 'IQMstructure';
+        IQMstructure = varargin{1};
+    elseif ischar(varargin{1}),
+        % check if '.txt' given as extension. If yes, then import text
+        % description
+        filename = varargin{1};
+        if ~isempty(strfind(filename,'.exp')),
+            inputType = 'TextExpFile';
+            if nargin == 2,
+                path2paramset = varargin{2};
+            end
+        elseif nargin == 2,
+            if strcmp('ExperimentAsTextString', varargin{2}),
+                inputType = varargin{2};
+            end
+        else
+            error('Input argument of unknown type');
+        end
+    else 
+        error('Input argument of unknown type');
+    end
+else
+    error('Wrong number of input arguments.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CONSTRUCT THE IQMexperiment OBJECT 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if strcmp('empty',inputType),
+    % Create empty IQMstructure
+    % parameter settings substructure
+    paramicsettingsStruct = struct('name',{},'formula',{},'notes',{},'icflag',{});
+    % parameter settings substructure
+    parameterchangesStruct = struct('name',{},'formula',{},'notes',{});
+    % event assignment substructure
+    eventassignmentStruct = struct('variable',{},'formula',{});
+    % state events substructure
+    stateeventsStruct = struct('name',{},'trigger',{},'assignment',eventassignmentStruct,'notes',{});
+    % Create IQMstructure
+    IQMstructure = struct('name','unnamed_experiment','notes','no notes','paramicsettings',paramicsettingsStruct,'parameterchanges',parameterchangesStruct,'stateevents',stateeventsStruct);
+    % construct the model object
+    exp = class(IQMstructure,'IQMexperiment');
+elseif strcmp('IQMexperiment',inputType),
+    % copy the model object
+    exp = expInput;
+elseif strcmp('IQMstructure',inputType),
+    % check if the given structure is a IQMstructure (only check the
+    % top-level fields)
+    checkFields = {'name','notes','paramicsettings','parameterchanges','stateevents'};
+    for k = 1:length(checkFields),
+        if ~isfield(IQMstructure,checkFields{k}),
+            error('Given structure is not a valid internal IQMexperiment structure.');
+        end
+    end
+    % construct the model object
+    exp = class(IQMstructure,'IQMexperiment');
+elseif strcmp('TextExpFile',inputType),
+    % check if a file with given filename exists
+    [path,filename,ext] = fileparts(filename);
+    if isempty(path2paramset),
+        filename = fullfile(path, [filename '.exp']); 
+    else
+        filename = fullfile(path2paramset,path, [filename '.exp']); 
+    end
+    if ~exist(filename),
+        errorMsg = sprintf('Experiment file, "%s", does not exist.', filename);
+        error(errorMsg);
+    end
+    % If file exists then first load it
+    expText = fileread(filename);
+	% take commented lines out of the experiment description
+	expText = regexprep(expText,'\n%[^\n]*','');
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % CHECK IF "activeSet" and/or "parameterSet" 
+    % definitions are used. If yes, then preprocess
+    % the experiment text.
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    expText = checkProcessActiveSetParameterSetIQM(expText,path2paramset);
+    % then convert it to IQMstructure
+    [IQMstructure, errorMsg] = convertTextToExpIQM(expText);
+    % Check if error occurred while importing the SBML model
+    if ~isempty(errorMsg),
+        error(errorMsg);
+    end
+    % construct the model object
+    exp = class(IQMstructure,'IQMexperiment');
+elseif strcmp('ExperimentAsTextString', inputType),
+    expText = varargin{1};
+	% take commented lines out of the experiment description
+	expText = regexprep(expText,'\n%[^\n]*','');
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % CHECK IF "activeSet" and/or "parameterSet" 
+    % definitions are used. If yes, then preprocess
+    % the experiment text.
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    expText = checkProcessActiveSetParameterSetIQM(expText,path2paramset);
+    % then convert text experiment to IQMstructure
+    [IQMstructure, errorMsg] = convertTextToExpIQM(expText);
+    % Check if error occurred while importing the SBML model
+    if ~isempty(errorMsg),
+        error(errorMsg);
+    end
+    % construct the model object
+    exp = class(IQMstructure,'IQMexperiment');
+else
+    error('Wrong input arguments.');
+end
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/classes/@IQMexperiment/IQMstruct.m b/IQMtools V1.2.2.2/IQMlite/classes/@IQMexperiment/IQMstruct.m
new file mode 100644
index 0000000000000000000000000000000000000000..7e6fcaa0688f8ac1a761214d0ba484998435e0b9
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classes/@IQMexperiment/IQMstruct.m	
@@ -0,0 +1,21 @@
+function [IQMstructure] = IQMstruct(iqm)
+% IQMstruct: This function returns the internal data structure
+% of an IQMexperiment object
+%
+% USAGE:
+% ======
+% [IQMstructure] = IQMstruct(experiment) 
+%
+% experiment: IQMexperiment object 
+%
+% Output Arguments:
+% =================
+% IQMstructure: internal data structure of the IQMexperiment object
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% VERY SIMPLE FUNCTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+IQMstructure = struct(iqm);
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classes/@IQMexperiment/display.m b/IQMtools V1.2.2.2/IQMlite/classes/@IQMexperiment/display.m
new file mode 100644
index 0000000000000000000000000000000000000000..c99e44be2d2ec6a06c0eb44ae7d1e34b043c91e0
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classes/@IQMexperiment/display.m	
@@ -0,0 +1,26 @@
+function [] = display(exp)
+% display: Displays information about IQMexperiment object. This function is 
+% called by MATLAB whenever an object is the result of a statement that
+% is not terminated by a semicolon. 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% COLLECT INFORMATION ABOUT THE EXPERIMENT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+name = exp.name;
+notes = exp.notes;
+nrparamicsettings = length(exp.paramicsettings);
+nrparameterchanges = length(exp.parameterchanges);
+nrstatechanges = length(exp.stateevents);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DISPLAY INFORMATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+text = sprintf('\tIQMexperiment\n\t============\n');
+text = sprintf('%s\tName:  %s\n',text,name);
+text = sprintf('%s\tNumber Param+IC Settings: %d\n',text,nrparamicsettings);
+text = sprintf('%s\tNumber Param Changes:     %d\n',text,nrparameterchanges);
+text = sprintf('%s\tNumber State Changes:     %d\n',text,nrstatechanges);
+disp(text);
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classes/@IQMmeasurement/IQMmeasurement.m b/IQMtools V1.2.2.2/IQMlite/classes/@IQMmeasurement/IQMmeasurement.m
new file mode 100644
index 0000000000000000000000000000000000000000..37b39c38836f88b6c0d208b4cc589ad373252387
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classes/@IQMmeasurement/IQMmeasurement.m	
@@ -0,0 +1,124 @@
+function [output] = IQMmeasurement(varargin)
+% IQMmeasurement: creates an object that is intended to contain 
+% measurement data - from real experiments or insilico computations
+%
+% USAGE:
+% ======
+% [output] = IQMmeasurement()                creates an empty IQMmeasurement object
+% [output] = IQMmeasurement(struct)          creates an IQMmeasurement object from
+%                                           a MATLAB structure in the internal 
+%                                           measurement object format
+% [output] = IQMmeasurement(inputobject)     construction from a given IQMmeasurement object 
+% [output] = IQMmeasurement('filename.xls')  converting an excel file to 
+%                                           an IQMmeasurement object.
+% [output] = IQMmeasurement('filename.csv')  converting an CSV (comma
+%                                           separated value) file to  
+%                                           an IQMmeasurement object
+%
+% Output Arguments:
+% =================
+% output: IQMmeasurement object 
+%         In the case that several sets of measurement data are defined in 
+%         an Excel file (on separate sheets) the output will be cell-array
+%         in which the elements are IQMmeasurement objects.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK THE TYPE OF THE INPUT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin==0,
+    inputType = 'empty';
+elseif nargin == 1,
+    if strcmp('IQMmeasurement',class(varargin{1})),
+        inputType = 'IQMmeasurement';
+        measurementinput = varargin{1};
+    elseif strcmp('struct',class(varargin{1})),
+        inputType = 'measurementstructure';
+        measurementstructure = varargin{1};
+    elseif strcmp('char',class(varargin{1})),
+        % assume filenamec given as input argument
+        % check if '.xls' given as extension. If yes, then import measurement from
+        % excel file format
+        filename = varargin{1};
+        if ~isempty(strfind(lower(filename),'.xls')),
+            inputType = 'XLSmeasurementFile';
+        elseif ~isempty(strfind(lower(filename),'.csv')),
+            inputType = 'CSVmeasurementFile';
+        else
+            error('Unknown filetype!');
+        end
+    else 
+        error('Input argument of unknown type');
+    end
+else
+    error('Wrong number of input arguments.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CONSTRUCT THE IQMMODEL OBJECT 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if strcmp('empty',inputType),
+    % Create empty measurement structure
+    % data substructure
+    datastructure = struct('name',{},'notes',{},'values',{},'maxvalues',{},'minvalues',{});
+    % Create measurement structure
+    measurementsStruct = struct('name','untitled','notes','','time',[],'data',datastructure);
+    output = class(measurementsStruct,'IQMmeasurement');
+elseif strcmp('IQMmeasurement',inputType),
+    % copy the model object
+    output = measurementinput;
+elseif strcmp('measurementstructure',inputType),
+    % check if the given structure is a measurement structure (only check the
+    % top-level fields)
+    checkFields = {'name','notes','time','data'};
+    for k = 1:length(checkFields),
+        if ~isfield(measurementstructure,checkFields{k}),
+            errorMsg = sprintf('Given structure is not a valid internal IQMmeasurement structure.');
+            error(errorMsg);
+        end
+    end
+    % construct the data object
+    output = class(measurementstructure,'IQMmeasurement');
+elseif strcmp('XLSmeasurementFile',inputType),
+    % check if a file with given filename exists
+    [path,filename,ext] = fileparts(filename);
+    filename = fullfile(path, [filename '.xls']); 
+    if ~exist(filename),
+        errorMsg = sprintf('XLS measurement file, "%s", does not exist.', filename);
+        error(errorMsg);
+    end
+    % If file exists then import it
+    [outputstructures,errorMsg] = IQMimportXLSmeasurement(filename);
+    % Check if error occurred while importing the XLS data
+    if length(errorMsg) ~= 0,
+        error(errorMsg);
+    end
+    % construct the data objects (one for each sheet)
+    if length(outputstructures) == 1,
+        output = class(outputstructures{1},'IQMmeasurement');
+    else
+        output = {};
+        for k = 1:length(outputstructures),
+            output{k} = class(outputstructures{k},'IQMmeasurement');
+        end
+    end
+elseif strcmp('CSVmeasurementFile',inputType),
+    % check if a file with given filename exists
+    [path,filename,ext] = fileparts(filename);
+    filename = fullfile(path, [filename '.csv']); 
+    if ~exist(filename),
+        errorMsg = sprintf('CSV measurement file, "%s", does not exist.', filename);
+        error(errorMsg);
+    end
+    % If file exists then import it
+    [measurementstructure,errorMsg] = IQMimportCSVmeasurement(filename);
+    % Check if error occurred while importing the CSV data
+    if length(errorMsg) ~= 0,
+        error(errorMsg);
+    end
+    % construct the measurement object
+    output = class(measurementstructure,'IQMmeasurement');
+end
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/classes/@IQMmeasurement/IQMstruct.m b/IQMtools V1.2.2.2/IQMlite/classes/@IQMmeasurement/IQMstruct.m
new file mode 100644
index 0000000000000000000000000000000000000000..f894b3a13b45740d326c51787a7cef153f7f4921
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classes/@IQMmeasurement/IQMstruct.m	
@@ -0,0 +1,21 @@
+function [datastructure] = IQMstruct(iqmmeasurement)
+% IQMstruct: This function returns the internal data structure
+% of an IQMmeasurement object
+%
+% USAGE:
+% ======
+% [datastructure] = IQMstruct(iqmmeasurement) 
+%
+% iqmmeasurement: IQMmeasurement data object 
+%
+% Output Arguments:
+% =================
+% datastructure: internal data structure of the IQMmeasurement object
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% VERY SIMPLE FUNCTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+datastructure = struct(iqmmeasurement);
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classes/@IQMmeasurement/display.m b/IQMtools V1.2.2.2/IQMlite/classes/@IQMmeasurement/display.m
new file mode 100644
index 0000000000000000000000000000000000000000..38f8f6a8ea5bc4cc29a91c923dbf725d0a3ce137
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classes/@IQMmeasurement/display.m	
@@ -0,0 +1,44 @@
+function [] = display(measurement)
+% display: Displays information about IQMmeasurement. This function is 
+% called by MATLAB whenever an object is the result of a statement that
+% is not terminated by a semicolon. 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% COLLECT INFORMATION ABOUT THE DATA OBJECT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+name = measurement.name;
+notes = measurement.notes;
+numbermeasurements = length(measurement.data);
+numbertimesteps = length(measurement.time);
+errorboundFlag = 0;
+allMeasurementsDone = 1;
+for k = 1:length(measurement.data),
+    % check if errorbounds are present
+    if ~isempty(measurement.data(k).maxvalues) && max(isnan(measurement.data(k).maxvalues))~=1,
+        errorboundFlag = 1;
+    end
+    % check if NaN present in data
+    if ~isempty(find(isnan(measurement.data(k).values))),
+        allMeasurementsDone = 0;
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DISPLAY INFORMATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+text = sprintf('\tIQMmeasurement\n\t=============\n');
+text = sprintf('%s\tName: %s\n',text,name);
+text = sprintf('%s\tMeasured components:\t%d\n',text,numbermeasurements);
+text = sprintf('%s\tNumber time points: \t%d\n',text,numbertimesteps);
+if errorboundFlag == 1,
+    text = sprintf('%s\tError bound information present at least for one measurement.\n',text);
+end
+if allMeasurementsDone == 1,
+    text = sprintf('%s\tMeasurements for all time points present\n',text);
+else
+    text = sprintf('%s\tMeasurements not present for all time points\n',text);
+end
+disp(text);
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classes/@IQMmodel/IQMmodel.m b/IQMtools V1.2.2.2/IQMlite/classes/@IQMmodel/IQMmodel.m
new file mode 100644
index 0000000000000000000000000000000000000000..15d4fe96178235fb4adb0e2069613a1d4711df2c
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classes/@IQMmodel/IQMmodel.m	
@@ -0,0 +1,281 @@
+function [model] = IQMmodel(varargin)
+% IQMmodel: creates a model object 
+%
+% [SYNTAX]
+% [model] = IQMmodel()                
+% [model] = IQMmodel(model)    
+% [model] = IQMmodel(model,nocheck) 
+% [model] = IQMmodel(model,nocheck,useSBMLnames) 
+% [model] = IQMmodel(model,nocheck,useSBMLnames,stripSBMLinfo) 
+%
+% [INPUT]
+% model:            Can have multiple meanings
+%                   - If it is an IQMmodel structure (struct(model)) then this structure
+%                     is converted to an IQMmodel
+%                   - If it is a filename (file.txt, file.txtbc, file.xml) then the
+%                     file is interpreted as a valid IQMmodel text file (txt or txtbc) 
+%                     or as an SBML file (.xml) and imported accordingly to an IQMmodel object.
+%                     If no extension is specified, then SBML format is assumed.
+%                   - If it is an IQMmodel, then this model is just passed through and 
+%                     returned as output argument.
+% nocheck:          0: standard behavior. Consistency of models is checked and errors 
+%                      are shown if something is wrong.
+%                   1: Consistency is not checked. Instead of errors warnings are shown.
+%                      This functionality is mainly thought for the import of (in)completely 
+%                      defined SBML models. It does not require that a model is fully defined 
+%                      in terms of parameter values, and rate equations, etc. 
+%                   (default: 0)
+% useSBMLnames:     0: During SBML import, use the element IDs as names of model components
+%                   1: During SBML import, use the element NAMEs as names of model components
+%                      This is needed for cases where the SBML modeling software in which the model
+%                      was created uses random SBML IDs, which translates to unreadable models.
+%                      This is the case for CellDesigner and Simbiology (e.g.). The names in SBML models
+%                      are not required to be unique. This is taken care off by making them unique through 
+%                      appending indices (_1, _2, ...).
+%                   (default: 0)
+% stripSBMLinfo:    0: keep additional information for SBML conversion in the model after import
+%                   1: remove additional information from SBML import
+%                   (default: 0)
+%
+% [OUTPUT]
+% model:            IQMmodel object 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+% Handle optional input flags
+nocheck         = 0;
+useSBMLnames    = 0;
+stripSBMLinfo   = 0;
+if nargin > 1,
+    nocheck = varargin{2};
+end
+if nargin > 2,
+    useSBMLnames = varargin{3};
+end
+if nargin > 3,
+    stripSBMLinfo = varargin{4};
+end
+
+% Check something
+if ~isnumeric(nocheck),
+    error('Problem with IQMmodel');
+end
+
+% CHECK THE TYPE OF THE INPUT
+if nargin==0,
+    inputType = 'empty';
+end
+
+if nargin >0,
+    if strcmp('IQMmodel',class(varargin{1})),
+        inputType = 'IQMmodel';
+        iqmInput = varargin{1};
+    elseif isstruct(varargin{1}),
+        inputType = 'IQMstructure';
+        IQMstructure = varargin{1};
+    elseif ischar(varargin{1}),
+        % check if '.txt' or '.txtbc' given as extension. If yes, then import text
+        % model, otherwise assume an SBML model is to be imported.
+        filename = varargin{1};
+        if ~isempty(strfind(filename,'.txtbc')),
+            inputType = 'TextBCModelFile';
+        elseif ~isempty(strfind(filename,'.txt')),
+            inputType = 'TextModelFile';
+%         elseif strcmp('ModelAsTextString', flag),
+%             modelText = varargin{1};
+%             inputType = flag;
+%         elseif strcmp('ModelAsTextBCString', flag),
+%             modelText = varargin{1};
+%             inputType = flag;
+        else
+            inputType = 'SBMLmodelFile';
+        end        
+    else 
+        error('Input argument of unknown type');
+    end
+end
+
+
+% model.inputs.name:       input name
+% model.inputs.factors:    cell-array with input factors
+% model.inputs.terms:      cell-array with complete input string (for
+%                          simpler removing)
+% model.inputs.stateindex: vector with stateindices to which the 
+%                          input is applied
+% model.inputs.parindex:   index of the INPUT* parameter definition in
+%                          the IQMmodel (used to remove it when
+%                          parameters are written to (e.g.) an MLXTRAN
+%                          file).   
+% model.outputs.name:      output name
+% model.outputs.formula:   output formula
+% model.outputs.notes:     output notes
+% model.outputs.varindex:  index of output in model variables
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CONSTRUCT THE IQMMODEL OBJECT 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if strcmp('empty',inputType),
+    % Create empty IQMstructure
+    % inputs substructure
+    inputsStruct = struct('name',{},'factors',{},'terms',{},'stateindex',{},'parindex',{});
+    % outputs substructure
+    outputsStruct = struct('name',{},'formula',{},'notes',{},'varindex',{});
+    % functions substructure
+    functionsStruct = struct('name',{},'arguments',{},'formula',{},'notes',{});
+    % states substructure
+    statesStruct = struct('name',{},'initialCondition',{},'ODE',{},'type',{},'compartment',{},'unittype',{},'notes',{});
+    % algebraic substructure
+    algebraicStruct = struct('name',{},'formula',{},'initialCondition',{},'type',{},'compartment',{},'unittype',{},'notes',{});
+    % parameters substructure
+    parametersStruct = struct('name',{},'value',{},'type',{},'compartment',{},'unittype',{},'notes',{});
+    % variables substructure
+    variablesStruct = struct('name',{},'formula',{},'type',{},'compartment',{},'unittype',{},'notes',{});
+    % reactions substructure
+    reactionsStruct = struct('name',{},'formula',{},'notes',{},'reversible',{},'fast',{});
+    % event assignment substructure
+    eventassignmentStruct = struct('variable',{},'formula',{});
+    % event substructure
+    eventStruct = struct('name',{},'trigger',{},'assignment',eventassignmentStruct,'notes',{});
+    % Create IQMstructure
+    IQMstructure = struct('name','unnamed_model','notes','','functions',functionsStruct,'states',statesStruct,'algebraic',algebraicStruct,'parameters',parametersStruct,'variables',variablesStruct,'reactions',reactionsStruct,'events',eventStruct,'functionsMATLAB','','inputs',inputsStruct,'outputs',outputsStruct);
+    % construct the model object
+    model = class(IQMstructure,'IQMmodel');
+elseif strcmp('IQMmodel',inputType),
+    % copy the model object
+    model = iqmInput;
+elseif strcmp('IQMstructure',inputType),
+    % check if given structure contains inputs and outputs. If not then add these 
+    if ~isfield(IQMstructure,'inputs'),
+        IQMstructure.inputs  = struct('name',{},'factors',{},'terms',{},'stateindex',{},'parindex',{});
+    end
+    if ~isfield(IQMstructure,'outputs'),
+        IQMstructure.outputs = struct('name',{},'formula',{},'notes',{},'varindex',{});
+    end
+    % check if the given structure is a IQMstructure (only check the
+    % top-level fields)
+    checkFields = {'name','notes','functions','states','algebraic','parameters','variables','reactions','events','functionsMATLAB'};
+    for k = 1:length(checkFields),
+        if ~isfield(IQMstructure,checkFields{k}),
+            errorMsg = sprintf('Given structure is not a valid internal IQMmodel structure.');
+            error(errorMsg);
+        end
+    end
+    % construct the model object
+    model = class(IQMstructure,'IQMmodel');
+elseif strcmp('SBMLmodelFile',inputType),
+    % check if a file with given filename exists
+    [path,filename,ext] = fileparts(filename);
+    filename = fullfile(path, [filename '.xml']); 
+    test = dir(filename);
+    if isempty(test),
+        errorMsg = sprintf('SBML model, "%s", does not exist in given folder.', filename);
+        error(errorMsg);
+    end
+    
+    % If file exists then import it
+    [IQMstructure,errorMsg] = importSBMLIQM(filename,useSBMLnames);
+    if nocheck == 0,
+        if ~isempty(errorMsg), error(errorMsg);  end
+    else
+        if ~isempty(errorMsg), warning on; warning(errorMsg);  end
+    end
+    
+    % Remove SBML information if requested
+    if stripSBMLinfo,
+        for k = 1:length(IQMstructure.states),
+            IQMstructure.states(k).type = '';
+            IQMstructure.states(k).compartment = '';
+            IQMstructure.states(k).unittype = '';
+        end
+        for k = 1:length(IQMstructure.variables),
+            IQMstructure.variables(k).type = '';
+            IQMstructure.variables(k).compartment = '';
+            IQMstructure.variables(k).unittype = '';
+        end
+        for k = 1:length(IQMstructure.parameters),
+            IQMstructure.parameters(k).type = '';
+            IQMstructure.parameters(k).compartment = '';
+            IQMstructure.parameters(k).unittype = '';
+        end
+    end
+    
+    
+    
+    % construct the model object
+    model = class(IQMstructure,'IQMmodel');
+elseif strcmp('TextModelFile',inputType),
+    % check if a file with given filename exists
+    [path,filename,ext] = fileparts(filename);
+    filename = fullfile(path, [filename '.txt']); 
+    if ~exist(filename),
+        errorMsg = sprintf('TEXT model, "%s", does not exist.', filename);
+        error(errorMsg);
+    end
+    % If file exists then first load it
+    modelText = fileread(filename);  
+    % then convert it to IQMstructure
+    [IQMstructure, errorMsg] = convertTextToModelIQM(modelText);
+    % Check if error occurred while importing the SBML model
+    if ~isempty(errorMsg),
+        error(errorMsg);
+    end
+    % handle arrays for TEXT models
+    IQMstructure = convertTEXTArrayDefIQM(IQMstructure);
+    % construct the model object
+    model = class(IQMstructure,'IQMmodel');
+elseif strcmp('TextBCModelFile',inputType),
+    % check if a file with given filename exists
+    [path,filename,ext] = fileparts(filename);
+    filename = fullfile(path, [filename '.txtbc']); 
+    if ~exist(filename),
+        errorMsg = sprintf('TEXTBC model, "%s", does not exist.', filename);
+        error(errorMsg);
+    end
+    % If file exists then first load it
+    modelText = fileread(filename);
+    % then convert it to IQMstructure
+    [IQMstructure, errorMsg] = convertTextBCToModelIQM(modelText);
+    % Check if error occurred while importing the SBML model
+    if ~isempty(errorMsg),
+        error(errorMsg);
+    end
+    % construct the model object
+    model = class(IQMstructure,'IQMmodel');
+elseif strcmp('ModelAsTextString', inputType),
+    % convert model text to IQMstructure
+    [IQMstructure, errorMsg] = convertTextToModelIQM(modelText);
+    % Check if error occurred while importing the SBML model
+    if ~isempty(errorMsg),
+        error(errorMsg);
+    end
+    % construct the model object
+    model = class(IQMstructure,'IQMmodel');
+elseif strcmp('ModelAsTextBCString', inputType),
+    % then convert model text to IQMstructure
+    [IQMstructure, errorMsg] = convertTextBCToModelIQM(modelText);
+    % Check if error occurred while importing the SBML model
+    if ~isempty(errorMsg),
+        error(errorMsg);
+    end
+    % construct the model object
+    model = class(IQMstructure,'IQMmodel');
+else
+    error('Wrong input arguments.');
+end
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle inputs and outputs (add info about them to the structure and
+% eventually add parameters for inputs)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+model = inputoutputIQMmodelParsingIQM(model);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DELETE WHITESPACES IN STRINGS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Useful for taking away whitespaces in kineticLaw formulas, as
+% seen in some example models
+function [outputString] = removeWhiteSpace(inputString)
+outputString = strrep(inputString,' ','');
+% return
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classes/@IQMmodel/IQMstruct.m b/IQMtools V1.2.2.2/IQMlite/classes/@IQMmodel/IQMstruct.m
new file mode 100644
index 0000000000000000000000000000000000000000..8531e945485e5c64cfc4b5b9daae9e1411919085
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classes/@IQMmodel/IQMstruct.m	
@@ -0,0 +1,23 @@
+function [IQMstructure] = IQMstruct(iqm)
+% IQMstruct: This function returns the internal data structure
+% of an IQMmodel
+%
+% USAGE:
+% ======
+% [IQMstructure] = IQMstruct(IQMmodel) 
+%
+% IQMmodel: IQMmodel 
+%
+% Output Arguments:
+% =================
+% IQMstructure: internal data structure of the IQMmodel
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% VERY SIMPLE FUNCTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+IQMstructure = struct(iqm);
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classes/@IQMmodel/display.m b/IQMtools V1.2.2.2/IQMlite/classes/@IQMmodel/display.m
new file mode 100644
index 0000000000000000000000000000000000000000..8127f655673b738707c2d7ebcdeea652cd690254
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classes/@IQMmodel/display.m	
@@ -0,0 +1,62 @@
+function [] = display(iqm)
+% display: Displays information about IQMmodel. This function is 
+% called by MATLAB whenever an object is the result of a statement that
+% is not terminated by a semicolon. 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% COLLECT INFORMATION ABOUT THE MODEL
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+numberStates = length(iqm.states);
+numberVariables = length(iqm.variables);
+numberParameters = length(iqm.parameters);
+numberReactions = length(iqm.reactions);
+numberFunctions = length(iqm.functions);
+numberEvents = length(iqm.events);
+functionsMATLABpresent = ~isempty(iqm.functionsMATLAB);
+delaysPresent = usedelayIQM(iqm);
+numberARs = length(iqm.algebraic);
+fastReactionsPresent = usefastIQM(iqm);
+nnICsPresent = ~hasonlynumericICsIQM(iqm);
+nrInputs = length(iqm.inputs);
+nrOutputs = length(iqm.outputs);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DISPLAY INFORMATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+text = sprintf('\tIQMmodel\n\t=======\n');
+text = sprintf('%s\tName: %s\n',text,iqm.name);
+text = sprintf('%s\tNumber States:\t\t\t%d\n',text,numberStates);
+text = sprintf('%s\tNumber Variables:\t\t%d\n',text,numberVariables);
+text = sprintf('%s\tNumber Parameters:\t\t%d\n',text,numberParameters);
+text = sprintf('%s\tNumber Reactions:\t\t%d\n',text,numberReactions);
+text = sprintf('%s\tNumber Functions:\t\t%d\n',text,numberFunctions);
+if numberEvents > 0,
+    text = sprintf('%s\tNumber Events:\t\t\t%d\n',text,numberEvents);
+end
+if numberARs > 0,
+    text = sprintf('%s\tNumber Algebraic Rules:\t%d\n',text,numberARs);
+end
+if nrInputs > 0,
+    text = sprintf('%s\tNumber Inputs:\t\t\t%d\n',text,nrInputs);
+end
+if nrOutputs > 0,
+    text = sprintf('%s\tNumber Outputs:\t\t\t%d\n',text,nrOutputs);
+end
+if functionsMATLABpresent,
+    text = sprintf('%s\tMATLAB functions present\n',text);
+end
+if delaysPresent,
+    text = sprintf('%s\tDelay function(s) present',text);
+end
+if fastReactionsPresent,
+    text = sprintf('%s\tFast reactions are present in the model:\n\t\tPlease note that this information is ONLY taken into account\n\t\tduring simulation using IQMsimulate. NO other function will\n\t\tconsider fast reactions.\n',text);
+end
+if nnICsPresent,
+    text = sprintf('%s\tNon-numeric initial conditions are present in the model.\n\t\tPlease check the documentation for further information.\n',text);
+end    
+if numberARs > 0,
+    text = sprintf('%s\tAlgebraic rules present in the model.\n\t\tYou should not use ANY other function on this model than IQMsimulate.\n',text);
+end
+disp(text);
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classes/@IQMmodel/private/inputoutputIQMmodelParsingIQM.m b/IQMtools V1.2.2.2/IQMlite/classes/@IQMmodel/private/inputoutputIQMmodelParsingIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..8945b432d336e931fa083ff75c523c98455fa9d2
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classes/@IQMmodel/private/inputoutputIQMmodelParsingIQM.m	
@@ -0,0 +1,562 @@
+function [model] = inputoutputIQMmodelParsingIQM(model)
+% inputoutputIQMmodelParsingIQM: This function is implemented as a private
+% method for IQMmodels. It is not supposed to be used by any other function
+% than IQMmodel. It takes a model, read in by the IQMmodel function,
+% processes it in terms of INPUT and OUTPUT handling and stores the found
+% information in the internal model structure. The involved fields and
+% handling features are described below. Error checks are done to ensure
+% the model is compatible with the items, described below. 
+%
+% Handling of INPUT* and OUTPUT* definitions in IQMmodels:
+%
+% INPUT*:
+%       - "*": 1,2,3,4,5, ...
+%       - input definitions are only allowed in differential equations
+%         but also input definitions in reactions are allowed. In this case
+%         the reaction name in the ODE is replaced by the reaction
+%         expression to have the input definition in the ODE.
+%       - a prefactor is allowed, e.g. +1.5*INPUT1 or (k1+k2)*INPUT2
+%         the prefactors can be arbitrarily chosen. No postfactors are
+%         allowed. Additionally the INPUT* element needs to be a
+%         multiplicative factor.
+%       - Input terms (INPUT* identifier and prefactor) are only allowed to
+%         be added (+) to the differential equation.
+%       - If INPUT* is already also present as a parameter, it will be used
+%         as defined. If the model does not contain an INPUT* parameter, it
+%         is added and set by default to "0". INPUT* is only allowed to be
+%         defined as a parameter. Not as a variable and not as a reaction.
+%       - Only parameters (and numerical values) are allowed to be used in
+%         the definition of INPUT* prefactors. But no states, variables and
+%         reactions.
+%
+% OUTPUT*:
+%       - "*": 1,2,3,4,5, ... sequential indices, starting from 1.
+%              no number is allowed to be excluded.
+%       - output definitions are only allowed to appear in the model
+%         variables section
+%       - output RHS expressions can depend on parameters, states, and
+%         previously defined model variables.
+%         OUTPUT* variables are NOT allowed to depend on INPUT* components
+%
+% IQMmodel structure changes:
+% model.inputs.name:       input name
+% model.inputs.factors:    cell-array with input factors
+% model.inputs.terms:      cell-array with complete input string (for
+%                          simpler removing)
+% model.inputs.stateindex: vector with stateindices to which the 
+%                          input is applied
+% model.inputs.parindex:   index of the INPUT* parameter definition in
+%                          the IQMmodel (used to remove it when
+%                          parameters are written to (e.g.) an MLXTRAN
+%                          file).   
+% model.outputs.name:      output name
+% model.outputs.formula:   output formula
+% model.outputs.notes:     output notes
+% model.outputs.varindex:  index of output in model variables
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% IMPORTANT: ALWAYS CLEAR FIRST THE inputs and outputs substructures before
+% running this function ... 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% inputs substructure
+inputsStruct = struct('name',{},'factors',{},'terms',{},'stateindex',{},'parindex',{});
+% outputs substructure
+outputsStruct = struct('name',{},'formula',{},'notes',{},'varindex',{});
+% clear the substructures
+model.inputs = inputsStruct;
+model.outputs = outputsStruct;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE POSSIBLE INPUT DEFINITIONS IN REACTIONS
+% if present then replace reaction name in ODE
+% with reaction expression
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+model = handleInputsInReactions(model);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK MODEL: INPUTS ONLY ON STATES?
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~inputsonlyonstates(model),
+    error(sprintf('The model contains ''INPUT'' on other elements than ODEs.\nPlease note that ''INPUT'' is a reserved word for input definitions.\nIf you do not want to use this feature, please rename your model\ncomponents to NOT include the string ''INPUT''. If you want to use\ninput definitions then please note that these are only allowed in ODEs.'));
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK MODEL: OUTPUTS ONLY IN VARIABLES?
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~outputsonlyasvariables(model),
+    error(sprintf('The model contains ''OUTPUT'' in at least one parameter, state or reaction name.\nPlease note that ''OUTPUT'' is a reserved word for output definitions.\nIf you do not want to use this feature, please rename your model\ncomponents to NOT include the string ''OUTPUT''. If you want to use\noutput definitions then please note that these are only allowed as variables.'));
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DETERMINE MODEL INPUT INFORMATION TO THE MODEL STRUCTURE AND DO SOME INITIAL CHECKING
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[statenames,ODEs] = IQMstates(model);
+% get model input names (unique)
+inputnames = {};
+inputodeindex = [];
+for k=1:length(ODEs),
+    y = regexp(ODEs{k},'(INPUT\w*)','tokens');
+    for k2=1:length(y),
+        x = y{k2};
+        inputnames{end+1} = x{1};
+        inputodeindex(end+1) = k;
+    end
+end    
+% add the inputs into to the model structure 
+for k=1:length(inputnames),
+    inputindex = strmatchIQM(inputnames{k},{model.inputs.name},'exact');
+    if isempty(inputindex),
+        model.inputs(end+1).name = inputnames{k};
+        model.inputs(end).stateindex = inputodeindex(k);
+    else
+        model.inputs(inputindex).stateindex = [model.inputs(inputindex).stateindex inputodeindex(k)];
+    end
+end
+% check if same input more than once on same ODE
+for k=1:length(model.inputs),
+    if length(model.inputs(k).stateindex) ~= length(unique(model.inputs(k).stateindex)),
+        error('Input ''%s'' appears more than once in the same ODE.',model.inputs(k).name);
+    end
+end
+% determine the input factors
+for k=1:length(model.inputs),
+    stateindex = model.inputs(k).stateindex;
+    for k2=1:length(stateindex),
+        [factor, term] = getInputFactorFromODE(ODEs{stateindex(k2)},model.inputs(k).name);
+        model.inputs(k).factors{end+1} = factor;
+        model.inputs(k).terms{end+1} = term;
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK THE INPUT NAMES FOR VALIDITY (only if inputs are present)
+% AND REORDER THE INPUTS IN THE MODEL STRUCTURE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Input names need to be numerically ordered. No index is allowed to be
+% omitted inbetween. INPUT1, INPUT2, INPUT3, ... allowed but NOT:
+% INPUT1, INPUT3, INPUT4, etc. Numbering always needs to start at 1.
+% It is probably not absolutely needed but to be consistent with the output
+% handling and consistent with the requirements of the input indexing, a
+% reordering of the inputs just makes sense.
+if ~isempty(model.inputs),
+    model = checkinputnumberingOKandreorder(model);
+end
+
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% % Check state, variable, reaction appearance in input factors (if yes => error)
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% sn = {model.states.name};
+% vn = {model.variables.name};
+% rn = {model.reactions.name};
+% allother = {sn{:} vn{:} rn{:}};
+% allfactors = {};
+% for k=1:length(model.inputs),
+%     allfactors = {allfactors{:} model.inputs(k).factors{:}};
+% end
+% for k=1:length(allfactors),
+%     test = ['#' allfactors{k} '#'];
+%     for k2=1:length(allother),
+%         index = regexp(test,['\W' allother{k2} '\W'], 'once' );
+%         if ~isempty(index),
+%             error(sprintf('The model component ''%s'' appears in an input pre-factor ''%s''.\nPlease note that no states, variables, or reactions are allowed to\nappear in these pre-factors. Only parameters and numerical values.',allother{k2},allfactors{k}));
+%         end
+%     end
+% end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE MODEL INPUT PARAMETERS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% For each INPUT* a parameter INPUT* needs to be defined. If not present in
+% the model, then it is added to the model with a default value of 0.
+% Also add the parameter index to the model.inputs structure.
+model = handleInputParameters(model);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET MODEL OUTPUT INFORMATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Outputs are defined be OUTPUT1 = ..., OUTPUT2 = ...
+% The ordering is done by the number after OUTPUT.
+% 1) Get all the OUTPUT* definitions in the model variable section
+vn = {model.variables.name};
+vf = {model.variables.formula};
+vnotes = {model.variables.notes};
+outputnames = {};
+outputformulas = {};
+outputnotes = {};
+outputvarindex = [];
+for k=1:length(vn),
+    y = regexp(vn{k},'(OUTPUT\w*)','tokens');
+    if ~isempty(y),
+        outputnames{end+1} = y{1}{1};
+        outputvarindex(end+1) = k;
+        outputformulas{end+1} = vf{k};
+        outputnotes{end+1} = vnotes{k};        
+    end
+end  
+% Check if same output defined several times
+if length(unique(outputnames)) ~= length(outputnames),
+    error('Each output identifier OUTPUT* is only allowed to be present once. (* = 1,2,3,4,...)');
+end
+% Add the outputs into to the model structure 
+for k=1:length(outputnames),
+    model.outputs(end+1).name = outputnames{k};
+    model.outputs(end).formula = outputformulas{k};
+    model.outputs(end).notes = outputnotes{k};
+    model.outputs(end).varindex = outputvarindex(k);
+end
+ 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK THE OUTPUT NAMES FOR VALIDITY (only if outputs are present)
+% AND REORDER THE OUTPUTS IN THE MODEL STRUCTURE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Output names need to be numerically ordered. No index is allowed to be
+% omitted inbetween. OUTPUT1, OUTPUT2, OUTPUT3, ... allowed but NOT:
+% OUTPUT1, INPUT3, OUTPUT4, etc. Numbering always needs to start at 1.
+% Outputs in the model structure are then ordered according to their name
+% for easier use of the information in later functions.
+if ~isempty(model.outputs),
+    model = checkoutputnumberingOKandreorder(model);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK THAT THE OUTPUT FORMULAS DO NOT DEPEND ON INPUT DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% This is important since people might try ... but it simply does not make
+% sense because INPUT definitions are more abstract constructs.
+% HERE WE DO NOT NEED TO CHECK IT, SINCE ALREADY ABOVE IT IS CHECKED THAT
+% INPUT DEFINITIONS ARE NOT PRESENT IN ALL VARIABLES!!!
+    
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% ITS DONE ... RETURN
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+return
+        
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE POSSIBLE INPUT DEFINITIONS IN REACTIONS
+% if present then delete reaction name from ODE and add the input as new
+% term to the ODE. If species in amount then just add as it is, if in
+% concentration, then divide the input term with the compartment name (if
+% available). If compartment name is not available then error!
+% Oh, and take into account potential stoichiometric coefficients of the
+% reaction!
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [model] = handleInputsInReactions(model)
+[rn,rf] = IQMreactions(model);
+removeReac = [];
+for k=1:length(rf),
+    if ~isempty(strfind(rf{k},'INPUT')),
+        % INPUT definition found in reaction
+        % Now remove the reaction name in ODEs with reaction formula. The
+        % reaction will then be appended to the ODE, taking into account
+        % the correct volume in the case of concentration ...
+        % We do not do any further checks regarding stoichiometric
+        % coefficients for this reaction etc. ... do it yourself:
+        disp('The following is not an error message, just a reminder:')
+        disp('  Please make sure that the reaction that contains the INPUT* definition');
+        disp('  does NOT have any stoichiometric factors associated with it!');
+        disp('  IT IS NOT ALLOWED TO INCLUDE THE REACTION IN THE ODE IN PARENTHESES!');
+        rfk = rf{k};
+        for k2=1:length(model.states),
+            ODE = model.states(k2).ODE;
+            % check if reaction name present in ODE
+            if ~isempty(strfind(ODE,rn{k})),
+                % reaction name is present => remove reaction in ODE and 
+                % append input reaction formula ...
+                ODE = regexprep(ODE,['\<' rn{k} '\>'],'0');
+                % remove "+0" and "-0" and "0"
+                ODE = regexprep(ODE,'+','#');
+                ODE = regexprep(ODE,['\<#0\>'],'');
+                ODE = regexprep(ODE,['\<-0\>'],'');
+                ODE = regexprep(ODE,['\<0\>'],'');
+                ODE = regexprep(ODE,'#','+');
+                % add input reaction formula to ODE:
+                comp = model.states(k2).compartment;
+                unittype = model.states(k2).unittype;
+                if strcmp(unittype,'concentration'),
+                    if isempty(comp),
+                        error('No compartment defined for species ''%s''.',model.states(k2).name);
+                    end
+                    ODE = [ODE sprintf('+1/%s*%s',comp,rfk)];
+                else
+                    % assume amount units and just add the reaction to the ODE
+                    ODE = [ODE sprintf('+%s',rfk)];
+                end
+                % check if ++ or +- or -+ present and exchange
+                ODE = regexprep(ODE,'++','+');
+                ODE = regexprep(ODE,'+-','-');
+                ODE = regexprep(ODE,'-+','-');
+                model.states(k2).ODE = ODE;
+            end
+        end
+        % Remove reaction from the model
+        removeReac = [removeReac k];
+    end
+end
+model.reactions(removeReac) = [];
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EXTRACT INPUT TERMS and check for validity
+% Only prefixes/prefactors to inputs allowed - otherwise error
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [factor,term] = getInputFactorFromODE(ODE,name)
+% find the start-index for the input name
+si = strfind(ODE,name);
+% get ODE text before input
+ODEpre = strtrim(ODE(1:si-1));
+ODEpost = strtrim(ODE(si+length(name):end));
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DO SOME CHECKS FIRST: 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% 1) the INPUT* identifier needs to be the last element in the input term.
+% => ODEpost needs to start by "+" or "-" and contain as many opening
+% parentheses than closing ones. Because otherwise INPUT* would be in at
+% least one parenthesis. => Not allowed. 
+if ~isempty(ODEpost),
+    if ODEpost(1) ~= '+' && ODEpost(1) ~= '-',
+        error(sprintf('The ''%s'' identifier must be the last element in the input term.\nExamplefor allowed syntax: d/dt(A) = ... + ("optional prefactor expresion")*INPUT1 + ...',name));
+    end
+end
+npo = length(strfind(ODEpost,'(')); 
+npc = length(strfind(ODEpost,')'));
+if npo ~= npc,
+    error(sprintf('The ''%s'' identifier is not allowed to be inside a parenthesis.\nExample for allowed syntax: d/dt(A) = ... + ("optional prefactor expresion")*INPUT1 + ...',name));
+end
+% 2) The last character in the ODEpre string needs to be a '+' or a '*'. So
+% that in the latter case the part in front of the INPUT* identifier can be
+% understood as a factor. 
+if ~isempty(ODEpre),
+    if ODEpre(end) ~= '+' && ODEpre(end) ~= '*',
+        error('The ''%s'' term is required to be multiplied to a prefactor.\nExample for allowed syntax: d/dt(A) = ... + ("optional prefactor expresion")*%s+...''.',name,name);
+    end
+end
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET THE FACTORS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% 3) If ODEpre is empty or ODEpre(end) = '+' then the factor is simply: 1
+if isempty(ODEpre),
+    factor = '1';
+    term = name;
+    return
+elseif ODEpre(end) == '+',
+    factor = '1';
+    term = ['+' name];
+    return
+end
+% 4) Parse the multiplicative input factor: We search for a '+' or '-'
+% outside of parentheses from right to left in ODEpre. If '-' then error.
+po = 0;
+for k=length(ODEpre):-1:1,
+    if ODEpre(k) == '(',
+        % count opening parenthesis
+        po = po+1;
+    end
+    if ODEpre(k) == ')',
+        % count closing parenthesis
+        po = po-1;
+    end
+    if ODEpre(k) == '+' && po == 0,
+        % start of factor found
+        break;
+    end
+    if ODEpre(k) == '-' && po == 0,
+        % start of factor found but '-' not allowed
+        error('The ''%s'' term is substracted from an ODE RHS. It is only allowed to ADD input terms.\nExample for allowed syntax: d/dt(A) = ... + ("optional prefactor expresion")*%s+...''.',name,name);        
+    end
+end
+% 5) extract the factor and return (ITS DONE :))
+factor = ODEpre(k:end-1);
+term = [ODEpre(k:end-1) '*' name];
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% inputsonlyonstates: checks that INPUT definitions are only made in ODEs
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [output] = inputsonlyonstates(model)
+% INITIALIZE OUTPUT
+output = 1;
+% CHECK RHSs of ODEs, variables and reactions
+statenames = {model.states.name};
+ODEs = {model.states.ODE};
+if ~isempty(model.reactions),
+    reacnames = {model.reactions.name};
+    reacformulas = {model.reactions.formula};
+else
+    reacnames = {};
+    reacformulas = {};
+end
+if ~isempty(model.reactions),
+    varnames = {model.variables.name};
+    varformulas = {model.variables.formula};
+else
+    varnames = {};
+    varformulas = {};
+end
+% Check if "INPUT" defined in varformulas or reacformulas => error
+for k=1:length(varformulas),
+    if ~isempty(strfind(varformulas{k},'INPUT')),
+        output = 0; 
+        return
+    end
+end    
+for k=1:length(reacformulas),
+    if ~isempty(strfind(reacformulas{k},'INPUT')),
+        output = 0;
+        return
+    end
+end    
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% outputsonlyasvariables: checks that OUTPUT definitions only as variables
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [output] = outputsonlyasvariables(model)
+% INITIALIZE OUTPUT
+output = 1;
+% CHECK Names of states and reactions and parameters
+[statenames] = {model.states.name};
+if ~isempty(model.reactions),
+    reacnames = {model.reactions.name};
+else
+    reacnames = {};
+end
+if ~isempty(model.parameters),
+    paramnames = {model.parameters.name};
+else
+    paramnames = {};
+end
+% Check if "OUTPUT" defined as states or reactions
+for k=1:length(statenames),
+    if ~isempty(strfind(statenames{k},'OUTPUT')),
+        output = 0; 
+        return
+    end
+end    
+for k=1:length(reacnames),
+    if ~isempty(strfind(reacnames{k},'OUTPUT')),
+        output = 0;
+        return
+    end
+end    
+for k=1:length(paramnames),
+    if ~isempty(strfind(paramnames{k},'OUTPUT')),
+        output = 0;
+        return
+    end
+end    
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% checkinputnumberingOKandreorder: checks correct input naming/numbering
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% No ordering of inputs required ... just makes no sense and creates
+% problems later on. Therefor, the following text is not true anymore :-) :
+%
+% "Input names need to be numerically ordered. No index is allowed to be
+% omitted inbetween. INPUT1, INPUT2, INPUT3, ... allowed but NOT:
+% INPUT1, INPUT3, INPUT4, etc. Numbering always needs to start at 1."
+%
+% The following text already told us that the ordering is not needed:
+%
+% "It is probably not absolutely needed but to be consistent with the output
+% handling and consistent with the requirements of the input indexing, a
+% reordering of the inputs just makes sense."
+%
+% And no, ordering makes no sense but just problmes during merging with
+% dosing objects. E.g., INPUT1 defined in dosing but INPUT2 not. Then
+% INPUT2 would be left on nominal values in the model, INPUT1 would be
+% replaced ... => ERROR (which is unnecessary and undesired).
+function [model] = checkinputnumberingOKandreorder(model)
+% get input names
+inputnames = {model.inputs.name};
+% get input indices
+inputindices = str2double(regexprep(inputnames,'INPUT',''));
+% if NaN or 0 present as index then nonnumeric input numbering was used => error
+if ~isempty(find(isnan(inputindices), 1)) || ~isempty(find(inputindices==0, 1)),
+    error(sprintf('Non-numeric input naming has been used in the model.\nPlease note that the input identifiers "INPUT" are only allowed\nto be followed by a number. Starting at "1" and continuing with "2", "3", ...\nExample: INPUT1, INPUT2, INPUT3, ... But NOT: INPUT, INPUT0, INPUTx, INPUT2e, ...'));
+end
+% % check if it starts at 1 and that continues 2, 3, 4, 5, 6 ...
+% % sort indices
+% si = sort(inputindices);
+% % first entry needs to be a "1" .. 
+% if si(1) ~= 1,
+%     error('Input identifier numbering needs to start at 1. E.g.: INPUT1.');
+% end
+% % check that it continues 2, 3, 4, 5, 6, ...
+% if length(si) > 1,
+%     dsi = si(2:end)-si(1:end-1);
+%     if ~isempty(find(dsi~=1, 1)),
+%         error('Indexing of input identifiers needs to be sequential. E.g.: INPUT1,2,3, ... not leaving out an index.');
+%     end
+% end
+% % finally do reorder the inputs in the model structure according to their indices
+% model.inputs(inputindices) = model.inputs;
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% handleInputParameters: HANDLE MODEL INPUT PARAMETERS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% For each INPUT* a parameter INPUT* needs to be defined. If not present in
+% the model, then it is added to the model with a default value of 0.
+% Also add the parameter index to the model.inputs structure.
+function [model] = handleInputParameters(model)
+% get input names
+in = {model.inputs.name};
+% get parameter names 
+pn = {model.parameters.name};
+% check all input names
+for k=1:length(in),
+    parindex = strmatchIQM(in{k},pn,'exact');
+    if isempty(parindex),
+        % add input parameter with 0 default value to the model
+        model.parameters(end+1).name = in{k};
+        model.parameters(end).value = 0; % default to 0
+        model.parameters(end).type = ''; % no need to export to SBML
+        model.parameters(end).compartment = ''; % no need to export to SBML
+        model.parameters(end).unittype = ''; % no need to export to SBML
+        model.parameters(end).notes = sprintf('default value for input function ''%s''',in{k});
+        % add the index of this parameter to the model.inputs.parindex field
+        model.inputs(k).parindex = length(model.parameters);
+    else
+        % input parameter is already defined. Just fill out the parindex field
+        model.inputs(k).parindex = parindex;
+    end
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% checkinputnumberingOKandreorder: % CHECK THE OUTPUT NAMES FOR VALIDITY 
+% AND REORDER THE OUTPUTS IN THE MODEL STRUCTURE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Output names need to be numerically ordered. No index is allowed to be
+% omitted inbetween. OUTPUT1, OUTPUT2, OUTPUT3, ... allowed but NOT:
+% OUTPUT1, INPUT3, OUTPUT4, etc. Numbering always needs to start at 1.
+% Outputs in the model structure are then ordered according to their name
+% for easier use of the information in later functions.
+function [model] = checkoutputnumberingOKandreorder(model)
+% get output names
+outputnames = {model.outputs.name};
+% get output indices
+outputindices = str2double(regexprep(outputnames,'OUTPUT',''));
+% if NaN or 0 present as index then nonnumeric output numbering was used => error
+if ~isempty(find(isnan(outputindices), 1)) || ~isempty(find(outputindices==0, 1)),
+    error(sprintf('Non-numeric output naming has been used in the model.\nPlease note that the output identifiers "OUTPUT" are only allowed\nto be followed by a number. Starting at "1" and continuing with "2", "3", ...\nExample: OUTPUT1, OUTPUT2, OUTPUT3, ... But NOT: OUTPUT, OUTPUT0, OUTPUTx, OUTPUT2e, ...'));
+end
+% check if it starts at 1 and that continues 2, 3, 4, 5, 6 ...
+% sort indices
+si = sort(outputindices);
+% first entry needs to be a "1" .. 
+if si(1) ~= 1,
+    error('Output identifier numbering needs to start at 1. E.g.: OUTPUT1.');
+end
+% check that it continues 2, 3, 4, 5, 6, ...
+if length(si) > 1,
+    dsi = si(2:end)-si(1:end-1);
+    if ~isempty(find(dsi~=1, 1)),
+        error('Indexing of output identifiers needs to be sequential. E.g.: OUTPUT1,2,3, ... not leaving out an index.');
+    end
+end
+% finally do reorder the outputs in the model structure according to their indices
+model.outputs(outputindices) = model.outputs;
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/dosehandling/IQMcreateDOSING.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/dosehandling/IQMcreateDOSING.m
new file mode 100644
index 0000000000000000000000000000000000000000..67e4063a229723a31ec442a6f0e4d4876f43d12a
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/dosehandling/IQMcreateDOSING.m	
@@ -0,0 +1,144 @@
+function [dosing] = IQMcreateDOSING(type,dose,time,parametervalue,tlagvalue)
+% IQMcreateDOSING: Creates a dosing scheme as desired based on inputs
+%
+% USAGE:
+% ======
+% [dosing] = IQMcreateDOSING(type)         
+% [dosing] = IQMcreateDOSING(type,dose,time,parametervalue)         
+% [dosing] = IQMcreateDOSING(type,dose,time,parametervalue,tlagvalue)         
+%
+% type:             cell-array with input types in the order as inputs will be defined
+%                   possible types: "INFUSION", "ABSORPTION0", "ABSORPTION1", "BOLUS"
+% dose:             cell-array with dose vectors for each defined input - if scalar then same dose will be used for each dosing time
+% time:             cell-array with time vectors for each defined input
+% parametervalue:   cell-array with TINF, ka, TK0 values - if scalar then
+%                   same value assumed for each dosing time. Empty cell entry if bolus.
+% tlagvalue:        cell-array with lag time for each input definition
+%
+% dosing:           produced dosing scheme
+%
+% If only type is provided, then all other entries are set to "zero".
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+% Create empty dosing scheme
+ds = struct(IQMdosing);
+
+% Check type first (needed in second step)
+if ~iscell(type), type = {type}; end
+
+% Variable input arguments
+if nargin == 1,
+    dose            = cell(1,length(type)); dose(1:end) = {0};
+    time            = cell(1,length(type)); time(1:end) = {0};
+    parametervalue  = cell(1,length(type)); parametervalue(strmatchIQM('INFUSION',type)) = {1}; parametervalue(strmatchIQM('ABSORPTION0',type)) = {1}; parametervalue(strmatchIQM('ABSORPTION1',type)) = {1};
+    tlagvalue       = [];
+elseif nargin == 4,
+    tlagvalue = [];
+elseif nargin == 5,
+    if ~iscell(tlagvalue), tlagvalue = {tlagvalue}; end
+else
+    error('Incorrect number of input arguments.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check inputs and convert to cells if needed
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~iscell(dose), dose = {dose}; end
+if ~iscell(time), time = {time}; end
+if ~iscell(parametervalue), parametervalue = {parametervalue}; end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Update name fields
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for k=1:length(type),
+    ds.inputs(k).name = sprintf('INPUT%d',k);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Update type fields
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for k=1:length(type),
+    ds.inputs(k).type = type{k};
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Update time fields
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if length(time) ~= length(type),
+    error('Number of entries in time cell-array different from number in type cell-array');
+end
+for k=1:length(time),
+    ds.inputs(k).time = time{k};
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Update dose fields
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if length(dose) ~= length(type),
+    error('Number of entries in dose cell-array different from number in type cell-array');
+end
+for k=1:length(dose),
+    dosek = dose{k};
+    if length(dosek) == 1,
+        ds.inputs(k).D = dosek*ones(1,length(ds.inputs(k).time));
+    else
+        if length(dosek) ~= length(ds.inputs(k).time),
+            error('Different lengths of time and dose vectors for input %d',k);
+        else
+            ds.inputs(k).D = dosek;
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Update parameters fields
+% Only handle if type not BOLUS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if length(parametervalue) ~= length(type),
+    error('Number of entries in parametervalue cell-array different from number in type cell-array');
+end
+for k=1:length(type),
+    if ~strcmp(type{k},'BOLUS'),
+        pvk = parametervalue{k};
+        if strcmp(type{k},'INFUSION'),
+            ds.inputs(k).parameters.name = 'Tinf';
+        elseif strcmp(type{k},'ABSORPTION1'),
+            ds.inputs(k).parameters.name = 'ka';
+        elseif strcmp(type{k},'ABSORPTION0'),
+            ds.inputs(k).parameters.name = 'Tk0';
+        end            
+        ds.inputs(k).parameters.notes = '';
+        
+        if length(pvk) == 1,
+            ds.inputs(k).parameters.value = pvk*ones(1,length(ds.inputs(k).time));
+        else
+            if length(pvk) ~= length(ds.inputs(k).time),
+                error('Different lengths of parameter values and dose vectors for input %d',k);
+            else
+                ds.inputs(k).parameters.value = pvk;
+            end
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Update Tlag fields
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(tlagvalue),
+    if length(tlagvalue) ~= length(type),
+        error('Number of entries in tlagvalue cell-array different from number in type cell-array');
+    end
+    for k=1:length(tlagvalue),
+        ds.inputs(k).Tlag = tlagvalue{k};
+    end
+% else
+%     for k=1:length(tlagvalue),
+%         ds.inputs(k).Tlag = 0;
+%     end
+end    
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Create dosing scheme
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+dosing = IQMdosing(ds);
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/dosehandling/IQMcreateDOSfile.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/dosehandling/IQMcreateDOSfile.m
new file mode 100644
index 0000000000000000000000000000000000000000..c8dd7780f5d08e0f2a1497ea54b440b03ab27e06
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/dosehandling/IQMcreateDOSfile.m	
@@ -0,0 +1,74 @@
+function IQMcreateDOSfile(varargin)
+% IQMcreateDOSfile: creates a *.dos file with the dosing text description
+%
+% USAGE:
+% ======
+% [] = IQMcreateDOSfile()         
+% [] = IQMcreateDOSfile(filename)         
+% [] = IQMcreateDOSfile(dos)         
+% [] = IQMcreateDOSfile(dos,filename)
+%
+% dos: IQMdosing object to convert to a textfile description
+% filename: filename for the created textfile 
+%
+% If dos is undefined, then an empty IQMdosing textfile will be created.
+%
+% DEFAULT VALUES:
+% ===============
+% dos: the IQMdosing object to be exported as DOS file. 
+% filename: constructed from the IQMdosing object name
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin == 0,
+    % create empty IQMdosing file with the name "unnamed.dos"
+    dos = IQMdosing();
+    filename = 'unnamed.dos';
+elseif nargin == 1,
+    % check if first input argument dosing object or filename
+    if isIQMdosing(varargin{1}),
+        % dosing object given
+        dos = varargin{1};
+        % if no filename provided then use the name of the IQMdosing
+        % object as filename but remove unwanted characters first
+        ds = struct(dos);
+        functionName = regexprep(ds.name,'\W','');
+        filename = strcat(functionName,'.dos');
+    else
+        % filename given?
+        if ~ischar(varargin{1}),
+            error('Wrong input argument.');
+        end
+        filename = strcat(varargin{1},'.dos');
+        dos = IQMdosing();
+    end
+elseif nargin == 2,
+    dos = varargin{1};
+    filename = strcat(varargin{2},'.dos');
+else
+    error('Incorrect number of input arguments.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK INPUT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isIQMdosing(dos),
+    error('No IQMdosing object as first argument.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CONVERT DOSING TO TEXT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[dosTextStructure] = convertDosToTextIQM(dos);
+[completeText] = setPartsToCompleteTextDosIQM(dosTextStructure);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% WRITE THE FILE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fid = fopen(filename,'w');
+fwrite(fid,completeText);
+fclose(fid);
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/dosehandling/IQMdoseupdatevalue.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/dosehandling/IQMdoseupdatevalue.m
new file mode 100644
index 0000000000000000000000000000000000000000..b34e0e78a1c2f192270be3600ac5f268ad318c07
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/dosehandling/IQMdoseupdatevalue.m	
@@ -0,0 +1,43 @@
+function [dosingchanged] = IQMdoseupdatevalue(dosing,inputname,value)
+% IQMdoseupdatevalue: Allows to update the dosing amount for a given
+%   input, defined in an IQMdosing object.
+%
+% USAGE:
+% ======
+% [dosingchanged] = IQMdoseupdatevalue(dosing,inputname,value)         
+%
+% dosing: IQMdosing object 
+% inputname: name of the input for which to change the dosing amount
+% value: value to set the dosing amount to (only scalar value allowed, used
+%   for all dosing instances in case of multiple doses)
+%
+% Output Arguments:
+% =================
+% dosingchanged: updated IQMdosing object with changed dosing amount
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get dosing structure
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ds = struct(dosing);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Find input name
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+index = strmatchIQM(inputname,{ds.inputs.name},'exact');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Change Dosing amount if index found
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(index),
+    disp(['Input ' inputname ' does not exist in the dosing schedule.']);
+else
+    % update dosing amount with new value
+    ds.inputs(index).D = value*ones(1,length(ds.inputs(index).time));
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DONE => Construct output
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+dosingchanged = IQMdosing(ds);
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/dosehandling/IQMmergemoddos.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/dosehandling/IQMmergemoddos.m
new file mode 100644
index 0000000000000000000000000000000000000000..6d4f8e9b55bcfb560b680edc877f1c6c25a7d755
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/dosehandling/IQMmergemoddos.m	
@@ -0,0 +1,48 @@
+function [simmodel] = IQMmergemoddos(model,dosing)
+% IQMmergemoddos: Based on a model and dosing object, a new IQMmodel is
+% generated, that implements the defined dosings. Multiple dosing schedules
+% are realized by updating the parameters of subsequent dosings using
+% events.
+%
+% This function is useful to simulate single dosing schedules. However, if
+% you want to run trial simulations, which change the dosing amounts (or
+% other things) between simulations, this function is not the best way to
+% go, since you would need to apply these changes to the dosing schedule,
+% run this function, recompile your model, etc.
+%
+% USAGE:
+% ======
+% [simmodel] = IQMmergemoddos(model,dosing) 
+%
+% model: IQMmodel
+% dosing: IQMdosing object
+%
+% Output Arguments:
+% =================
+% simmodel: Simulation model, implementing the dosing scheme, defined in
+%   the model and the IQMdosing object.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check input
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isIQMmodel(model),
+    error('First input argument is not an IQMmodel.');
+end
+if ~isIQMdosing(dosing),
+    error('Second input argument is not an IQMdosing object.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get model augmented with dosing related 
+% components and the experiment description,
+% implementing the dosing applications
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[moddos,experiment] = mergemoddosIQM(model,dosing);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Combine new model with experiment to get the
+% simulation model
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+simmodel = IQMmergemodexp(moddos,experiment);
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/dosehandling/auxiliary/IQMdose2text/convertDosToTextIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/dosehandling/auxiliary/IQMdose2text/convertDosToTextIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..7b56f2cd78524a864b8fb6e5085c44fde6788c80
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/dosehandling/auxiliary/IQMdose2text/convertDosToTextIQM.m	
@@ -0,0 +1,86 @@
+function [dosTextStructure] = convertDosToTextIQM(dos)
+% convertDosToTextIQM: Converts an IQMdosing object to a structure
+% containing the different parts of the text description of the dosing
+% scheme.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+% Initialize variables
+dosTextStructure = [];
+% Get IQMstructure
+ds = IQMstruct(dos);
+% Parse structure into the dosTextStructure description
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Name
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+dosTextStructure.name = ds.name;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Notes
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+dosTextStructure.notes = ds.notes;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Inputs
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+dosTextStructure.inputs = {};
+allInputText = {};
+for k=1:length(ds.inputs),
+    inputText = '';
+    input = ds.inputs(k);
+    % Write the limiter (name)
+    inputText = sprintf('********** %s\n',input.name);
+    % Type
+    inputText = sprintf('%stype:         %s\n',inputText,input.type);
+    % Time
+    if length(input.time) == 1,
+        inputText = sprintf('%stime:         %g\n',inputText,input.time);
+    else
+        timeText = sprintf('%g, ',input.time);
+        inputText = sprintf('%stime:         [%s]\n',inputText,timeText(1:end-2));
+    end
+    % Tlag (write only if non-empty or non-zero)
+    if ~isempty(input.Tlag),
+        if ischar(input.Tlag),
+            if isempty(input.TlagNotes),
+                inputText = sprintf('%sTlag:         %s\n',inputText,input.Tlag);
+            else
+                inputText = sprintf('%sTlag:         %s    %% %s\n',inputText,input.Tlag,input.TlagNotes);
+            end
+        elseif isnumeric(input.Tlag),
+            if input.Tlag~=0,
+                if isempty(input.TlagNotes),
+                    inputText = sprintf('%sTlag:         %g\n',inputText,input.Tlag);
+                else
+                    inputText = sprintf('%sTlag:         %g    %% %s\n',inputText,input.Tlag,input.TlagNotes);
+                end
+            end
+        end
+    end
+    % D
+    if length(input.D) == 1,
+        inputText = sprintf('%sD:            %g\n',inputText,input.D);
+    else
+        doseText = sprintf('%g, ',input.D);
+        inputText = sprintf('%sD:            [%s]\n',inputText,doseText(1:end-2));
+    end
+    % parameters
+    if ~isempty(input.parameters),
+        for k2=1:length(input.parameters),
+            parametersValueText = sprintf('%g, ',input.parameters(k2).value);
+            if isempty(input.parameters(k2).notes),
+                inputText = sprintf('%s%s:%s[%s]\n',inputText,input.parameters(k2).name,char(32*ones(1,14-length(input.parameters(k2).name)-1)),parametersValueText(1:end-2));
+            else
+                inputText = sprintf('%s%s:%s[%s]    %% %s\n',inputText,input.parameters(k2).name,char(32*ones(1,14-length(input.parameters(k2).name)-1)),parametersValueText(1:end-2),input.parameters(k2).notes);
+            end
+        end
+    end
+    % notes
+    if ~isempty(input.notes),
+        inputText = sprintf('%snotes:        %s\n',inputText,input.notes);
+    end
+    % save text
+    dosTextStructure.inputs{k} = inputText;
+end
+
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/dosehandling/auxiliary/IQMdose2text/setPartsToCompleteTextDosIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/dosehandling/auxiliary/IQMdose2text/setPartsToCompleteTextDosIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..376c81a219f2f2c291e28a020f7e47ead7cb95fc
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/dosehandling/auxiliary/IQMdose2text/setPartsToCompleteTextDosIQM.m	
@@ -0,0 +1,67 @@
+function [completeText] = setPartsToCompleteTextDosIQM(dosTextStructure)
+% setPartsToCompleteTextDosIQM: Sets the different parts of a dosing 
+% scheme description of an IQMdosing object together to the complete text
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+completeText = sprintf('********** DOSING NAME\n%s\n\n',dosTextStructure.name);
+completeText = sprintf('%s********** DOSING NOTES\n%s\n\n',completeText,dosTextStructure.notes);
+if ~isempty(dosTextStructure.inputs),
+    for k=1:length(dosTextStructure.inputs),
+        completeText = sprintf('%s%s\n',completeText,dosTextStructure.inputs{k});
+    end
+else
+    % If no inputs defined in the structure then print out a guideline on
+    % how to represent the different type of input.
+    completeText = sprintf('%s********** INPUT1\n',completeText);
+    completeText = sprintf('%s%%%% Data required to define an Bolus (single, multiple)\n',completeText);
+    completeText = sprintf('%s%%type: BOLUS\n',completeText);
+    completeText = sprintf('%s%%notes:              %% (optional)\n',completeText);
+    completeText = sprintf('%s%%time:               %% time for first application or all applications (scalar or vector)\n',completeText);
+    completeText = sprintf('%s%%deltaT:             %% time inbetween applications (only if time scalar)\n',completeText);
+    completeText = sprintf('%s%%nr_repetitions:  	%% number of applications (only if time scalar + optional if time scalar)\n',completeText);
+    completeText = sprintf('%s%%D:                  %% dose (scalar or vector)\n',completeText);
+    completeText = sprintf('%s%%Tlag:               %% lag time for input application (optional). Default: 0\n',completeText);
+    completeText = sprintf('%s\n',completeText);
+    completeText = sprintf('%s%%%% Data required to define an Infusion (with infusion rate as parameter) (single, multiple)\n',completeText);
+    completeText = sprintf('%s%%type: INFUSION\n',completeText);
+    completeText = sprintf('%s%%notes:              %% (optional)\n',completeText);
+    completeText = sprintf('%s%%time:               %% time for first application or all applications (scalar or vector)\n',completeText);
+    completeText = sprintf('%s%%deltaT:             %% time inbetween applications (only if time scalar)\n',completeText);
+    completeText = sprintf('%s%%nr_repetitions: 	%% number of applications (only if time scalar + optional if time scalar)\n',completeText);
+    completeText = sprintf('%s%%D:                  %% dose (scalar or vector)\n',completeText);
+    completeText = sprintf('%s%%Rate:               %% Infusion rate (required)\n',completeText);
+    completeText = sprintf('%s%%Tlag:               %% lag time for input application (optional). Default: 0\n',completeText);
+    completeText = sprintf('%s\n',completeText);
+    completeText = sprintf('%s%%%% ALTERNATIVE: Data required to define an Infusion (with infusion time as parameter) (single, multiple)\n',completeText);
+    completeText = sprintf('%s%%type: INFUSION\n',completeText);
+    completeText = sprintf('%s%%notes:              %% (optional)\n',completeText);
+    completeText = sprintf('%s%%time:               %% time for first application or all applications (scalar or vector)\n',completeText);
+    completeText = sprintf('%s%%deltaT:             %% time inbetween applications (only if time scalar)\n',completeText);
+    completeText = sprintf('%s%%nr_repetitions: 	%% number of applications (only if time scalar + optional if time scalar)\n',completeText);
+    completeText = sprintf('%s%%D:                  %% dose (scalar or vector)\n',completeText);
+    completeText = sprintf('%s%%Tinf:               %% Infusion time (required)\n',completeText);
+    completeText = sprintf('%s%%Tlag:               %% lag time for input application (optional). Default: 0\n',completeText);
+    completeText = sprintf('%s\n',completeText);
+    completeText = sprintf('%s%%%% Data required to define a 1st order absorption (single, multiple)\n',completeText);
+    completeText = sprintf('%s%%type: ABSORPTION1\n',completeText);
+    completeText = sprintf('%s%%notes:              %% (optional)\n',completeText);
+    completeText = sprintf('%s%%time:               %% time for first application or all applications (scalar or vector)\n',completeText);
+    completeText = sprintf('%s%%deltaT:             %% time inbetween applications (only if time scalar)\n',completeText);
+    completeText = sprintf('%s%%nr_repetitions: 	%% number of applications (only if time scalar + optional if time scalar)\n',completeText);
+    completeText = sprintf('%s%%D:                  %% dose (scalar or vector)\n',completeText);
+    completeText = sprintf('%s%%ka:                 %% Absorption rate constant (required)\n',completeText);
+    completeText = sprintf('%s%%Tlag:               %% lag time for input application (optional). Default: 0\n',completeText);
+    completeText = sprintf('%s\n',completeText);
+    completeText = sprintf('%s%%%% Data required to define a 0th order absorption (single, multiple)\n',completeText);
+    completeText = sprintf('%s%%type: ABSORPTION0\n',completeText);
+    completeText = sprintf('%s%%notes:              %% (optional)\n',completeText);
+    completeText = sprintf('%s%%time:               %% time for first application or all applications (scalar or vector)\n',completeText);
+    completeText = sprintf('%s%%deltaT:             %% time inbetween applications (only if time scalar)\n',completeText);
+    completeText = sprintf('%s%%nr_repetitions: 	%% number of applications (only if time scalar + optional if time scalar)\n',completeText);
+    completeText = sprintf('%s%%D:                  %% dose (scalar or vector)\n',completeText);
+    completeText = sprintf('%s%%Tk0:                %% time for absorption (required)\n',completeText);
+    completeText = sprintf('%s%%Tlag:               %% lag time for input application (optional). Default: 0\n',completeText);
+    completeText = sprintf('%s\n',completeText);
+end
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/dosehandling/auxiliary/doseinputsIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/dosehandling/auxiliary/doseinputsIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..5028f84ab40c21057baee568ead90707919330cb
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/dosehandling/auxiliary/doseinputsIQM.m	
@@ -0,0 +1,30 @@
+function [names,types] = doseinputsIQM(dos)
+% doseinputsIQM: Extracts names and types of dosing inputs from a
+% IQMdosing object.
+%
+% USAGE:
+% ======
+% [names,types] = doseinputsIQM(dos) 
+%
+% dos: IQMdosing object
+%
+% Output Arguments:
+% =================
+% names: cell-array with input names
+% types: cell-array with input types
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check input
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isIQMdosing(dos),
+    error('Input argument is not an IQMdosing object.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get names and types
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ds = struct(dos);
+names = {ds.inputs.name};
+types = {ds.inputs.type};
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/dosehandling/auxiliary/dosing2doseeventIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/dosehandling/auxiliary/dosing2doseeventIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..6a2178a74cf52778be64da7e1622849bc769c5c6
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/dosehandling/auxiliary/dosing2doseeventIQM.m	
@@ -0,0 +1,141 @@
+function [doseeventstruct] = dosing2doseeventIQM(dosing)
+% dosing2doseeventIQM: This function takes an IQMdosing object as
+% input and returns a structure in which the dosing events, happening, are
+% sorted according to the times at which they happen. Additionally, the
+% output structure contains information about the dosing amount and the
+% names of the parameters in a model to change in order to apply the
+% dosing. Also lag and the other dosing type dependend informations are
+% collected. Lag information is only collected if lag is numeric ... if
+% non-numeric then it is assumed to be defined in the model already as
+% parameter of variable and then there is no need to get it from the dosing
+% scheme.
+% 
+% USAGE:
+% ======
+% [doseeventstruct] = dosing2doseeventIQM(dosing) 
+%
+% dosing: IQMdosing object
+%
+% Output Arguments:
+% =================
+% doseeventstruct: output argument with the following structure:
+%   .time                   time of dosing application
+%   .input 
+%   .input.index            index of dosing input in dosing object to be applied
+%   .input.timeparname      name of time parameter for this input
+%   .input.parameternames   cell-array with other parameter names to change the values for
+%   .input.parametervalues  vector with new parameter values (same order as
+%                           parameternames cell-array)
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check input
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isIQMdosing(dosing),
+    error('Input argument is not an IQMdosing object.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get dosing structure
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ds = struct(dosing);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get a dosing matrix and dose/time parameter 
+% names as added to a model
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+dosingmatrix = [];
+inames = {}; 
+for k=1:length(ds.inputs),
+    dosingmatrix = [dosingmatrix; ds.inputs(k).time(:) ds.inputs(k).D(:) k*ones(length(ds.inputs(k).D),1)];
+    inames{k} = ds.inputs(k).name;
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Check if dosing times unique
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    if length(ds.inputs(k).time) ~= length(unique(ds.inputs(k).time)),
+        error('Dosing times in dosing object are not unique.');
+    end
+end
+% sort the dosing matrix according to the time vector
+dosingmatrix = sortrows(dosingmatrix,1);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% For each input in dosing scheme get info about 
+% Tlag and the parameter
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+inputinfoadditional = [];
+for k=1:length(ds.inputs),
+    inputinfoadditional(k).input = ds.inputs(k).name; % unused but just to have it in there when looking at this structure
+    inputinfoadditional(k).index = k; % unused but just to have it in there when looking at this structure
+    try
+        inputinfoadditional(k).paramname = ds.inputs(k).parameters.name;
+        inputinfoadditional(k).param = ds.inputs(k).parameters.value;
+    catch
+        inputinfoadditional(k).paramname = {};
+        inputinfoadditional(k).param = [];
+    end
+    inputinfoadditional(k).Tlag = ds.inputs(k).Tlag;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% convert dosing matrix to structure
+% dosingevent.time
+% dosingevent.input.index
+% dosingevent.input.timeparname
+% dosingevent.input.parameternames
+% dosingevent.input.parametervalues
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+inputstruct = struct('index',{},'timeparname',{},'parameternames',{},'parametervalues',{});
+dosingevent = struct('time',{},'input',inputstruct);
+times = unique(dosingmatrix(:,1));
+for k=1:length(times),
+    % find dosings for current time
+    di = find(dosingmatrix(:,1)==times(k));
+    % add info to dosingevent structure
+    dosingevent(k).time = times(k);
+    for k2=1:length(di),
+        index = dosingmatrix(di(k2),3);
+        dosingevent(k).input(k2).index = index;
+        dosingevent(k).input(k2).timeparname = ['Time' lower(inames{index})]; % Name definition used in mergemoddosIQM
+        % other parameters
+        parameternames = {};
+        parameternames{end+1} = ['Dose' lower(inames{index})];
+        if ~isempty(inputinfoadditional(index).Tlag),
+            % Only add Tlag if it is numeric
+            if isnumeric(inputinfoadditional(index).Tlag),
+                parameternames{end+1} = ['Tlag' lower(inames{index})];
+            end
+        end
+        
+        if ~isempty(inputinfoadditional(index).paramname),
+            parameternames{end+1} = [inputinfoadditional(index).paramname '' lower(inames{index})];
+        end
+
+        parametervalues = [];
+        parametervalues(end+1) = dosingmatrix(di(k2),2);
+        if ~isempty(inputinfoadditional(index).Tlag),
+            % Only add Tlag if it is numeric
+            if isnumeric(inputinfoadditional(index).Tlag),
+                parametervalues(end+1) = inputinfoadditional(index).Tlag;
+            end
+        end
+
+        if ~isempty(inputinfoadditional(index).param),
+            timedoseinput = dosingevent(k).time;
+            timeINPUT = ds.inputs(dosingevent(k).input(k2).index).time;
+            paramvalueINPUT = ds.inputs(dosingevent(k).input(k2).index).parameters.value;
+            pvalue = paramvalueINPUT(timeINPUT==timedoseinput);
+            parametervalues(end+1) = pvalue;
+        end
+        
+        dosingevent(k).input(k2).parameternames = parameternames;
+        dosingevent(k).input(k2).parametervalues = parametervalues;
+    end
+end
+%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Return the result
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+doseeventstruct = dosingevent;
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/dosehandling/auxiliary/getmoddosinputinfoIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/dosehandling/auxiliary/getmoddosinputinfoIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..a2bd66e9846159bddb5810587ea1fe5c638390f4
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/dosehandling/auxiliary/getmoddosinputinfoIQM.m	
@@ -0,0 +1,101 @@
+function [inputinfo] = getmoddosinputinfoIQM(model,dosing)
+% getmoddosinputinfoIQM: Checks the availability of dosing input
+% definitions used in the model in the dosing object and returns a
+% structure similar to the "input" field structure of an IQMmodel, augmented
+% with the dosing information, defined in the IQMdosing object.
+%
+% If the dosing object does not contain all inputs, required by the model,
+% a warning is displayed and the undefined inputs are deleted from the
+% "inputinfo" structure. This allows inputs in an IQMmodel to be kept
+% undefined.
+%
+% USAGE:
+% ======
+% [inputinfo] = getmoddosinputinfoIQM(model,dosing) 
+%
+% model: IQMmodel
+% dose: IQMdosing object
+%
+% Output Arguments:
+% =================
+% inputinfo: Same structure as defined in the IQMmodel "input" field.
+%   Augmented by the dosing input information, stroed in the dosing object.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check input
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isIQMmodel(model),
+    error('First input argument is not an IQMmodel.');
+end
+if ~isIQMdosing(dosing),
+    error('Second input argument is not an IQMdosing object.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get model and dosing structures
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ms = struct(model);
+ds = struct(dosing);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check if model contains inputs.
+% If not => error!
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%    
+if isempty(ms.inputs),
+    error('The model does not contain any inputs. Merging with dosing objects does not make sense.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Initialize the inputinfo structure
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+inputinfo = [];
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Run through all inputs, defined in the model 
+% and process the information in the dosing
+% object accordingly
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+minputs = ms.inputs;
+dinputs = ds.inputs;
+for k=1:length(minputs),
+    % First get the info stored in the model
+    minfo = minputs(k);
+    % Check if input exists in the dosing object
+    index = strmatchIQM(minfo.name,{dinputs.name},'exact');
+    if ~isempty(index),
+        % Input does exist in the dosing object => Now add the complete
+        % input information to the inputinfo structure 
+        % Get the info for this input stored in the dosing object
+        dinfo = dinputs(index);
+        % Add dosing schedule information to the minfo structure
+        minfo.type = dinfo.type;
+        minfo.time = dinfo.time;
+        minfo.Tlag = dinfo.Tlag;
+        minfo.D = dinfo.D;
+        minfo.parameters = dinfo.parameters;
+        minfo.notes = dinfo.notes;
+        % Check if Tlag to be estimated
+        minfo.TlagNotes = dinfo.TlagNotes;
+        % Add minfo structure to the inputinfo output structure
+        if isempty(inputinfo),
+            inputinfo = minfo;
+        else
+            inputinfo(end+1) = minfo;
+        end
+    else
+        % Input does not exist in the dosing object => warning to user 
+        % and do not put it into the inputinfo structure
+%         disp(sprintf('The input ''%s'', defined in the model, is not defined in the IQMdosing object.',minfo.name));
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check if any inputs of the models have been 
+% found in the dosing object. If not => error!
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%    
+if isempty(inputinfo),
+    error('No inputs defined in the model could be found in the dosing object. This should be wrong ...')        
+end
+    
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/dosehandling/auxiliary/text2IQMdose/convertTextToDosIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/dosehandling/auxiliary/text2IQMdose/convertTextToDosIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..9624d78731ae550c01deaafe0c4c31f8a4f36892
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/dosehandling/auxiliary/text2IQMdose/convertTextToDosIQM.m	
@@ -0,0 +1,403 @@
+function [IQMstructure,errorMsg] = convertTextToDosIQM(dosText)
+% convertTextToDosIQM: Converts a text description of an IQMdosing
+% object to the internal IQMdosing data structure representation.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+% % initialize variables
+errorMsg = '';
+% errorConditions = '';
+% errorParameterChanges = '';
+% errorStateEvents = '';
+IQMstructure = [];
+
+% cut text into pieces
+dosTextStructure = getPartsFromCompleteTextDosIQM(dosText);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%% Initialize structure
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+IQMstructure = struct(IQMdosing());
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%% Name
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+IQMstructure.name = strtrim(removeCharacters(dosTextStructure.name));
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%% Notes
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+IQMstructure.notes = strtrim(dosTextStructure.notes);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%% READ INPUTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% 0) create empty input structure
+parametersStruct = struct('name',{},'value',{},'notes',{});
+inputStruct = struct('name',{},'type',{},'time',{},'Tlag',{},'D',{},'parameters',parametersStruct,'TlagNotes',{},'notes',{});
+inputfieldnames = fieldnames(inputStruct);
+timeDefStruct = struct('deltaT',{},'nr_repetitions',{});
+for k=1:length(dosTextStructure.input),
+    inputText = dosTextStructure.input{k};
+    % all data for an input is organized in rows. each row holds a
+    % statement. statements over several rows are NOT allowed.
+    % ordering is arbitrary except that the name (INPUTx) will always be in
+    % the first row. all other rows have an identifier followed by a colon
+    % followed by a value.
+    % 1) split text in rows
+    rows = explodePCIQM(inputText,char(10));
+    % 2) INPUT name (check that "INPUT" is present)
+    if isempty(regexp(rows{1},'INPUT', 'once' )),
+        error('Please check input dose definitions. An "INPUTx" identifier seems to be corrupted.');
+    end
+    % 3) add name to struct
+    inputStruct(k).name = strtrim(rows{1});
+    % 3b) Initialize Tlag with default empty value
+    inputStruct(k).Tlag = [];   % if undefined then leave empty!!!   
+    % 4) add the rest (if row identifier equal to a input field ... add it
+    % there, otherwise add it as a parameter).
+    nr_repetitions = [];
+    deltaT = [];
+    for k2=2:length(rows),
+        % check if row is empty dont consider it
+        if ~isempty(strtrim(rows{k2})),
+            % cut of everything from first percentage sign on (comment)
+            % comment is saved since used for the additional parameters
+            % (Rate, Tk0, ka)
+            commentindex = strfind(rows{k2},'%');
+            if ~isempty(commentindex),
+                savenotes = strtrim(rows{k2}(commentindex(1)+1:end));
+                rows{k2} = strtrim(rows{k2}(1:commentindex(1)-1));
+            else
+                savenotes = '';
+            end
+            % find first colon (if no colon then error
+            colonindex = strfind(rows{k2},':');
+            if isempty(colonindex),
+                error('Syntax error in dose description. No colon in a row for input "%s".',inputStruct(k).name);
+            end
+            % get identifier and value
+            identifier = strtrim(rows{k2}(1:colonindex-1));
+            valuetry = strtrim(rows{k2}(colonindex+1:end));
+            % evaluate the value (matlab notation allowed e.g. for vectors)
+            % need to try and catch, since some values are strings :)
+            try
+                value = eval(valuetry);
+            catch
+                value = valuetry;
+            end
+            % Add value to field if identifier is fieldname
+            if ~isempty(strmatchIQM(identifier,inputfieldnames)),
+                inputStruct(k) = setfield(inputStruct(k),identifier,value);
+                if strcmp(identifier,'Tlag'),
+                    inputStruct(k).TlagNotes = savenotes;
+                end
+            else
+                % handle nr_repetitions and deltaT here
+                if strcmp(identifier,'nr_repetitions'),
+                    nr_repetitions = value;
+                elseif strcmp(identifier,'deltaT'),
+                    deltaT = value;
+                else
+                    % remaining non-field identifiers become parameters for the
+                    % input to be handled later.
+                    inputStruct(k).parameters(end+1).name = identifier;
+                    inputStruct(k).parameters(end).value = value;
+                    inputStruct(k).parameters(end).notes = savenotes;
+                end
+            end                
+        end
+    end
+    % store deltaT and nr_repetitions information to be used in check
+    timeDefStruct(k).deltaT = deltaT;
+    timeDefStruct(k).nr_repetitions = nr_repetitions;
+end
+IQMstructure.inputs = inputStruct;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%% CHECK INPUTS for consistency
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for k=1:length(IQMstructure.inputs),
+    input = IQMstructure.inputs(k);
+    deltaT = timeDefStruct(k).deltaT;
+    nr_repetitions = timeDefStruct(k).nr_repetitions;
+   
+    % Check general input consistency (time, deltaT, nr_repetitions, D,
+    % notes)
+    
+    % 1) Dose D needs to be present and positive
+    if isempty(input.D),
+        error('No dose "D" defined for input "%s".',input.name);
+    end
+    if input.D < 0, 
+        error('Dose "D" not allowed to be negative in input "%s".',input.name);
+    end
+    
+    % 2) time needs to be defined
+    if isempty(input.time),
+        error('"time" needs to be defined in input "%s".',input.name);
+    end
+    
+    % Check time against deltaT and nr_repetitions
+    % 3a) If time is a vector deltaT and nr_rep need to be empty
+    if length(input.time) > 1 && (~isempty(deltaT) || ~isempty(nr_repetitions)),
+        error('When defining a time vector in "time", "nr_repetitions" and "deltaT" are not allowed to be defined in input "%s".',input.name);
+    end
+    % 3b) further checks
+    if ~isempty(nr_repetitions),
+        if nr_repetitions == 1,
+            error('Do not use "nr_repetitions: 1" to specify single applications in input "%s".\nJust remove the "nr_repetitions" identifier.',input.name);
+        end
+        if isempty(deltaT),
+            error('When defining "nr_repetitions", also "deltaT" needs to be defined in input "%s".',input.name);
+        end
+    else
+        if ~isempty(deltaT),
+            error('When defining "deltaT", also "nr_repetitions" needs to be defined in input "%s".',input.name);
+        end
+    end    
+    
+    % 4) Construct the time field (scalar for single or vector for multiple applications)
+    if ~isempty(nr_repetitions),
+        addTimeVector = [0:deltaT:deltaT*(nr_repetitions-1)];
+        input.time = input.time+addTimeVector;
+        % update in final IQMdosing structure
+        IQMstructure.inputs(k).time = input.time;
+    end
+    
+    % 5) Check length of dose vector (either scalar or same length as time vector)
+    if length(input.D) > 1,
+        if length(input.D) ~= length(input.time),
+            error('Length of "D" vector and "time" vector does not match in input "%s".',input.name);
+        end
+    elseif length(input.time) > 1,
+        % If D scalar and time vector then expand D to a vector with the
+        % same size as time ...
+        D = input.D * ones(1,length(input.time));
+        IQMstructure.inputs(k).D = D;
+    end
+       
+    % 5) Check that Tlag is positive
+    if ~isempty(input.Tlag),
+        if isnumeric(input.Tlag),
+            if input.Tlag < 0,
+                error('"Tlag" is not allowed to be negative in input "%s".',input.name);
+            end
+        end
+    end
+
+    % 6) Check parameter value of input
+    if ~isempty(input.parameters),
+        parametervalue = input.parameters.value;
+        if length(parametervalue) == 1,
+            % make vector out of it
+            IQMstructure.inputs(k).parameters.value = parametervalue*ones(1,length(IQMstructure.inputs(k).time));
+        else
+            % Check length
+            if length(parametervalue) ~= length(IQMstructure.inputs(k).time),
+                error('Length of "parameter value" vector and "time" vector does not match in input "%s".',input.name);
+            end
+        end
+    end
+    
+    % Check input type and input type specific information
+    if strcmp(input.type,'BOLUS'),
+        % 1) Check Bolus inputs
+        checkBolusInput(input);
+    elseif strcmp(input.type,'INFUSION'),
+        % 2) Check Infusion inputs
+        checkInfusionInput(input)
+    elseif strcmp(input.type,'ABSORPTION1'),
+        % 3) Check 1st order absorbption inputs
+        checkAbsorption1Input(input)
+    elseif strcmp(input.type,'ABSORPTION0'),
+        % 4) Check 0th order absorbption inputs
+        checkAbsorption0Input(input)
+    else
+        % Error: unknown input type
+        error('Unknown input type in dosing description in input "%s".',input.type);
+    end
+end
+
+% Finally check if inputs with same names
+a = {IQMstructure.inputs.name};
+if length(a) ~= length(unique(a)),
+    error('At least two inputs are defined in the dosing scheme, which have the same name.');
+end
+
+
+%%%%%%%%%%%%%%%%%% END OF FUNCTION
+return
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check Bolus inputs
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [] = checkBolusInput(input)
+    % no additional parameters are required => check that input.parameters
+    % is empty
+    if ~isempty(input.parameters),
+        error('Bolus definition does not require additional parameters in input "%s".',input.name);
+    end
+    % Do check that Tlag is not to large. Tlag+(Tk0 or Dmax/Rate or deltaTBolus) < min delta T dosing is acceptable.
+    % This limitation exists due to the implementation of the multiple
+    % dosings for simulation using events to update the parameters that
+    % perform the multiple inputs. (only if multiple inputs)
+    % Only test if Tlag is numeric
+    if ~isempty(input.Tlag) && isnumeric(input.Tlag),
+        if length(input.time) > 1,
+            % Determine the minimum time between dosing instances
+            minDeltaT = min(input.time(2:end)-input.time(1:end-1));
+            if input.Tlag + 0.0001 >= minDeltaT,
+                error('Tlag in ''%s'' is to large. Please choose it smaller than the min time between dosings.',input.name);
+            end
+        end
+    end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check Infusion inputs
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% We need to check that multiple infusions do not lead to one infusion
+% overlaying the previous one(s). This is done by checking that 
+% max(D)/Rate < min delta time in application
+function [] = checkInfusionInput(input)
+    % Rate is required as additional input. 
+    if length(input.parameters) ~= 1,
+        error('Infusion definition does require a single additional parameter "Rate" or "Tinf" in input "%s".',input.name);
+    end
+    % Check name of parameter (required: Rate)
+    if ~strcmp(input.parameters(1).name,'Rate') && ~strcmp(input.parameters(1).name,'Tinf'),
+        error('Please use "Rate" or "Tinf" as infusion related parameter in input "%s".',input.name);
+    end
+    % Check non overlapping infusion inputs (only if multiple inputs)
+    if length(input.time) > 1,
+        if strcmp(input.parameters(1).name,'Rate'),
+            % Determine minimum required time between dosing instances
+            Rate = min(input.parameters(1).value);
+            maxDose = max(input.D);
+            minRequiredDeltaT = maxDose/Rate;
+            % Determine the minimum time between dosing instances
+            minDeltaT = min(input.time(2:end)-input.time(1:end-1));
+            % Do the check
+            if minRequiredDeltaT > minDeltaT,
+                error('Infusion rate for input ''%s'' to low. Previous infusion would not be finished before the next one.',input.name);
+            end
+            % Do check that Tlag is not to large. Tlag+(Tk0 or Dmax/Rate or deltaTBolus) < min delta T dosing is acceptable.
+            % This limitation exists due to the implementation of the multiple
+            % dosings for simulation using events to update the parameters that
+            % perform the multiple inputs. (only if multiple inputs)
+            % Determine the minimum time between dosing instances
+            % Only test if Tlag is numeric
+            if ~isempty(input.Tlag) && isnumeric(input.Tlag),
+                if input.Tlag + minRequiredDeltaT >= minDeltaT,
+                    error('Tlag in ''%s'' is to large. Please choose it smaller than the min time between dosings minus max(Dose)/Rate.',input.name);
+                end
+            end
+        elseif strcmp(input.parameters(1).name,'Tinf'),
+            % Determine minimum required time between dosing instances
+            Tinf = max(input.parameters(1).value);
+            minRequiredDeltaT = Tinf;
+            % Determine the minimum time between dosing instances
+            minDeltaT = min(input.time(2:end)-input.time(1:end-1));
+            % Do the check
+            if minRequiredDeltaT > minDeltaT,
+                error('Infusion time for input ''%s'' to low. Previous infusion would not be finished before the next one.',input.name);
+            end
+            % Do check that Tlag is not to large. Tlag+(Tk0 or Dmax/Rate or deltaTBolus) < min delta T dosing is acceptable.
+            % This limitation exists due to the implementation of the multiple
+            % dosings for simulation using events to update the parameters that
+            % perform the multiple inputs. (only if multiple inputs)
+            % Determine the minimum time between dosing instances
+            % Only test if Tlag is numeric
+            if ~isempty(input.Tlag) && isnumeric(input.Tlag),
+                if input.Tlag + minRequiredDeltaT >= minDeltaT,
+                    error('Tlag in ''%s'' is to large. Please choose it smaller than the min time between dosings minus Tinf.',input.name);
+                end
+            end
+        end
+    end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check 1st order Absorption inputs
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [] = checkAbsorption1Input(input)
+    % ka is required as additional input.
+    if length(input.parameters) ~= 1,
+        error('1st order Absorption definition does require a single additional parameter "ka" in input "%s".',input.name);
+    end
+    % Check name of parameter (required: ka)
+    if ~strcmp(input.parameters(1).name,'ka'),
+        error('Please use "ka" as absorption rate parameter in input "%s".',input.name);
+    end
+    % Do check that Tlag is not to large. Tlag+(Tk0 or Dmax/Rate or deltaTBolus) < min delta T dosing is acceptable.
+    % This limitation exists due to the implementation of the multiple
+    % dosings for simulation using events to update the parameters that
+    % perform the multiple inputs. (only if multiple inputs)
+    % Only test if Tlag is numeric
+    if ~isempty(input.Tlag) && isnumeric(input.Tlag),
+        if length(input.time) > 1,
+            % Determine the minimum time between dosing instances
+            minDeltaT = min(input.time(2:end)-input.time(1:end-1));
+            if input.Tlag + 0.0001 >= minDeltaT,
+                error('Tlag in ''%s'' is to large. Please choose it smaller than the min time between dosings.',input.name);
+            end
+        end
+    end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check 0th order Absorption inputs
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% We need to check that multiple 0 absorptions do not lead to one
+% absorption overlaying the previous one(s). This is done by checking that 
+% Tk0 < min delta time in application
+function [] = checkAbsorption0Input(input)
+    % Tk0 is required as additional input.
+    if length(input.parameters) ~= 1,
+        error('0th order Absorption definition does require a single additional parameter "Tk0" in input "%s".',input.name);
+    end
+    % Check name of parameter (required: Tk0)
+    if ~strcmp(input.parameters(1).name,'Tk0'),
+        error('Please use "Tk0" as absorption time parameter in input "%s".',input.name);
+    end
+    % Check non overlaying absorption0 inputs (only if multiple inputs)
+    if length(input.time) > 1,
+        % Determine minimum required time between dosing instances
+        minRequiredDeltaT = max(input.parameters(1).value);  % corresponds to Tk0
+        % Determine the minimum time between dosing instances
+        minDeltaT = min(input.time(2:end)-input.time(1:end-1));
+        % Do the check
+        if minRequiredDeltaT > minDeltaT,
+            error('Absorption time Tk0 for input ''%s'' to large. Previous dosing would not be finished before the next one.',input.name);
+        end
+        % Do check that Tlag is not to large. Tlag+(Tk0 or Dmax/Rate or deltaTBolus) < min delta T dosing is acceptable.
+        % This limitation exists due to the implementation of the multiple
+        % dosings for simulation using events to update the parameters that
+        % perform the multiple inputs. (only if multiple inputs)
+        % Determine the minimum time between dosing instances
+        % Only test if Tlag is numeric
+        if ~isempty(input.Tlag) && isnumeric(input.Tlag),
+            if input.Tlag + minRequiredDeltaT >= minDeltaT,
+                error('Tlag in ''%s'' is to large. Please choose it smaller than the min time between dosings minus Tk0.',input.name);
+            end 
+        end
+    end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Remove character function
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [output] = removeCharacters(input)
+% delete all line breaks and tabs from the input string
+temp = double(input);
+temp(find(temp==13)) = 32;  % replace '\cr' by white space
+temp(find(temp==10)) = 32;  % replace '\n' by white space
+temp(find(temp==9)) = 32;   % replace '\t' by white space
+output = char(temp);
+% remove all spaces
+%    output = strrep(output,' ','');
+return
+
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/dosehandling/auxiliary/text2IQMdose/getPartsFromCompleteTextDosIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/dosehandling/auxiliary/text2IQMdose/getPartsFromCompleteTextDosIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..72af7aa4a60bacc8511eaa3d7fe56077d47725ff
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/dosehandling/auxiliary/text2IQMdose/getPartsFromCompleteTextDosIQM.m	
@@ -0,0 +1,54 @@
+function [dosTextStructure] = getPartsFromCompleteTextDosIQM(dosText)
+% getPartsFromCompleteTextDosIQM: Cuts a text description of an
+% IQMdosing object into the different parts and returns them in a
+% structure 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+% take commented lines out of the dosing description
+dosText = regexprep(dosText,'\n%[^\n]*','');
+
+% Find the starts of the different sections. NAME and NOTES are required.
+% Following these there can be an arbitrary number of input definitions. 
+% The order of the inputs is defined through the naming of a section 
+% ********** INPUT1  => corresponds to "INPUT1" in a model file.
+
+% Required sections
+nameStart = strfind(dosText,'********** DOSING NAME');
+notesStart = strfind(dosText,'********** DOSING NOTES');
+
+% Check if they are present
+if isempty(nameStart),
+    error('No "DOSING NAME" section in dosing description.');
+end
+if isempty(notesStart),
+    error('No "DOSING NOTES" section in dosing description.');
+end
+
+% Parse the INPUTx sections. They are optional (No input is allowed).
+% 1) Count all *****... etc.
+nrAllSections = length(strfind(dosText,'**********'));
+nrInputSections = length(strfind(dosText,'********** INPUT'));
+
+% 2) Check the number of the sections (allows detecting syntax errors in
+% input section definitions)
+if nrInputSections+2 ~= nrAllSections,
+    error('Please check the input section identifiers in the dose description file for errors.');
+end
+
+% 3) get startindices of input sections
+startIndexInput = strfind(dosText,'********** INPUT');
+
+% 4) Get all sections
+dosTextStructure.name = strtrim(dosText(nameStart+length('********** DOSING NAME'):notesStart-1));
+if isempty(startIndexInput),
+    dosTextStructure.notes = strtrim(dosText(notesStart+length('********** DOSING NOTES'):end));
+else
+    dosTextStructure.notes = strtrim(dosText(notesStart+length('********** DOSING NOTES'):startIndexInput(1)-1));
+end
+dosTextStructure.input = {};
+for k=1:length(startIndexInput)-1,
+    dosTextStructure.input{k} = strtrim(dosText(startIndexInput(k)+length('********** '):startIndexInput(k+1)-1));
+end
+dosTextStructure.input{end+1} = strtrim(dosText(startIndexInput(end)+length('********** '):end));
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/dosehandling/isIQMdosing.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/dosehandling/isIQMdosing.m
new file mode 100644
index 0000000000000000000000000000000000000000..e3838ddec8b50e140cfb616b2458aa66ba9aab26
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/dosehandling/isIQMdosing.m	
@@ -0,0 +1,6 @@
+function [output] = isIQMdosing(input)
+% isIQMdosing: check if input argument is an IQMdosing object.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+output = strcmp(class(input),'IQMdosing');
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/dosehandling/mergemoddosIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/dosehandling/mergemoddosIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..b96a1332b0d8677b8e94da4857af74735d4ce9d0
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/dosehandling/mergemoddosIQM.m	
@@ -0,0 +1,628 @@
+function [moddos,expdos] = mergemoddosIQM(model,dosing)
+% mergemoddosIQM: This function takes an IQMmodel and an IQMdosing
+% scheme as inputs. It adds necessary elements to the model that are
+% required to implement the different dosing inputs (bolus, infusion,
+% absorption0, absorption1) for simulation purposes. MLXTRAN and
+% NONMEM will not be handled using this function. 
+%
+% The dose parameters are set to zero, independently of the dosing values
+% given in the dosing settings.
+%
+% The second output argument "expdos" is an experiment description,
+% which contains all state-events that are necessary to realize the dosing
+% applications defined in the dosing object. 
+%
+% USAGE:
+% ======
+% [moddos,expdos] = mergemoddosIQM(model,dosing) 
+%
+% model: IQMmodel
+% dosing: IQMdosing object
+%
+% Output Arguments:
+% =================
+% moddos: IQMmodel with added components to implement the different types of
+%  inputs.
+% expdos: IQMexperiment containing all information to simulate the dosing
+%  schedule, defined in the IQMdosing object.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check input
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isIQMmodel(model),
+    error('First input argument is not an IQMmodel.');
+end
+if ~isIQMdosing(dosing),
+    error('Second input argument is not an IQMdosing object.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get model, experiment and dosing structures
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ms = struct(model);
+ds = struct(dosing);
+mds = ms;               % initialize new model structure
+eds = struct(IQMexperiment());
+eds.name = ds.name;
+eds.notes = ds.notes;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get the inputinfo structure
+% This structure contains now all necessary
+% information about all inputs that need to be 
+% implemented.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%    
+inputinfo = getmoddosinputinfoIQM(model,dosing);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Run through the inputinfo struct and modify the model
+% Additionally update the experiment structure ...
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for k=1:length(inputinfo),
+    % Handle the different types differently
+    switch inputinfo(k).type,
+        case 'BOLUS',
+            [mds,eds] = handleBolus(ms,mds,eds,inputinfo(k));
+        case 'INFUSION',
+            [mds,eds] = handleInfusion(ms,mds,eds,inputinfo(k));
+        case 'ABSORPTION1',
+            [mds,eds] = handleAbsorption1(ms,mds,eds,inputinfo(k));
+        case 'ABSORPTION0',
+            [mds,eds] = handleAbsorption0(ms,mds,eds,inputinfo(k));
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Delete the inputs implemented into the model
+% from the input field structure in the model
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+removeInputIndex = [];
+for k=1:length(mds.inputs),
+    iname = mds.inputs(k).name;
+    % check if the name exists as parameter in the model (then dont remove it)
+    if isempty(strmatchIQM(iname,{mds.parameters.name},'exact')),
+        % input parameter removed => remove input definition
+        removeInputIndex(end+1) = k;
+    end
+end
+if ~isempty(removeInputIndex),
+    mds.inputs(removeInputIndex) = [];
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Construct output model and experimet
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+moddos = IQMmodel(mds);
+expdos = IQMexperiment(eds);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Return
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% handle BOLUS input
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% also add dosing time and amount names to the inputinfo structure
+function [mds,eds] = handleBolus(ms,mds,eds,inputinfo)
+% Get input name
+iname = inputinfo.name;
+% Cycle through all input different input terms
+for k=1:length(inputinfo.terms),
+    % a) Determine the input variable name and other names to be used in the model
+    ivarname = getoutname(lower(iname), length(inputinfo.terms), k);
+    iDosename = ['Dose' lower(iname)];
+    iTimename = ['Time' lower(iname)];
+    iBolusTimename = ['DeltaT' lower(iname)];
+    iTlagname = ['Tlag' lower(iname)];
+    % b) Replace ODE INPUT definition with input variable
+    term = inputinfo.terms{k};
+    stateindex = inputinfo.stateindex(k);
+    ODE = mds.states(stateindex).ODE;
+    ODE = strrep(ODE,term,['+' ivarname]);
+    mds.states(stateindex).ODE = ODE;
+    % b2) Handle Tlag 
+    if k==1,    % only add Tlag parameters once!
+        % Tlag (only if defined in dosing schedule)
+        % If defined numerically, then as parameter, non-numerically as
+        % variable ...
+        if ~isempty(inputinfo.Tlag) && isnumeric(inputinfo.Tlag),
+            % Add as parameter
+            mds.parameters(end+1).name = iTlagname;
+            mds.parameters(end).value = inputinfo.Tlag;
+            mds.parameters(end).type = '';
+            mds.parameters(end).compartment = '';
+            mds.parameters(end).unittype = '';
+            mds.parameters(end).notes = sprintf('%s Dosing lag time, used in variable ''%s'' (BOLUS).',inputinfo.TlagNotes,ivarname);
+        elseif ~isempty(inputinfo.Tlag) && ischar(inputinfo.Tlag),
+            % Add as variable
+            mds.variables(end+1).name = iTlagname;
+            mds.variables(end).formula = inputinfo.Tlag;
+            mds.variables(end).type = '';
+            mds.variables(end).compartment = '';
+            mds.variables(end).unittype = '';
+            mds.variables(end).notes = sprintf('%s Dosing lag time, used in variable ''%s'' (BOLUS).',inputinfo.TlagNotes,ivarname);
+        end
+    end
+    % c) Create the input variable (differently, depending if Tlag is
+    % defined or not)
+    if ~isempty(inputinfo.Tlag),    
+        vformula = sprintf('%s*%s/%s * piecewiseIQM(1,andIQM(ge(time,%s+%s),lt(time,%s+%s+%s)),0)',inputinfo.factors{k},iDosename,iBolusTimename,iTimename,iTlagname,iTimename,iTlagname,iBolusTimename);
+    else
+        vformula = sprintf('%s*%s/%s * piecewiseIQM(1,andIQM(ge(time,%s),lt(time,%s+%s)),0)',inputinfo.factors{k},iDosename,iBolusTimename,iTimename,iTimename,iBolusTimename);
+    end        
+    % d) Add the variable to the moddos model
+    mds.variables(end+1).name = ivarname;
+    mds.variables(end).formula = vformula;
+    mds.variables(end).type = '';
+    mds.variables(end).compartment = '';
+    mds.variables(end).unittype = '';
+    mds.variables(end).notes = sprintf(' Input variable realizing ''%s'' on state ''%s'' (BOLUS).',iname,ms.states(stateindex).name);
+    % e) Remove the INPUT* parameter (will change the parindex fields but
+    % doesn't matter, since this input parameters are not used anymore ...
+    % if a dosing input is defined for this INPUT* element).
+    index = strmatchIQM(iname,{mds.parameters.name},'exact');
+    mds.parameters(index) = [];
+    % f) Need to define an initial set of parameters used in the vformula.
+    % Single dosing events can be implemented in this way. In the case of
+    % multiple dosing events only the first will be implemented in the
+    % model. The remaining ones will be handled using an outside loop in a
+    % higher level function.
+    if k==1,    % only add Dose and Time parameters once! (also the bolus deltaT)
+        % Dose
+        mds.parameters(end+1).name = iDosename;
+        mds.parameters(end).value = 0; %inputinfo.D(1);
+        mds.parameters(end).type = '';
+        mds.parameters(end).compartment = '';
+        mds.parameters(end).unittype = '';
+        mds.parameters(end).notes = sprintf(' Dose amount for INPUT ''%s'' (BOLUS).', iname);
+        % Time
+        mds.parameters(end+1).name = iTimename;
+        mds.parameters(end).value = inputinfo.time(1);
+        mds.parameters(end).type = '';
+        mds.parameters(end).compartment = '';
+        mds.parameters(end).unittype = '';
+        mds.parameters(end).notes = sprintf(' Dosing instant for INPUT ''%s'' (BOLUS).', iname);
+        % iBolusTimename
+        mds.parameters(end+1).name = iBolusTimename;
+        mds.parameters(end).value = 0.0001; % Assume 1e-4 of time units (should be fast enough to realistically implement a BOLUS)
+        mds.parameters(end).type = '';
+        mds.parameters(end).compartment = '';
+        mds.parameters(end).unittype = '';
+        mds.parameters(end).notes = sprintf(' Very small dosing duration for INPUT ''%s'' (BOLUS).', iname);
+        % Add the necessary information to the experiment structure (only time
+        % and dosing amounts can change between subsequent dosing instants
+[eds] = buildexpstruct(eds,iDosename,iTimename,iTlagname,inputinfo,iname,'',[]);
+    end
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% handle Infusion input
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% also add dosing time and amount names to the inputinfo structure
+function [mds,eds] = handleInfusion(ms,mds,eds,inputinfo)
+% Get input name
+iname = inputinfo.name;
+% Cycle through all input different input terms
+for k=1:length(inputinfo.terms),
+    % Check if infusion time or infusion rate
+    paramname = inputinfo.parameters.name;
+    if strcmp(paramname,'Tinf'),
+        TinfFlag = 1;
+    else
+        TinfFlag = 0;
+    end
+    % a) Determine the input variable name and other names to be used in the model
+    ivarname = getoutname(lower(iname), length(inputinfo.terms), k);
+    iDosename = ['Dose' lower(iname)];
+    if TinfFlag,
+        iParamNameInfusion = ['Tinf' lower(iname)];
+    else
+        iParamNameInfusion = ['Rate' lower(iname)];
+    end
+    iTimename = ['Time' lower(iname)];
+    iTlagname = ['Tlag' lower(iname)];
+    % b) Replace ODE INPUT definition with input variable
+    term = inputinfo.terms{k};
+    stateindex = inputinfo.stateindex(k);
+    ODE = mds.states(stateindex).ODE;
+    ODE = strrep(ODE,term,['+' ivarname]);
+    mds.states(stateindex).ODE = ODE;
+    % b2) Handle Tlag 
+    if k==1,    % only add Tlag parameters once!
+        % Tlag (only if defined in dosing schedule)
+        % If defined numerically, then as parameter, non-numerically as
+        % variable ...
+        if ~isempty(inputinfo.Tlag) && isnumeric(inputinfo.Tlag),
+            % Add as parameter
+            mds.parameters(end+1).name = iTlagname;
+            mds.parameters(end).value = inputinfo.Tlag;
+            mds.parameters(end).type = '';
+            mds.parameters(end).compartment = '';
+            mds.parameters(end).unittype = '';
+            mds.parameters(end).notes = sprintf('%s Dosing lag time, used in variable ''%s'' (INFUSION).',inputinfo.TlagNotes,ivarname);
+        elseif ~isempty(inputinfo.Tlag) && ischar(inputinfo.Tlag),
+            % Add as variable
+            mds.variables(end+1).name = iTlagname;
+            mds.variables(end).formula = inputinfo.Tlag;
+            mds.variables(end).type = '';
+            mds.variables(end).compartment = '';
+            mds.variables(end).unittype = '';
+            mds.variables(end).notes = sprintf('%s Dosing lag time, used in variable ''%s'' (INFUSION).',inputinfo.TlagNotes,ivarname);
+        end
+    end
+    % c) Create the input variable (differently, depending if Tlag is
+    % defined or not)
+    if TinfFlag,
+        % Implement infusion time
+        if ~isempty(inputinfo.Tlag),
+            vformula = sprintf('%s*%s/%s * piecewiseIQM(1,andIQM(ge(time,%s+%s),lt(time,%s+%s+%s)),0)',inputinfo.factors{k},iDosename,iParamNameInfusion,iTimename,iTlagname,iTimename,iTlagname,iParamNameInfusion);
+        else
+            vformula = sprintf('%s*%s/%s * piecewiseIQM(1,andIQM(ge(time,%s),lt(time,%s+%s)),0)',inputinfo.factors{k},iDosename,iParamNameInfusion,iTimename,iTimename,iParamNameInfusion);
+        end
+    else
+        % Implement infusion Rate
+        if ~isempty(inputinfo.Tlag),
+            vformula = sprintf('%s*%s * piecewiseIQM(1,andIQM(ge(time,%s+%s),lt(time,%s+%s+%s/%s)),0)',inputinfo.factors{k},iParamNameInfusion,iTimename,iTlagname,iTimename,iTlagname,iDosename,iParamNameInfusion);
+        else
+            vformula = sprintf('%s*%s * piecewiseIQM(1,andIQM(ge(time,%s),lt(time,%s+%s/%s)),0)',inputinfo.factors{k},iParamNameInfusion,iTimename,iTimename,iDosename,iParamNameInfusion);
+        end
+    end
+    % d) Add the variable to the moddos model
+    mds.variables(end+1).name = ivarname;
+    mds.variables(end).formula = vformula;
+    mds.variables(end).type = '';
+    mds.variables(end).compartment = '';
+    mds.variables(end).unittype = '';
+    mds.variables(end).notes = sprintf(' Input variable realizing ''%s'' on state ''%s'' (INFUSION).',iname,ms.states(stateindex).name);
+    % e) Remove the INPUT* parameter (will change the parindex fields but
+    % doesn't matter, since this input parameters are not used anymore ...
+    % if a dosing input is defined for this INPUT* element).
+    index = strmatchIQM(iname,{mds.parameters.name},'exact');
+    mds.parameters(index) = [];
+    % f) Need to define an initial set of parameters used in the vformula.
+    % Single dosing events can be implemented in this way. In the case of
+    % multiple dosing events the parameters will be changed using events.
+    if k==1,    % only add Dose and Time parameters once!
+        % Dose
+        mds.parameters(end+1).name = iDosename;
+        mds.parameters(end).value = 0;%inputinfo.D(1);
+        mds.parameters(end).type = '';
+        mds.parameters(end).compartment = '';
+        mds.parameters(end).unittype = '';
+        mds.parameters(end).notes = sprintf(' Dose amount for INPUT ''%s'' (INFUSION).', iname);
+        % Time
+        mds.parameters(end+1).name = iTimename;
+        mds.parameters(end).value = inputinfo.time(1);
+        mds.parameters(end).type = '';
+        mds.parameters(end).compartment = '';
+        mds.parameters(end).unittype = '';
+        mds.parameters(end).notes = sprintf(' Dosing instant for INPUT ''%s'' (INFUSION).', iname);
+        % Rate
+        mds.parameters(end+1).name = iParamNameInfusion;
+        mds.parameters(end).value = inputinfo.parameters(1).value(1);
+        mds.parameters(end).type = '';
+        mds.parameters(end).compartment = '';
+        mds.parameters(end).unittype = '';
+        if TinfFlag,
+            mds.parameters(end).notes = sprintf(' Dosing infusion time, used in variable ''%s'' (INFUSION).', ivarname);
+        else
+            mds.parameters(end).notes = sprintf(' Dosing infusion rate, used in variable ''%s'' (INFUSION).', ivarname);
+        end
+        % Add the necessary information to the experiment structure (only time
+        % and dosing amounts can change between subsequent dosing instants
+[eds] = buildexpstruct(eds,iDosename,iTimename,iTlagname,inputinfo,iname,iParamNameInfusion,inputinfo.parameters(1).value);
+%         % Additionally set the Rate/Tinf parameter in the experiment
+%         eds = addparamicsetting(eds,iParamNameInfusion,num2str(inputinfo.parameters(1).value),0,'');
+    end
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% handle Absorption1 input
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% also add dosing time and amount names to the inputinfo structure
+function [mds,eds] = handleAbsorption1(ms,mds,eds,inputinfo)
+% Get input name
+iname = inputinfo.name;
+% Cycle through all input different input terms
+for k=1:length(inputinfo.terms),
+    % a) Determine the input variable name and other names to be used in the model
+    ivarname = getoutname(lower(iname), length(inputinfo.terms), k);
+    iCompname = ['Comp_' ivarname];
+    iabsorptvarname =['vAbsorption_' ivarname];
+    iDosename = ['Dose' lower(iname)];
+    iTimename = ['Time' lower(iname)];
+    iBolusTimename = ['DeltaT' lower(iname)];    
+
+    iKaname   = ['ka' lower(iname)];
+    iTlagname = ['Tlag' lower(iname)];
+    
+    % b) Replace ODE INPUT definition with ABSORPTION input variable
+    % (difference to all the other dosing application types).
+    term = inputinfo.terms{k};
+    stateindex = inputinfo.stateindex(k);
+    ODE = mds.states(stateindex).ODE;
+    ODE = strrep(ODE,term,['+' iabsorptvarname]);
+    mds.states(stateindex).ODE = ODE;
+    % b2) Handle Tlag 
+    if k==1,    % only add Tlag parameters once!
+        % Tlag (only if defined in dosing schedule)
+        % If defined numerically, then as parameter, non-numerically as
+        % variable ...
+        if ~isempty(inputinfo.Tlag) && isnumeric(inputinfo.Tlag),
+            % Add as parameter
+            mds.parameters(end+1).name = iTlagname;
+            mds.parameters(end).value = inputinfo.Tlag;
+            mds.parameters(end).type = '';
+            mds.parameters(end).compartment = '';
+            mds.parameters(end).unittype = '';
+            mds.parameters(end).notes = sprintf('%s Dosing lag time, used in variable ''%s'' (ABSORPTION1).',inputinfo.TlagNotes,ivarname);
+        elseif ~isempty(inputinfo.Tlag) && ischar(inputinfo.Tlag),
+            % Add as variable
+            mds.variables(end+1).name = iTlagname;
+            mds.variables(end).formula = inputinfo.Tlag;
+            mds.variables(end).type = '';
+            mds.variables(end).compartment = '';
+            mds.variables(end).unittype = '';
+            mds.variables(end).notes = sprintf('%s Dosing lag time, used in variable ''%s'' (ABSORPTION1).',inputinfo.TlagNotes,ivarname);
+        end
+    end
+    % c) Add a dosing compartment for the ABSORPTION1 input
+    mds.states(end+1).name = iCompname;
+    mds.states(end).initialCondition = 0;
+    mds.states(end).ODE = [ivarname '-' iabsorptvarname];
+    mds.states(end).type = '';
+    mds.states(end).compartment = '';
+    mds.states(end).unittype = '';
+    mds.states(end).notes = sprintf(' Dosing compartment for input ''%s'' (ABSORPTION1).',iname);
+    % d) Add a variable to define the absorption equation
+    mds.variables(end+1).name = iabsorptvarname;
+    mds.variables(end).formula = [iKaname '*' iCompname];
+    mds.variables(end).type = '';
+    mds.variables(end).compartment = '';
+    mds.variables(end).unittype = '';
+    mds.variables(end).notes = sprintf(' Absorption rate for input ''%s'' (ABSORPTION1).',iname);
+    % e) Create the input variable for application of the bolus to the
+    % dosing compartment (use same approach as for BOLUS applications, this
+    % means, a small application time of 0.0001).
+    if ~isempty(inputinfo.Tlag),    
+        vformula = sprintf('%s*%s/%s * piecewiseIQM(1,andIQM(ge(time,%s+%s),lt(time,%s+%s+%s)),0)',inputinfo.factors{k},iDosename,iBolusTimename,iTimename,iTlagname,iTimename,iTlagname,iBolusTimename);
+    else
+        vformula = sprintf('%s*%s/%s * piecewiseIQM(1,andIQM(ge(time,%s),lt(time,%s+%s)),0)',inputinfo.factors{k},iDosename,iBolusTimename,iTimename,iTimename,iBolusTimename);
+    end        
+    % f) Add the variable to the moddos model
+    mds.variables(end+1).name = ivarname;
+    mds.variables(end).formula = vformula;
+    mds.variables(end).type = '';
+    mds.variables(end).compartment = '';
+    mds.variables(end).unittype = '';
+    mds.variables(end).notes = sprintf(' Input variable realizing a BOLUS on state ''%s'', implementing input ''%s'' (ABSORPTION1).',iCompname,iname);
+    % f) Remove the INPUT* parameter (will change the parindex fields but
+    % doesn't matter, since this input parameters are not used anymore ...
+    % if a dosing input is defined for this INPUT* element).
+    index = strmatchIQM(iname,{mds.parameters.name},'exact');
+    mds.parameters(index) = [];
+    % f) Need to define an initial set of parameters used in the vformula.
+    % Single dosing events can be implemented in this way. In the case of
+    % multiple dosing events only the first will be implemented in the
+    % model. The remaining ones will be handled using an outside loop in a
+    % higher level function.
+    if k==1,    % only add Dose and Time parameters once! also bolus deltaT
+        % Dose
+        mds.parameters(end+1).name = iDosename;
+        mds.parameters(end).value = 0;%inputinfo.D(1);
+        mds.parameters(end).type = '';
+        mds.parameters(end).compartment = '';
+        mds.parameters(end).unittype = '';
+        mds.parameters(end).notes = sprintf(' Dose amount for INPUT ''%s'' (ABSORPTION1).', iname);
+        % Time
+        mds.parameters(end+1).name = iTimename;
+        mds.parameters(end).value = inputinfo.time(1);
+        mds.parameters(end).type = '';
+        mds.parameters(end).compartment = '';
+        mds.parameters(end).unittype = '';
+        mds.parameters(end).notes = sprintf(' Dosing instant for INPUT ''%s'' (ABSORPTION1).', iname);
+        % iBolusTimename
+        mds.parameters(end+1).name = iBolusTimename;
+        mds.parameters(end).value = 0.0001; % Assume 1e-4 of time units (should be fast enough to realistically implement a BOLUS)
+        mds.parameters(end).type = '';
+        mds.parameters(end).compartment = '';
+        mds.parameters(end).unittype = '';
+        mds.parameters(end).notes = sprintf(' Very small dosing duration (implementing a BOLUS into dosing compartment) for INPUT ''%s'' (ABSORPTION1).', iname);
+        % Ka
+        mds.parameters(end+1).name = iKaname;
+        mds.parameters(end).value = inputinfo.parameters(1).value(1);
+        mds.parameters(end).type = '';
+        mds.parameters(end).compartment = '';
+        mds.parameters(end).unittype = '';
+        mds.parameters(end).notes = sprintf(' Dose absorption rate constant, used in variable ''%s'' (ABSORPTION1).', iabsorptvarname);
+        % Add the necessary information to the experiment structure (only time
+        % and dosing amounts can change between subsequent dosing instants
+[eds] = buildexpstruct(eds,iDosename,iTimename,iTlagname,inputinfo,iname,iKaname,inputinfo.parameters(1).value);
+%         % Additionally set the ka rate parameters in the experiment
+%         eds = addparamicsetting(eds,iKaname,num2str(inputinfo.parameters(1).value),0,'');
+    end
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% handle Absorption0 input
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% also add dosing time and amount names to the inputinfo structure
+function [mds,eds] = handleAbsorption0(ms,mds,eds,inputinfo)
+% Get input name
+iname = inputinfo.name;
+% Cycle through all input different input terms
+for k=1:length(inputinfo.terms),
+    % a) Determine the input variable name and other names to be used in the model
+    ivarname = getoutname(lower(iname), length(inputinfo.terms), k);
+    iDosename = ['Dose' lower(iname)];
+    iTimename = ['Time' lower(iname)];
+    iTk0name = ['Tk0' lower(iname)];
+    iTlagname = ['Tlag' lower(iname)];
+    % b) Replace ODE INPUT definition with input variable
+    term = inputinfo.terms{k};
+    stateindex = inputinfo.stateindex(k);
+    ODE = mds.states(stateindex).ODE;
+    ODE = strrep(ODE,term,['+' ivarname]);
+    mds.states(stateindex).ODE = ODE;
+    % b2) Handle Tlag 
+    if k==1,    % only add Tlag parameters once!
+        % Tlag (only if defined in dosing schedule)
+        % If defined numerically, then as parameter, non-numerically as
+        % variable ...
+        if ~isempty(inputinfo.Tlag) && isnumeric(inputinfo.Tlag),
+            % Add as parameter
+            mds.parameters(end+1).name = iTlagname;
+            mds.parameters(end).value = inputinfo.Tlag;
+            mds.parameters(end).type = '';
+            mds.parameters(end).compartment = '';
+            mds.parameters(end).unittype = '';
+            mds.parameters(end).notes = sprintf('%s Dosing lag time, used in variable ''%s'' (ABSORPTION0).',inputinfo.TlagNotes,ivarname);
+        elseif ~isempty(inputinfo.Tlag) && ischar(inputinfo.Tlag),
+            % Add as variable
+            mds.variables(end+1).name = iTlagname;
+            mds.variables(end).formula = inputinfo.Tlag;
+            mds.variables(end).type = '';
+            mds.variables(end).compartment = '';
+            mds.variables(end).unittype = '';
+            mds.variables(end).notes = sprintf('%s Dosing lag time, used in variable ''%s'' (ABSORPTION0).',inputinfo.TlagNotes,ivarname);
+        end
+    end
+    % c) Create the input variable (differently, depending if Tlag is
+    % defined or not)
+    if ~isempty(inputinfo.Tlag),    
+        vformula = sprintf('%s*%s/%s * piecewiseIQM(1,andIQM(ge(time,%s+%s),lt(time,%s+%s+%s)),0)',inputinfo.factors{k},iDosename,iTk0name,iTimename,iTlagname,iTimename,iTlagname,iTk0name);
+    else
+        vformula = sprintf('%s*%s/%s * piecewiseIQM(1,andIQM(ge(time,%s),lt(time,%s+%s)),0)',inputinfo.factors{k},iDosename,iTk0name,iTimename,iTimename,iTk0name);
+    end        
+    % d) Add the variable to the moddos model
+    mds.variables(end+1).name = ivarname;
+    mds.variables(end).formula = vformula;
+    mds.variables(end).type = '';
+    mds.variables(end).compartment = '';
+    mds.variables(end).unittype = '';
+    mds.variables(end).notes = sprintf(' Input variable realizing ''%s'' on state ''%s'' (ABSORPTION0).',iname,ms.states(stateindex).name);
+    % e) Remove the INPUT* parameter (will change the parindex fields but
+    % doesn't matter, since this input parameters are not used anymore ...
+    % if a dosing input is defined for this INPUT* element).
+    index = strmatchIQM(iname,{mds.parameters.name},'exact');
+    mds.parameters(index) = [];
+    % f) Need to define an initial set of parameters used in the vformula.
+    % Single dosing events can be implemented in this way. In the case of
+    % multiple dosing events only the first will be implemented in the
+    % model. The remaining ones will be handled using an outside loop in a
+    % higher level function.
+    if k==1,    % only add Dose and Time parameters once!
+        % Dose
+        mds.parameters(end+1).name = iDosename;
+        mds.parameters(end).value = 0;%inputinfo.D(1);
+        mds.parameters(end).type = '';
+        mds.parameters(end).compartment = '';
+        mds.parameters(end).unittype = '';
+        mds.parameters(end).notes = sprintf(' Dose amount for INPUT ''%s'' (ABSORPTION0).', iname);
+        % Time
+        mds.parameters(end+1).name = iTimename;
+        mds.parameters(end).value = inputinfo.time(1);
+        mds.parameters(end).type = '';
+        mds.parameters(end).compartment = '';
+        mds.parameters(end).unittype = '';
+        mds.parameters(end).notes = sprintf(' Dosing instant for INPUT ''%s'' (ABSORPTION0).', iname);
+        % Tk0
+        mds.parameters(end+1).name = iTk0name;
+        mds.parameters(end).value = inputinfo.parameters(1).value(1);
+        mds.parameters(end).type = '';
+        mds.parameters(end).compartment = '';
+        mds.parameters(end).unittype = '';
+        mds.parameters(end).notes = sprintf('%s Dosing duration, used in variable ''%s'' (ABSORPTION0).', inputinfo.parameters(1).notes,ivarname);
+        % Add the necessary information to the experiment structure (only time
+        % and dosing amounts can change between subsequent dosing instants
+[eds] = buildexpstruct(eds,iDosename,iTimename,iTlagname,inputinfo,ivarname,iTk0name,inputinfo.parameters(1).value);
+%         % Additionally set the ka rate parameters in the experiment
+%         eds = addparamicsetting(eds,iTk0name,num2str(inputinfo.parameters(1).value),0,'');
+    end
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% help function to get right names
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function outname = getoutname(base, kmax, k)
+if kmax == 1,
+    outname = base;
+else
+    outname = [base '_' sprintf('%d',k)];
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle the experiment description for simulation
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% The first dosing instant is going to be put into the parameter and ic
+% settings section (same as already in the model). The subsequent
+% dosings in case of multiple doses is put into the event section.
+% parameter section. This function is the same for all dosing types. So no
+% need to write it 4 times.
+function [eds] = buildexpstruct(eds,iDosename,iTimename,iTlagname,inputinfo,ivarname,iParName,iParValue)
+eds = addparamicsetting(eds,iDosename,num2str(inputinfo.D(1)),0,'');
+eds = addparamicsetting(eds,iTimename,num2str(inputinfo.time(1)),0,'');
+% Same with the additional dosing parameter if defined
+if ~isempty(iParName),
+    eds = addparamicsetting(eds,iParName,num2str(iParValue(1)),0,'');
+end
+
+% Tlag (only if defined in dosing schedule) added for each input instant
+if ~isempty(inputinfo.Tlag),
+    eds = addparamicsetting(eds,iTlagname,num2str(inputinfo.Tlag),0,'');
+end
+
+% subsequent dosings in the events (Time and Dose needs to be
+% updated by events and also the dosing parameter, if defined)
+if length(inputinfo.time) > 1,
+    % multiple dosings => get time vector and dose vector (without
+    % first dosing instance)
+    timevec = inputinfo.time(2:end);
+    Dvec = inputinfo.D(2:end);
+    if ~isempty(iParValue),
+        parvec = iParValue(2:end);
+    else
+        parvec = [];
+    end
+    for k2=1:length(timevec),
+        % add the events
+        name = sprintf('%s_event_%d',ivarname,k2);
+        if ~isempty(parvec),
+            eds = addstateevent(eds,name,timevec(k2),{iDosename,iTimename,iParName},{num2str(Dvec(k2)),num2str(timevec(k2)),num2str(parvec(k2))},'');
+        else
+            eds = addstateevent(eds,name,timevec(k2),{iDosename,iTimename},{num2str(Dvec(k2)),num2str(timevec(k2))},'');
+        end            
+    end
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% add parameter or ic to experiment
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [eds] = addparamicsetting(eds,name,formula,icflag,notes)
+    eds.paramicsettings(end+1).name = name;
+    eds.paramicsettings(end).formula = formula;
+    eds.paramicsettings(end).icflag = icflag;
+    eds.paramicsettings(end).notes = notes;
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% add stateevents to experiment
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [eds] = addstateevent(eds,name,time,compnames,compformulas,notes)
+    eds.stateevents(end+1).name = name;
+    eds.stateevents(end).trigger = ['ge(time,' num2str(time) ')'];
+    for k=1:length(compnames),
+        eds.stateevents(end).assignment(k).variable = compnames{k};
+        eds.stateevents(end).assignment(k).formula = compformulas{k};
+    end
+    eds.stateevents(end).notes = notes;
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/experimenthandling/IQMcreateEXPfile.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/experimenthandling/IQMcreateEXPfile.m
new file mode 100644
index 0000000000000000000000000000000000000000..a57b24db780a3781c07a59f672cb2404860adf9d
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/experimenthandling/IQMcreateEXPfile.m	
@@ -0,0 +1,76 @@
+function IQMcreateEXPfile(varargin)
+% IQMcreateEXPfile: creates a *.exp file with the experiments text description
+%
+% USAGE:
+% ======
+% [] = IQMcreateEXPfile()         
+% [] = IQMcreateEXPfile(filename)         
+% [] = IQMcreateEXPfile(exp)         
+% [] = IQMcreateEXPfile(exp,filename)
+%
+% exp: IQMexperiment object to convert to a textfile description
+% filename: filename for the created textfile 
+%
+% If exp is undefined, then an empty experiment file will be created. 
+%
+% DEFAULT VALUES:
+% ===============
+% exp: the experiment to be exported as EXP file. 
+% filename: constructed from the experiments name
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin == 0,
+    % create empty experiment file with the name "unnamed.exp"
+    exp = IQMexperiment();
+    filename = 'unnamed.exp';
+elseif nargin == 1,
+    % check if first input argument experiment or filename
+    if isIQMexperiment(varargin{1}),
+        % experiment given
+        exp = varargin{1};
+        % if no filename provided then use the name of the IQMexperiment object as filename
+        % remove unwanted characters first
+        es = struct(exp);
+%         functionName = regexprep(es.name,'\W','');
+        functionName = es.name;
+        filename = strcat(functionName,'.exp');
+    else
+        % filename given?
+        if ~ischar(varargin{1}),
+            error('Wrong input argument.');
+        end
+        filename = strcat(varargin{1},'.exp');
+        exp = IQMexperiment();
+    end
+elseif nargin == 2,
+    exp = varargin{1};
+    filename = strcat(varargin{2},'.exp');
+else
+    error('Incorrect number of input arguments.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK INPUT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isIQMexperiment(exp),
+    error('No IQMexperiment as first argument.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CONVERT MODEL TO TEXT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[expTextStructure] = convertExpToTextIQM(exp);
+[completeText] = setPartsToCompleteTextExpIQM(expTextStructure);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% WRITE THE FILE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fid = fopen(filename,'w');
+fwrite(fid,completeText);
+fclose(fid);
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/experimenthandling/IQMmergemodexp.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/experimenthandling/IQMmergemodexp.m
new file mode 100644
index 0000000000000000000000000000000000000000..992e382bd8191b0e49e31c2490fd1688b065e197
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/experimenthandling/IQMmergemodexp.m	
@@ -0,0 +1,200 @@
+function [expmodel] = IQMmergemodexp(model, experiment)
+% IQMmergemodexp: combines an experiment with a model, and produces a "merged 
+% model", as output. The original model and experiment arguments can be
+% given as textfiles, or IQMexperiment objects. The output model is an
+% IQMmodel.
+%
+% DESCRIPTIONS + SYNTAX:
+% ======================
+% To fill in!
+%
+% USAGE:
+% ======
+% [expmodel] = IQMmergemodexp(model, experiment)        
+% [expmodel] = IQMmergemodexp(model, experimentfile)        
+%
+% model: IQMmodel 
+% experiment: An IQMexperiment object describing an experiment that should be done
+%             with the model
+% experimentfile: String with the name of an experiment file
+%
+% Output Arguments:
+% =================
+% Merged model containing the original model and the experimental settings.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+expmodel = [];
+time = 0;   % per default time=0 is assumed
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check input arguments 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isIQMmodel(model),
+    error('The first input argument needs to be an IQMmodel.');
+else
+    modelstruct = IQMstruct(model);
+end
+if ~isIQMexperiment(experiment),
+    % Then see if this file exists
+    if (exist(experiment, 'file') == 2)
+       % try open this experiment file 
+       try
+          experiment = IQMexperiment(experiment); 
+       catch exception
+           error('The second input argument needs to be either a IQMexperiment or an experiment text file.');
+       end
+    else    
+        error('The second input argument needs to be either a IQMexperiment or an experiment text file.');
+    end
+end
+expstruct = IQMstruct(experiment);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Initialize the output model structure
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+newmodstruct = modelstruct;                    
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Define all initial conditions and parameters in the workspace. Do not
+% define VARIABLES and REACTIONS! FIRST DEFINE PARAMETERS ... then ICs,
+% since ICs can depend on parameters.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for kkkloopnotuseinmodel = 1:length(newmodstruct.parameters),
+    if ~isempty(newmodstruct.parameters(kkkloopnotuseinmodel).value),
+        eval([newmodstruct.parameters(kkkloopnotuseinmodel).name '=' num2str(newmodstruct.parameters(kkkloopnotuseinmodel).value) ';']);
+    else
+        error('Value for parameter ''%s'' is undefined.',newmodstruct.parameters(kkkloopnotuseinmodel).name);
+    end
+end
+for kkkloopnotuseinmodel = 1:length(newmodstruct.states),
+    if ~isempty(newmodstruct.states(kkkloopnotuseinmodel).initialCondition),
+        eval([newmodstruct.states(kkkloopnotuseinmodel).name '=' num2str(newmodstruct.states(kkkloopnotuseinmodel).initialCondition) ';']);
+    else
+        error('Initial condition for state ''%s'' is undefined.',newmodstruct.states(kkkloopnotuseinmodel).name);
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Define all MODEL FUNCTIONS as inline objects to be used in the
+% determination of initial conditions and initial parameter settings
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for kkkloopnotuseinmodel = 1:length(newmodstruct.functions),
+    eval(sprintf('%s = @(%s)%s;',newmodstruct.functions(kkkloopnotuseinmodel).name,newmodstruct.functions(kkkloopnotuseinmodel).arguments,newmodstruct.functions(kkkloopnotuseinmodel).formula));
+end
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Now just evaluate the paramicsettings sequentially 
+% and add the new models to the structure
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for kkkloopnotuseinmodel = 1:length(expstruct.paramicsettings)
+    if ~isempty(expstruct.paramicsettings(kkkloopnotuseinmodel).formula),
+        try
+            % get value and assign value to variable in workspace
+            valuenotuseinmodel = eval(expstruct.paramicsettings(kkkloopnotuseinmodel).formula);
+            eval([expstruct.paramicsettings(kkkloopnotuseinmodel).name '=' num2str(valuenotuseinmodel) ';']);
+        catch
+            if expstruct.paramicsettings(kkkloopnotuseinmodel).icflag==1,
+                text = sprintf('Error in initial condition setting for state ''%s'':\n\n"%s"',expstruct.paramicsettings(kkkloopnotuseinmodel).name,lasterr);
+                text = sprintf('%s\n\nNote: Only a models states and parameters can be used in mathematical\nexpressions for the initial parameter and state settings.',text);
+                error(text);
+            else
+                text = sprintf('Error in initial condition setting for parameter ''%s'':\n\n"%s"',expstruct.paramicsettings(kkkloopnotuseinmodel).name,lasterr);
+                text = sprintf('%s\n\nOnly a models states and parameters can be used in mathematical\nexpressions for the initial parameter and state settings.',text);
+                error(text);
+            end
+        end
+    else
+        error('Formula for initial condition for state ''%s'' is undefined: %s',expstruct.paramicsettings(kkkloopnotuseinmodel).name,lasterr);
+    end
+    % value determined (valuenotuseinmodel). Add it to the model structure
+    if expstruct.paramicsettings(kkkloopnotuseinmodel).icflag==1,
+        % if initial condition then search states
+        indexnotuseinmodel = strmatchIQM(expstruct.paramicsettings(kkkloopnotuseinmodel).name,{newmodstruct.states.name},'exact');
+        if isempty(indexnotuseinmodel),
+            error('Initial condition for ''%s'' defined in experiment but state does not exist in the model.',expstruct.paramicsettings(kkkloopnotuseinmodel).name);
+        end 
+        newmodstruct.states(indexnotuseinmodel).initialCondition = valuenotuseinmodel;
+        newmodstruct.states(indexnotuseinmodel).notes = expstruct.paramicsettings(kkkloopnotuseinmodel).notes;
+    else
+        % if not initial condition then search in parameters 
+        indexnotuseinmodel = strmatchIQM(expstruct.paramicsettings(kkkloopnotuseinmodel).name,{newmodstruct.parameters.name},'exact');
+        if ~isempty(indexnotuseinmodel),
+            % only update value if parameter appears in the model (help
+            % variables are handled fine).
+            newmodstruct.parameters(indexnotuseinmodel).value = valuenotuseinmodel;
+            newmodstruct.parameters(indexnotuseinmodel).notes = expstruct.paramicsettings(kkkloopnotuseinmodel).notes;
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Add the parameter changes to the model
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Copy old variables to be able to add the new variables (parameters) first
+oldvariables = newmodstruct.variables;
+modelstructempty = struct(IQMmodel());
+newmodstruct.variables = modelstructempty.variables;
+% Add new variables as first in the list
+for k = 1:length(expstruct.parameterchanges),
+    % check that no parameter is defined twice
+    if ~isempty(strmatchIQM(expstruct.parameterchanges(k).name,{expstruct.paramicsettings.name},'exact')),
+        error('Parameter ''%s'' is defined twice (settings and changes).',expstruct.parameterchanges(k).name);
+    end
+    % delete this parameter from the model parameters
+    index = strmatchIQM(expstruct.parameterchanges(k).name,{newmodstruct.parameters.name},'exact');
+    if isempty(index),
+        error('Parameter ''%s'' not present in the model but changed in the experiment.',expstruct.parameterchanges(k).name);
+    end
+    newmodstruct.parameters(index) = [];
+    newmodstruct.variables(end+1).name = expstruct.parameterchanges(k).name;
+    newmodstruct.variables(end).formula = expstruct.parameterchanges(k).formula;
+    newmodstruct.variables(end).notes = expstruct.parameterchanges(k).notes;
+    newmodstruct.variables(end).type = '';
+    newmodstruct.variables(end).compartment = '';
+    newmodstruct.variables(end).unittype = '';
+end
+% Add old variables at the end
+for k = 1:length(oldvariables),
+    newmodstruct.variables(end+1).name = oldvariables(k).name;
+    newmodstruct.variables(end).formula = oldvariables(k).formula;
+    newmodstruct.variables(end).notes = oldvariables(k).notes;
+    newmodstruct.variables(end).type = oldvariables(k).type;
+    newmodstruct.variables(end).compartment = oldvariables(k).compartment;
+    newmodstruct.variables(end).unittype = oldvariables(k).unittype;    
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Add experiment events to the model
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for k = 1:length(expstruct.stateevents)
+    newmodstruct.events(end+1) = expstruct.stateevents(k);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% return the experiment model
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+expmodel = IQMmodel(newmodstruct);
+return
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%% The "find index" function
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [index] = find_index(name_array, comp_string)
+k = 0;
+l = length(name_array);
+index = inf;
+while k < l
+    k = k+1;
+    if strcmp(comp_string, name_array(k))
+        index = k;
+    end
+end
+if index == inf,
+    error('The experiment description contains the element ''%s'' that is not present in the model.',comp_string);
+end
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/experimenthandling/auxiliary/checkProcessActiveSetParameterSetIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/experimenthandling/auxiliary/checkProcessActiveSetParameterSetIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..4bfa70a4ba8e82790ca18d8ca490536e8b29d4bb
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/experimenthandling/auxiliary/checkProcessActiveSetParameterSetIQM.m	
@@ -0,0 +1,130 @@
+function [expText] = checkProcessActiveSetParameterSetIQM(expText,path2paramset)
+% checkProcessActiveSetParameterSetIQM checks the expText if "activeSet"
+% and/or "parameterSet" definitions are present. If yes, then these
+% IQMexperiments are loaded first and then the contents added to expText.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check "activeSet", "parameterSet"
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(strfind(expText,'activeSet(')) && isempty(strfind(expText,'parameterSet(')),
+    % Nothing to be done
+    return
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check if "path2paramset" is non-empty
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(path2paramset),
+    error(sprintf('The experiment contains "activeSet" and/or "parameterSet" definitions.\nFor that to be handled you need to provide the path to the root folder of these definitions.'));
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Remove \r from expText
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+expText = double(expText);
+expText(expText==13) = [];
+expText = char(expText);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle the activeSet definitions
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+index = strfind(expText,'activeSet(');
+while ~isempty(index),
+    % Handle first occurrence of "activeSet"
+    % 1) Get the corresponding line
+    row = double(expText(index:end)); 
+    i = find(row == 10);
+    row = char(row(1:i));
+    filename = [row(12:end-3) '.exp'];
+    % Read the corresponding "activeSet" experiment
+    file = fullfile(path2paramset,'Parameter Sets/Active Sets',filename);
+    content = getandcheckExpfile(file);
+    % Insert the "content" text into "expText" instead of "activeSet" definition
+    expText = strrep(expText,(expText(index(1):index(1)+i-2)),content);
+    % Search again for "activeSet("
+    index = strfind(expText,'activeSet(');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle the parameterSet definitions
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+index = strfind(expText,'parameterSet(');
+while ~isempty(index),
+    % Handle first occurrence of "parameterSet"
+    % Get the corresponding line
+    row = double(expText(index:end));
+    i = find(row == 10);
+    row = char(row(1:i));
+    file = row(15:end-3);
+    % Check if direct file or if interpolation necessary
+    x = length(explodePCIQM(file,','));
+    if x == 4,
+        % Handle interpolation
+        content = doInterpolation(file,path2paramset);
+    elseif x == 1,
+        filename = [file '.exp'];
+        % Read the corresponding "activeSet" experiment
+        filecomplete = fullfile(path2paramset,'Parameter Sets/Parameter Sets',filename);
+        content = getandcheckExpfile(filecomplete);
+        content = ['% ' file char(10) content char(10)];
+    else
+        error('checkProcessActiveSetParameterSetIQM: error in parameterSet definition ... maybe a "," to much?');
+    end
+    % Insert the "content" text into "expText" instead of "parameterSet" definition
+    expText = strrep(expText,(expText(index(1):index(1)+i-2)),content);
+    % Search again for "parameterSet("
+    index = strfind(expText,'parameterSet(');
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Perform the parameterSet interpolation and construct the content text
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [content] = doInterpolation(file,path2paramset)
+terms = explodePCIQM(file,',');
+% Check if linear interpolation (only supported for the moment)
+linear = strfind(terms{4},'Linear');
+if isempty(linear),
+    error('checkProcessActiveSetParameterSetIQM: Only linear interpolation of parameter sets allowed at the moment.');
+end
+% Get coefficient
+coefficient = str2double(terms{3});
+% Get lower and upper experiments and remove "dirt" around the strings
+lowerfilename = fullfile(path2paramset,'Parameter Sets/Parameter Sets',[terms{1}(1:end-1) '.exp']);
+upperfilename = fullfile(path2paramset,'Parameter Sets/Parameter Sets',[terms{2}(2:end-1) '.exp']);
+% Check the two experiments for errors
+getandcheckExpfile(lowerfilename);
+getandcheckExpfile(upperfilename);
+% Load the two experiments
+eLs = struct(IQMexperiment(lowerfilename));
+eUs = struct(IQMexperiment(upperfilename));
+% Create interpolated experiment
+eIs = eLs;
+% Do the interpolation
+for k=1:length(eIs.paramicsettings),
+    vL = eval(eLs.paramicsettings(k).formula);
+    vH = eval(eUs.paramicsettings(k).formula);
+    vI = vL+coefficient*(vH-vL);
+    eIs.paramicsettings(k).formula = num2str(vI);
+end
+eI = IQMexperiment(eIs);
+[eIstruct] = convertExpToTextIQM(eI);
+content = ['% ''' file '''' char(10) eIstruct.paramicsettings];
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check parameterSet and activeSet IQMexperiments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [content] = getandcheckExpfile(file)
+content = fileread(file);
+parts = getPartsFromCompleteTextExpIQM(content);
+% Check if only "conditions" field filled in
+if ~isempty(parts.parameterchanges) || ~isempty(parts.stateevents),
+    error('checkProcessActiveSetParameterSetIQM: parameter changes and state events not allowed in activeSet or parameterSet IQMexperiments!');
+end
+content = parts.conditions;
+% Check if 'activeSet' or 'parameterSet' definitions present (not allowed)
+if ~isempty(strfind(content,'activeSet(')) || ~isempty(strfind(content,'parameterSet(')),
+    error('checkProcessActiveSetParameterSetIQM: activeSet and parameterSet definitions in IQMexperiments can not be nested!');
+end
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/experimenthandling/auxiliary/exp2text/convertExpToTextIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/experimenthandling/auxiliary/exp2text/convertExpToTextIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..9d64d80c9aa6f09f880870d8bbd05451ca3c1575
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/experimenthandling/auxiliary/exp2text/convertExpToTextIQM.m	
@@ -0,0 +1,137 @@
+function [expTextStructure] = convertExpToTextIQM(exp)
+% convertExpToTextIQM: Converts an IQMexperiment object to a structure containing the 
+% different parts of the text description of the experiment. 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+% Initialize variables
+expTextStructure = [];
+% Get IQMstructure
+IQMstructure = IQMstruct(exp);
+% Parse structure into the expTextStructure description
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Name
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+expTextStructure.name = IQMstructure.name;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Notes
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+expTextStructure.notes = IQMstructure.notes;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% error variables
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+informationErrorText = '';
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Parameters and Initial conditions
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+listofstatesic = {};
+expTextStructure.paramicsettings = '';
+for k = 1:length(IQMstructure.paramicsettings),
+    name = IQMstructure.paramicsettings(k).name;
+    formula = IQMstructure.paramicsettings(k).formula;
+    notes = IQMstructure.paramicsettings(k).notes;
+    if IQMstructure.paramicsettings(k).icflag == 0,
+        if ~isempty(notes),
+            expTextStructure.paramicsettings = sprintf('%s%s = %s %% %s\n',expTextStructure.paramicsettings,name,formula,notes);
+        else
+            expTextStructure.paramicsettings = sprintf('%s%s = %s\n',expTextStructure.paramicsettings,name,formula);
+        end
+    else
+        if ~isempty(notes),
+            expTextStructure.paramicsettings = sprintf('%s%s(0) = %s %% %s\n',expTextStructure.paramicsettings,name,formula,notes);
+        else
+            expTextStructure.paramicsettings = sprintf('%s%s(0) = %s\n',expTextStructure.paramicsettings,name,formula);
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Parameters changes
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+expTextStructure.parameterchanges = '';
+for k = 1:length(IQMstructure.parameterchanges),
+    name = IQMstructure.parameterchanges(k).name;
+    formula = IQMstructure.parameterchanges(k).formula;
+    notes = IQMstructure.parameterchanges(k).notes;
+%     % check if piecewise in formula
+%     % piecewise in formula can have two different origins. on one hand it
+%     % can come from a real piecewise expression in the original experiment
+%     % description. on the other hand it can come from the piecewise
+%     % shorthand syntax. just assume shorthand syntax and if it fails write
+%     % out the piecewise statement.
+%     if ~isempty(strfind(formula,'piecewiseIQM')),
+%         formulabackup = formula;
+%         % delete piecewiseIQM from formula
+%         formula = formula(13:end-1)
+%         % delete ge(time, ...) from formula
+%         terms = explodePCIQM(formula,',');
+%         values = terms(1:2:end);
+%         triggers = terms(2:2:end);
+%         times = [];
+%         shorthand = 1;
+%         try
+%             % try to assume shorthand syntax
+%             for k2 = 1:length(triggers),
+%                 data = regexp(triggers{k2},'ge\(time,([^)]*)\),le\(time,([^)]*)\)','tokens');
+%                 times = [times, str2num(data{1}{1}), str2num(data{1}{2})];
+%             end
+%         catch
+%             shorthand = 0;
+%         end
+%         if shorthand,
+%             times = unique(times);
+%             timescell = {};
+%             for k2 = 1:length(times),
+%                 timescell{k2} = num2str(times(k2));
+%             end
+%             formuladata = {};
+%             formuladata(1:2:length(times)+length(values)) = timescell;
+%             formuladata(2:2:length(times)+length(values)) = values;
+%             formula = '';
+%             for k = 1:length(formuladata),
+%                 if mod(k,2) == 0,
+%                     formula = sprintf('%s%s, ',formula,formuladata{k});
+%                 else
+%                     formula = sprintf('%s%s, ',formula,formuladata{k});
+%                 end
+%             end
+%             formula = sprintf('{%s}',formula(1:end-2));
+%         else
+%             formula = formulabackup;
+%         end
+%     else
+        formula = formula;
+%     end
+    % update structure
+     if ~isempty(notes),
+         expTextStructure.parameterchanges = sprintf('%s%s = %s %% %s\n',expTextStructure.parameterchanges,name,formula,notes);
+     else
+         expTextStructure.parameterchanges = sprintf('%s%s = %s\n',expTextStructure.parameterchanges,name,formula);
+     end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% State events
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+expTextStructure.stateevents = '';
+for k = 1:length(IQMstructure.stateevents),
+    name = IQMstructure.stateevents(k).name;
+    trigger = IQMstructure.stateevents(k).trigger;
+    notes = IQMstructure.stateevents(k).notes;
+    % delete ge(time, ...) from trigger
+    trigger = trigger(9:end-1);
+    formula = sprintf('time = %s', trigger);
+    for k2 = 1:length(IQMstructure.stateevents(k).assignment),
+        formula = sprintf('%s, %s = %s',formula,IQMstructure.stateevents(k).assignment(k2).variable,IQMstructure.stateevents(k).assignment(k2).formula);
+    end
+     if ~isempty(notes),
+         expTextStructure.stateevents = sprintf('%s%s %% %s\n',expTextStructure.stateevents,formula,notes);
+     else
+         expTextStructure.stateevents = sprintf('%s%s\n',expTextStructure.stateevents,formula);
+     end
+end
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/experimenthandling/auxiliary/exp2text/setPartsToCompleteTextExpIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/experimenthandling/auxiliary/exp2text/setPartsToCompleteTextExpIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..15a80ec0aa823bd2da9bec0cb310a053f25c5ec3
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/experimenthandling/auxiliary/exp2text/setPartsToCompleteTextExpIQM.m	
@@ -0,0 +1,13 @@
+function [completeText] = setPartsToCompleteTextExpIQM(expTextStructure)
+% setPartsToCompleteTextExpIQM: Sets the different parts of an experiment description
+% of an IQMexperiment object together to the complete text
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+completeText = sprintf('********** EXPERIMENT NAME\n%s\n',expTextStructure.name);
+completeText = sprintf('%s\n********** EXPERIMENT NOTES\n%s\n',completeText,expTextStructure.notes);
+completeText = sprintf('%s\n********** EXPERIMENT INITIAL PARAMETER AND STATE SETTINGS\n%s',completeText,expTextStructure.paramicsettings);
+completeText = sprintf('%s\n********** EXPERIMENT PARAMETER CHANGES\n%s',completeText,expTextStructure.parameterchanges);
+completeText = sprintf('%s\n********** EXPERIMENT STATE CHANGES\n%s',completeText,expTextStructure.stateevents);
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/experimenthandling/auxiliary/text2exp/convertTextToExpIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/experimenthandling/auxiliary/text2exp/convertTextToExpIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..763400cd144932601853badfebacc0cb1197e51e
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/experimenthandling/auxiliary/text2exp/convertTextToExpIQM.m	
@@ -0,0 +1,236 @@
+function [IQMstructure,errorMsg] = convertTextToExpIQM(expText)
+% convertTextToExpIQM: Converts a text description of an IQMexperiment object to 
+% the internal IQMexperiment data structure representation.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+% initialize variables
+errorMsg = '';
+errorConditions = '';
+errorParameterChanges = '';
+errorStateEvents = '';
+IQMstructure = [];
+
+% cut text into pieces
+expTextStructure = getPartsFromCompleteTextExpIQM(expText);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%% Name
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+IQMstructure.name = strtrim(removeCharacters(expTextStructure.name));
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%% Notes
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+IQMstructure.notes = strtrim(expTextStructure.notes);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%% Conditions (parameters and initial conditions)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try
+    [IQMstructure.paramicsettings, errorConditions] = getConditions(expTextStructure.conditions);
+catch
+    errorMsg = sprintf('%sPlease check the syntax of the ''Parameter and initial conditions'' definitions.\n',errorMsg);
+end
+if ~isempty(errorConditions),
+    errorMsg = sprintf('%s%s\n',errorMsg,errorConditions);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%% Parameter changes
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%try
+    [IQMstructure.parameterchanges, errorParameterChanges] = getParameterChanges(expTextStructure.parameterchanges);
+%catch
+%    errorMsg = sprintf('%sPlease check the syntax of the ''Parameter Changes'' definitions.\n',errorMsg);
+%end
+if ~isempty(errorParameterChanges),
+    errorMsg = sprintf('%s%s\n',errorMsg,errorParameterChanges);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%% State changes
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%try
+    [IQMstructure.stateevents, errorStateEvents] = getStateEvents(expTextStructure.stateevents);
+%catch
+%    errorMsg = sprintf('%sPlease check the syntax of the ''States Changes'' definitions.\n',errorMsg);
+%end
+if ~isempty(errorStateEvents),
+    errorMsg = sprintf('%s%s\n',errorMsg,errorStateEvents);
+end
+return
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [paramicsettings, error] = getConditions(conditionsString)
+error = '';
+% create empty structures
+paramicsettings = struct('name',{},'formula',{},'notes',{},'icflag',{});
+% parse the strings and fill the structures
+conditionsString = char([double(conditionsString) 10]); % need to add a '\n' at the end
+allelements = regexp(conditionsString,'([^\n]*)=([^\n]*)\n','tokens');
+for k = 1:length(allelements),
+    element = allelements{k};
+    leftside = strtrim(removeCharacters(element{1}));
+    rightsideandcomment = strtrim(removeCharacters(element{2}));
+    % parse right side and comment (remove (0) from the right side)
+    rightsideandcomment = regexp(rightsideandcomment,'([^%]*)','tokens');
+    rightside = regexprep(strtrim(rightsideandcomment{1}{1}),'\(0\)','');
+    if length(rightsideandcomment) == 2,
+        comment = strtrim(rightsideandcomment{2}{1});
+    else
+        comment = '';
+    end
+    % check if state initial condition or if parameter definition
+    if isempty(strfind(leftside,'(0)')),
+        paramicsettings(end+1).name = leftside;
+        try
+            eval(['zzz =' rightside ';']);
+            paramicsettings(end).formula = num2str(zzz);
+        catch
+            paramicsettings(end).formula = rightside;
+        end
+        %paramicsettings(end).formula = rightside;
+        paramicsettings(end).notes = comment;
+        paramicsettings(end).icflag = 0;
+    else
+        paramicsettings(end+1).name = regexprep(leftside,'\(0\)','');
+        %%% ADD VARIABILITY - BRUNO
+        try
+            eval(['zzz =' rightside ';']);
+            paramicsettings(end).formula = num2str(zzz);
+        catch
+            paramicsettings(end).formula = rightside;
+        end
+        %%% Initial code 
+        %paramicsettings(end).formula = rightside;
+        paramicsettings(end).notes = comment;
+        paramicsettings(end).icflag = 1;
+    end
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [parameterchanges, error] = getParameterChanges(parameterchangesString)
+error = '';
+% create empty structure
+parameterchanges = struct('name',{},'formula',{},'notes',{});
+% parse the strings and fill the structures
+parameterchangesString = char([double(parameterchangesString) 10]); % need to add a '\n' at the end
+allelements = regexp(parameterchangesString,'([^\n]*)=([^\n]*)\n','tokens');
+for k = 1:length(allelements),
+    element = allelements{k};
+    leftside = strtrim(removeCharacters(element{1}));
+    rightsideandcomment = strtrim(removeCharacters(element{2}));
+    % parse right side and comment
+    rightsideandcomment = regexp(rightsideandcomment,'([^%]*)','tokens');
+    rightside = strtrim(removeCharacters(rightsideandcomment{1}{1}));
+    if length(rightsideandcomment) == 2,
+        comment = strtrim(removeCharacters(rightsideandcomment{2}{1}));
+    else
+        comment = '';
+    end
+    % check if a piecewisestatement is present
+    if ~isempty(strfind(rightside,'{')),
+        % construct piecewise statement
+        rightside = rightside(2:end-1);  % take away the outer parentheses
+        terms = explodePCIQM(rightside,',');
+        if mod(length(terms),2) == 1, % (if uneven)
+            error = sprintf('%sParameter change for ''%s'' does not have a default value defined.',error,leftside);
+            return
+        end
+        if length(terms) <= 2,
+            error = sprintf('Wrong definition of parameter setting for parameter ''%s''.\n',leftside);
+            return
+        end
+        formula = 'piecewiseIQM(';
+        times = terms(1:2:length(terms));
+        values = terms(2:2:length(terms));
+        triggers = {};
+        for k2 = 1:length(times)-1,
+            triggers{k2} = sprintf('and(ge(time,%s),le(time,%s))',times{k2},times{k2+1});
+        end
+        valuestimes = {};
+        valuestimes(1:2:length(triggers)+length(values)) = values;
+        valuestimes(2:2:length(triggers)+length(values)) = triggers;
+        % construct piecewise statement
+        formula = 'piecewiseIQM(';
+        for k2 = 1:length(valuestimes),
+            formula = sprintf('%s%s,',formula,valuestimes{k2});
+        end
+        formula =sprintf('%s)',formula(1:end-1));
+    else
+        % no piecewise statement detected => just take formula as it is
+        formula = rightside;
+    end
+    % add data
+    parameterchanges(end+1).name = leftside;
+    parameterchanges(end).formula = formula;
+    parameterchanges(end).notes = comment;
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [stateevents, error] = getStateEvents(stateeventsString)
+error = '';
+% create empty structure
+eventassignment = struct('variable',{},'formula',{});
+stateevents = struct('name',{},'trigger',{},'assignment',eventassignment,'notes',{});
+% parse the strings and fill the structures
+stateeventsString = char([double(stateeventsString) 13 10]); % need to add a '\n' at the end
+if isempty(strtrim(stateeventsString)),
+    stateeventsString = strtrim(stateeventsString);
+end
+allelements = regexp(stateeventsString,'([^\n]*)\n','tokens');
+for k=1:length(allelements),
+    stateevents(end+1).name = sprintf('StateChange_%d',k);
+    % determine the comment
+    element = regexp(allelements{k}{1},'([^%]*)','tokens');
+    eventdata = element{1}{1};
+    if length(element) == 1,
+        comment = '';
+    else
+        comment = element{2}{1};
+    end
+    stateevents(end).notes = strtrim(removeCharacters(comment));
+    % get event data
+    terms = explodePCIQM(eventdata,',');
+    if length(terms) < 2,
+        error = sprintf('%s\nState change nr. %d wrongly defined.',error,k);
+        return
+    end
+    % the first term needs to define the time of the event. format: time = xxx
+    test = explodePCIQM(terms{1},'=');
+    if isempty(strcmp(test{1},'time')) || length(test) ~= 2,
+        error = sprintf('%s\nState change nr. %d wrongly defined ("time = numeric value" needs to be the first element).',error,k);
+        return
+    end
+    % get trigger function
+    stateevents(end).trigger = sprintf('ge(time,%s)',test{2});
+    % determine event assignments
+    for k2 = 2:length(terms),
+        assterms = explodePCIQM(terms{k2},'=');
+        stateevents(end).assignment(k2-1).variable = assterms{1};
+        stateevents(end).assignment(k2-1).formula = assterms{2};
+    end
+end
+return
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [output] = removeCharacters(input)
+% delete all line breaks and tabs from the input string
+temp = double(input);
+temp(find(temp==13)) = 32;  % replace '\cr' by white space
+temp(find(temp==10)) = 32;  % replace '\n' by white space
+temp(find(temp==9)) = 32;   % replace '\t' by white space
+output = char(temp);
+% remove all spaces
+%    output = strrep(output,' ','');
+return
+
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/experimenthandling/auxiliary/text2exp/getPartsFromCompleteTextExpIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/experimenthandling/auxiliary/text2exp/getPartsFromCompleteTextExpIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..a8a26a6f9b1ef9a8e26e9e027cb5042745176fb5
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/experimenthandling/auxiliary/text2exp/getPartsFromCompleteTextExpIQM.m	
@@ -0,0 +1,23 @@
+function [expTextStructure] = getPartsFromCompleteTextExpIQM(expText)
+% getPartsFromCompleteTextExpIQM: Cuts a text description of an IQMexperiment object
+% into the different parts and returns them in a structure
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+% take commented lines out of the experiment description
+expText = regexprep(expText,'\n%[^\n]*','');
+
+% Find the starts of the different view data
+nameStart = strfind(expText,'********** EXPERIMENT NAME');
+notesStart = strfind(expText,'********** EXPERIMENT NOTES');
+conditionsStart = strfind(expText,'********** EXPERIMENT INITIAL PARAMETER AND STATE SETTINGS');
+parameterchangesStart = strfind(expText,'********** EXPERIMENT PARAMETER CHANGES');
+stateeventsStart = strfind(expText,'********** EXPERIMENT STATE CHANGES');
+% Cut out the different pieces and assign them to the expTextStructure structure
+expTextStructure.name = strtrim(expText(nameStart+length('********** EXPERIMENT NAME'):notesStart-1));
+expTextStructure.notes = strtrim(expText(notesStart+length('********** EXPERIMENT NOTES'):conditionsStart-1));
+expTextStructure.conditions = strtrim(expText(conditionsStart+length('********** EXPERIMENT INITIAL PARAMETER AND STATE SETTINGS'):parameterchangesStart-1));
+expTextStructure.parameterchanges = strtrim(expText(parameterchangesStart+length('********** EXPERIMENT PARAMETER CHANGES'):stateeventsStart-1));
+expTextStructure.stateevents = strtrim(expText(stateeventsStart+length('********** EXPERIMENT STATE CHANGES'):end));
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/experimenthandling/isIQMexperiment.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/experimenthandling/isIQMexperiment.m
new file mode 100644
index 0000000000000000000000000000000000000000..eaf4dce7a56be6bd10fb2363c9c595f6d1cac1e7
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/experimenthandling/isIQMexperiment.m	
@@ -0,0 +1,6 @@
+function [output] = isIQMexperiment(input)
+% isIQMexperiment: check if input argument is an IQMexperiment.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+output = strcmp(class(input),'IQMexperiment');
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/measurementhandling/IQMexportCSVmeasurement.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/measurementhandling/IQMexportCSVmeasurement.m
new file mode 100644
index 0000000000000000000000000000000000000000..616f1db25bf7bb463274d80d534e3f83d8e98615
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/measurementhandling/IQMexportCSVmeasurement.m	
@@ -0,0 +1,138 @@
+function [] = IQMexportCSVmeasurement(varargin)
+% IQMexportCSVmeasurement
+% Exports an IQMmeasurement object to a CSV (comma separated value) file.
+% The format of the written CSV file is explained in the user's reference
+% manual and example files can be found in the IQMlite/examples folder.
+% 
+% USAGE:
+% ======
+% [] = IQMexportCSVmeasurement(measurement)
+% [] = IQMexportCSVmeasurement(measurement,filename)
+%
+% measurement: IQMmeasurement object containing the data
+% filename:    desired filename for CSV file. The extension '.csv' is not
+%              required.
+%
+% DEFAULT VALUES:
+% ===============
+% filename: constructed from the data objects name
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin == 1,
+    measurement = varargin{1};
+    % convert object to structure
+    measurement = struct(measurement);    
+    % if no filename provided then use the name of the IQMmeasurement object 
+    % as filename. Just delete all the special characters.
+    filename = measurement.name;   % white spaces
+elseif nargin == 2,
+    measurement = varargin{1};
+    % convert object to structure
+    measurement = struct(measurement);    
+    % extract filename from input arguments to skip eventual extension
+    [PATHSTR,filename,EXT] = fileparts(varargin{2});
+else
+    error('Incorrect number of input arguments.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF OBJECT CONTAINS MEASUREMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if length(measurement.data) == 0,
+    error('The object does not contain any measurements');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Create the file 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fid = fopen(strcat(filename,'.csv'),'w');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Write header
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'%% Measurement file generated: %s\n\n',date);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% NAME
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'[Name]\n');
+fprintf(fid,'%s\n',measurement.name);
+fprintf(fid,'\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% NOTES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'[Notes]\n');
+fprintf(fid,'%s\n',measurement.notes);
+fprintf(fid,'\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% COMPONENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'[Components]\n');
+text = 'time,';
+for k=1:length(measurement.data),
+    text = sprintf('%s%s,',text,measurement.data(k).name);
+    % add error bound names
+    if ~isempty(measurement.data(k).maxvalues) && max(isnan(measurement.data(k).maxvalues))~=1,
+        text = sprintf('%s%s+,',text,measurement.data(k).name);
+    end
+    if ~isempty(measurement.data(k).minvalues) && max(isnan(measurement.data(k).minvalues))~=1,
+        text = sprintf('%s%s-,',text,measurement.data(k).name);
+    end
+end
+text = text(1:end-1);
+fprintf(fid,'%s\n',text);
+fprintf(fid,'\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% COMPONENTNOTES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'[Componentnotes]\n');
+for k=1:length(measurement.data),
+    if ~isempty(measurement.data(k).notes),
+        notes = regexprep(measurement.data(k).notes,'\n',' ');
+        notes = regexprep(notes,'  ',' ');
+        notes = regexprep(notes,'  ',' ');
+        if ~isempty(measurement.data(k).name),
+            fprintf(fid,'%s: %s\n',measurement.data(k).name,notes);
+        else
+            fprintf(fid,'%s: %s\n',measurement.data(k).formula,notes);
+        end
+    end
+end
+fprintf(fid,'\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Values
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'[Values]\n');
+experimentData = measurement.time(:);
+for k = 1:length(measurement.data),
+    experimentData(:,end+1) = measurement.data(k).values(:);
+    % add error bound values
+    if ~isempty(measurement.data(k).maxvalues) && max(isnan(measurement.data(k).maxvalues))~=1,
+        experimentData(:,end+1) = measurement.data(k).maxvalues(:);
+    end
+    if ~isempty(measurement.data(k).minvalues) && max(isnan(measurement.data(k).minvalues))~=1,
+        experimentData(:,end+1) = measurement.data(k).minvalues(:);
+    end
+end
+dataString = '';
+for k = 1:size(experimentData,1),
+    % Change for accurate printing of low values
+    %dataString = sprintf('%f,',experimentData(k,:));
+    dataString = sprintf('%14.12g,',experimentData(k,:));
+    fprintf(fid,'%s\n',dataString(1:end-1));
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Close the file
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fclose(fid);
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/measurementhandling/IQMexportXLSmeasurement.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/measurementhandling/IQMexportXLSmeasurement.m
new file mode 100644
index 0000000000000000000000000000000000000000..fd032ef8cca49337b9c42bffce5dcd7308c837d3
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/measurementhandling/IQMexportXLSmeasurement.m	
@@ -0,0 +1,154 @@
+function [] = IQMexportXLSmeasurement(varargin)
+% IQMexportXLSmeasurement
+% Exports an IQMmeasurement object to an XLS (excel) file.
+% The format of the written XLS file is explained in the user's reference
+% manual and example files can be found in the IQMlite/examples folder.
+%
+% USAGE:
+% ======
+% [] = IQMexportXLSmeasurement(measurement)
+% [] = IQMexportXLSmeasurement(measurement,filename)
+% [] = IQMexportXLSmeasurement(measurement,filename,sheet)
+%
+% measurement: IQMmeasurement object containing the data
+% filename:    desired filename for XLS file. The extension '.xls' is not
+%              required.
+% sheet:       number of the sheet in the Excel file to which the data
+%              should be written.
+%
+% DEFAULT VALUES:
+% ===============
+% filename: constructed from the data objects name
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+sheet = 1;
+if nargin == 1,
+    measurement = varargin{1};
+    % convert object to structure
+    measurement = struct(measurement);
+    % if no filename provided then use the name of the IQMmeasurement object
+    % as filename. Just delete all the special characters.
+    filename = regexprep(measurement.name,'\s','');   % white spaces
+    filename = regexprep(filename,'\W','');    % other
+elseif nargin == 2,
+    measurement = varargin{1};
+    % convert object to structure
+    measurement = struct(measurement);
+    % extract filename from input arguments to skip eventual extension
+    [PATHSTR,filename,EXT] = fileparts(varargin{2});
+elseif nargin == 3,
+    measurement = varargin{1};
+    % convert object to structure
+    measurement = struct(measurement);
+    % extract filename from input arguments to skip eventual extension
+    [PATHSTR,filename,EXT] = fileparts(varargin{2});
+    sheet = varargin{3};
+else
+    error('Incorrect number of input arguments.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF OBJECT CONTAINS MEASUREMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+numberComponents = length(measurement.data);
+if numberComponents == 0,
+    error('The object does not contain any measurements');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Construct Cell-Array Matrix of correct size
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+RAW = NaN*ones(4+length(measurement.time),numberComponents+2);
+RAW = num2cell(RAW);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% NAME
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+RAW{1,1} = 'Name';
+RAW{1,2} = measurement.name;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% NOTES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% It seems that matlab requires the entry sizes to be max 911.
+% So lets split them up. Make sure we truncate at a space.
+RAW{2,1} = 'Notes';
+offset = 0;
+if length(measurement.notes) <= 911,
+    RAW{2,2} = measurement.notes;
+else
+    notes = measurement.notes;
+    while length(notes) > 911,
+        index = 911;
+        while double(notes(index)) ~= 32,
+            index = index - 1;
+        end
+        RAW{2+offset,2} = notes(1:index-1);
+        offset = offset + 1;
+        notes = notes(index+1:end);
+    end
+    RAW{2+offset,2} = notes;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% COMPONENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+componentsall = {};
+RAW{4+offset,1} = 'Components';
+RAW{4+offset,2} = 'time';
+index = 3;
+for k=1:numberComponents,
+    RAW{4+offset,index} = measurement.data(k).name;
+    componentsall{end+1} = measurement.data(k).name;
+    index = index+1;
+    % add error bound names
+    if ~isempty(measurement.data(k).maxvalues) && max(isnan(measurement.data(k).maxvalues))~=1,
+        RAW{4+offset,index} = sprintf('%s+',measurement.data(k).name);
+        componentsall{end+1} = sprintf('%s+',measurement.data(k).name);
+        index = index + 1;
+    end
+    if ~isempty(measurement.data(k).minvalues) && max(isnan(measurement.data(k).minvalues))~=1,
+        RAW{4+offset,index} = sprintf('%s-',measurement.data(k).name);
+        componentsall{end+1} = sprintf('%s-',measurement.data(k).name);
+        index = index + 1;
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% COMPONENTNOTES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+RAW{3+offset,1} = 'Componentnotes';
+for k=1:numberComponents,
+    index = strmatchIQM(measurement.data(k).name,componentsall,'exact');
+    RAW{3+offset,index+2} = measurement.data(k).notes;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% VALUES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+RAW{5+offset,1} = 'Values';
+RAW(5+offset:5+offset+length(measurement.time)-1,2) = num2cell(measurement.time);
+index = 3;
+for k=1:numberComponents,
+    RAW(5+offset:5+offset+length(measurement.data(k).values)-1,index) = num2cell(measurement.data(k).values);
+    index = index + 1;
+    if ~isempty(measurement.data(k).maxvalues) && max(isnan(measurement.data(k).maxvalues))~=1,
+        RAW(5+offset:5+offset+length(measurement.data(k).values)-1,index) = num2cell(measurement.data(k).maxvalues);
+        index = index + 1;
+    end
+    if ~isempty(measurement.data(k).minvalues) && max(isnan(measurement.data(k).minvalues))~=1,
+        RAW(5+offset:5+offset+length(measurement.data(k).values)-1,index) = num2cell(measurement.data(k).minvalues);
+        index = index + 1;
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% WRITE TO FILE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[success,message] = xlswrite(strcat(filename,'.xls'),RAW,sheet);
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/measurementhandling/IQMexportXLSmeasurements.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/measurementhandling/IQMexportXLSmeasurements.m
new file mode 100644
index 0000000000000000000000000000000000000000..52132d6c1a063e600430cd26b5af4fe8b7c31f8d
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/measurementhandling/IQMexportXLSmeasurements.m	
@@ -0,0 +1,41 @@
+function [] = IQMexportXLSmeasurements(measurements,filename)
+% IQMexportXLSmeasurement
+% Exports several IQMmeasurement objects to the same XLS (excel) file.
+% Each measurement will be added to a separate sheet in the file.
+%
+% USAGE:
+% ======
+% [] = IQMexportXLSmeasurement(measurements,filename)
+%
+% measurements: A cell-array in which all the elements are IQMmeasurement objects.
+% filename:     Desired filename for XLS file. The extension '.xls' is not
+%               required.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+[PATHSTR,filename,EXT] = fileparts(filename);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF MULTIPLE MEASUREMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~iscell(measurements),
+    input = {measurements};
+else
+    input = measurements;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DELETE FILE WITH FILENAME IF PRESENT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+warning off;
+delete(strcat(filename,'.xls'));
+warning on;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% LOOP THROUGH THE MEASUREMENTS AND EXPORT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for sheet=1:length(input),
+    measurement = input{sheet};
+    IQMexportXLSmeasurement(measurement,strcat(filename,'.xls'),sheet);
+end
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/measurementhandling/IQMimportCSVmeasurement.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/measurementhandling/IQMimportCSVmeasurement.m
new file mode 100644
index 0000000000000000000000000000000000000000..a079bde2de5e00d5e205dbbd992333e27350c7c5
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/measurementhandling/IQMimportCSVmeasurement.m	
@@ -0,0 +1,163 @@
+function [measurementstructure,errorMsg] = IQMimportCSVmeasurement(filename)
+% IQMimportCSVmeasurement
+% Imports experimental measurement data stored in an CSV (comma separated 
+% value) file into the measurement structure used by the IQMmeasurement
+% object. Please note that a special format of the CSV measurement is
+% required. This format is explained in the user's reference manual and
+% example files can be found in the IQMlite/examples folder.
+% 
+% filename: name of the .csv file containing the measurement
+%
+% measurementstructure: measurement structure used by IQMmeasurement object 
+%                      (empty if error occurred)
+% errorMsg: string containing possible error messages. 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INITIALIZATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+errorMsg = '';
+measurementstructure = struct(IQMmeasurement());
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Open the file and read all its content 
+% Skip the comments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+content = sprintf('\n%s',fileread(filename));
+content = regexprep(content,'\n%[^\n]*','');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Extract the pieces
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Find the starts of the different view data
+nameStart = regexp(content,'\[Name\]');
+notesStart = regexp(content,'\[Notes\]');
+componentsStart = regexp(content,'\[Components\]');
+componentnotesStart = regexp(content,'\[Componentnotes\]');
+valuesStart = regexp(content,'\[Values\]');
+if isempty(nameStart) || isempty(notesStart) || isempty(componentsStart) || isempty(componentnotesStart) || isempty(valuesStart),
+    errorMsg = sprintf('%sAt least one of the identifiers in the measurement file is missing or misspelled.\n',errorMsg);
+end
+% Cut out the different pieces and assign them to the modelTextStructure structure
+nameraw = strtrim(content(nameStart+length('[Name]'):notesStart-1));
+notesraw = strtrim(content(notesStart+length('[Notes]'):componentsStart-1));
+componentsraw = strtrim(content(componentsStart+length('[Components]'):componentnotesStart-1));
+componentnotesraw = strtrim(content(componentnotesStart+length('[Componentnotes]'):valuesStart-1));
+valuesraw = strtrim(content(valuesStart+length('[Values]'):end));
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get name
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(nameraw),
+    measurementstructure.name = 'untitled';
+else
+    % just remove special signs that are not allowed for file names.
+    measurementstructure.name = regexprep(nameraw,'\W','');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get notes
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+measurementstructure.notes = notesraw;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get components - check also for timeindex
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% explode the components
+components = explodePCIQM(componentsraw);
+% remove spaces from comment names
+for k = 1:length(components),
+    components = regexprep(components,' ','');
+end
+% find 'time' component
+timeindex = strmatchIQM('time',components,'exact');
+% initialize help structure for min max values (error bounds) + components
+errorbounddata = struct('name',{},'type',{},'indexvalues',{});
+componentdata = struct('name',{},'indexvalues',{});
+% fill in component names/formulas in structure
+for k=1:length(components),
+    if k ~= timeindex,
+        % check if componentname defines an upper or lower bound
+        if ~isempty(regexp(components{k},'[+]')),
+            % component defines an upper bound
+            errorbounddata(end+1).name = regexprep(components{k},'\W','');
+            errorbounddata(end).type = 'max';
+            errorbounddata(end).indexvalues = k;
+        elseif ~isempty(regexp(components{k},'[-]')),
+            % component defines a lower bound
+            errorbounddata(end+1).name = regexprep(components{k},'\W','');
+            errorbounddata(end).type = 'min';
+            errorbounddata(end).indexvalues = k;
+        else
+            measurementstructure.data(end+1).name = components{k};
+            componentdata(end+1).name = components{k};
+            componentdata(end).indexvalues = k;
+        end
+    end
+end
+    
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get componentnotes
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%    
+% parse the componentnotes
+componentnotesall = regexp(componentnotesraw,'([^\n]*)','tokens');
+for k = 1:length(componentnotesall),
+    componentnotesk = componentnotesall{k}{1};
+    % get componentname
+    index = strfind(componentnotesk,':');
+    componentname = componentnotesk(1:index(1)-1);
+    componentnotes = componentnotesk(index(1)+1:end);
+    index = strmatchIQM(componentname,{componentdata.name},'exact');
+    if isempty(index),
+        errorMsg = sprintf('%sNote for component ''%s'' defined but the component does not exist.\n',errorMsg,componentname);
+    else
+        if ~isempty(componentnotes),
+            measurementstructure.data(index).notes = strtrim(componentnotes);
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get values and time
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% delete spaces
+values = regexprep(valuesraw,' ','');
+% replace ",," events by ",NaN,"
+values = regexprep(values,',,',',NaN,');
+values = regexprep(values,',,',',NaN,');
+% replace empty elements at the end of each row with ",NaN"
+values = regexprep(values,',\n',',NaN\n');
+valuesmatrix = eval(sprintf('[%s]',values));
+% assign the time vector into the structure
+measurementstructure.time = valuesmatrix(:,timeindex);
+% assign the measurement data into the structure
+for k=1:length(componentdata),
+    measurementstructure.data(k).values = valuesmatrix(:,componentdata(k).indexvalues);
+end
+% assign the error bound data if present (and corresponding component
+% present too ... otherwise warning).
+for k=1:length(errorbounddata),
+    indexcomponent = strmatchIQM(errorbounddata(k).name,{componentdata.name},'exact');
+    if isempty(indexcomponent),
+        warning('Component ''%s'' has given error bound but does not exist in the data file.',errorbounddata(k).name);
+    else
+        if strcmp(errorbounddata(k).type,'max'),
+            measurementstructure.data(indexcomponent).maxvalues = valuesmatrix(:,errorbounddata(k).indexvalues);
+        else
+            measurementstructure.data(indexcomponent).minvalues = valuesmatrix(:,errorbounddata(k).indexvalues);
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Fill the nonavailable errorbounds with NaN
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for k=1:length(measurementstructure.data),
+    if isempty(measurementstructure.data(k).minvalues) || isempty(measurementstructure.data(k).maxvalues),
+        measurementstructure.data(k).maxvalues = NaN(size(measurementstructure.data(k).values));
+        measurementstructure.data(k).minvalues = NaN(size(measurementstructure.data(k).values));
+    end
+end
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/measurementhandling/IQMimportXLSmeasurement.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/measurementhandling/IQMimportXLSmeasurement.m
new file mode 100644
index 0000000000000000000000000000000000000000..68a3b5bfe68cedcb4a53a70c7897d9ee58961859
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/measurementhandling/IQMimportXLSmeasurement.m	
@@ -0,0 +1,256 @@
+function [output,errorMsg] = IQMimportXLSmeasurement(filename)
+% IQMimportXLSmeasurement
+% Imports experimental measurement data stored in an XLS Excel file
+% into the measurementstructure used by the IQMmeasurement object.
+% Please note that a special format of the excel data is required. 
+% This format is explained in the user's reference manual and example 
+% files can be found in the IQMlite/examples folder.
+% 
+% filename: name of the .xls file containing the data
+%
+% output: cell-array with data structures used by
+%         IQMmeasurement object  (empty if error occurred).
+%         One element of the cell-array corresponds to one
+%         sheet in the excel file.
+% errorMsg: string containing possible error messages. 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INITIALIZATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+errorMsg = '';
+measurementstructure = struct(IQMmeasurement());
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Determine number of sheets
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[typ, dsc] = xlsfinfo(filename);
+nrsheets = length(dsc);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Process one sheet at a time
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+output = {};
+for sheet=1:nrsheets,
+    % Read the current sheet
+    warning off;
+    [NUMERIC,TXT,RAW] = xlsread(filename,dsc{sheet});
+    warning on;
+    % Check if current sheet is a valid measurement sheet
+    % to be that it requires 'Name' in A1.
+    if iscell(RAW),
+        testSheet = RAW{1,1};
+        if ischar(testSheet),
+            if strcmp(strtrim(lower(RAW{1,1})),'name'),
+                % Sheet is valid (probably ;))
+                % Process the raw information and fill in the measurement data
+                % structure
+                [output{end+1}, errorMsg] = processData(RAW,sheet,errorMsg);
+            end
+        end
+    end
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Process RAW Data
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [measurementstructure,errorMsg] = processData(RAW,sheet,errorMsg)
+% initialize empty measurement structure
+measurementstructure = struct(IQMmeasurement());
+% get size of RAW matrix
+[nrows, ncols] = size(RAW);
+% each identifier needs to appear but only once!
+% furthermore, the identifieres need to appear in the correct order!
+rowName = 0;
+rowNotes = 0;
+rowComponentnotes = 0;
+rowComponents = 0;
+rowValues = 0;
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% get rows of identifiers and check the order
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for row=1:nrows,
+    if ~isnan(RAW{row,1}),
+        if strcmp(strtrim(lower(RAW{row,1})),'name'),
+            rowName = row;
+            if rowNotes+rowComponents+rowComponentnotes+rowValues ~= 0,
+                errorMsg = sprintf('%sIdentifier ''Name'' in sheet %d does not come in correct order.\n',errorMsg,sheet);
+            end
+        end
+        if strcmp(strtrim(lower(RAW{row,1})),'notes'),
+            rowNotes = row;
+            if rowComponents+rowComponentnotes+rowValues ~= 0,
+                errorMsg = sprintf('%sIdentifier ''Notes'' in sheet %d does not come in correct order.\n',errorMsg,sheet);
+            end
+        end
+        if strcmp(strtrim(lower(RAW{row,1})),'componentnotes'),
+            rowComponentnotes = row;
+            if rowComponents + rowValues ~= 0,
+                errorMsg = sprintf('%sIdentifier ''Componentnotes'' in sheet %d does not come in correct order.\n',errorMsg,sheet);
+            end
+        end
+        if strcmp(strtrim(lower(RAW{row,1})),'components'),
+            rowComponents = row;
+            if rowValues ~= 0,
+                errorMsg = sprintf('%sIdentifier ''Components'' in sheet %d does not come in correct order.\n',errorMsg,sheet);
+            end
+        end
+        if strcmp(strtrim(lower(RAW{row,1})),'values'),
+            rowValues = row;
+        end
+        % check if all identifiers found then break the loop
+        if rowName*rowNotes*rowComponents*rowComponentnotes*rowValues ~= 0,
+            break;
+        end
+    end
+end
+% check if all identifiers present
+if rowName*rowNotes*rowComponents*rowComponentnotes*rowValues == 0,
+    errorMsg = sprintf('%sAt least one identifier is missing in in sheet %d.\n',errorMsg,sheet);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Name
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Name only one line but several columns
+name = '';
+for col=2:ncols,
+    if ~isnan(RAW{rowName,col}),
+        if ischar(RAW{rowName,col}),
+            name = sprintf('%s %s',name,RAW{rowName,col});
+        end
+    else
+        break;
+    end
+end
+measurementstructure.name = strtrim(name);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Notes
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Notes several lines and several columns
+notes = '';
+spaceYes = 1;
+for row=rowNotes:rowComponentnotes-1,
+    for col=2:ncols,
+        if ~isnan(RAW{row,col}),
+            if ischar(RAW{row,col}),
+                if spaceYes,
+                    notes = sprintf('%s %s',notes,strtrim(RAW{row,col}));
+                else
+                    notes = sprintf('%s%s',notes,strtrim(RAW{row,col}));
+                    spaceYes = 1;
+                end
+            end
+        end
+    end
+    notes = sprintf('%s\n',strtrim(notes)); 
+    spaceYes = 0;
+end
+measurementstructure.notes = notes;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Components
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+components = {};
+for col = 2:ncols,
+    if ~isnan(RAW{rowComponents,col}),
+        components{end+1} = regexprep(RAW{rowComponents,col},' ','');
+    else
+        break;
+    end
+end
+% find 'time' component
+timeindex = strmatchIQM('time',components,'exact');
+% initialize help structure for min max values (error bounds) + components
+errorbounddata = struct('name',{},'type',{},'indexvalues',{});
+componentdata = struct('name',{},'indexvalues',{});
+% fill in component names/formulas in structure
+for k=1:length(components),
+    if k ~= timeindex,
+        % check if componentname defines an upper or lower bound
+        if ~isempty(regexp(components{k},'[+]')),
+            % component defines an upper bound
+            errorbounddata(end+1).name = regexprep(components{k},'\W','');
+            errorbounddata(end).type = 'max';
+            errorbounddata(end).indexvalues = k;
+        elseif ~isempty(regexp(components{k},'[-]')),
+            % component defines a lower bound
+            errorbounddata(end+1).name = regexprep(components{k},'\W','');
+            errorbounddata(end).type = 'min';
+            errorbounddata(end).indexvalues = k;
+        else
+            measurementstructure.data(end+1).name = components{k};
+            componentdata(end+1).name = components{k};
+            componentdata(end).indexvalues = k;
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Componentnotes
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+index = 1;
+for k = 1:length(componentdata)
+    col = componentdata(k).indexvalues+1;
+    if ~isnan(RAW{rowComponentnotes,col}),
+        if ischar(RAW{rowComponentnotes,col}),
+            componentnotes = RAW{rowComponentnotes,col};
+            measurementstructure.data(k).notes = strtrim(componentnotes);
+        end
+    else
+        measurementstructure.data(k).notes = '';
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Values and errorbounds
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% get values matrix
+try
+    valuesmatrix = cell2mat(RAW(rowValues:nrows,2:length(components)+1));
+catch
+    error('Please check the datatypes in the values section of the Excel file.');
+end
+time = valuesmatrix(:,timeindex);
+% check for first occurrence of NaN in time vector ... then cut off.
+indexNaN = find(isnan(time)==1);
+if isempty(indexNaN),
+    numbertimesteps = length(time);
+else
+    numbertimesteps = indexNaN(1)-1;
+end
+measurementstructure.time = time(1:numbertimesteps);
+% assign the measurement data into the structure
+% assign the measurement data into the structure
+for k=1:length(componentdata),
+    measurementstructure.data(k).values = valuesmatrix(1:numbertimesteps,componentdata(k).indexvalues);
+end
+% assign the error bound data if present (and corresponding component
+% present too ... otherwise warning).
+for k=1:length(errorbounddata),
+    indexcomponent = strmatchIQM(errorbounddata(k).name,{componentdata.name},'exact');
+    if isempty(indexcomponent),
+        warning('Component ''%s'' has given error bound but does not exist in the data file.',errorbounddata(k).name);
+    else
+        if strcmp(errorbounddata(k).type,'max'),
+            measurementstructure.data(indexcomponent).maxvalues = valuesmatrix(1:numbertimesteps,errorbounddata(k).indexvalues);
+        else
+            measurementstructure.data(indexcomponent).minvalues = valuesmatrix(1:numbertimesteps,errorbounddata(k).indexvalues);
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Fill the nonavailable errorbounds with NaN
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for k=1:length(measurementstructure.data),
+    if isempty(measurementstructure.data(k).minvalues) || isempty(measurementstructure.data(k).maxvalues),
+        measurementstructure.data(k).maxvalues = NaN(size(measurementstructure.data(k).values));
+        measurementstructure.data(k).minvalues = NaN(size(measurementstructure.data(k).values));
+    end
+end
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/measurementhandling/IQMmeasurementdata.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/measurementhandling/IQMmeasurementdata.m
new file mode 100644
index 0000000000000000000000000000000000000000..06ede8b426a8e2e9009cffb0086eb4d3a104d546
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/measurementhandling/IQMmeasurementdata.m	
@@ -0,0 +1,64 @@
+function [time, componentNames, values, minvalues, maxvalues] = IQMmeasurementdata(measurement)
+% IQMmeasurementdata
+% This functions allows to extract information from an IQMmeasurement structure
+% 
+% USAGE:
+% ======
+% [time, componentNames] = IQMmeasurementdata(measurement)
+% [time, componentNames, values] = IQMmeasurementdata(measurement)
+% [time, componentNames, values,minvalues,maxvalues] = IQMmeasurementdata(measurement)
+% 
+% measurement: IQMmeasurement object
+%
+% Output Arguments:
+% =================
+% time: time vector of all measurement instants
+% componentNames: cell-array containing the names of the measured components
+% values: matrix containing all the measurements of the components.
+%   One row per time instant and one column per measured component.
+%   The ordering of the columns corresponds to the ordering of the names in
+%   the "componentNames" output variable. Non measured elements are set to
+%   NaN (not a number).
+% minvalues: matrix containing all the min values for the measured components.
+%   One row per time instant and one column per measured component.
+%   The ordering of the columns corresponds to the ordering of the names in
+%   the "componentNames" output variable. Non measured elements are set to
+%   NaN (not a number).
+% maxvalues: matrix containing all the max values for the measured components.
+%   One row per time instant and one column per measured component.
+%   The ordering of the columns corresponds to the ordering of the names in
+%   the "componentNames" output variable. Non measured elements are set to
+%   NaN (not a number).
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+if ~isIQMmeasurement(measurement),
+    error('Input argument is not an IQMmeasurement.');
+end
+measurement = struct(measurement);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF MODEL CONTAINS MEASUREMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if length(measurement.data) == 0,
+    error('The model does not contain any measurements');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET INFORMATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% get time vector
+time = measurement.time;
+% get component names
+componentNames = {};
+values = [];
+minvalues = [];
+maxvalues = [];
+for k=1:length(measurement.data),
+    componentNames{end+1} = measurement.data(k).name;
+    values(:,end+1) = measurement.data(k).values;
+    minvalues(:,end+1) = measurement.data(k).minvalues;
+    maxvalues(:,end+1) = measurement.data(k).maxvalues;
+end
+return
+
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/measurementhandling/IQMvisualizemeasurement.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/measurementhandling/IQMvisualizemeasurement.m
new file mode 100644
index 0000000000000000000000000000000000000000..e59ec3f3dbb90425a086905748a45e1fe1ea0736
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/measurementhandling/IQMvisualizemeasurement.m	
@@ -0,0 +1,90 @@
+function [varargout] = IQMvisualizemeasurement(measurement)
+% IQMvisualizemeasurement
+% Function allowing to visualize the content of an IQMmeasurement object. 
+% The function just prepares the data. Display is then realized using
+% the IQMplot function.
+% 
+% USAGE:
+% ======
+% [] = IQMvisualizemeasurement(measurement)
+% [output] = IQMvisualizemeasurement(measurement)
+%
+% measurement: IQMmeasurement object containing the data
+%
+% Output Arguments:
+% =================
+% If an output argument is specified, the data are not plotted, but a
+% structure is returned that can be used as input argument for IQMplot to
+% show the data.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+% convert IQMmeasurement object to struct
+measurement = IQMstruct(measurement);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF MODEL CONTAINS MEASUREMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if length(measurement.data) == 0,
+    error('The IQMmeasurement object does not contain any measurements.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET TIME VECTOR
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+time = measurement.time;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS THE DATA INTO A MATRIX
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% also construct dataNames and legendtext data
+dataNames = {};
+dataMatrix = NaN*ones(length(measurement.time),length(measurement.data));
+timeMatrix = dataMatrix;
+dataErrorindices = [];
+dataMinvalues = [];
+dataMaxvalues = [];
+
+legendtext = {};
+for k = 1:length(measurement.data),
+    name = measurement.data(k).name;
+    dataNames{k} = name;
+    if ~isempty(measurement.data(k).notes),
+        legendtext{k} = sprintf('%s (%s)',name,measurement.data(k).notes);
+    else
+        legendtext{k} = sprintf('%s',name);
+    end
+    dataComponent = measurement.data(k).values;
+    timeComponent = measurement.time;
+    dataComponent = dataComponent;
+    timeComponent = timeComponent;
+    dataMatrix(1:length(dataComponent),k) = dataComponent;
+    timeMatrix(1:length(timeComponent),k) = timeComponent;
+
+    % Process error bounds if present (only if both are present)
+    if ~isempty(measurement.data(k).maxvalues) && ~isempty(measurement.data(k).minvalues),
+        if length(measurement.data(k).minvalues) ~= length(measurement.data(k).maxvalues),
+            warning('Measurement ''%s'' does have different numbers of max and min bounds.',measurement.data(k).name);
+        else
+            dataErrorindices(end+1) = k;
+            dataMinvalues(1:length(measurement.data(k).minvalues),end+1) = measurement.data(k).minvalues;
+            dataMaxvalues(1:length(measurement.data(k).maxvalues),end+1) = measurement.data(k).maxvalues;
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle variable output arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Keep the commented part as long as it works!
+if nargout==0,
+    % plot
+%    IQMplot(timeMatrix,dataMatrix,dataNames,dataErrorindices,dataMinvalues,dataMaxvalues,legendtext,'*:',measurement.name);
+    IQMplot(timeComponent,dataMatrix,dataNames,dataErrorindices,dataMinvalues,dataMaxvalues,legendtext,'*',measurement.name);
+elseif nargout == 1,
+%    varargout{1} = createdatastructIQMplotIQM(timeMatrix,dataMatrix,dataNames,dataErrorindices,dataMinvalues,dataMaxvalues,legendtext,'*:',measurement.name);
+    varargout{1} = createdatastructIQMplotIQM(timeComponent,dataMatrix,dataNames,dataErrorindices,dataMinvalues,dataMaxvalues,legendtext,'*',measurement.name);
+else
+    error('Incorrect number of output arguments.');
+end
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/measurementhandling/isIQMmeasurement.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/measurementhandling/isIQMmeasurement.m
new file mode 100644
index 0000000000000000000000000000000000000000..7a476026708356092d34d39cf39d75894d8e4365
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/measurementhandling/isIQMmeasurement.m	
@@ -0,0 +1,6 @@
+function [output] = isIQMmeasurement(input)
+% isIQMmeasurement: check if input argument is an IQMmeasurement.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+output = strcmp(class(input),'IQMmeasurement');
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMalgebraic.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMalgebraic.m
new file mode 100644
index 0000000000000000000000000000000000000000..1244905c60585d28d55e29b788bf04d0f68f2490
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMalgebraic.m	
@@ -0,0 +1,31 @@
+function [names,formulas] = IQMalgebraic(model)
+% IQMalgebraic: Returns information about the algebraic equations in a model.
+%
+% USAGE:
+% ======
+% [names,formulas] = IQMalgebraic(model)
+%
+% model: IQMmodel or m-file ODE description of model
+%
+% Output Arguments:
+% =================
+% names: cell-array with names of the variables that are determined using
+% algebraic equations.
+% formulas: cell-array with right hand side formula for the algebraic rules
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS IQMMODEL OR ODE FILE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isIQMmodel(model),
+    iqm = IQMstruct(model);
+    names = {iqm.algebraic.name};
+    formulas = {iqm.algebraic.formula};
+else
+    names = feval(model,'algebraic');
+    formulas = {};
+end
+names = names(:);
+formulas = formulas(:);
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMcalcICvector.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMcalcICvector.m
new file mode 100644
index 0000000000000000000000000000000000000000..686a5d7419c3e561cf2d8f586ce252844a6e3e12
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMcalcICvector.m	
@@ -0,0 +1,182 @@
+function [output] = IQMcalcICvector(model,varargin)
+% IQMcalcICvector: This function determines an IC vector for models with
+% non-numeric initial conditions. These can depend on other initial
+% conditions and on the model parameters. If no new initial conditions or
+% parameters are specified as input arguments to the function the nominal
+% values are used that are stored in the model. Otherwise the information
+% in the additional input arguments is used to determine the new initial
+% conditions. For models with only numeric initial conditions either the
+% ones stored in the model are returned or the ICs provided as input
+% argument are returned. The definition of a parameter vector as input
+% argument will not have an effect in this case.
+%
+% USAGE:
+% ======
+% [output] = IQMcalcICvector(model)
+% [output] = IQMcalcICvector(model,IC)
+% [output] = IQMcalcICvector(model,IC,parametervector)
+%
+% model: IQMmodel, ODE, or MEX file model description
+% IC: cell-array with statenames for which to give back the initial
+%   conditions.
+% parametervector: vector with initial conditions to update the model with
+%
+% Output Arguments:
+% =================
+% output: determined numeric initial condition vector
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EXTRACT SOME INFO FROM THE MODEL
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% get the models ICs and statenames
+if isIQMmodel(model),
+    ms = struct(model);
+    if hasonlynumericICsIQM(model),
+        mics = [ms.states.initialCondition];
+    else
+        mics = {ms.states.initialCondition};
+    end
+    sn = {ms.states.name};    
+else
+    % assume model is an ODE or MEX file
+    % We need to handle ODE and MEX files differently, since ODE files can use 
+    % algebraic expressions, but MEX files can not and this translates to different lengths in the IC vector
+    
+    % Handling MEX models
+    mics = feval(model);
+    sn = feval(model,'states'); 
+    
+    % Append some info if using ODE models and algebraic equations present
+    try
+        % only working for ODE models -  in case of MEX models an error will occurr
+        an = feval(model,'algebraic');
+        for ii = 1:length(an)
+            sn{end+ii} = an{ii};
+        end
+    catch
+        % do nothing in case of MEX models
+    end
+end
+% get the models parameter values
+[pn,pv] = IQMparameters(model);
+[vn,vf] = IQMvariables(model);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin == 1,
+    IC = [];
+    % use the models nominal parameters
+    parametervector = pv;
+elseif nargin == 2,
+    IC = varargin{1};
+    % use the models nominal parameters
+    parametervector = pv;
+elseif nargin == 3,
+    IC = varargin{1};
+    parametervector = varargin{2};
+else
+    error('Incorrect number of input arguments.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK INPUTS (IC and parametervector)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(IC) && length(IC) ~= length(mics),
+    error('Length of initial condition vector does not fit the number of states in the model.');
+end
+if ~isempty(parametervector) && length(parametervector) ~= length(pv),
+    error('Length of parameter vector does not fit the number of parameters in the model.');
+end
+if isempty(parametervector),
+    parametervector = pv;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE MODEL WITH NUMERIC ICs
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if hasonlynumericICsIQM(model),
+    if isempty(IC),
+        % return the nominal initial condition vector in the model
+        output = mics(:);
+        return
+    else
+        % return the initial condition vector provided as input argument
+        output = IC(:);
+        return
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE MODEL WITH NON NUMERIC ICs
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% mics is a cell-array, IC a double vector either empty or with new values.
+% the ones corresponding to non-numeric ICs are neglected. 
+% 1) update the mics vector by merging with the IC vector
+if ~isempty(IC),
+    for k=1:length(mics),
+        % do not change the non-numeric ICs
+        if isnumeric(mics{k}),
+            mics{k} = IC(k);
+        end
+    end
+end
+% 2) From now on we only need to handle mics and parametervector. For 
+% uniqueness "parametervector" is renamed to "pv_1a2b3c" and pn to 
+% "pn_1a2b3c", etc.
+pv_1a2b3c = parametervector;
+pn_1a2b3c = pn;
+vn_1a2b3c = vn;
+vf_1a2b3c = vf;
+mics_1a2b3c = mics;
+sn_1a2b3c = sn;
+% 3) define all model parameters (nominal or provided) in the workspace
+for k_1a2b3c = 1:length(pv_1a2b3c),
+    eval(sprintf('%s = pv_1a2b3c(k_1a2b3c);',pn_1a2b3c{k_1a2b3c}));
+end
+allDefined = 0;
+ic_1a2b3c = [];
+count = 0;
+while ~allDefined && count<10,
+    count = count + 1;
+    % 4) define all model variables in the workspace
+    for k_1a2b3c = 1:length(vn_1a2b3c),
+        try
+            eval(sprintf('%s = %s;',vn_1a2b3c{k_1a2b3c},vf_1a2b3c{k_1a2b3c}));
+            allDefined = 1;            
+        catch
+            allDefined = 0;
+        end
+    end
+    % 5) determine the output initial condition vector by evaluating all cells
+    % in mics (in the order of mics).
+
+    for k_1a2b3c = 1:length(mics_1a2b3c),
+        if isnumeric(mics_1a2b3c{k_1a2b3c}),
+            % if ic entry is numeric then copy it in ic_1a2b3c and
+            % define the corresponding state in the workspace
+            ic_1a2b3c(k_1a2b3c) = mics_1a2b3c{k_1a2b3c};
+            eval(sprintf('%s = ic_1a2b3c(end);',sn_1a2b3c{k_1a2b3c}));
+        else
+            % if ic entry is non-numeric then evaluate this entry, store it in
+            % the ic_1a2b3c vector and define the corresponding state in the
+            % workspace
+            try
+                ic_1a2b3c(k_1a2b3c) = eval(mics_1a2b3c{k_1a2b3c});
+                eval(sprintf('%s = ic_1a2b3c(end);',sn_1a2b3c{k_1a2b3c}));
+                allDefined = 1;
+            catch
+                allDefined = 0;                
+                %             error('Problem with non-numeric initial condition for state ''%s''.\nNOTE: non-numeric ICs are evaluated in a certain order:\n  1) TEXT-models:   order given by the ordering of the ODEs.\n  2) TEXTBC-models: order given by the ordering of the initial conditions.',sn_1a2b3c{k_1a2b3c});
+            end
+        end
+    end
+end
+if ~allDefined,
+    error('Trouble finding numeric initial conditions.');
+end
+% Its done, just return the calculated ic vector
+output = ic_1a2b3c;
+end
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMconvert2MA.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMconvert2MA.m
new file mode 100644
index 0000000000000000000000000000000000000000..7feca53d6e007e01cad8569cfba3f433af587fd4
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMconvert2MA.m	
@@ -0,0 +1,129 @@
+function [MAstructure] = IQMconvert2MA(model)
+% IQMconvert2MA: Takes an IQMmodel and if possible returns the stoichiometric
+% matrix, the numeric kinetic parameters, and the initial conditions. The
+% IQMmodel is not allowed to contain variables, functions, events, or
+% functionsMATLAB. All right hand sides of the ODEs have to be defined in
+% terms of reaction names. All reactions need to be irreversible and mass action type! 
+%
+% Please note that the function is NOT parsing the reaction kinetics to
+% check if they are correct mass action kinetic rate laws. The user needs
+% to make sure that this is the case. Examples of correct expressions are:
+%   Reaction = k * species1 * species2
+%   Reaction = species1 * species2 * k
+%   Reaction = k * species1
+%   Reaction = 3.141592 * species1^2
+%   Reaction = species1^2
+% The kinetic rate constant is then simply determined by setting all
+% species concentrations to 1 and evaluating the rate expressions.
+%
+% USAGE:
+% ======
+% [MAstructure] = IQMconvert2MA(model) 
+%
+% model: IQMmodel 
+%
+% Output Arguments:
+% =================
+% MAstructure: structure containing information about the MA model
+%          MAstructure.N: stoichiometric matrix
+%          MAstructure.L: reactant stoichiometric matrix
+%          MAstructure.kineticParameters: vector containing the kinetic
+%               parameters for each reaction
+%          MAstructure.initialConditions: vector of initial conditions for all
+%               species
+%          MAstructure.species: cell-array with species names
+%          MAstructure.reactions: cell-array with reaction names
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE NON-NUMERIC INITIAL CONDITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% just by replacing them
+model = IQMconvertNonNum2NumIC(model);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Process the model
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% make all reactions irreversible (if necessary)
+modelirr = IQMmakeirreversible(model);
+% take away parenthesis around backward reaction expressions
+ms = struct(modelirr);
+for k = 1:length(ms.reactions),
+    ms.reactions(k).formula = strrep(ms.reactions(k).formula,'(','');
+    ms.reactions(k).formula = strrep(ms.reactions(k).formula,')','');
+end
+model = IQMmodel(ms);
+IQMstructure = IQMstruct(model);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF NON DESIRED ELEMENTS ARE PRESENT IN THE MODEL
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% undesired: 
+%            - functions
+%            - variables
+%            - events
+%            - functionsMATLAB
+%            - states defined by rule
+% check functions, variables, events, functionsMATLAB
+if ~isempty(IQMstructure.functions),
+    error('The model contains functions. This is not allowed when converting it to an MA representation.');
+end
+if ~isempty(IQMstructure.variables),
+    error('The model contains variables. This is not allowed when converting it to an MA representation.');
+end
+if ~isempty(IQMstructure.events),
+    error('The model contains events. This is not allowed when converting it to an MA representation.');
+end
+if ~isempty(IQMstructure.functionsMATLAB),
+    error('The model contains MATLAB functions. This is not allowed when converting it to an MA representation.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK FOR REVERSIBLE REACTIONS (NOT ALLOWED)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[reactionNames, reactionFormulas] = IQMreactions(model);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET THE (REACTANT) STOICHIOMETRIC MATRIX 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% also check if states are defined by rules, that is, not by summation of
+% reaction terms. easily done by checking the stoichiometric matrix and 
+% comparing number of components in it and number of all states in the
+% model.
+allStates = IQMstates(model);
+[N,componentNames,reactionNames,reversibleFlag] = IQMstoichiometry(model);
+if length(allStates) ~= length(componentNames),
+    error('Not all ODEs are expressed in terms of reactions. The full stoichiometric matrix can thus not be determined.');
+end
+L = IQMreactantstoichiometry(model);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET THE KINETIC PARAMETERS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% do it very easy ... just set all concentrations to 1 and evaluate the
+% rate expressions. Under the required format for the rate expressions this
+% gives the kinetic parameters.
+[x,y,z,a,kineticParameters] = IQMreactions(model,ones(1,length(allStates)));
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET THE INITIAL CONDITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+initialconditions = IQMinitialconditions(model);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% FORMAT OUTPUT VALUES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+MAstructure.N = N;
+MAstructure.L = L;
+MAstructure.kineticParameters = kineticParameters(:);
+MAstructure.initialConditions = initialconditions(:);
+MAstructure.species = allStates;
+MAstructure.reactions = {IQMstructure.reactions.name}';
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% RETURN
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+return
+
+
+
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMconvertNonNum2NumIC.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMconvertNonNum2NumIC.m
new file mode 100644
index 0000000000000000000000000000000000000000..ca6b54495ecc57077d4abe7faf84a33c3487702a
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMconvertNonNum2NumIC.m	
@@ -0,0 +1,41 @@
+function [newmodel] = IQMconvertNonNum2NumIC(model)
+% IQMconvertNonNum2NumIC: This function converts non-numeric iniital
+% conditions to numeric initial conditions in the model and returns the
+% updated model. Models with numeric ICs are unaffected.
+%
+% USAGE:
+% ======
+% [newmodel] = IQMconvertNonNum2NumIC(model)
+%
+% model: IQMmodel
+%
+% Output Arguments:
+% =================
+% newmodel: IQMmodel where non-numeric ICs have been replaced by numeric ICs
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isIQMmodel(model),
+    error('Input argument needs to be an IQMmodel.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% NUMERIC ICs ONLY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if hasonlynumericICsIQM(model),
+    newmodel = model;
+    return
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% NON-NUMERIC ICs
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+numICs = IQMcalcICvector(model);
+ms = struct(model);
+for k=1:length(ms.states),
+    ms.states(k).initialCondition = numICs(k);
+end
+newmodel = IQMmodel(ms);
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMcreateODEfile.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMcreateODEfile.m
new file mode 100644
index 0000000000000000000000000000000000000000..a143acc7e570aa1c16f962aa518406b9ce38ea0f
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMcreateODEfile.m	
@@ -0,0 +1,633 @@
+function IQMcreateODEfile(varargin)
+% IQMcreateODEfile: creates an m-file that can be simulated by 
+% using standard MATLAB integrators (ODE45, ODE23s, etc.)
+%
+% USAGE:
+% ======
+% [] = IQMcreateODEfile(iqm)         
+% [] = IQMcreateODEfile(iqm,filename)
+% [] = IQMcreateODEfile(iqm,filename,dataFileFlag)
+% [] = IQMcreateODEfile(iqm,filename,dataFileFlag,eventFlag)
+% [] = IQMcreateODEfile(iqm,filename,dataFileFlag,eventFlag,augmKernelName)
+%
+% iqm: IQMmodel to convert to an ODE file description
+% filename: filename for the created ODE file (without extension)
+% dataFileFlag: =1: creates an additional file allowing to determine
+%                   variable and reaction rate values for given state values 
+%                   and time vector.
+%               =0: doe not create the additional file
+% eventFlag: =1: creates 2 additional files for the handling of events in the model. 
+%            =0: does not create these two files.
+%            THE EVENT FILES ARE ONLY CREATED IN CASE THAT EVENTS ARE
+%            PRESENT IN THE MODEL
+% augmKernelName: needed for the simulation of fast reactions. It is the
+%           name of the global variable in which the mass matrix is
+%           defined. The name comes from the fact that the null space of
+%           the fast stoichiometric matrix is contained in the mass matrix.
+%            
+% DEFAULT VALUES:
+% ===============
+% filename: constructed from the models name
+% dataFileFlag: 0
+% eventFlag: 0
+% augmKernelName: ''
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GENERATE DELAY BASE NAME
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[dummy,delaybase] = fileparts(tempname);
+delaybase = char([double('delaybase_') double(delaybase(1:8))]);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+dataFileFlag = 0;
+eventFlag = 0;
+augmKernelName = '';
+tempFlag = 0;
+if nargin == 1,
+    iqm = varargin{1};
+    % convert object to structure
+    iqmstruct = struct(iqm);
+    % if no filename provided then use the name of the IQMmodel as filename
+    % remove white spaces from the name.
+    functionName = strrep(iqmstruct.name,' ','');
+    functionName = strrep(functionName,'-','');
+    functionName = strrep(functionName,'+','');
+    functionName = strrep(functionName,'*','');
+    functionName = strrep(functionName,'/','');
+    filename = strcat(functionName,'.m');
+elseif nargin == 2,
+    iqm = varargin{1};
+    % convert object to structure
+    iqmstruct = struct(iqm);    
+    % extract filename from input argument number 2 - needed since 
+    % IQMsimulate gives a whole path as filename
+    [PATHSTR,functionName,EXT] = fileparts(varargin{2});
+    if isempty(PATHSTR),
+        filename = strcat(functionName,'.m');
+    else
+        filename = strcat(PATHSTR,'/',functionName,'.m');
+    end
+elseif nargin == 3,
+    iqm = varargin{1};
+    % convert object to structure
+    iqmstruct = struct(iqm);    
+    % extract filename from input argument number 2 - needed since 
+    % IQMsimulate gives a whole path as filename
+    [PATHSTR,functionName,EXT] = fileparts(varargin{2});
+    if isempty(PATHSTR),
+        filename = strcat(functionName,'.m');
+    else
+        filename = strcat(PATHSTR,'/',functionName,'.m');
+    end
+    dataFileFlag = varargin{3};
+elseif nargin == 4,
+    iqm = varargin{1};
+    % convert object to structure
+    iqmstruct = struct(iqm);    
+    % extract filename from input argument number 2 - needed since 
+    % IQMsimulate gives a whole path as filename
+    [PATHSTR,functionName,EXT] = fileparts(varargin{2});
+    if isempty(PATHSTR),
+        filename = strcat(functionName,'.m');
+    else
+        filename = strcat(PATHSTR,'/',functionName,'.m');
+    end
+    dataFileFlag = varargin{3};
+    eventFlag = varargin{4};
+elseif nargin == 5,
+    iqm = varargin{1};
+    % convert object to structure
+    iqmstruct = struct(iqm);    
+    % extract filename from input argument number 2 - needed since 
+    % IQMsimulate gives a whole path as filename
+    [PATHSTR,functionName,EXT] = fileparts(varargin{2});
+    if isempty(PATHSTR),
+        filename = strcat(functionName,'.m');
+    else
+        filename = strcat(PATHSTR,'/',functionName,'.m');
+    end
+    dataFileFlag = varargin{3};
+    eventFlag = varargin{4};   
+    augmKernelName = varargin{5};
+elseif nargin == 6,
+    iqm = varargin{1};
+    % convert object to structure
+    iqmstruct = struct(iqm);    
+    % extract filename from input argument number 2 - needed since 
+    % IQMsimulate gives a whole path as filename
+    [PATHSTR,functionName,EXT] = fileparts(varargin{2});
+    if isempty(PATHSTR),
+        filename = strcat(functionName,'.m');
+    else
+        filename = strcat(PATHSTR,'/',functionName,'.m');
+    end
+    dataFileFlag = varargin{3};
+    eventFlag = varargin{4};   
+    augmKernelName = varargin{5};
+    tempFlag = varargin{6}; % set only by IQMcreateTempODEfile to avoid event error message ... its annoying
+else
+    error('Incorrect number of input arguments.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% MAKE augmKernelName a global variable
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(augmKernelName),
+    eval(sprintf('global %s',augmKernelName));
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF MODEL CONTAINS STATES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(iqmstruct.states),
+    error('The model does not contain any states');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE THE EVENT FLAG
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% if the eventflag is set to a non-zero value AND at least on event is
+% present in the model an event function file is created that has to be 
+% used when calling the integrator. additionally a function is created 
+% that determines the new values to which the states have to be set. 
+if eventFlag == 1 && ~isempty(iqmstruct.events),
+    filenameEvent = strrep(filename,functionName,strcat('event_',functionName));
+    filenameEventAssignment = strrep(filename,functionName,strcat('event_assignment_',functionName));
+    createEventFunctionIQM(iqm,filenameEvent,delaybase);
+    createEventAssignmentFunctionIQM(iqm,filenameEventAssignment,delaybase);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE THE DATAFILE FLAG
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if dataFileFlag == 1,
+    filenameDataFile = strrep(filename,functionName,strcat('datafile_',functionName));
+    createSimulationDataFunctionIQM(iqm,filenameDataFile,delaybase);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% WRITE WARNING MESSAGE IN CASE EVENT FLAG IS NOT SET AND EVENTS ARE PRESENT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if eventFlag == 0 && ~isempty(iqmstruct.events) && tempFlag ~= 1,
+    if length(iqmstruct.events) == 1,
+        disp(sprintf('Warning: 1 event is present in the model.\nFor this analysis it is not taken into account.'));
+    else
+        disp(sprintf('Warning: %d events are present in the model.\nFor this analysis they are not taken into account.',length(iqmstruct.events)));
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% OPEN FILE FOR WRITING
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fid = fopen(filename,'w');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% WRITE FUNCTION DEFINITION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'function [output] = %s(varargin)\n',functionName);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% WRITE THE HEADER
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+fprintf(fid,'%% %s\n',iqmstruct.name);
+fprintf(fid,'%% Generated: %s\n',datestr(now));
+fprintf(fid,'%% \n');
+fprintf(fid,'%% [output] = %s() => output = initial conditions in column vector\n',functionName);
+fprintf(fid,'%% [output] = %s(''states'') => output = state names in cell-array\n',functionName);
+fprintf(fid,'%% [output] = %s(''algebraic'') => output = algebraic variable names in cell-array\n',functionName);
+fprintf(fid,'%% [output] = %s(''parameters'') => output = parameter names in cell-array\n',functionName);
+fprintf(fid,'%% [output] = %s(''parametervalues'') => output = parameter values in column vector\n',functionName);
+fprintf(fid,'%% [output] = %s(''variablenames'') => output = variable names in cell-array\n',functionName);
+fprintf(fid,'%% [output] = %s(''variableformulas'') => output = variable formulas in cell-array\n',functionName);
+fprintf(fid,'%% [output] = %s(time,statevector) => output = time derivatives in column vector\n',functionName);
+fprintf(fid,'%% \n');
+fprintf(fid,'%% State names and ordering:\n');
+fprintf(fid,'%% \n');
+for k = 1:length(iqmstruct.states),
+    fprintf(fid,'%% statevector(%d): %s\n',k,iqmstruct.states(k).name);
+end
+fprintf(fid,'%% \n');
+if ~isempty(iqmstruct.algebraic),
+    didWriteStart = 0;
+    offset = length(iqmstruct.states);
+    offset2 = 1;
+    for k = 1:length(iqmstruct.algebraic),
+        if ~isempty(iqmstruct.algebraic(k).name) && didWriteStart == 0,    
+            fprintf(fid,'%% Algebraic variable names and ordering (included in state and IC vector):\n');
+            fprintf(fid,'%% \n'); 
+            didWriteStart = 1;
+        end
+        if ~isempty(iqmstruct.algebraic(k).name),
+            fprintf(fid,'%% statevector(%d): %s\n',offset+offset2,iqmstruct.algebraic(k).name);
+            offset2 = offset2 + 1;
+        end
+    end
+    if didWriteStart == 1,
+        fprintf(fid,'%% \n');
+    end
+end
+fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+fprintf(fid,'\n');
+fprintf(fid,'global time\n');
+if ~isempty(augmKernelName),
+    fprintf(fid,'global %s\n',augmKernelName);
+end 
+fprintf(fid,'parameterValuesNew = [];\n\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE VARARGINS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+fprintf(fid,'%% HANDLE VARIABLE INPUT ARGUMENTS\n');
+fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+fprintf(fid,'if nargin == 0,\n');
+    % Return initial conditions for state variables
+    % If all initial conditions are numeric then a vector is defined.
+    % Otherwise a cell-array with the corresponding entries. An additional
+    % outside function then needs to be used to calculate the correct ICs
+    % from the IC cellarray, IC values, and parameter values.
+    fprintf(fid,'\t%% Return initial conditions of the state variables (and possibly algebraic variables)\n');
+    if hasonlynumericICsIQM(iqm),
+        icvector = [iqmstruct.states.initialCondition iqmstruct.algebraic.initialCondition];
+        if ~isempty(icvector),
+            fprintf(fid,'\toutput = [');
+        else
+            fprintf(fid,'\toutput = [];\n');
+        end
+        count = 0;
+        for k = 1:length(icvector)-1,
+            fprintf(fid,'%1.6g, ',icvector(k));
+            count = count + 1;
+            if count == 10, fprintf(fid,'...\n\t\t'); count = 0; end
+        end
+        if ~isempty(icvector),
+            fprintf(fid,'%1.6g];\n',icvector(end));
+        end
+        fprintf(fid,'\toutput = output(:);\n');
+    else
+        % the model contains non-numeric initial conditions
+        % get the ICs as cell-array
+        icvector = {iqmstruct.states.initialCondition iqmstruct.algebraic.initialCondition};
+        if ~isempty(icvector),
+            fprintf(fid,'\toutput = {');
+        else
+            fprintf(fid,'\toutput = {};\n');
+        end
+        count = 0;
+        for k = 1:length(icvector)-1,
+            if isnumeric(icvector{k}),
+                fprintf(fid,'%g, ',icvector{k});
+            else
+                fprintf(fid,'''%s'', ',strtrim(icvector{k}));
+            end
+            count = count + 1;
+            if count == 10, fprintf(fid,'...\n\t\t'); count = 0; end
+        end
+        if ~isempty(icvector),
+            if isnumeric(icvector{end}),
+                fprintf(fid,'%g};\n',icvector{end});
+            else
+                fprintf(fid,'''%s''};\n',strtrim(icvector{end}));
+            end
+        end
+    end
+    fprintf(fid,'\treturn\n');
+fprintf(fid,'elseif nargin == 1,\n');
+	fprintf(fid,'\tif strcmp(varargin{1},''states''),\n');
+        fprintf(fid,'\t\t%% Return state names in cell-array\n');
+        if ~isempty(iqmstruct.states),
+            fprintf(fid,'\t\toutput = {');
+        else
+            fprintf(fid,'\t\toutput = {};\n');
+        end 
+        count = 0;
+        for k = 1:length(iqmstruct.states)-1,
+            fprintf(fid,'''%s'', ',iqmstruct.states(k).name);
+            count = count + 1;
+            if count == 10, fprintf(fid,'...\n\t\t\t'); count = 0; end
+        end
+        if ~isempty(iqmstruct.states),
+            fprintf(fid,'''%s''};\n',iqmstruct.states(end).name);
+        end
+	fprintf(fid,'\telseif strcmp(varargin{1},''algebraic''),\n');
+        fprintf(fid,'\t\t%% Return algebraic variable names in cell-array\n');
+        if ~isempty(iqmstruct.algebraic),
+            fprintf(fid,'\t\toutput = {');
+        else
+            fprintf(fid,'\t\toutput = {};\n');
+        end 
+        count = 0;
+        for k = 1:length(iqmstruct.algebraic)-1,
+            if ~isempty(iqmstruct.algebraic(k).name),
+                fprintf(fid,'''%s'', ',iqmstruct.algebraic(k).name);
+                count = count + 1;
+                if count == 10, fprintf(fid,'...\n\t\t\t'); count = 0; end
+            end
+        end
+        if ~isempty(iqmstruct.algebraic),
+            if ~isempty(iqmstruct.algebraic(end).name),
+                fprintf(fid,'''%s''};\n',iqmstruct.algebraic(end).name);
+            else
+                fprintf(fid,'};\n');
+            end
+        end
+    fprintf(fid,'\telseif strcmp(varargin{1},''parameters''),\n');
+        fprintf(fid,'\t\t%% Return parameter names in cell-array\n');
+        if ~isempty(iqmstruct.parameters),
+            fprintf(fid,'\t\toutput = {');
+        else
+            fprintf(fid,'\t\toutput = {};\n');
+        end 
+        count = 0;
+        for k = 1:length(iqmstruct.parameters)-1,
+            fprintf(fid,'''%s'', ',iqmstruct.parameters(k).name);
+            count = count + 1;
+            if count == 10, fprintf(fid,'...\n\t\t\t'); count = 0; end
+        end
+        if ~isempty(iqmstruct.parameters),
+            fprintf(fid,'''%s''};\n',iqmstruct.parameters(length(iqmstruct.parameters)).name);
+        end
+    fprintf(fid,'\telseif strcmp(varargin{1},''parametervalues''),\n');
+        fprintf(fid,'\t\t%% Return parameter values in column vector\n');
+        if ~isempty(iqmstruct.parameters),
+            fprintf(fid,'\t\toutput = [');
+        else
+            fprintf(fid,'\t\toutput = [];\n');
+        end 
+        count = 0;
+        for k = 1:length(iqmstruct.parameters)-1,
+            fprintf(fid,'%1.6g, ',iqmstruct.parameters(k).value);
+            count = count + 1;
+            if count == 10, fprintf(fid,'...\n\t\t\t'); count = 0; end
+        end
+        if ~isempty(iqmstruct.parameters),
+            fprintf(fid,'%1.6g];\n',iqmstruct.parameters(length(iqmstruct.parameters)).value);
+        end
+        
+        
+    fprintf(fid,'\telseif strcmp(varargin{1},''variablenames''),\n');
+        fprintf(fid,'\t\t%% Return variable names in cell-array\n');
+        if ~isempty(iqmstruct.variables),
+            fprintf(fid,'\t\toutput = {');
+        else
+            fprintf(fid,'\t\toutput = {};\n');
+        end 
+        count = 0;
+        for k = 1:length(iqmstruct.variables)-1,
+            fprintf(fid,'''%s'', ',iqmstruct.variables(k).name);
+            count = count + 1;
+            if count == 10, fprintf(fid,'...\n\t\t\t'); count = 0; end
+        end
+        if ~isempty(iqmstruct.variables),
+            fprintf(fid,'''%s''};\n',iqmstruct.variables(length(iqmstruct.variables)).name);
+        end
+    fprintf(fid,'\telseif strcmp(varargin{1},''variableformulas''),\n');
+        fprintf(fid,'\t\t%% Return variable formulas in cell-array\n');
+        if ~isempty(iqmstruct.variables),
+            fprintf(fid,'\t\toutput = {');
+        else
+            fprintf(fid,'\t\toutput = {};\n');
+        end 
+        count = 0;
+        for k = 1:length(iqmstruct.variables)-1,
+            fprintf(fid,'''%s'', ',iqmstruct.variables(k).formula);
+            count = count + 1;
+            if count == 10, fprintf(fid,'...\n\t\t\t'); count = 0; end
+        end
+        if ~isempty(iqmstruct.variables),
+            fprintf(fid,'''%s''};\n',iqmstruct.variables(length(iqmstruct.variables)).formula);
+        end
+        
+        
+    fprintf(fid,'\telse\n');
+        fprintf(fid,'\t\terror(''Wrong input arguments! Please read the help text to the ODE file.'');\n');
+    fprintf(fid,'\tend\n');
+    fprintf(fid,'\toutput = output(:);\n');
+    fprintf(fid,'\treturn\n');
+fprintf(fid,'elseif nargin == 2,\n');
+    fprintf(fid,'\ttime = varargin{1};\n');
+    fprintf(fid,'\tstatevector = varargin{2};\n');
+fprintf(fid,'elseif nargin == 3,\n');
+    fprintf(fid,'\ttime = varargin{1};\n');
+    fprintf(fid,'\tstatevector = varargin{2};\n');
+    fprintf(fid,'\tparameterValuesNew = varargin{3};\n');
+    fprintf(fid,'\tif length(parameterValuesNew) ~= %d,\n',length(iqmstruct.parameters));
+    fprintf(fid,'\t\tparameterValuesNew = [];\n');
+    fprintf(fid,'\tend\n');
+fprintf(fid,'elseif nargin == 4,\n');
+    fprintf(fid,'\ttime = varargin{1};\n');
+    fprintf(fid,'\tstatevector = varargin{2};\n');
+    fprintf(fid,'\tparameterValuesNew = varargin{4};\n');
+fprintf(fid,'else\n');
+    fprintf(fid,'\terror(''Wrong input arguments! Please read the help text to the ODE file.'');\n');
+fprintf(fid,'end\n');
+fprintf(fid,'\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INITIALIZE THE STATES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+fprintf(fid,'%% STATES\n');
+fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+for k = 1:length(iqmstruct.states)
+    fprintf(fid,'%s = statevector(%d);\n',iqmstruct.states(k).name,k);
+end
+fprintf(fid,'\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INITIALIZE THE ALGEBRAIC VARIABLES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(iqmstruct.algebraic),
+    didWriteStart = 0;
+    offset = length(iqmstruct.states);
+    offset2 = 1;
+    for k = 1:length(iqmstruct.algebraic)
+        if ~isempty(iqmstruct.algebraic(k).name) && didWriteStart == 0,
+            fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+            fprintf(fid,'%% ALGEBRAIC VARIABLES\n');
+            fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+            didWriteStart = 1;
+        end
+        if ~isempty(iqmstruct.algebraic(k).name),
+            fprintf(fid,'%s = statevector(%d);\n',iqmstruct.algebraic(k).name,offset+offset2);
+            offset2 = offset2 + 1;
+        end
+    end
+    if didWriteStart == 1,
+        fprintf(fid,'\n');
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INITIALIZE THE PARAMETES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(iqmstruct.parameters),
+    fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+    fprintf(fid,'%% PARAMETERS\n');
+    fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+    fprintf(fid,'if isempty(parameterValuesNew),\n');
+    for k = 1:length(iqmstruct.parameters),
+        fprintf(fid,'\t%s = %1.6g;\n',iqmstruct.parameters(k).name,iqmstruct.parameters(k).value);
+    end
+    fprintf(fid,'else\n');
+    for k = 1:length(iqmstruct.parameters),
+        fprintf(fid,'\t%s = parameterValuesNew(%d);\n',iqmstruct.parameters(k).name,k);
+    end
+    fprintf(fid,'end\n');
+    fprintf(fid,'\n');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INITIALIZE THE VARIABLES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(iqmstruct.variables),
+    fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+    fprintf(fid,'%% VARIABLES\n');
+    fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+    for k = 1:length(iqmstruct.variables),
+        delayname = [delaybase '_var_' sprintf('%d',k)];
+        fprintf(fid,'%s = %s;\n',iqmstruct.variables(k).name,processFormulaIQM(iqmstruct.variables(k).formula,delayname));
+    end
+    fprintf(fid,'\n');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INITIALIZE THE REACTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(iqmstruct.reactions),
+    fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+    fprintf(fid,'%% REACTION KINETICS \n');
+    fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+    for k = 1:length(iqmstruct.reactions),
+        delayname = [delaybase '_reac_' sprintf('%d',k)];
+        fprintf(fid,'%s = %s;\n',iqmstruct.reactions(k).name,processFormulaIQM(iqmstruct.reactions(k).formula,delayname));
+    end
+    fprintf(fid,'\n');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DETERMINE ALSO EVENTASSIGNMENTS (NEEDED TO BE ABLE TO HANDEL DELAYS IN
+% EVENT ASSIGNMENTS (for delayed events)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(iqmstruct.events),
+    fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+    fprintf(fid,'%% EVENT ASSIGNMENTS AND TRIGGERS ... to handle delayed events\n');
+    fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+    for k = 1:length(iqmstruct.events),
+        delayname = [delaybase '_eventtrigger_' sprintf('%d',k)];        
+        fprintf(fid,'eventtrigger_%d = %s;\n',k,processFormulaIQM(iqmstruct.events(k).trigger,delayname));
+        for k2 = 1:length(iqmstruct.events(k).assignment),
+            delayname = [delaybase '_eventassign_' sprintf('%d',k) '_' sprintf('%d',k2)];        
+            fprintf(fid,'eventassign_%d_%d = %s;\n',k,k2,processFormulaIQM(iqmstruct.events(k).assignment(k2).formula,delayname));
+        end
+    end
+    fprintf(fid,'\n');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% WRITE THE ODES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+fprintf(fid,'%% DIFFERENTIAL EQUATIONS\n');
+fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+for k = 1:length(iqmstruct.states),   
+    delayname = [delaybase '_ode_' sprintf('%d',k)];
+    fprintf(fid,'%s_dot = %s;\n',iqmstruct.states(k).name,processFormulaIQM(iqmstruct.states(k).ODE,delayname));
+end
+fprintf(fid,'\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% WRITE THE ALGEBRAIC RULES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(iqmstruct.algebraic),
+    fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+    fprintf(fid,'%% ALGEBRAIC RULES\n');
+    fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+    for k = 1:length(iqmstruct.algebraic)
+        fprintf(fid,'AlgebraicRule_%d = %s;\n',k,iqmstruct.algebraic(k).formula);
+    end
+    fprintf(fid,'\n');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% WRITE RETURN VALUES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+fprintf(fid,'%% RETURN VALUES\n');
+fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+if isempty(augmKernelName),
+    fprintf(fid,'%% STATE ODEs\n');
+    for k = 1:length(iqmstruct.states),
+        fprintf(fid,'output(%d) = %s_dot;\n',k,iqmstruct.states(k).name);
+    end
+    if ~isempty(iqmstruct.algebraic),
+        fprintf(fid,'%% ARs\n');
+        offset = length(iqmstruct.states);
+        for k = 1:length(iqmstruct.algebraic),
+            fprintf(fid,'output(%d) = AlgebraicRule_%d;\n',k+offset,k);
+        end
+    end
+else
+    fprintf(fid,'%% STATE ODEs ... HANDLING FAST REACTIONS\n');
+    for k = 1:length(iqmstruct.states),
+        fprintf(fid,'states(%d) = %s_dot;\n',k,iqmstruct.states(k).name);
+    end
+    fprintf(fid,'%% MULTIPLY WITH AUGMENTED KERNEL\n');
+    fprintf(fid,'output = %s*states(:);\n',augmKernelName);
+    if ~isempty(iqmstruct.algebraic),
+        fprintf(fid,'%% ARs\n');
+        offset = eval(sprintf('size(%s,1);',augmKernelName));
+        for k = 1:length(iqmstruct.algebraic),
+            fprintf(fid,'output(%d) = AlgebraicRule_%d;\n',k+offset,k);
+        end
+    end    
+end
+fprintf(fid,'%% return a column vector \n');
+% Return a column vector
+fprintf(fid,'output = output(:);\n');
+fprintf(fid,'return\n');
+fprintf(fid,'\n');
+fprintf(fid,'\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% WRITE THE FUNCTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(iqmstruct.functions),
+    fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+    fprintf(fid,'%% FUNCTIONS\n');
+    fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+    for k = 1:length(iqmstruct.functions),
+        fprintf(fid,'function [result] = %s(%s)\n',iqmstruct.functions(k).name,iqmstruct.functions(k).arguments);
+        fprintf(fid,'global time\n');
+        delayname = [delaybase '_func_' sprintf('%d',k)];        
+        fprintf(fid,'result = %s;\n',processFormulaIQM(iqmstruct.functions(k).formula,delayname));
+        fprintf(fid,'return\n');
+        fprintf(fid,'\n');
+    end
+    fprintf(fid,'\n');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% WRITE THE MATLAB FUNCTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(iqmstruct.functionsMATLAB),
+    fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+    fprintf(fid,'%% MATLAB FUNCTIONS\n');
+    fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+    delayname = [delaybase '_funcmatlab'];
+    fprintf(fid,'%s',processFormulaIQM(iqmstruct.functionsMATLAB,delayname));
+    fprintf(fid,'\n');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CLOSE THE FILE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+status = fclose(fid);
+rehash
+% Return
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMcreateTEXTBCfile.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMcreateTEXTBCfile.m
new file mode 100644
index 0000000000000000000000000000000000000000..3eb999f14859d78c7ba1d05c408e9f05b4b08a37
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMcreateTEXTBCfile.m	
@@ -0,0 +1,49 @@
+function IQMcreateTEXTBCfile(varargin)
+% IQMcreateTEXTBCfile: creates a *.txtbc file with the models text
+% description in a biochemically oriented format
+%
+% USAGE:
+% ======
+% [] = IQMcreateTEXTBCfile(iqm)         
+% [] = IQMcreateTEXTBCfile(iqm,filename)
+%
+% iqm: IQMmodel to convert to a textfile description
+% filename: filename for the created textfile (.txtbc)
+%
+% DEFAULT VALUES:
+% ===============
+% filename: constructed from the models name
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin == 1,
+    iqm = varargin{1};
+    % convert object to structure
+    ms = struct(iqm);    
+    % if no filename provided then use the name of the IQMmodel as filename
+    % remove unwanted characters first
+    functionName = regexprep(ms.name,'\W','');
+    filename = strcat(functionName,'.txtbc');
+elseif nargin == 2,
+    iqm = varargin{1};
+    filename = strcat(varargin{2},'.txtbc');
+else
+    error('Incorrect number of input arguments.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CONVERT MODEL TO TEXT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[modelTextBCStructure] = convertModelToTextBCIQM(iqm);
+[completeTextBC] = setPartsToCompleteTextBCIQM(modelTextBCStructure);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% WRITE THE FILE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fid = fopen(filename,'w');
+fwrite(fid,completeTextBC);
+fclose(fid);
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMcreateTEXTBCmodel.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMcreateTEXTBCmodel.m
new file mode 100644
index 0000000000000000000000000000000000000000..0c844b5c70da069fba04d13f00854e8cd246c88f
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMcreateTEXTBCmodel.m	
@@ -0,0 +1,45 @@
+function [] = IQMcreateTEXTBCmodel(name,varargin)
+% IQMcreateTEXTBCmodel: Creates a new TEXTBC model, saves the corresponding
+% file in the current directory and opens it in the editor, if opening is
+% desired.
+%
+% USAGE:
+% ======
+% IQMcreateTEXTBCmodel(name)
+% IQMcreateTEXTBCmodel(name,openFlag)
+%
+% name: filename of the model and model name
+% openFlag: decides if the created model is automatically opened in the
+%           editor or not. (=0: do not open, =1: do open)
+%
+% DEFAULT VALUES:
+% ===============
+% openFlag: 1 (do open)
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE VARIABE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+openFlag = 1;
+if nargin == 2,
+    openFlag = varargin{1};
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CREATE NEW MODEL
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+model = IQMmodel();
+ms = struct(model);
+ms.name = name;
+model = IQMmodel(ms);
+IQMcreateTEXTBCfile(model,name);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% OPEN IF DESIRED
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if openFlag,
+    edit(strcat(name,'.txtbc'));
+end
+
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMcreateTEXTfile.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMcreateTEXTfile.m
new file mode 100644
index 0000000000000000000000000000000000000000..6e959782d1bcbbee117993f341e238d5a9464f65
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMcreateTEXTfile.m	
@@ -0,0 +1,51 @@
+function IQMcreateTEXTfile(varargin)
+% IQMcreateTEXTfile: creates a *.txt file with the models text description
+% based on ordinary differential equations
+%
+% USAGE:
+% ======
+% [] = IQMcreateTEXTfile(iqm)         
+% [] = IQMcreateTEXTfile(iqm,filename)
+%
+% iqm: IQMmodel to convert to a textfile description
+% filename: filename for the created textfile 
+%
+% DEFAULT VALUES:
+% ===============
+% filename: constructed from the models name
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin == 1,
+    iqm = varargin{1};
+    % convert object to structure
+    ms = struct(iqm);    
+    % if no filename provided then use the name of the IQMmodel as filename
+    % remove unwanted characters first
+    functionName = regexprep(ms.name,'\W','');
+    filename = strcat(functionName,'.txt');
+elseif nargin == 2,
+    iqm = varargin{1};
+    filename = strcat(varargin{2},'.txt');
+else
+    error('Incorrect number of input arguments.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CONVERT MODEL TO TEXT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[modelTextStructure] = convertModelToTextIQM(iqm);
+[completeText] = setPartsToCompleteTextIQM(modelTextStructure);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% WRITE THE FILE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fid = fopen(filename,'w');
+fwrite(fid,completeText);
+fclose(fid);
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMcreateTEXTmodel.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMcreateTEXTmodel.m
new file mode 100644
index 0000000000000000000000000000000000000000..a60dd2621f731ce9c3e869474e141925af5f03a7
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMcreateTEXTmodel.m	
@@ -0,0 +1,45 @@
+function [] = IQMcreateTEXTmodel(name,varargin)
+% IQMcreateTEXTmodel: Creates a new TEXT model, saves the corresponding file
+% in the current directory and opens it in the editor, if opening is
+% desired.
+%
+% USAGE:
+% ======
+% IQMcreateTEXTmodel(name)
+% IQMcreateTEXTmodel(name,openFlag)
+%
+% name: filename of the model and model name
+% openFlag: decides if the created model is automatically opened in the
+%           editor or not. (=0: do not open, =1: do open)
+%
+% DEFAULT VALUES:
+% ===============
+% openFlag: 1 (do open)
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE VARIABE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+openFlag = 1;
+if nargin == 2,
+    openFlag = varargin{1};
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CREATE NEW MODEL
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+model = IQMmodel();
+ms = struct(model);
+ms.name = name;
+model = IQMmodel(ms);
+IQMcreateTEXTfile(model,name);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% OPEN IF DESIRED
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if openFlag,
+    edit(strcat(name,'.txt'));
+end
+
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMcreateTempODEfile.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMcreateTempODEfile.m
new file mode 100644
index 0000000000000000000000000000000000000000..cf70d634c09252e7b0357fce29f27f2d307fd4f0
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMcreateTempODEfile.m	
@@ -0,0 +1,100 @@
+function [ODEfctname, ODEfilefullpath, DATAfctname, EVENTfctname, EVENTASSGNfctname] = IQMcreateTempODEfile(varargin)
+% IQMcreateTempODEfile: creates a temporary ODE file, same as
+% IQMcreateODEfile, but the file is written in the systems temporary
+% directory. Creates also datafile and eventhandling files if wanted.
+% No filename is passed, but a temporary filename is chosen automatically
+% and returned back as output argument.
+%
+% USAGE:
+% ======
+% [ODEfctname, ODEfilefullpath] = IQMcreateTempODEfile(iqm)
+% [ODEfctname, ODEfilefullpath, DATAfctname] = IQMcreateTempODEfile(iqm,dataFileFlag)
+% [ODEfctname, ODEfilefullpath, DATAfctname, EVENTfctname, EVENTASSGNfctname] = IQMcreateTempODEfile(iqm,dataFileFlag,eventFlag)
+% [ODEfctname, ODEfilefullpath, DATAfctname, EVENTfctname, EVENTASSGNfctname] = IQMcreateTempODEfile(iqm,dataFileFlag,eventFlag,augmKernelName)
+%
+% iqm: IQMmodel to convert to an ODE file description
+% dataFileFlag: =1: creates an additional file allowing to determine
+%                   variable and reaction rate values for given state values 
+%                   and time vector.
+%               =0: doe not create the additional file
+% eventFlag: =1: creates 2 additional files for the handling of events in the model. 
+%            =0: does not create these two files.
+%            THE EVENT FILES ARE ONLY CREATED IN CASE THAT EVENTS ARE
+%            PRESENT IN THE MODEL            
+%
+% DEFAULT VALUES:
+% ===============
+% dataFileFlag: 0
+% eventFlag: 0
+%
+% OUTPUT ARGUMENTS:
+% =================
+% ODEfctname: name of the function (filename without .m extension)
+% DATAfctname: name of the datafile function (filename without .m extension)
+% EVENTfctname: name of the event function (filename without .m extension)
+% EVENTASSGNfctname: name of the event assignment function (filename without .m extension)
+% ODEfilefullpath: complete path to the created ODE file (including .m extension)
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% TEMPDIR 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+addpath(tempdirIQM);   % add it to the path
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+eventFlag = 0;
+dataFileFlag = 0;
+augmKernelName = '';
+if nargin == 1,
+    iqm = varargin{1};
+elseif nargin == 2,
+    iqm = varargin{1};
+    dataFileFlag = varargin{2};
+elseif nargin == 3,
+    iqm = varargin{1};
+    dataFileFlag = varargin{2};
+    eventFlag = varargin{3};
+elseif nargin == 4,
+    iqm = varargin{1};
+    dataFileFlag = varargin{2};
+    eventFlag = varargin{3};
+    augmKernelName = varargin{4};
+else
+    error('Incorrect number of input arguments.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET TEMP FILE NAME
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get temporary filenme
+tempfilefullpath = tempnameIQM;
+[pathstr,tempfilename,ext] = fileparts(tempfilefullpath);     
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CREATE THE FILES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+tempFlag = 1; % to avoid the event warning when creating files for models with events w/o setting the event flag
+IQMcreateODEfile(iqm,tempfilefullpath,dataFileFlag,eventFlag,augmKernelName,tempFlag);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CREATE THE FILE NAMES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ODEfctname = tempfilename;
+if dataFileFlag == 1,
+    DATAfctname = strcat('datafile_',ODEfctname);
+else 
+    DATAfctname = '';
+end
+if eventFlag == 1,
+    EVENTfctname = strcat('event_',ODEfctname);
+    EVENTASSGNfctname = strcat('event_assignment_',ODEfctname);
+else
+    EVENTfctname = '';
+    EVENTASSGNfctname = '';
+end
+ODEfilefullpath = strcat(tempfilefullpath,'.m');
+
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMdeleteTempODEfile.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMdeleteTempODEfile.m
new file mode 100644
index 0000000000000000000000000000000000000000..639b3e3cc11478f2485e7f9fc06aee8735efd58e
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMdeleteTempODEfile.m	
@@ -0,0 +1,22 @@
+function [] = IQMdeleteTempODEfile(fullpathfilename)
+% This function takes as input argument the full path to an ODE file that
+% is to be deleted. It also tries to delete the datafile_* and the event
+% files that belong to this ODE file. Warnings are switched of not to enoy
+% the user with unecessary warnings when a file is not present.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+% initialize simulation results
+
+[pathstr,filename,ext] = fileparts(fullpathfilename);
+ODEfilename = strcat(pathstr,'/',filename,'.m');
+DATAfilename = strcat(pathstr,'/','datafile_',filename,'.m');
+EVENTfilename = strcat(pathstr,'/','event_',filename,'.m');
+EVENTASSIGNfilename = strcat(pathstr,'/','event_assignment_',filename,'.m');
+warning off;  % toggle warnings off as not all files might exist
+delete(ODEfilename);
+delete(DATAfilename);
+delete(EVENTfilename);
+delete(EVENTASSIGNfilename);
+warning on;  % toggle warnings on again
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMevents.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMevents.m
new file mode 100644
index 0000000000000000000000000000000000000000..cb1b88fd0c0b1d9af414fddcce91fae953581099
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMevents.m	
@@ -0,0 +1,43 @@
+function [names,triggers,variables,formulas] = IQMevents(model)
+% IQMevents: Returns information about the events in an IQMmodel.
+%
+% USAGE:
+% ======
+% [names,triggers,variables,formulas] = IQMevents(model)
+%
+% model: IQMmodel (function can not be used on M-file model)
+%
+% Output Arguments:
+% =================
+% names: cell-array with models event names
+% triggers: cell-array with triggers for the events
+% variables: cell-array with the variables affected by the events
+% formulas: cell-array with the formulas how to affect the variables if an
+%   event is fired
+%
+% The ordering of the elements in the cell-arrays is important. The i-th
+% elements in the output variables belongs to the i-th event.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS IQMMODEL OR ODE FILE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if strcmp('IQMmodel',class(model)),
+    iqm = IQMstruct(model);
+    names = {};
+    triggers = {};
+    variables = {};
+    formulas = {};
+    for k = 1:length(iqm.events),
+        names{k} = iqm.events(k).name;
+        triggers{k} = iqm.events(k).trigger;
+        variables{k} = {iqm.events(k).assignment.variable};
+        formulas{k} = {iqm.events(k).assignment.formula};
+    end
+else
+    error('The function can only be used on IQMmodels, not on M-file ODE models');
+end
+names = names(:);
+triggers = triggers(:);
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMexportSBML.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMexportSBML.m
new file mode 100644
index 0000000000000000000000000000000000000000..d7b0c9d476a3d05450c93d332861708d4185f4cf
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMexportSBML.m	
@@ -0,0 +1,892 @@
+function [] = IQMexportSBML(iqm, filename)
+% IQMexportSBML 
+% exports an IQMmodel to an SBML Level 2 Version 1 model using the OutputSBML function
+% from the SBML toolbox. Non-numeric ICs are not handled but converted to
+% numeric ICs. 
+%
+% IMPORTANT:
+% ==========
+% To export a model, the user is required to provide correct information in 
+% the "type,compartment,unittype" fields of the internal IQMmodel data structure.
+%
+% This information can be added by directly editing the models structure,
+% or by providing the information in the model text representation.
+%
+% 1) Editing the structure
+% ------------------------
+% The model structure is obtained by typing "modelstruct = IQMstruct(iqmmodel)"
+% The 'states', 'algebraic', 'parameters', and 'variables' fields of the structure have the 
+% following subfields that need to be set to correct values.
+%   subfields       needed content          comment
+%   'type':      	'isSpecie'              in case the state/parameter/variable in
+%                                           the IQMmodel is an SBML specie
+%                   'isParameter'           in case the state/parameter/variable in
+%                                           the IQMmodel is an SBML
+%                                           parameter
+%                   'isCompartment'         in case the state/parameter/variable in
+%                                           the IQMmodel is an SBML compartment
+%
+%   'compartment':  specie compartment      if type='isSpecie' it defines the name of the
+%                                           compartment the specie is located in.
+%                   outside compartment     if type='isCompartment' it defined the name 
+%                                           of the compartment outside
+%                   ''                      if type='isParameter' or type='isCompartment' 
+%                                           and there is no outside compartment or 
+%                                           type='isSpecie' and there is no
+%                                           compartment defined.
+%
+%   'unittype':     'amount'                if type='isSpecie' and the
+%   species units 
+%                                           are in 'amount'
+%                   'concentration'         if type='isSpecie' and the species units 
+%                                           are in 'concentration'
+%                   ''                      if type is not 'isSpecie'                   
+%
+% 2) Providing the information in the model text description, by IQMedit,
+%    IQMeditBC or directly by editing text files
+% ----------------------------------------------------------------------
+% For each state, parameter, and variable the additional information has
+% the following syntax:
+%
+% {type:compartment:unittype}
+%
+% where 'type', 'compartment', and 'unittype' is defined as above.
+% This argument needs to be placed in each definition of a state,
+% algebraic, parameter, and variable just before the optional comment.
+%
+% Example:
+% --------
+% An example model that has been correctly prepared for SBML export 
+% is defined in the file IQMlite/examples/exampleSBMLexport.txt
+%
+% USAGE:
+% ======
+% [] = IQMexportSBML(model)
+% [] = IQMexportSBML(model,filename)
+%
+% model:    IQMmodel to export to SBML
+% filename: Name of the xml file to export to (optional: dialog window opens)
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE NON NUMERIC ICs
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~hasonlynumericICsIQM(iqm),
+    iqm = IQMconvertNonNum2NumIC(iqm);
+    disp('Model contains non-numeric initial conditions. For the SBML export');
+    disp('these are converted to numeric ones using the IQMconvertNonNum2NumIC function.');
+end
+
+
+% skipSBMLpreset = 0;
+% if nargin == 2,
+%     skipSBMLpreset = varargin{1};
+% end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PREPROCESS and CHECK IQMmodel (fill type, compartment, unittype fields if possible)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% if ~skipSBMLpreset,
+    iqm = IQMmakeSBMLpresets(iqm);
+% end
+
+% test wether all name fields are filled and are unique
+namesOK = checkNamesInIQMmodel(iqm, 1);
+if ~namesOK,
+    errorMessage{1} = 'SBML export aborted because of errors concerning the names used in the given IQMmodel. For further information use "checkNamesInIQMmodel" function!';
+    messageOutput(errorMessage, 1);
+    return    
+end
+% if test shows that model isn't SBML compliant abort export
+[sbmlCompliant, onlyCompartmentError] = testSBMLsettings(iqm, 1);
+if ~sbmlCompliant,
+    if onlyCompartmentError,
+        iqm = addDefaultCompartment(iqm);
+    else
+        errorMessage{1} = 'SBML export aborted because of errors concerning the SBML compliance. For further information use "testSBMLsettings" function!';
+        messageOutput(errorMessage, 1);
+        return
+    end
+end
+
+% convert object to structure
+ms = struct(iqm);  
+
+%% Handle the division by compartments if amount and revert that
+tempfile = tempname;
+IQMcreateTEXTfile(iqm,tempfile);
+contents = fileread([tempfile '.txt']);
+% Get the species and compartment names for amount species
+speciesNames = {};
+compartmentNames = {};
+for k=1:length(ms.states),
+    if strcmp(ms.states(k).type,'isSpecie') && strcmp(ms.states(k).unittype,'amount'),
+        speciesNames{end+1} = ms.states(k).name;
+        compartmentNames{end+1} = ms.states(k).compartment;
+    end
+end
+for k=1:length(ms.parameters),
+    if strcmp(ms.parameters(k).type,'isSpecie') && strcmp(ms.parameters(k).unittype,'amount'),
+        speciesNames{end+1} = ms.parameters(k).name;
+        compartmentNames{end+1} = ms.parameters(k).compartment;
+    end
+end
+for k=1:length(ms.variables),
+    if strcmp(ms.variables(k).type,'isSpecie') && strcmp(ms.variables(k).unittype,'amount'),
+        speciesNames{end+1} = ms.variables(k).name;
+        compartmentNames{end+1} = ms.variables(k).compartment;
+    end
+end
+% Cycle through the species and remove the division by compartment if amount
+for k=1:length(speciesNames),
+    old = ['(' speciesNames{k} '/' compartmentNames{k} ')'];
+    new = speciesNames{k};
+    contents = strrep(contents,old,new);
+end
+% Save file again
+fid = fopen([tempfile '.txt'],'w');
+fprintf(fid,'%s',contents);
+fclose(fid);
+% Load changed model
+iqm = IQMmodel([tempfile '.txt']);
+% Get structure again
+ms = struct(iqm);
+% Delete tempfile
+delete([tempfile '.txt']);
+
+%%
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF MODEL CONTAINS MATLAB FUNCTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(ms.functionsMATLAB),
+    error('Model contains MATLAB functions. Such functions are not supported in SBML.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DETERMINE STOICHIOMETRIX MATRIX and related stuff (to determine if
+% boundary species or species)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[StoichiometricMatrix,SBMLspeciesNames,SBMLreactionNames,SBMLreversibleFlag] = IQMstoichiometry(iqm,1,1);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CREATE AN EMPTY SBML MATLAB STRUCTURE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Create empty SBMLstructure
+% functionDefinition substructure
+functionDefinitionStruct = struct('typecode', {}, 'metaid', '', 'notes', {}, 'annotation', {}, 'name', {}, 'id', {}, 'math', {});
+% unitDefinition substructure
+unitDefinitionStruct = struct('typecode',{}, 'metaid', '','notes',{},'annotation',{}, 'name', {}, 'id', {}, 'unit', {});
+% compartment substructure
+compartmentStruct = struct('typecode', {}, 'metaid', '', 'notes', {}, 'annotation', {}, 'name', {}, 'id', {}, 'spatialDimensions', {}, 'size', {}, 'units', {}, 'outside', {}, 'constant', {}, 'isSetSize', {}, 'isSetVolume', {});
+% species substructure
+speciesStruct = struct('typecode', {}, 'metaid', '', 'notes', {}, 'annotation', {}, 'name', {},'id', {}, 'compartment', {}, 'initialAmount', {}, 'initialConcentration', {}, 'substanceUnits', {}, 'spatialSizeUnits', {}, 'hasOnlySubstanceUnits', {}, 'boundaryCondition', {}, 'charge', {}, 'constant', {}, 'isSetInitialAmount', {}, 'isSetInitialConcentration', {}, 'isSetCharge', {});
+% parameter substructure
+parameterStruct = struct('typecode', {}, 'metaid', '', 'notes', {}, 'annotation', {}, 'name', {}, 'id', {}, 'value', {}, 'units', {}, 'constant', {}, 'isSetValue', {});
+% rule substructure
+ruleStruct = struct('typecode', {}, 'metaid', '', 'notes', {}, 'annotation', {}, 'formula', {}, 'variable', {}, 'species', {}, 'compartment', {}, 'name', {}, 'units', {});
+% reaction substructure
+reactantStruct = struct('typecode', {}, 'metaid', '', 'notes', {}, 'annotation', {}, 'species', {}, 'stoichiometry', {}, 'denominator', {}, 'stoichiometryMath', {});
+productStruct = struct('typecode', {}, 'metaid', '', 'notes', {}, 'annotation', {}, 'species', {}, 'stoichiometry', {}, 'denominator', {}, 'stoichiometryMath', {});
+modifierStruct = struct('typecode', {}, 'metaid', '', 'notes', {}, 'annotation', {}, 'species', {});
+kineticLawParameterStruct = struct('typecode', {}, 'metaid', '', 'notes', {}, 'annotation', {}, 'name', {}, 'id', {}, 'value', {}, 'units', {}, 'constant', {}, 'isSetValue', {});
+kineticLawStruct = struct('typecode', {}, 'metaid', '', 'notes', {}, 'annotation', {}, 'formula', {}, 'math', {}, 'parameter', kineticLawParameterStruct, 'timeUnits', {}, 'substanceUnits', {});
+reactionStruct = struct('typecode', {}, 'metaid', '', 'notes', {}, 'annotation', {}, 'name', {}, 'id', {}, 'reactant', reactantStruct, 'product', productStruct, 'modifier', modifierStruct, 'kineticLaw', kineticLawStruct, 'reversible', {}, 'fast', {}, 'isSetFast', {});
+eventStruct = struct('typecode', {}, 'metaid', '', 'notes', {}, 'annotation', {}, 'name', {}, 'id', {}, 'trigger', {}, 'delay', {}, 'timeUnits', {}, 'eventAssignment', {});
+namespaceStruct = struct('prefix', '', 'uri', 'http://www.sbml.org/sbml/level2');
+% Create IQMstructure
+SBMLstructure = struct('typecode', 'SBML_MODEL',...
+                       'metaid', '', ...
+                       'notes', '', ...
+                       'annotation', '', ...
+                       'SBML_level', 2, ...
+                       'SBML_version', 1, ...
+                       'name', '', ...
+                       'id', '', ...
+                       'functionDefinition', functionDefinitionStruct, ...
+                       'unitDefinition', unitDefinitionStruct, ...
+                       'compartment', compartmentStruct, ...
+                       'species', speciesStruct, ...
+                       'parameter', parameterStruct, ...
+                       'rule', ruleStruct, ...
+                       'reaction', reactionStruct, ...
+                       'event', eventStruct, ...
+                       'time_symbol', 'time', ...
+                       'delay_symbol', '', ...
+                       'namespaces', namespaceStruct);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% SOME VARIABLES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%                       
+ruleIndex = 1;
+parameterIndex = 1;
+compartmentIndex = 1;
+specieIndex = 1;
+                       
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% COPY NAME AND NOTES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%                       
+SBMLstructure.name = ms.name;
+SBMLstructure.notes = convert2SBMLNotes(ms.notes);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS COMPARTMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%                       
+% compartments can be defined as parameters, variables or states. 
+% If the field 'type' is set to 'isCompartment' it indicates a compartment. 
+% check parameters for compartments
+for k = 1:length(ms.parameters),
+    if strcmp(ms.parameters(k).type,'isCompartment'),
+        % current parameter determines compartment size
+        % always use spatial dimensions 3
+        SBMLstructure.compartment(compartmentIndex).typecode = 'SBML_COMPARTMENT';
+        SBMLstructure.compartment(compartmentIndex).metaid = '';
+        SBMLstructure.compartment(compartmentIndex).notes = convert2SBMLNotes(ms.parameters(k).notes);
+        SBMLstructure.compartment(compartmentIndex).annotation = '';
+        SBMLstructure.compartment(compartmentIndex).name = ms.parameters(k).name;
+        SBMLstructure.compartment(compartmentIndex).id = ms.parameters(k).name;
+        SBMLstructure.compartment(compartmentIndex).spatialDimensions = 3;
+        SBMLstructure.compartment(compartmentIndex).size = ms.parameters(k).value;
+        SBMLstructure.compartment(compartmentIndex).units = '';
+        SBMLstructure.compartment(compartmentIndex).outside = ms.parameters(k).compartment;
+        SBMLstructure.compartment(compartmentIndex).constant = 1;
+        SBMLstructure.compartment(compartmentIndex).isSetSize = 1;
+        SBMLstructure.compartment(compartmentIndex).isSetVolume = 1;
+        compartmentIndex = compartmentIndex + 1;
+    end
+end
+% check states for compartments
+for k = 1:length(ms.states),
+    if strcmp(ms.states(k).type,'isCompartment'),
+        % current state determines compartment size
+        % set size to initial condition of state
+        SBMLstructure.compartment(compartmentIndex).typecode = 'SBML_COMPARTMENT';
+        SBMLstructure.compartment(compartmentIndex).metaid = '';
+        SBMLstructure.compartment(compartmentIndex).notes = convert2SBMLNotes(ms.states(k).notes);
+        SBMLstructure.compartment(compartmentIndex).annotation = '';
+        SBMLstructure.compartment(compartmentIndex).name = ms.states(k).name;
+        SBMLstructure.compartment(compartmentIndex).id = ms.states(k).name;
+        SBMLstructure.compartment(compartmentIndex).spatialDimensions = 3;
+        SBMLstructure.compartment(compartmentIndex).size = ms.states(k).initialCondition;
+        SBMLstructure.compartment(compartmentIndex).units = '';
+        SBMLstructure.compartment(compartmentIndex).outside = ms.states(k).compartment;
+        SBMLstructure.compartment(compartmentIndex).constant = 0;
+        SBMLstructure.compartment(compartmentIndex).isSetSize = 1;
+        SBMLstructure.compartment(compartmentIndex).isSetVolume = 1;
+        compartmentIndex = compartmentIndex + 1;
+        % Compartment defined by a rule. Include this rule in the structure
+        SBMLstructure.rule(ruleIndex).typecode = 'SBML_RATE_RULE';
+        SBMLstructure.rule(ruleIndex).metaid = '';
+        SBMLstructure.rule(ruleIndex).notes = convert2SBMLNotes(ms.states(k).notes);
+        SBMLstructure.rule(ruleIndex).annotation = '';
+        SBMLstructure.rule(ruleIndex).formula = replaceMATLABexpressions(ms.states(k).ODE);
+        SBMLstructure.rule(ruleIndex).variable = ms.states(k).name;
+        SBMLstructure.rule(ruleIndex).species = '';
+        SBMLstructure.rule(ruleIndex).compartment = '';
+        SBMLstructure.rule(ruleIndex).name = '';
+        SBMLstructure.rule(ruleIndex).units = '';
+        ruleIndex = ruleIndex + 1;        
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS PARAMETERS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 
+% parameters can be defined as parameters, variables or states. If the
+% field 'type' is set to 'isParameter' it indicates an SBML parameter.  
+% we only will have global parameters in the SBML model.
+% check parameters for parameters
+for k = 1:length(ms.parameters),
+    if strcmp(ms.parameters(k).type,'isParameter'),
+        % current parameter determines compartment size
+        SBMLstructure.parameter(parameterIndex).typecode = 'SBML_PARAMETER';
+        SBMLstructure.parameter(parameterIndex).metaid = '';
+        SBMLstructure.parameter(parameterIndex).notes = convert2SBMLNotes(ms.parameters(k).notes);
+        SBMLstructure.parameter(parameterIndex).annotation = '';
+        SBMLstructure.parameter(parameterIndex).name = ms.parameters(k).name;
+        SBMLstructure.parameter(parameterIndex).id = ms.parameters(k).name;
+        SBMLstructure.parameter(parameterIndex).value = ms.parameters(k).value;
+        SBMLstructure.parameter(parameterIndex).units = '';
+        SBMLstructure.parameter(parameterIndex).constant = 1;
+        SBMLstructure.parameter(parameterIndex).isSetValue = 1;
+        parameterIndex = parameterIndex + 1;
+    end
+end
+% check states for parameters
+for k = 1:length(ms.states),
+    if strcmp(ms.states(k).type,'isParameter'),
+        % current state determines compartment size
+        SBMLstructure.parameter(parameterIndex).typecode = 'SBML_PARAMETER';
+        SBMLstructure.parameter(parameterIndex).metaid = '';
+        SBMLstructure.parameter(parameterIndex).notes = convert2SBMLNotes(ms.states(k).notes);
+        SBMLstructure.parameter(parameterIndex).annotation = '';
+        SBMLstructure.parameter(parameterIndex).name = ms.states(k).name;
+        SBMLstructure.parameter(parameterIndex).id = ms.states(k).name;
+        SBMLstructure.parameter(parameterIndex).value = ms.states(k).initialCondition;
+        SBMLstructure.parameter(parameterIndex).units = '';
+        SBMLstructure.parameter(parameterIndex).constant = 0;
+        SBMLstructure.parameter(parameterIndex).isSetValue = 1;
+        parameterIndex = parameterIndex + 1;        
+        % Parameter defined by a rule. Include this rule in the structure
+        SBMLstructure.rule(ruleIndex).typecode = 'SBML_RATE_RULE';
+        SBMLstructure.rule(ruleIndex).metaid = '';
+        SBMLstructure.rule(ruleIndex).notes = convert2SBMLNotes(ms.states(k).notes);
+        SBMLstructure.rule(ruleIndex).annotation = '';
+        SBMLstructure.rule(ruleIndex).formula = replaceMATLABexpressions(ms.states(k).ODE);
+        SBMLstructure.rule(ruleIndex).variable = ms.states(k).name;
+        SBMLstructure.rule(ruleIndex).species = '';
+        SBMLstructure.rule(ruleIndex).compartment = '';
+        SBMLstructure.rule(ruleIndex).name = '';
+        SBMLstructure.rule(ruleIndex).units = '';
+        ruleIndex = ruleIndex + 1;        
+    end
+end            
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS FUNCTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 
+% add functions
+for k = 1:length(ms.functions),
+    SBMLstructure.functionDefinition(k).typecode = 'SBML_FUNCTION_DEFINITION';
+    SBMLstructure.functionDefinition(k).metaid = '';
+    SBMLstructure.functionDefinition(k).notes = convert2SBMLNotes(ms.functions(k).notes);
+    SBMLstructure.functionDefinition(k).annotation = '';
+    SBMLstructure.functionDefinition(k).name = ms.functions(k).name;
+    SBMLstructure.functionDefinition(k).id = ms.functions(k).name;
+    SBMLstructure.functionDefinition(k).math = sprintf('lambda(%s,%s)',ms.functions(k).arguments,replaceMATLABexpressions(ms.functions(k).formula));
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS CONSTANT (BOUNDARY) SPECIES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 
+% constant species can only be defined as parameters.
+% If the field 'type' of a parameter is set to 'isSpecie' we assume that
+% this indicates a constant boundary species.
+for k = 1:length(ms.parameters),
+    if strcmp(ms.parameters(k).type,'isSpecie'),
+        % Determine if amount or concentration
+        if strcmp(ms.parameters(k).unittype,'amount'), 
+            isAmount = 1;
+            isConcentration = 0;
+            hasOnlySubstanceUnits = 1;
+        elseif strcmp(ms.parameters(k).unittype,'concentration'),
+            isAmount = 0;
+            isConcentration = 1;
+            hasOnlySubstanceUnits = 0;
+        end
+        % import constant boundary species
+        SBMLstructure.species(specieIndex).typecode = 'SBML_SPECIES';
+        SBMLstructure.species(specieIndex).metaid = '';
+        SBMLstructure.species(specieIndex).notes = convert2SBMLNotes(ms.parameters(k).notes);
+        SBMLstructure.species(specieIndex).annotation = '';
+        SBMLstructure.species(specieIndex).name = ms.parameters(k).name;
+        SBMLstructure.species(specieIndex).id = ms.parameters(k).name;
+        SBMLstructure.species(specieIndex).compartment = ms.parameters(k).compartment;
+        SBMLstructure.species(specieIndex).initialAmount = ms.parameters(k).value;
+        SBMLstructure.species(specieIndex).initialConcentration = ms.parameters(k).value;
+        SBMLstructure.species(specieIndex).substanceUnits = '';         % no units!
+        SBMLstructure.species(specieIndex).spatialSizeUnits = '';       % no units!
+        SBMLstructure.species(specieIndex).hasOnlySubstanceUnits = hasOnlySubstanceUnits;
+        SBMLstructure.species(specieIndex).boundaryCondition = 1;       % boundary 
+        SBMLstructure.species(specieIndex).charge = 0;                  
+        SBMLstructure.species(specieIndex).constant = 1;                % species is set constant
+        SBMLstructure.species(specieIndex).isSetInitialAmount = isAmount;
+        SBMLstructure.species(specieIndex).isSetInitialConcentration = isConcentration;
+        SBMLstructure.species(specieIndex).isSetCharge = 0;             % charge not supported
+        specieIndex = specieIndex + 1;
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS BOUNDARY SPECIES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 
+% boundary species can be defined variables or states (not as parameters,
+% since then they become constant boundary species).
+% The difference between species and boundary species is here that species
+% are only defined by reactions, while boundary species are defined by
+% rules. The variable "SBMLspeciesNames" contains the names of all states
+% that are defined only by reactions.
+% now check states (boundary if isSpecie and not in the SBMLspeciesNames list)
+for k = 1:length(ms.states),
+    if strcmp(ms.states(k).type,'isSpecie') && isempty(strmatchIQM(ms.states(k).name,SBMLspeciesNames)),
+        % Determine if amount or concentration
+        if strcmp(ms.states(k).unittype,'amount') 
+            isAmount = 1;
+            isConcentration = 0;
+            hasOnlySubstanceUnits = 1;
+        elseif strcmp(ms.states(k).unittype,'concentration') 
+            isAmount = 0;
+            isConcentration = 1;
+            hasOnlySubstanceUnits = 0;
+        end
+        % import boundary species
+        SBMLstructure.species(specieIndex).typecode = 'SBML_SPECIES';
+        SBMLstructure.species(specieIndex).metaid = '';
+        SBMLstructure.species(specieIndex).notes = convert2SBMLNotes(ms.states(k).notes);
+        SBMLstructure.species(specieIndex).annotation = '';
+        SBMLstructure.species(specieIndex).name = ms.states(k).name;
+        SBMLstructure.species(specieIndex).id = ms.states(k).name;
+        SBMLstructure.species(specieIndex).compartment = ms.states(k).compartment;
+        SBMLstructure.species(specieIndex).initialAmount = ms.states(k).initialCondition;
+        SBMLstructure.species(specieIndex).initialConcentration = ms.states(k).initialCondition;
+        SBMLstructure.species(specieIndex).substanceUnits = '';         % no units!
+        SBMLstructure.species(specieIndex).spatialSizeUnits = '';       % no units!
+        SBMLstructure.species(specieIndex).hasOnlySubstanceUnits = hasOnlySubstanceUnits;
+        SBMLstructure.species(specieIndex).boundaryCondition = 1;       % boundary 
+        SBMLstructure.species(specieIndex).charge = 0;                  
+        SBMLstructure.species(specieIndex).constant = 0;                % species is not set constant
+        SBMLstructure.species(specieIndex).isSetInitialAmount = isAmount;
+        SBMLstructure.species(specieIndex).isSetInitialConcentration = isConcentration;
+        SBMLstructure.species(specieIndex).isSetCharge = 0;             % charge not supported
+        specieIndex = specieIndex + 1;
+        % Boundary species defined by a rule. Include this rule in the structure
+        SBMLstructure.rule(ruleIndex).typecode = 'SBML_RATE_RULE';
+        SBMLstructure.rule(ruleIndex).metaid = '';
+        SBMLstructure.rule(ruleIndex).notes = convert2SBMLNotes(ms.states(k).notes);
+        SBMLstructure.rule(ruleIndex).annotation = '';
+        SBMLstructure.rule(ruleIndex).formula = replaceMATLABexpressions(ms.states(k).ODE);
+        SBMLstructure.rule(ruleIndex).variable = ms.states(k).name;
+        SBMLstructure.rule(ruleIndex).species = '';
+        SBMLstructure.rule(ruleIndex).compartment = '';
+        SBMLstructure.rule(ruleIndex).name = '';
+        SBMLstructure.rule(ruleIndex).units = '';
+        ruleIndex = ruleIndex + 1;
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS SPECIES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 
+% we assume that species are only defined as states and determined by
+% reactions
+% check simple species defined by reactions
+% save the species name and the species ODE for use when processing the
+% reactions
+speciesReactions = [];
+for k = 1:length(ms.states),
+    if strcmp(ms.states(k).type,'isSpecie') && ~isempty(strmatchIQM(ms.states(k).name,SBMLspeciesNames)),
+        % Determine if amount or concentration
+        if strcmp(ms.states(k).unittype,'amount') 
+            isAmount = 1;
+            isConcentration = 0;
+            hasOnlySubstanceUnits = 1;
+        elseif strcmp(ms.states(k).unittype,'concentration') 
+            isAmount = 0;
+            isConcentration = 1;
+            hasOnlySubstanceUnits = 0;
+        end
+        % import constant species
+        SBMLstructure.species(specieIndex).typecode = 'SBML_SPECIES';
+        SBMLstructure.species(specieIndex).metaid = '';
+        SBMLstructure.species(specieIndex).notes = convert2SBMLNotes(ms.states(k).notes);
+        SBMLstructure.species(specieIndex).annotation = '';
+        SBMLstructure.species(specieIndex).name = ms.states(k).name;
+        SBMLstructure.species(specieIndex).id = ms.states(k).name;
+        SBMLstructure.species(specieIndex).compartment = ms.states(k).compartment;
+        SBMLstructure.species(specieIndex).initialAmount = ms.states(k).initialCondition;
+        SBMLstructure.species(specieIndex).initialConcentration = ms.states(k).initialCondition;
+        SBMLstructure.species(specieIndex).substanceUnits = '';         % no units!
+        SBMLstructure.species(specieIndex).spatialSizeUnits = '';       % no units!
+        SBMLstructure.species(specieIndex).hasOnlySubstanceUnits = hasOnlySubstanceUnits;
+        SBMLstructure.species(specieIndex).boundaryCondition = 0;       % not boundary 
+        SBMLstructure.species(specieIndex).charge = 0;                  
+        SBMLstructure.species(specieIndex).constant = 0;                % species is not set constant
+        SBMLstructure.species(specieIndex).isSetInitialAmount = isAmount;
+        SBMLstructure.species(specieIndex).isSetInitialConcentration = isConcentration;
+        SBMLstructure.species(specieIndex).isSetCharge = 0;             % charge not supported
+        specieIndex = specieIndex + 1;
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS ASSIGNMENT RULES ... NEED TO BE ORDERED ... THUS HERE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for k = 1:length(ms.variables),
+    if strcmp(ms.variables(k).type,'isCompartment'),
+        % current variable determines compartment size
+        % set size to 1 (not important, since not used)
+        SBMLstructure.compartment(compartmentIndex).typecode = 'SBML_COMPARTMENT';
+        SBMLstructure.compartment(compartmentIndex).metaid = '';
+        SBMLstructure.compartment(compartmentIndex).notes = convert2SBMLNotes(ms.variables(k).notes);
+        SBMLstructure.compartment(compartmentIndex).annotation = '';
+        SBMLstructure.compartment(compartmentIndex).name = ms.variables(k).name;
+        SBMLstructure.compartment(compartmentIndex).id = ms.variables(k).name;
+        SBMLstructure.compartment(compartmentIndex).spatialDimensions = 3;
+        SBMLstructure.compartment(compartmentIndex).size = 1;
+        SBMLstructure.compartment(compartmentIndex).units = '';
+        SBMLstructure.compartment(compartmentIndex).outside = ms.variables(k).compartment;
+        SBMLstructure.compartment(compartmentIndex).constant = 0;
+        SBMLstructure.compartment(compartmentIndex).isSetSize = 1;
+        SBMLstructure.compartment(compartmentIndex).isSetVolume = 1;
+        compartmentIndex = compartmentIndex + 1;
+        % Compartment defined by a rule. Include this rule in the structure
+        SBMLstructure.rule(ruleIndex).typecode = 'SBML_ASSIGNMENT_RULE';
+        SBMLstructure.rule(ruleIndex).metaid = '';
+        SBMLstructure.rule(ruleIndex).notes = convert2SBMLNotes(ms.variables(k).notes);
+        SBMLstructure.rule(ruleIndex).annotation = '';
+        SBMLstructure.rule(ruleIndex).formula = replaceMATLABexpressions(ms.variables(k).formula);
+        SBMLstructure.rule(ruleIndex).variable = ms.variables(k).name;
+        SBMLstructure.rule(ruleIndex).species = '';
+        SBMLstructure.rule(ruleIndex).compartment = '';
+        SBMLstructure.rule(ruleIndex).name = '';
+        SBMLstructure.rule(ruleIndex).units = '';
+        ruleIndex = ruleIndex + 1;
+    end
+    if strcmp(ms.variables(k).type,'isParameter'),
+        % current variable determines compartment size
+        % value set to zero (not needed)
+        SBMLstructure.parameter(parameterIndex).typecode = 'SBML_PARAMETER';
+        SBMLstructure.parameter(parameterIndex).metaid = '';
+        SBMLstructure.parameter(parameterIndex).notes = convert2SBMLNotes(ms.variables(k).notes);
+        SBMLstructure.parameter(parameterIndex).annotation = '';
+        SBMLstructure.parameter(parameterIndex).name = ms.variables(k).name;
+        SBMLstructure.parameter(parameterIndex).id = ms.variables(k).name;
+        SBMLstructure.parameter(parameterIndex).value = 0;  % no value needed (assignment rule)
+        SBMLstructure.parameter(parameterIndex).units = '';
+        SBMLstructure.parameter(parameterIndex).constant = 0;
+        SBMLstructure.parameter(parameterIndex).isSetValue = 1;
+        parameterIndex = parameterIndex + 1;        
+        % Parameter defined by a rule. Include this rule in the structure
+        SBMLstructure.rule(ruleIndex).typecode = 'SBML_ASSIGNMENT_RULE';
+        SBMLstructure.rule(ruleIndex).metaid = '';
+        SBMLstructure.rule(ruleIndex).notes = convert2SBMLNotes(ms.variables(k).notes);
+        SBMLstructure.rule(ruleIndex).annotation = '';
+        SBMLstructure.rule(ruleIndex).formula = replaceMATLABexpressions(ms.variables(k).formula);
+        SBMLstructure.rule(ruleIndex).variable = ms.variables(k).name;
+        SBMLstructure.rule(ruleIndex).species = '';
+        SBMLstructure.rule(ruleIndex).compartment = '';
+        SBMLstructure.rule(ruleIndex).name = '';
+        SBMLstructure.rule(ruleIndex).units = '';
+        ruleIndex = ruleIndex + 1;
+    end
+    if strcmp(ms.variables(k).type,'isSpecie'),
+        % Determine if amount or concentration
+        if strcmp(ms.variables(k).unittype,'amount'), 
+            isAmount = 1;
+            isConcentration = 0;
+            hasOnlySubstanceUnits = 1;
+        elseif strcmp(ms.variables(k).unittype,'concentration'), 
+            isAmount = 0;
+            isConcentration = 1;
+            hasOnlySubstanceUnits = 0;
+        end
+        % import boundary species
+        SBMLstructure.species(specieIndex).typecode = 'SBML_SPECIES';
+        SBMLstructure.species(specieIndex).metaid = '';
+        SBMLstructure.species(specieIndex).notes = convert2SBMLNotes(ms.variables(k).notes);
+        SBMLstructure.species(specieIndex).annotation = '';
+        SBMLstructure.species(specieIndex).name = ms.variables(k).name;
+        SBMLstructure.species(specieIndex).id = ms.variables(k).name;
+        SBMLstructure.species(specieIndex).compartment = ms.variables(k).compartment;
+        SBMLstructure.species(specieIndex).initialAmount = 0;  % not set (assignment rule)
+        SBMLstructure.species(specieIndex).initialConcentration = 0; % not set (assignment rule)
+        SBMLstructure.species(specieIndex).substanceUnits = '';         % no units!
+        SBMLstructure.species(specieIndex).spatialSizeUnits = '';       % no units!
+        SBMLstructure.species(specieIndex).hasOnlySubstanceUnits = hasOnlySubstanceUnits;
+        SBMLstructure.species(specieIndex).boundaryCondition = 1;       % boundary 
+        SBMLstructure.species(specieIndex).charge = 0;                  
+        SBMLstructure.species(specieIndex).constant = 0;                % species is not set constant
+        SBMLstructure.species(specieIndex).isSetInitialAmount = isAmount;
+        SBMLstructure.species(specieIndex).isSetInitialConcentration = isConcentration;
+        SBMLstructure.species(specieIndex).isSetCharge = 0;             % charge not supported
+        specieIndex = specieIndex + 1;
+        % Boundary species defined by a rule. Include this rule in the structure
+        SBMLstructure.rule(ruleIndex).typecode = 'SBML_ASSIGNMENT_RULE';
+        SBMLstructure.rule(ruleIndex).metaid = '';
+        SBMLstructure.rule(ruleIndex).notes = convert2SBMLNotes(ms.variables(k).notes);
+        SBMLstructure.rule(ruleIndex).annotation = '';
+        SBMLstructure.rule(ruleIndex).formula = replaceMATLABexpressions(ms.variables(k).formula);
+        SBMLstructure.rule(ruleIndex).variable = ms.variables(k).name;
+        SBMLstructure.rule(ruleIndex).species = '';
+        SBMLstructure.rule(ruleIndex).compartment = '';
+        SBMLstructure.rule(ruleIndex).name = '';
+        SBMLstructure.rule(ruleIndex).units = '';
+        ruleIndex = ruleIndex + 1;
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS REACTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Before processing the reactions we are checking for moiety conservations
+% and reversing them into the stoichiometric matrix (to be able to draw the
+% full picture)
+[StoichiometricMatrix,SBMLspeciesNames] = reverseMoietyConservationsIQM(iqm, 1);
+for k1 = 1:length(ms.reactions),
+    reactionName = ms.reactions(k1).name;
+    reactionFormula = ms.reactions(k1).formula;
+    % get needed information about reaction
+    [reactant, product, modifier] = getReactionInfo(reactionName,StoichiometricMatrix,SBMLspeciesNames,SBMLreactionNames,SBMLreversibleFlag,iqm,ms);
+    % add reaction to the structure
+    SBMLstructure.reaction(k1).typecode = 'SBML_REACTION';
+    SBMLstructure.reaction(k1).metaid = '';
+    SBMLstructure.reaction(k1).notes = convert2SBMLNotes(ms.reactions(k1).notes);
+    SBMLstructure.reaction(k1).annotation = '';
+    SBMLstructure.reaction(k1).name = reactionName;
+    SBMLstructure.reaction(k1).id = reactionName;
+    
+    SBMLstructure.reaction(k1).reactant = reactant;
+    SBMLstructure.reaction(k1).product = product;
+    SBMLstructure.reaction(k1).modifier = modifier; 
+    
+    SBMLstructure.reaction(k1).kineticLaw.typecode = 'SBML_KINETIC_LAW';
+    SBMLstructure.reaction(k1).kineticLaw.metaid = '';
+    SBMLstructure.reaction(k1).kineticLaw.notes = '';
+    SBMLstructure.reaction(k1).kineticLaw.annotation = '';
+    SBMLstructure.reaction(k1).kineticLaw.formula = replaceMATLABexpressions(reactionFormula);
+    SBMLstructure.reaction(k1).kineticLaw.math = replaceMATLABexpressions(reactionFormula);
+    SBMLstructure.reaction(k1).kineticLaw.parameter = kineticLawParameterStruct;    % no local parameters
+    
+    SBMLstructure.reaction(k1).kineticLaw.timeUnits = '';
+    SBMLstructure.reaction(k1).kineticLaw.substanceUnits = '';
+    
+    SBMLstructure.reaction(k1).reversible = ms.reactions(k1).reversible;
+    
+    % handle set the fast flag
+    if ms.reactions(k1).fast == 0,
+        SBMLstructure.reaction(k1).fast = 0;
+        SBMLstructure.reaction(k1).isSetFast = 0;
+    else
+        SBMLstructure.reaction(k1).fast = 1;
+        SBMLstructure.reaction(k1).isSetFast = 1;
+    end        
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% LEAVE UNITDEFINITIONS EMPTY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%                       
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Process Events
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%                       
+for k1=1:length(ms.events),
+    SBMLstructure.event(k1).typecode = 'SBML_EVENT';
+    SBMLstructure.event(k1).metaid = '';
+    SBMLstructure.event(k1).notes = convert2SBMLNotes(ms.events(k1).notes);
+    SBMLstructure.event(k1).annotation = '';
+    SBMLstructure.event(k1).name = ms.events(k1).name;
+    SBMLstructure.event(k1).id = ms.events(k1).name;
+    SBMLstructure.event(k1).trigger = replaceMATLABexpressions(ms.events(k1).trigger);
+    SBMLstructure.event(k1).delay = '0'; % always zero
+    SBMLstructure.event(k1).timeUnits = '';
+    for k2 = 1:length(ms.events(k1).assignment),
+        SBMLstructure.event(k1).eventAssignment(k2).typecode = 'SBML_EVENT_ASSIGNMENT';
+        SBMLstructure.event(k1).eventAssignment(k2).metaid = '';
+        SBMLstructure.event(k1).eventAssignment(k2).notes = '';
+        SBMLstructure.event(k1).eventAssignment(k2).annotation = '';
+        SBMLstructure.event(k1).eventAssignment(k2).variable = ms.events(k1).assignment(k2).variable;
+        SBMLstructure.event(k1).eventAssignment(k2).math =  replaceMATLABexpressions(ms.events(k1).assignment(k2).formula);
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Process Algebraic Rules
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%                       
+% algebraic rules are just added. names NEED to be present otherwise it
+% makes no sense
+for k=1:length(ms.algebraic),
+    name = ms.algebraic(k).name;
+    formula = ms.algebraic(k).formula;
+    initialCondition = ms.algebraic(k).initialCondition;
+    type = ms.algebraic(k).type;
+    compartment = ms.algebraic(k).compartment;
+    unittype = ms.algebraic(k).unittype;
+    notes = ms.algebraic(k).notes;
+    % add the rule
+    SBMLstructure.rule(end+1).typecode = 'SBML_ALGEBRAIC_RULE';
+    SBMLstructure.rule(end).metaid = '';
+    SBMLstructure.rule(end).notes = convert2SBMLNotes(notes);
+    SBMLstructure.rule(end).annotation = '';
+    SBMLstructure.rule(end).formula = formula;
+    SBMLstructure.rule(end).variable = '';
+    SBMLstructure.rule(end).species = '';
+    SBMLstructure.rule(end).compartment = '';
+    SBMLstructure.rule(end).name = '';
+    SBMLstructure.rule(end).units = '';
+    % add name as specie, parameter, or compartment
+    if strcmp(type,'isSpecie'),
+        SBMLstructure.species(end+1).typecode = 'SBML_SPECIES';
+        SBMLstructure.species(end).metaid = '';
+        SBMLstructure.species(end).notes = convert2SBMLNotes(notes);
+        SBMLstructure.species(end).annotation = '';
+        SBMLstructure.species(end).name = name;
+        SBMLstructure.species(end).id = name;
+        SBMLstructure.species(end).compartment = compartment;
+        SBMLstructure.species(end).initialAmount = initialCondition;
+        SBMLstructure.species(end).initialConcentration = initialCondition;
+        SBMLstructure.species(end).substanceUnits = '';         % no units!
+        SBMLstructure.species(end).spatialSizeUnits = '';       % no units!
+        SBMLstructure.species(end).hasOnlySubstanceUnits = strcmp(unittype,'amount');
+        SBMLstructure.species(end).boundaryCondition = 1;       % set boundary cond (det. by rule) 
+        SBMLstructure.species(end).charge = 0;                  
+        SBMLstructure.species(end).constant = 0;                % species is not set constant
+        SBMLstructure.species(end).isSetInitialAmount = strcmp(unittype,'amount');
+        SBMLstructure.species(end).isSetInitialConcentration = strcmp(unittype,'concentration');
+        SBMLstructure.species(end).isSetCharge = 0;             % charge not supported       
+    end
+    if strcmp(type,'isParameter'),
+        SBMLstructure.parameter(end+1).typecode = 'SBML_PARAMETER';
+        SBMLstructure.parameter(end).metaid = '';
+        SBMLstructure.parameter(end).notes = convert2SBMLNotes(notes);
+        SBMLstructure.parameter(end).annotation = '';
+        SBMLstructure.parameter(end).name = name;
+        SBMLstructure.parameter(end).id = name;
+        SBMLstructure.parameter(end).value = initialCondition;
+        SBMLstructure.parameter(end).units = '';
+        SBMLstructure.parameter(end).constant = 0;
+        SBMLstructure.parameter(end).isSetValue = 1;
+    end
+    if strcmp(type,'isCompartment'),
+        SBMLstructure.compartment(end+1).typecode = 'SBML_COMPARTMENT';
+        SBMLstructure.compartment(end).metaid = '';
+        SBMLstructure.compartment(end).notes = convert2SBMLNotes(notes);
+        SBMLstructure.compartment(end).annotation = '';
+        SBMLstructure.compartment(end).name = name;
+        SBMLstructure.compartment(end).id = name;
+        SBMLstructure.compartment(end).spatialDimensions = 3;
+        SBMLstructure.compartment(end).size = initialCondition;
+        SBMLstructure.compartment(end).units = '';
+        SBMLstructure.compartment(end).outside = compartment;
+        SBMLstructure.compartment(end).constant = 0;
+        SBMLstructure.compartment(end).isSetSize = 1;
+        SBMLstructure.compartment(end).isSetVolume = 1;
+    end    
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% WRITE SBML FILE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%                       
+result = SBMLstructure;
+try 
+    if nargin==1,
+        OutputSBML(SBMLstructure);
+    else
+        OutputSBML(SBMLstructure,strrep(filename,'.xml',''));
+    end
+catch
+    if ~strcmp(lasterr, 'Cannot copy filename'),
+        warning(sprintf('Error occurred: %s\n',lasterr));
+    end
+end
+return
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DETERMINE REACTION INFORMATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%                       
+% we look through all ODEs where the gioven reaction is involved in.
+% we determine reversibility, reactants, products, and modifiers.
+function [reactant, product, modifier] = getReactionInfo(reactionName,StoichiometricMatrix,SBMLspeciesNames,SBMLreactionNames,SBMLreversibleFlag,iqm,ms)
+    % initialize the structures
+    reactant = struct('typecode', {}, 'metaid', {}, 'notes', {}, 'annotation', {}, 'species', {}, 'stoichiometry', {}, 'denominator', {}, 'stoichiometryMath', {});
+    product = struct('typecode', {}, 'metaid', {}, 'notes', {}, 'annotation', {}, 'species', {}, 'stoichiometry', {}, 'denominator', {}, 'stoichiometryMath', {});
+    modifier = struct('typecode', {}, 'metaid', {}, 'notes', {}, 'annotation', {}, 'species', {});
+    % get index of current reaction
+    reactionIndex = strmatchIQM(reactionName,SBMLreactionNames,'exact');
+    % get corresponding stoichiometries
+    [stoichRows, stoichCols] = size(StoichiometricMatrix);
+    if (stoichCols >= reactionIndex),
+        Nreaction = StoichiometricMatrix(:,reactionIndex);
+    else
+        % for the current reaction there's no stoichiometry
+        % or products, reactants or modifierer found
+        return
+    end
+    % get reactant indices (Nreaction < 0)
+    reactantIndices = find(Nreaction < 0);
+    % get product indices (Nreaction > 0)
+    productIndices = find(Nreaction > 0);
+    % add reactants
+    for k = 1:length(reactantIndices),
+        reactant(k).typecode = 'SBML_SPECIES_REFERENCE';
+        reactant(k).metaid = '';
+        reactant(k).notes = '';
+        reactant(k).annotation = '';
+        reactant(k).species = SBMLspeciesNames{reactantIndices(k)};
+        reactant(k).stoichiometry = abs(Nreaction(reactantIndices(k)));
+        reactant(k).denominator = 1;
+        reactant(k).stoichiometryMath = '';
+    end
+    % add products
+    for k = 1:length(productIndices),
+        product(k).typecode = 'SBML_SPECIES_REFERENCE';
+        product(k).metaid = '';
+        product(k).notes = '';
+        product(k).annotation = '';
+        product(k).species = SBMLspeciesNames{productIndices(k)};
+        product(k).stoichiometry = Nreaction(productIndices(k));
+        product(k).denominator = 1;
+        product(k).stoichiometryMath = '';
+    end
+    % search for modifiers among the non reactants and non products and add them
+    specieListPossible = SBMLspeciesNames(find(Nreaction == 0));
+    modifierList = {};
+    modifierList = search4Modifiers(modifierList,ms.reactions(reactionIndex).formula,specieListPossible,{ms.variables.name},iqm,ms);
+    modifierList = unique(modifierList);
+    for k = 1:length(modifierList),
+        modifier(k).typecode = 'SBML_MODIFIER_SPECIES_REFERENCE';
+        modifier(k).metaid = '';
+        modifier(k).notes = '';
+        modifier(k).annotation = '';
+        modifier(k).species = modifierList{k};
+    end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DETERMINE REACTION INFORMATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%                       
+% we go through all reactions and eventually variables to determine the
+% modifiers (recursively)
+function [modifierList] = search4Modifiers(modifierList,formula,specieListPossible,variableNames,iqm,ms)
+    % search in current formula for modifiers
+    formula = strcat('#',formula,'#');
+    for k=1:length(specieListPossible),
+        if ~isempty(regexp(formula,strcat('\W',specieListPossible{k},'\W'))),
+            modifierList{end+1} = specieListPossible{k};
+        end
+    end
+    % search in current formula for variable names
+    searchVariablesIndices = [];
+    for k=1:length(variableNames),
+        if ~isempty(regexp(formula,strcat('\W',variableNames{k},'\W'))),
+            searchVariablesIndices(end+1) = k;
+        end
+    end
+    % loop through variable names and search for modifiers
+    for k=1:length(searchVariablesIndices),
+        formula = ms.variables(searchVariablesIndices(k)).formula;
+        modifierList = search4Modifiers(modifierList,formula,specieListPossible,variableNames,iqm,ms);
+    end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EXCHANGE MATLAB FUNCTION NAMES TO MATHML FUNCTION NAMES IN ALL FORMULAS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% MathML functions can have different names than MATLAB function names
+% we need to exchange them in the formula strings. The term 'MathML
+% expression' relates to what is required by OutputSBML!
+function [formula] = replaceMATLABexpressions(formula)
+% MathML expressions 
+MathMLexpressions = {'arccos(','arcsin(','arctan(','ceiling(','ln(','log(10,',...
+    'pow(','arccos(','arccosh(','arccot(','arccoth(','arccsc(','arccsch(',...
+    'arcsec(','arcsech(','arcsin(','arcsinh(','arctan(','arctanh(',...
+    'exponentiale','log(','piecewise(','leq(','geq(','and(','or('};
+% Corresponding MATLAB expressions
+MATLABexpressions = {'acos(','asin(','atan(','ceil(','log(','log10(',...
+    'power(','acos(','acosh(','acot(','acoth(','acsc(','acsch(',...
+    'asec(','asech(','asin(','asinh(','atan(','atanh('...
+    'exp(1)','logbase(','piecewiseIQM(','le(','ge(','andIQM(','orIQM('};
+% do the simple replace
+for k = 1:length(MathMLexpressions),
+    formula = strrep(formula,MATLABexpressions{k},MathMLexpressions{k});
+end
+return
+
+
+    
+    
+    
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMfunctions.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMfunctions.m
new file mode 100644
index 0000000000000000000000000000000000000000..501bddf5539382fb0dbfed260ad333de466f6c7b
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMfunctions.m	
@@ -0,0 +1,38 @@
+function [names,formulas,arguments] = IQMfunctions(model)
+% IQMfunctions: Returns information about the functions in an IQMmodel.
+%
+% USAGE:
+% ======
+% [names,formulas,arguments] = IQMfunctions(model)
+%
+% model: IQMmodel (function can not be used on M-file model)
+%
+% Output Arguments:
+% =================
+% names: cell-array with models function names
+% formulas: cell-array with formuas for the functions
+% arguments: cell-array with arguments for the functions
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS IQMMODEL OR ODE FILE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if strcmp('IQMmodel',class(model)),
+    iqm = IQMstruct(model);
+    if ~isempty(iqm.functions),
+        names = {iqm.functions.name};
+        formulas = {iqm.functions.formula};
+        arguments = {iqm.functions.arguments};
+    else
+        names = {};
+        formulas = {};
+        arguments = {};
+    end
+else
+    error('The function can only be used on IQMmodels, not on M-file ODE models');
+end
+names = names(:);
+formulas = formulas(:);
+arguments = arguments(:);
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMfunctionsMATLAB.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMfunctionsMATLAB.m
new file mode 100644
index 0000000000000000000000000000000000000000..d600398b8865084a98cb71af98184e7087a11c74
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMfunctionsMATLAB.m	
@@ -0,0 +1,27 @@
+function [functionsMATLAB] = IQMfunctionsMATLAB(model)
+% IQMfunctionsMATLAB: Returns information about the MATLAB functions in an
+% IQMmodel. 
+%
+% USAGE:
+% ======
+% [functionsMATLAB] = IQMfunctionsMATLAB(model)
+%
+% model: IQMmodel (function can not be used on M-file model)
+%
+% Output Arguments:
+% =================
+% functionsMATLAB: string containing eventual MATLAB functions defined in
+%   the model.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS IQMMODEL OR ODE FILE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if strcmp('IQMmodel',class(model)),
+    iqm = IQMstruct(model);
+    functionsMATLAB = iqm.functionsMATLAB;
+else
+    error('The function can only be used on IQMmodels, not on M-file ODE models');
+end
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMinitialconditions.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMinitialconditions.m
new file mode 100644
index 0000000000000000000000000000000000000000..67b65168b3eab1bb91bf62f9e5e5272d3b65e244
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMinitialconditions.m	
@@ -0,0 +1,146 @@
+function [output] = IQMinitialconditions(model,varargin)
+% IQMinitialconditions: This functions does the following:
+%   1) Returns the initial conditions, stored in a model. For models with
+%      numeric initial conditions, these are returned in a vector. For
+%      models with non-numeric initial conditions the ICs are returned in a
+%      cell-array.
+%   2) Same as point 1) but for selected states.
+%   3) Changes the initial conditions in an IQMmodel. The non-numeric ICs
+%      are unaffected. Only the numeric ones are changed. Despite that, a
+%      full numeric IC vector needs to be provided, in which the values
+%      corresponding to the non-numeric ICs are arbitrary and have no
+%      meaning.
+%
+% USAGE:
+% ======
+% [ICs] = IQMinitialconditions(model)
+% [ICs] = IQMinitialconditions(model,statenames) 
+% [model] = IQMinitialconditions(model,values) 
+% [model] = IQMinitialconditions(model,statenames,values) 
+%
+% model: IQMmodel, ODE, or MEX file model description (in the two last cases
+%   the initial conditions can't be set!)
+% statenames: cell-array with statenames for which to give back the initial
+%   conditions.
+% values: vector with initial conditions to update the model with
+%
+% Output Arguments:
+% =================
+% ICs: initial conditions (vector or cell-array)
+% model: IQMmodel with changed initial conditions
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EXTRACT SOME INFO FROM THE MODEL
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% get the models ICs and statenames
+if isIQMmodel(model),
+    ms = struct(model);
+    if hasonlynumericICsIQM(model),
+        ICs = [ms.states.initialCondition];
+    else
+        ICs = {ms.states.initialCondition};
+    end
+    sn = {ms.states.name};
+else
+    % assume model is an ODE or MEX file
+    ICs = feval(model);
+    sn = feval(model,'states');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin == 1,
+    % simply return the initial conditions for all states
+    output = ICs;
+elseif nargin == 2,
+    % check if values to be changed or ICs for certain states returned
+    if isnumeric(varargin{1}),
+        % change values
+        values = varargin{1};
+        % Check if IQMmodel
+        if ~isIQMmodel(model),
+            error('Initial conditions can only be changed for IQMmodels.');
+        end
+        ms = struct(model);
+        % check length of values vector
+        if length(values) ~= length(ms.states),
+            error('The length of the values vector does not match the number of states in the model.');
+        end
+        % Check if numeric ICs
+        if hasonlynumericICsIQM(model),
+            % model has only numeric ICs => simple update
+            cellvalues = mat2cell(values(:)',1,ones(1,length(values)));
+            [ms.states.initialCondition] = deal(cellvalues{:});
+        else
+            % model has non-numeric ICs => update only the numeric values
+            for k=1:length(ms.states),
+                if isnumeric(ms.states(k).initialCondition),
+                    ms.states(k).initialCondition = values(k);
+                end
+            end
+            disp('Please note that only the numeric ICs in the model have been set to the new values.');
+        end            
+
+        % Return the IQMmodel with new initial values
+        output = IQMmodel(ms);
+    elseif ischar(varargin{1}) || iscell(varargin{1}),
+        % return specific state values
+        statenames = varargin{1};
+        if ischar(statenames),
+            statenames = {statenames};
+        end
+        % check if numeric or non-numeric
+        if iscell(ICs),
+            % non-numeric
+            output = {};
+            for k=1:length(statenames),
+                index = strmatchIQM(statenames{k},sn,'exact');
+                if isempty(index),
+                    error('State ''%s'' does not exist in the model.\n',statenames{k});
+                end
+                output{k} = ICs{index};
+            end
+        else
+            % numeric
+            output = [];
+            for k=1:length(statenames),
+                index = strmatchIQM(statenames{k},sn,'exact');
+                if isempty(index),
+                    error('State ''%s'' does not exist in the model.\n',statenames{k});
+                end
+                output(k) = ICs(index);
+            end
+        end
+    else
+        error('Incorrect second input argument.');
+    end
+elseif nargin == 3,
+    states = varargin{1};
+    newvalues = varargin{2};
+    if ischar(states),
+        states = {states};
+    end
+    % check if given states exists in model and do the changes
+    modelstruct = IQMstruct(model);
+    for k0 = 1:length(states),
+        state = states{k0};
+        newvalue = newvalues(k0);
+        stateIndex = strmatchIQM(state,{modelstruct.states.name},'exact');
+        if isempty(stateIndex),
+            error(sprintf('State ''%s'' does not exist in model.\n',state));
+        end
+        if length(stateIndex) > 1,
+            error(sprintf('State ''%s'' is defined %d times.\n',state,length(stateIndex)));
+        end
+        % update state with new value
+        modelstruct.states(stateIndex).initialCondition = newvalue;
+    end
+    model = IQMmodel(modelstruct);
+    output = model;    
+else
+    error('Incorrect number of input arguments.');
+end
+
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMmodelnotes.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMmodelnotes.m
new file mode 100644
index 0000000000000000000000000000000000000000..4d22bf77f96d1f3331c5ed7139767969b9eb612f
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMmodelnotes.m	
@@ -0,0 +1,19 @@
+function notes = IQMmodelnotes(model)
+% IQMmodelnotes: displays the notes in model.
+%
+% USAGE:
+% ======
+% [notes] = IQMmodelnotes(model)
+%
+% model: IQMmodel description of model
+%
+% Output Arguments:
+% =================
+% notes: notes, stored in the model
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+ms = struct(model);
+notes = ms.notes;
+
+
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMoverwriteICs.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMoverwriteICs.m
new file mode 100644
index 0000000000000000000000000000000000000000..594c1f90e07ce8f87e0655565da0e0ee930aa702
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMoverwriteICs.m	
@@ -0,0 +1,35 @@
+function [newmodel] = IQMoverwriteICs(model,icvector)
+% IQMoverwriteICs: This function sets new initial conditions, specified as
+% input argument. If the input model contains non-numeric initial
+% conditions, these are overwritten (in contrast, the function
+% IQMinitialconditions only overwrites the ICs that are defined by numerical
+% values).
+%
+% USAGE:
+% ======
+% [newmodel] = IQMoverwriteICs(model,icvector)
+%
+% model: IQMmodel
+% icvector: numeric vector, defining the new initial conditions for the model
+%
+% Output Arguments:
+% =================
+% newmodel: IQMmodel with new initial conditions
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isIQMmodel(model),
+    error('First input argument needs to be an IQMmodel.');
+end
+if length(icvector) ~= length(IQMinitialconditions(model)),
+    error('Provided initial condition vector does not have the correct length.');
+end
+    
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% UPDATE MODEL WITH ICVECTOR
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+newmodel = IQMconvertNonNum2NumIC(model);            % convert to numeric
+newmodel = IQMinitialconditions(newmodel,icvector);  % then update ics
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMparameters.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMparameters.m
new file mode 100644
index 0000000000000000000000000000000000000000..964fbdcf04b8d61188a2982ed1d67a7c384bddf5
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMparameters.m	
@@ -0,0 +1,103 @@
+function [varargout] = IQMparameters(model,varargin)
+% IQMparameters: Returns information about the parameters in a model, can
+% also be used to set a parameter value.
+%
+% USAGE:
+% ======
+% [names,values] = IQMparameters(model)
+% [values] = IQMparameters(model,parameters)
+% [model] = IQMparameters(model,parameters,newvalues)  (not working for ODE
+% file model)
+%
+% model: IQMmodel or m-file ODE description of model
+% parameters: Name of the parameter for which the value is to be returned
+%   or for which a new value is to be set. Alternatively ''parameters'' can
+%   be a cell array, containing several parameter names.
+% newvalues: Vector of new parameter values for parameters defined by
+%   'parameters'
+%
+% Output Arguments:
+% =================
+% names: cell-array with models parameter names
+% values: vector with parameter values
+% model: if parameter value changed then this is the new model
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+errorMsg = '';
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS IQMMODEL OR ODE FILE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if strcmp('IQMmodel',class(model)),
+    iqm = IQMstruct(model);
+    if ~isempty(iqm.parameters),
+        names = {iqm.parameters.name};
+        values = [iqm.parameters.value];
+    else
+        names = {};
+        values = {};
+    end
+else
+    if nargin > 2,
+        error('Parameters can not be changed when model is given as ODE file.');
+    end
+    names = feval(model,'parameters');
+    values = feval(model,'parametervalues');
+end
+names = names(:);
+values = values(:);
+
+% return values if information requested
+if nargin == 1,
+    varargout{1} = names;
+    varargout{2} = values;
+elseif nargin == 2,
+    parameters = varargin{1};
+    if ischar(parameters),
+        parameters = {parameters};
+    end
+    % check if given parameters exists in model and do the changes
+    outputvalues = [];
+    for k0 = 1:length(parameters),
+        parameter = parameters{k0};
+        parameterIndex = strmatchIQM(parameter,names,'exact');
+        if isempty(parameterIndex),
+            errorMsg = sprintf('%sParameter ''%s'' does not exist in model.\n',errorMsg,parameter);
+        elseif length(parameterIndex) > 1,
+            errorMsg = sprintf('%sParameter ''%s'' is defined %d times.\n',errorMsg,parameter,length(parameterIndex));
+        else
+            outputvalues = [outputvalues values(parameterIndex)];
+        end
+    end
+    varargout{1} = outputvalues(:);
+elseif nargin == 3,
+    parameters = varargin{1};
+    newvalues = varargin{2};
+    if ischar(parameters),
+        parameters = {parameters};
+    end
+    % check if given parameters exists in model and do the changes
+    modelstruct = IQMstruct(model);
+    for k0 = 1:length(parameters),
+        parameter = parameters{k0};
+        newvalue = newvalues(k0);
+        parameterIndex = strmatchIQM(parameter,{modelstruct.parameters.name},'exact');
+        if isempty(parameterIndex),
+            errorMsg = sprintf('%sParameter ''%s'' does not exist in model.\n',errorMsg,parameter);
+        end
+        if length(parameterIndex) > 1,
+            errorMsg = sprintf('%sParameter ''%s'' is defined %d times.\n',errorMsg,parameter,length(parameterIndex));
+        end
+        % update parameter with new value
+        modelstruct.parameters(parameterIndex).value = newvalue;
+    end
+    model = IQMmodel(modelstruct);
+    varargout{1} = model;
+else
+    error('Incorrect number of input arguments.');
+end
+if ~isempty(errorMsg),
+    error(errorMsg);
+end
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMreactions.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMreactions.m
new file mode 100644
index 0000000000000000000000000000000000000000..bae55892063550a1993fa181d96ad0735179c9b9
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMreactions.m	
@@ -0,0 +1,80 @@
+function [names,formulas,reversibleFlag,fastFlag,varargout] = IQMreactions(model,varargin)
+% IQMreactions: Returns information about the reactions in an IQMmodel.
+% If a state vector is passed additionally, the corresponding reaction
+% rates are returned also.
+%
+% USAGE:
+% ======
+% [names,formulas,reversibleFlag,fastFlag] = IQMreactions(model)
+% [names,formulas,reversibleFlag,fastFlag,reactionrates] = IQMreactions(model,statevector)
+% [names,formulas,reversibleFlag,fastFlag,reactionrates] = IQMreactions(model,time,statevector)
+%
+% model: IQMmodel (function can not be used on M-file model)
+% statevector: vector with corresponding statevalues
+% time: time instant of the statevector (only needed for time variant
+% systems)
+%
+% DEFAULT VALUES:
+% ===============
+% statevector: not needed 
+% time: 0  (makes no difference for time invariant systems)
+%
+% Output Arguments:
+% =================
+% names: cell-array with models reaction names
+% formulas: cell-array with formuas for the kinetic laws of the reactions
+% reversibleFlag: vector with same number of entries as reactions. An entry
+%   of 0 indicates an irreversible reaction, an entry of 1 indicates a
+%   reversible reaction. The ordering is the same as the reaction names.
+% fastFlag: vector with same number of entries as reactions. An entry
+%   of 1 indicates a fast reaction, an entry of 0 indicates a
+%   reaction that is determined by its kinetic rate law.
+% reactionrates: the reaction rates at the given state and time
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS IQMMODEL OR ODE FILE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if strcmp('IQMmodel',class(model)),
+    iqm = IQMstruct(model);
+    if ~isempty(iqm.reactions),
+        names = {iqm.reactions.name};
+        formulas = {iqm.reactions.formula};
+        reversibleFlag = [iqm.reactions.reversible];
+        fastFlag = [iqm.reactions.fast];
+    else 
+        names = {};
+        formulas = {};
+        reversibleFlag = [];
+        fastFlag = [];
+    end
+else
+    error('The function can only be used on IQMmodels, not on M-file ODE models');
+end
+names = names(:);
+formulas = formulas(:);
+reversibleFlag = reversibleFlag(:);
+fastFlag = fastFlag(:);
+
+% check if the reaction rates need to be determined:
+if nargin == 2,    
+    statevector = varargin{1};
+    time = 0;
+    % create data file (using IQMcreateTempODEfile function)
+    [ODEfctname, ODEfilefullpath, DATAfctname] = IQMcreateTempODEfile(model,1);
+    data = feval(DATAfctname, time, statevector);
+    % delete all temporary m files
+    IQMdeleteTempODEfile(ODEfilefullpath);
+    varargout{1} = data.reactionvalues';
+elseif nargin == 3,
+    time = varargin{1};
+    statevector = varargin{2};
+    % create data file (using IQMcreateTempODEfile function)
+    [ODEfctname, ODEfilefullpath, DATAfctname] = IQMcreateTempODEfile(model,1);
+    data = feval(DATAfctname, time, statevector);
+    % delete all temporary m files
+    IQMdeleteTempODEfile(ODEfilefullpath);
+    varargout{1} = data.reactionvalues';
+end
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMstates.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMstates.m
new file mode 100644
index 0000000000000000000000000000000000000000..198770f7fd1c5cedabc6bbc757d0d3471c7f6a7f
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMstates.m	
@@ -0,0 +1,36 @@
+function [names,ODEs,initialConditions] = IQMstates(model)
+% IQMstates: Returns information about the states in a model.
+%
+% USAGE:
+% ======
+% [names,ODEs,initialConditions] = IQMstates(model)
+%
+% model: IQMmodel or m-file ODE description of model
+%
+% Output Arguments:
+% =================
+% names: cell-array with models state names
+% ODEs: cell-array with right hand side formula for the states ODE
+%       This output variable is empty if the model is defined by an ODE
+%       file, and non-empty in case the model is defined as an IQMmodel
+% initialConditions: vector with initial conditions for states
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS IQMMODEL OR ODE FILE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if strcmp('IQMmodel',class(model)),
+    iqm = IQMstruct(model);
+    names = {iqm.states.name};
+    ODEs = {iqm.states.ODE};
+    initialConditions = IQMinitialconditions(model);
+else
+    names = feval(model,'states');
+    ODEs = {};
+    initialConditions = IQMinitialconditions(model);
+end
+names = names(:);
+ODEs = ODEs(:);
+initialConditions = initialConditions(:);
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMvariables.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMvariables.m
new file mode 100644
index 0000000000000000000000000000000000000000..e0009bfd7e1946deb05a78808f6fc4a11fad0123
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/IQMvariables.m	
@@ -0,0 +1,72 @@
+function [names,formulas,varargout] = IQMvariables(model,varargin)
+% IQMvariables: Returns information about the variables in an IQMmodel.
+% If a state vector is passed additionally, the corresponding values of the
+% variables are returned also.
+%
+% USAGE:
+% ======
+% [names,formulas] = IQMvariables(model)
+% [names,formulas,variablevalues] = IQMvariables(model,statevector)
+% [names,formulas,variablevalues] = IQMvariables(model,time,statevector)
+%
+% model: IQMmodel (function can not be used on M-file model)
+% statevector: vector with corresponding statevalues
+% time: time instant of the statevector (only needed for time variant
+% systems)
+%
+% DEFAULT VALUES:
+% ===============
+% statevector: not needed 
+% time: 0  (makes no difference for time invariant systems)
+%
+% Output Arguments:
+% =================
+% names: cell-array with models variable names
+% formulas: cell-array with formuals for the variables
+% variablevalues: the values of the variables in the model for the given state and time
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS IQMMODEL OR ODE FILE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if strcmp('IQMmodel',class(model)),
+    iqm = IQMstruct(model);
+    if ~isempty(iqm.variables),
+        names = {iqm.variables.name};
+        formulas = {iqm.variables.formula};
+    else
+        names = {};
+        formulas = {};
+    end
+else
+    if nargin>1,
+        error('On ODE models this function can only return variable names and formulas.');
+    end
+    names = feval(model,'variablenames');
+    formulas = feval(model,'variableformulas');
+end
+names = names(:);
+formulas = formulas(:);
+
+% check if the variable values need to be determined:
+if nargin == 2,    
+    statevector = varargin{1};
+    time = 0;
+    % create data file (using IQMcreateTempODEfile function)
+    [ODEfctname, ODEfilefullpath, DATAfctname] = IQMcreateTempODEfile(model,1);
+    data = feval(DATAfctname, time, statevector);
+    % delete all temporary m files
+    IQMdeleteTempODEfile(ODEfilefullpath);
+    varargout{1} = data.variablevalues';
+elseif nargin == 3,
+    time = varargin{1};
+    statevector = varargin{2};
+    % create data file (using IQMcreateTempODEfile function)
+    [ODEfctname, ODEfilefullpath, DATAfctname] = IQMcreateTempODEfile(model,1);
+    data = feval(DATAfctname, time, statevector);
+    % delete all temporary m files
+    IQMdeleteTempODEfile(ODEfilefullpath);
+    varargout{1} = data.variablevalues';
+end
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/IQMmodel2text/convertModelToTextBCIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/IQMmodel2text/convertModelToTextBCIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..ca68a4148cec7f0070029b398db810ceb133af2e
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/IQMmodel2text/convertModelToTextBCIQM.m	
@@ -0,0 +1,361 @@
+function [modelTextBCStructure] = convertModelToTextBCIQM(iqm)
+% convertModelToTextBCIQM: Converts an IQMmodel to a structure containing the 
+% different parts of the biochemical oriented text description of the
+% model.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+% first check if the complete stoichiometric matrix can be determined.
+% otherwise a biochemical representation is not fully possible and some
+% states still need to be defined by differential equations.
+% determine the names of that states that need to be described by ODEs
+rawFlag = 1;
+silentFlag = 1;
+[N,stateNamesBC] = IQMstoichiometry(iqm,rawFlag,silentFlag);
+stateNames = IQMstates(iqm);
+stateNamesODE = setdiff(stateNames,stateNamesBC);
+
+% Initialize variables
+modelTextBCStructure = [];
+% Get IQMstructure
+IQMstructure = IQMstruct(iqm);
+% Parse structure into the modelTextBCStructure description
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% define filename used for intermediate saving
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+filename = strcat(tempdirIQM,'tempsavingfile.temp');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Name
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+modelTextBCStructure.name = IQMstructure.name;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Notes
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+modelTextBCStructure.notes = IQMstructure.notes;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS THE states
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fid = fopen(filename,'w');
+% first the definition of the states+ODEs that need to be described by ODEs
+for k = 1:length(stateNamesODE),
+    % get index of state name
+    index = strmatchIQM(stateNamesODE{k},{IQMstructure.states.name},'exact');
+    fprintf(fid,'d/dt(%s) = %s\n',stateNamesODE{k},IQMstructure.states(index).ODE);
+end
+if ~isempty(stateNamesODE),
+	fprintf(fid,'\n');
+end
+
+% WRITE OUT ALGEBRAIC RULES
+for k = 1:length(IQMstructure.algebraic),
+    if ~isempty(IQMstructure.algebraic(k).name),
+        fprintf(fid,'0 = %s : %s\n',IQMstructure.algebraic(k).formula,IQMstructure.algebraic(k).name);
+    else
+        fprintf(fid,'0 = %s\n',IQMstructure.algebraic(k).formula);
+    end
+end
+if ~isempty(IQMstructure.algebraic),
+	fprintf(fid,'\n');
+end
+
+% WRITE OUT INITIAL CONDITIONS
+% definition of the initial conditions of the states.
+% additionally for each component optional additional information
+% is processed and written behind the initial conditions.
+% states.type
+% states.compartment
+% states.unittype
+% now construct the states text
+for k = 1:length(IQMstructure.states),
+    name = IQMstructure.states(k).name;
+    if isnumeric(IQMstructure.states(k).initialCondition),
+        fprintf(fid,'%s(0) = %1.6g',name,IQMstructure.states(k).initialCondition);
+    else
+        fprintf(fid,'%s(0) = %s',name,IQMstructure.states(k).initialCondition);
+    end
+    % construct and the additional information
+    type = strtrim(IQMstructure.states(k).type);
+    compartment = strtrim(IQMstructure.states(k).compartment);
+    unittype = strtrim(IQMstructure.states(k).unittype);
+    % check if all information is given
+    if ~isempty(strfind(lower(type),'specie')),
+        informationText = strcat('{',type,':',compartment,':',unittype,'}');
+    elseif ~isempty(strfind(lower(type),'compartment')),
+        informationText = strcat('{',type,':',compartment,'}');
+    elseif ~isempty(strfind(lower(type),'parameter')),
+        informationText = strcat('{',type,'}');
+    else
+        informationText = '';
+    end
+    fprintf(fid,' %s',informationText);
+    if ~isempty(IQMstructure.states(k).notes)
+        fprintf(fid,' %% %s',IQMstructure.states(k).notes);
+    end
+    fprintf(fid,'\n');
+end
+% do the same for algebraic variable initial conditions
+for k = 1:length(IQMstructure.algebraic),
+    if ~isempty(IQMstructure.algebraic(k).name),
+        name = IQMstructure.algebraic(k).name;
+        if isnumeric(IQMstructure.algebraic(k).initialCondition),
+            fprintf(fid,'%s(0) = %1.6g',name,IQMstructure.algebraic(k).initialCondition);
+        else
+            fprintf(fid,'%s(0) = %s',name,IQMstructure.algebraic(k).initialCondition);
+        end
+        % construct the additional information
+        type = strtrim(IQMstructure.algebraic(k).type);
+        compartment = strtrim(IQMstructure.algebraic(k).compartment);
+        unittype = strtrim(IQMstructure.algebraic(k).unittype);
+        % check if all information is given
+        if ~isempty(strfind(lower(type),'specie')),
+            informationText = strcat('{',type,':',compartment,':',unittype,'}');
+        elseif ~isempty(strfind(lower(type),'compartment')),
+            informationText = strcat('{',type,':',compartment,'}');
+        elseif ~isempty(strfind(lower(type),'parameter')),
+            informationText = strcat('{',type,'}');
+        else
+            informationText = '';
+        end
+        fprintf(fid,' %s',informationText);
+        if ~isempty(IQMstructure.algebraic(k).notes)
+            fprintf(fid,' %% %s',IQMstructure.algebraic(k).notes);
+        end
+        fprintf(fid,'\n');
+    end
+end
+% rewind the file and read it out
+fclose(fid); fid = fopen(filename,'r');
+modelTextBCStructure.states = fread(fid,inf,'uint8=>char')';
+fclose(fid);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Parameters
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% add the parameters
+% additionally for each parameter optional additional information
+% is processed and written behind the parameters.
+% parameters.type
+% parameters.compartment
+% parameters.unittype
+fid = fopen(filename,'w');
+for k = 1:length(IQMstructure.parameters),
+    fprintf(fid,'%s = %1.6g',IQMstructure.parameters(k).name,IQMstructure.parameters(k).value);
+    % construct and the additional information
+    type = strtrim(IQMstructure.parameters(k).type);
+    compartment = strtrim(IQMstructure.parameters(k).compartment);
+    unittype = strtrim(IQMstructure.parameters(k).unittype);
+    % check if all information is given
+    if ~isempty(strfind(lower(type),'specie')),
+        informationText = strcat('{',type,':',compartment,':',unittype,'}');
+    elseif ~isempty(strfind(lower(type),'compartment')),
+        informationText = strcat('{',type,':',compartment,'}');
+    elseif ~isempty(strfind(lower(type),'parameter')),
+        informationText = strcat('{',type,'}');
+    else
+        informationText = '';
+    end
+    fprintf(fid,' %s',informationText);
+    if ~isempty(IQMstructure.parameters(k).notes)
+        fprintf(fid,' %% %s',IQMstructure.parameters(k).notes);
+    end
+    fprintf(fid,'\n');
+end
+% rewind the file and read it out
+fclose(fid); fid = fopen(filename,'r');
+modelTextBCStructure.parameters = fread(fid,inf,'uint8=>char')';
+fclose(fid);
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Variables
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fid = fopen(filename,'w');
+for k = 1:length(IQMstructure.variables),
+    fprintf(fid,'%s = %s',IQMstructure.variables(k).name,IQMstructure.variables(k).formula);
+    % construct and the additional information
+    type = strtrim(IQMstructure.variables(k).type);
+    compartment = strtrim(IQMstructure.variables(k).compartment);
+    unittype = strtrim(IQMstructure.variables(k).unittype);
+    % check if all information is given
+    if ~isempty(strfind(lower(type),'specie')),
+        informationText = strcat('{',type,':',compartment,':',unittype,'}');
+    elseif ~isempty(strfind(lower(type),'compartment')),
+        informationText = strcat('{',type,':',compartment,'}');
+    elseif ~isempty(strfind(lower(type),'parameter')),
+        informationText = strcat('{',type,'}');
+    else
+        informationText = '';
+    end
+    fprintf(fid,' %s',informationText);
+    if ~isempty(IQMstructure.variables(k).notes)
+        fprintf(fid,' %% %s',IQMstructure.variables(k).notes);
+    end
+    fprintf(fid,'\n');
+end
+% rewind the file and read it out
+fclose(fid); fid = fopen(filename,'r');
+modelTextBCStructure.variables = fread(fid,inf,'uint8=>char')';
+fclose(fid);
+
+[N, stateNames] = reverseMoietyConservationsIQM(iqm);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS THE REACTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Use the stoichiometric matrix determined above (by eventually adding
+% species that are defined by variables)
+% get reaction names, kinetics, and reversibility flag
+[reactionNames,reactionFormulas,reactionRevFlags] = IQMreactions(iqm);
+% now the reaction text can be built
+fid = fopen(filename,'w');
+% cycle through the columns of the stoichiometric matrix N to build the 
+% reaction expressions
+for k1 = 1:size(N,2),
+    Ncol = N(:,k1);
+    % first get the substrates by finding the negative elements in Ncol
+    substrateIndices = find(Ncol < 0);
+    % then get the products by finding the positive elements in Ncol
+    productIndices = find(Ncol > 0);
+    % determine the needed information
+    reactionName = reactionNames{k1};
+    reactionRevFlag = reactionRevFlags(k1);
+    reactionFormula = reactionFormulas{k1};
+    substrateNames = stateNames(substrateIndices);
+    productNames = stateNames(productIndices);
+    substrateStoichiometries = abs(Ncol(substrateIndices));
+    productStoichiometries = abs(Ncol(productIndices));
+    % if reversible split up the reaction rate in two parts. if this is not
+    % possible, issue a warning and set the reaction as irreversible
+    if reactionRevFlag ~= 0,
+        irreversibleRates = explodePCIQM(reactionFormula,'-');
+        if length(irreversibleRates) ~= 2,
+            % Need to have two parts that are separated by a '-' sign. (Forward
+            % first, then reverse reaction kinetics).
+            warning(sprintf('Reaction ''%s'' is marked reversible but rate expression is not given in the\nrequired format (R = Rf-Rr). The reaction will be treated as irreversible.\n', reactionName));
+            reactionRevFlag = 0;
+        else
+            reactionForward = irreversibleRates{1};
+            reactionReverse = irreversibleRates{2};
+        end
+    end
+    % format the output of the reaction text
+    % first the reaction expression, e.g. 2*A + 4*C => 3*B
+    % the substrates
+    if ~isempty(substrateNames),
+        if substrateStoichiometries(1) ~= 1,
+            fprintf(fid,'%g*%s',substrateStoichiometries(1),substrateNames{1});
+        else
+            fprintf(fid,'%s',substrateNames{1});
+        end
+    end
+    for k2 = 2:length(substrateNames),
+        if substrateStoichiometries(k2) ~= 1,
+            fprintf(fid,'+%g*%s',substrateStoichiometries(k2),substrateNames{k2});
+        else
+            fprintf(fid,'+%s',substrateNames{k2});
+        end
+    end
+    % the reaction equation sign
+    if reactionRevFlag == 0,
+        fprintf(fid,' => ');  % irreversible
+    else
+        fprintf(fid,' <=> '); % reversible
+    end
+    % the products
+    if ~isempty(productNames),
+        if productStoichiometries(1) ~= 1,
+            fprintf(fid,'%g*%s',productStoichiometries(1),productNames{1});
+        else
+            fprintf(fid,'%s',productNames{1});
+        end
+    end
+    for k2 = 2:length(productNames),
+        if productStoichiometries(k2) ~= 1,
+            fprintf(fid,'+%g*%s',productStoichiometries(k2),productNames{k2});
+        else
+            fprintf(fid,'+%s',productNames{k2});
+        end
+    end
+    % separator and reaction name
+    fprintf(fid,' : %s',reactionName); 
+    % fast flag
+    if IQMstructure.reactions(k1).fast == 1,
+        fprintf(fid,' {fast}'); 
+    end
+    % notes
+    if ~isempty(IQMstructure.reactions(k1).notes),
+        fprintf(fid,' %% %s',IQMstructure.reactions(k1).notes);
+    end
+    % new line 
+    fprintf(fid,'\n'); 
+    % now the reaction rate expression(s)
+    if reactionRevFlag == 0,
+        fprintf(fid,'\tvf = %s\n',reactionFormula); 
+    else
+        fprintf(fid,'\tvf = %s\n\tvr = %s\n',reactionForward,reactionReverse); 
+    end
+    % new line after reaction definition
+    fprintf(fid,'\n'); 
+end
+% rewind the file and read it out
+fclose(fid); fid = fopen(filename,'r');
+modelTextBCStructure.reactions = fread(fid,inf,'uint8=>char')';
+fclose(fid);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Functions
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fid = fopen(filename,'w');
+for k = 1:length(IQMstructure.functions),
+    fprintf(fid,'%s(%s) = %s',IQMstructure.functions(k).name,IQMstructure.functions(k).arguments,IQMstructure.functions(k).formula);
+    if ~isempty(IQMstructure.functions(k).notes)
+        fprintf(fid,' %% %s\n',IQMstructure.functions(k).notes);
+    else
+        fprintf(fid,'\n');
+    end
+end
+% rewind the file and read it out
+fclose(fid); fid = fopen(filename,'r');
+modelTextBCStructure.functions = fread(fid,inf,'uint8=>char')';
+fclose(fid);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Events
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fid = fopen(filename,'w');
+for k = 1:length(IQMstructure.events),
+    fprintf(fid,'%s = %s',IQMstructure.events(k).name,IQMstructure.events(k).trigger);
+    for k2 = 1:length(IQMstructure.events(k).assignment),
+        fprintf(fid,',%s,%s',IQMstructure.events(k).assignment(k2).variable,IQMstructure.events(k).assignment(k2).formula);
+    end
+    if ~isempty(IQMstructure.events(k).notes)
+        fprintf(fid,' %% %s\n',IQMstructure.events(k).notes);
+    else
+        fprintf(fid,'\n');
+    end
+end
+% rewind the file and read it out
+fclose(fid); fid = fopen(filename,'r');
+modelTextBCStructure.events = fread(fid,inf,'uint8=>char')';
+fclose(fid);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% MATLAB functions
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+modelTextBCStructure.functionsMATLAB = IQMstructure.functionsMATLAB;
+
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DELETE WHITESPACES IN STRINGS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Useful for taking away whitespaces in kineticLaw formulas, as
+% seen in some example models
+function [outputString] = removeWhiteSpace(inputString)
+outputString = strrep(inputString,' ','');
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/IQMmodel2text/convertModelToTextIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/IQMmodel2text/convertModelToTextIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..3612f342e7fc9cebad4909d0d39e709cd2e08b87
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/IQMmodel2text/convertModelToTextIQM.m	
@@ -0,0 +1,303 @@
+function [modelTextStructure] = convertModelToTextIQM(iqm)
+% convertModelToTextIQM: Converts an IQMmodel to a structure containing the 
+% different parts of the text description of the model. 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+% Initialize variables
+modelTextStructure = [];
+% Get IQMstructure
+IQMstructure = IQMstruct(iqm);
+% Parse structure into the modelTextStructure description
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% define filename used for intermediate saving
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+filename = strcat(tempdirIQM,'tempsavingfile.temp');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Name
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+modelTextStructure.name = IQMstructure.name;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Notes
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+modelTextStructure.notes = IQMstructure.notes;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% error variables
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+informationErrorText = '';
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% States and algebraic rules
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fid = fopen(filename,'w');
+for k = 1:length(IQMstructure.states),
+    % Get ODEs
+    fprintf(fid,'d/dt(%s) = %s',IQMstructure.states(k).name,IQMstructure.states(k).ODE);
+    % construct the additional information (type, compartment, unittype)
+    type = IQMstructure.states(k).type;
+    compartment = IQMstructure.states(k).compartment;
+    unittype = IQMstructure.states(k).unittype;
+    if ~isempty(type) || ~isempty(compartment) || ~isempty(unittype),
+        % at least one information present
+        if ~isempty(strfind(lower(type),'specie')),
+            % all three information fields need to be written out
+            informationText = strcat('{',type,':',compartment,':',unittype,'}');
+        elseif ~isempty(strfind(lower(type),'parameter')),
+            % just the type
+            informationText = strcat('{',type,'}');
+        elseif ~isempty(strfind(lower(type),'compartment')),
+            % type and compartment
+            informationText = strcat('{',type,':',compartment,'}');
+        else
+            % error
+            informationErrorText = sprintf('%sType information for state ''%s'' seems to be wrong.\n',informationErrorText,IQMstructure.states(k).name);
+        end
+    else
+        % no text needed, since no information provided
+        informationText = '';
+    end
+    % add information text
+    fprintf(fid,' %s',informationText);    
+    % add eventual notes
+    if ~isempty(IQMstructure.states(k).notes)
+        fprintf(fid,' %%%s',IQMstructure.states(k).notes);
+    end
+    % add line break
+    fprintf(fid,'\n');
+end
+% WRITE OUT ALGEBRAIC RULES
+for k = 1:length(IQMstructure.algebraic),
+    if ~isempty(IQMstructure.algebraic(k).name),
+        fprintf(fid,'\n0 = %s : %s',IQMstructure.algebraic(k).formula,IQMstructure.algebraic(k).name);
+    else
+        fprintf(fid,'\n0 = %s',IQMstructure.algebraic(k).formula);
+    end
+    % construct the additional information (type, compartment, unittype)
+    type = IQMstructure.algebraic(k).type;
+    compartment = IQMstructure.algebraic(k).compartment;
+    unittype = IQMstructure.algebraic(k).unittype;
+    if ~isempty(type) || ~isempty(compartment) || ~isempty(unittype),
+        % at least one information present
+        if ~isempty(strfind(lower(type),'specie')),
+            % all three information fields need to be written out
+            informationText = strcat('{',type,':',compartment,':',unittype,'}');
+        elseif ~isempty(strfind(lower(type),'parameter')),
+            % just the type
+            informationText = strcat('{',type,'}');
+        elseif ~isempty(strfind(lower(type),'compartment')),
+            % type and compartment
+            informationText = strcat('{',type,':',compartment,'}');
+        else
+            % error
+            informationErrorText = sprintf('%sType information for algebraic rule ''%s'' seems to be wrong.\n',informationErrorText,IQMstructure.algebraic(k).name);
+        end
+    else
+        % no text needed, since no information provided
+        informationText = '';
+    end
+    % add information text
+    fprintf(fid,' %s',informationText);    
+    % add notes if present
+    if ~isempty(IQMstructure.algebraic(k).notes),
+        fprintf(fid,' %% %s',IQMstructure.algebraic(k).notes);
+    end    
+end
+if ~isempty(IQMstructure.algebraic),
+	fprintf(fid,'\n');
+end
+% WRITE OUT INITIAL CONDITIONS
+% states
+for k = 1:length(IQMstructure.states),
+    if isnumeric(IQMstructure.states(k).initialCondition),
+        fprintf(fid,'\n%s(0) = %1.6g',IQMstructure.states(k).name,IQMstructure.states(k).initialCondition);
+    else
+        fprintf(fid,'\n%s(0) = %s',IQMstructure.states(k).name,IQMstructure.states(k).initialCondition);
+    end
+end
+% algebraic variables
+for k = 1:length(IQMstructure.algebraic),
+    if ~isempty(IQMstructure.algebraic(k).name),
+        if isnumeric(IQMstructure.algebraic(k).initialCondition),
+            fprintf(fid,'\n%s(0) = %1.6g',IQMstructure.algebraic(k).name,IQMstructure.algebraic(k).initialCondition);
+        else
+            fprintf(fid,'\n%s(0) = %s',IQMstructure.algebraic(k).name,IQMstructure.algebraic(k).initialCondition);
+        end
+    end
+end
+% rewind the file and read it out
+fclose(fid); fid = fopen(filename,'r');
+modelTextStructure.states = fread(fid,inf,'uint8=>char')';
+fclose(fid);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Parameters
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fid = fopen(filename,'w');
+for k = 1:length(IQMstructure.parameters),
+    fprintf(fid,'%s = %1.6g',IQMstructure.parameters(k).name,IQMstructure.parameters(k).value);
+    % construct the additional information (type, compartment, unittype)
+    type = IQMstructure.parameters(k).type;
+    compartment = IQMstructure.parameters(k).compartment;
+    unittype = IQMstructure.parameters(k).unittype;
+    if ~isempty(type) || ~isempty(compartment) || ~isempty(unittype),
+        % at least one information present
+        if ~isempty(strfind(lower(type),'specie')),
+            % all three information fields need to be written out
+            informationText = strcat('{',type,':',compartment,':',unittype,'}');
+        elseif ~isempty(strfind(lower(type),'parameter')),
+            % just the type
+            informationText = strcat('{',type,'}');
+        elseif ~isempty(strfind(lower(type),'compartment')),
+            % type and compartment
+            informationText = strcat('{',type,':',compartment,'}');
+        else
+            % error
+            informationErrorText = sprintf('%sType information for parameter ''%s'' seems to be wrong.\n',informationErrorText,IQMstructure.parameters(k).name);
+        end
+    else
+        % no text needed, since no information provided
+        informationText = '';
+    end
+    % add information text
+    fprintf(fid,' %s',informationText);    
+    % add eventual notes
+    if ~isempty(IQMstructure.parameters(k).notes)
+        fprintf(fid,' %%%s',IQMstructure.parameters(k).notes);
+    end
+    % add a line break
+    fprintf(fid,'\n');
+end
+% rewind the file and read it out
+fclose(fid); fid = fopen(filename,'r');
+modelTextStructure.parameters = fread(fid,inf,'uint8=>char')';
+fclose(fid);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Variables
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fid = fopen(filename,'w');
+for k = 1:length(IQMstructure.variables),
+    fprintf(fid,'%s = %s',IQMstructure.variables(k).name,IQMstructure.variables(k).formula);
+    % construct the additional information (type, compartment, unittype)
+    type = IQMstructure.variables(k).type;
+    compartment = IQMstructure.variables(k).compartment;
+    unittype = IQMstructure.variables(k).unittype;
+    if ~isempty(type) || ~isempty(compartment) || ~isempty(unittype),
+        % at least one information present
+        if ~isempty(strfind(lower(type),'specie')),
+            % all three information fields need to be written out
+            informationText = strcat('{',type,':',compartment,':',unittype,'}');
+        elseif ~isempty(strfind(lower(type),'parameter')),
+            % just the type
+            informationText = strcat('{',type,'}');
+        elseif ~isempty(strfind(lower(type),'compartment')),
+            % type and compartment
+            informationText = strcat('{',type,':',compartment,'}');
+        else
+            % error
+            informationErrorText = sprintf('%sType information for variable ''%s'' seems to be wrong.\n',informationErrorText,IQMstructure.variables(k).name);
+        end
+    else
+        % no text needed, since no information provided
+        informationText = '';
+    end
+    % add information text
+    fprintf(fid,' %s',informationText);    
+    % add eventual notes
+    if ~isempty(IQMstructure.variables(k).notes)
+        fprintf(fid,' %%%s',IQMstructure.variables(k).notes);
+    end
+    % add a line break
+    fprintf(fid,'\n');
+end
+% rewind the file and read it out
+fclose(fid); fid = fopen(filename,'r');
+modelTextStructure.variables = fread(fid,inf,'uint8=>char')';
+fclose(fid);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check information text error
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(informationErrorText),
+    error(informationErrorText);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Reactions
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fid = fopen(filename,'w');
+for k = 1:length(IQMstructure.reactions),
+    fprintf(fid,'%s = %s',IQMstructure.reactions(k).name,IQMstructure.reactions(k).formula);
+    if IQMstructure.reactions(k).reversible == 1,
+        fprintf(fid,' {reversible}');
+    end
+    if IQMstructure.reactions(k).fast == 1,
+        fprintf(fid,' {fast}');
+    end
+    if ~isempty(IQMstructure.reactions(k).notes)
+        fprintf(fid,' %%%s\n',IQMstructure.reactions(k).notes);
+    else
+        fprintf(fid,'\n');
+    end
+end
+% rewind the file and read it out
+fclose(fid); fid = fopen(filename,'r');
+modelTextStructure.reactions = fread(fid,inf,'uint8=>char')';
+fclose(fid);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Functions
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fid = fopen(filename,'w');
+for k = 1:length(IQMstructure.functions),
+    fprintf(fid,'%s(%s) = %s',IQMstructure.functions(k).name,IQMstructure.functions(k).arguments,IQMstructure.functions(k).formula);
+    if ~isempty(IQMstructure.functions(k).notes)
+        fprintf(fid,' %%%s\n',IQMstructure.functions(k).notes);
+    else
+        fprintf(fid,'\n');
+    end
+end
+% rewind the file and read it out
+fclose(fid); fid = fopen(filename,'r');
+modelTextStructure.functions = fread(fid,inf,'uint8=>char')';
+fclose(fid);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Events
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fid = fopen(filename,'w');
+for k = 1:length(IQMstructure.events),
+    fprintf(fid,'%s = %s',IQMstructure.events(k).name,IQMstructure.events(k).trigger);
+    for k2 = 1:length(IQMstructure.events(k).assignment),
+        fprintf(fid,',%s,%s',IQMstructure.events(k).assignment(k2).variable,IQMstructure.events(k).assignment(k2).formula);
+    end
+    if ~isempty(IQMstructure.events(k).notes)
+        fprintf(fid,' %%%s\n',IQMstructure.events(k).notes);
+    else
+        fprintf(fid,'\n');
+    end
+end
+% rewind the file and read it out
+fclose(fid); fid = fopen(filename,'r');
+modelTextStructure.events = fread(fid,inf,'uint8=>char')';
+fclose(fid);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% MATLAB functions
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+modelTextStructure.functionsMATLAB = IQMstructure.functionsMATLAB;
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DELETE WHITESPACES IN STRINGS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Useful for taking away whitespaces in kineticLaw formulas, as
+% seen in some example models
+function [outputString] = removeWhiteSpace(inputString)
+outputString = strrep(inputString,' ','');
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/IQMmodel2text/reverseMoietyConservationsIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/IQMmodel2text/reverseMoietyConservationsIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..8df01162ba3562505a8e3e62b6351f448b200660
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/IQMmodel2text/reverseMoietyConservationsIQM.m	
@@ -0,0 +1,138 @@
+function [N,stateNames] = reverseMoietyConservationsIQM(iqm,varargin)
+% reverseMoietyConservationsIQM: Function searching for moietyconservations
+% in the system. Then an augmented stoichiometric matrix is calculated in 
+% which also the species determined by moiety conservations appear.
+%
+% input arguments: iqm, specieFlag (optional)
+% if the flag is set only variables that are species will be considered
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+specieFlag = 0;
+if nargin == 2,
+    specieFlag = varargin{1};
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET INFORMATION ABOUT EVENTUAL MOIETY CONSERVATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% This is done by searching all variables for a variable defined in the
+% format of:    VARIABLE = PARAMETER - factor*STATE ... - factor*STATE ... - factor*STATE 		
+% Then it is assumed that VARIABLE + factor*STATE + ... is a conserved moiety and
+% stored as such for later use. The "factor*" is optional but if existent
+% has to be numerical.
+
+if ~specieFlag,
+    % just consider all variables
+    [allVariables, allVariableFormulas] = IQMvariables(iqm);
+else
+    allVariables = {};
+    allVariableFormulas = {};
+    iqmstruct = struct(iqm);
+    for k=1:length(iqmstruct.variables),
+        if strcmp(iqmstruct.variables(k).type,'isSpecie'),
+            allVariables{end+1} = iqmstruct.variables(k).name;
+            allVariableFormulas{end+1} = iqmstruct.variables(k).formula;
+        end
+    end
+end
+
+moietyconservations = [];
+indexMC = 1;
+for k1 = 1:length(allVariables),
+    variableFormula = allVariableFormulas{k1};
+    terms = explodePCIQM(variableFormula,'-');
+    if length(terms) > 1,
+        % process the terms only in the case that there are more than one single term.
+        % first check if the first term is composed only of a parameter
+        % name or a numeric value
+        firstTerm = strtrim(terms{1});
+        if isparameterIQM(iqm,firstTerm) || ~isempty(str2num(firstTerm)),
+            % only continue if first term was a parameter
+            % now cycle through the remaining terms and check if they 
+            % are states or factor*states
+            formatCorrect = 1;
+            listofstates = {};  % list of states in conservation
+            listoffactors = []; % list of factors in conservation
+            indexstates = 1;
+            for k2 = 2:length(terms),
+                checkStateTerms = explodePCIQM(terms{k2},'*');
+                % only accept lengths 1 or 2 (possibly with or without
+                % factor) otherwise break
+                if length(checkStateTerms) == 1,
+                    if isstateIQM(iqm,strtrim(checkStateTerms{1})),
+                        % yes, state found => add it to the list
+                        listofstates{indexstates} = strtrim(checkStateTerms{1});
+                        listoffactors(indexstates) = 1;
+                        indexstates = indexstates + 1;
+                    else
+                        formatCorrect = 0;
+                        break;
+                    end
+                elseif length(checkStateTerms) == 2,
+                    % second term needs to be a state
+                    % if this is the case the first term needs to be
+                    % numeric
+                    if isstateIQM(iqm,strtrim(checkStateTerms{2})),
+                        % yes, state found => check if first term is
+                        % numeric
+                        value = str2num(checkStateTerms{1});
+                        if ~isempty(value),
+                            listofstates{indexstates} = strtrim(checkStateTerms{2});
+                            listoffactors(indexstates) = value;
+                            indexstates = indexstates + 1;
+                        else
+                            formatCorrect = 0;
+                            break;
+                        end
+                    else
+                        formatCorrect = 0;
+                        break;
+                    end
+                else
+                    formatCorrect = 0;
+                    break;
+                end
+            end
+            % if formatCorrect = 1 use it as moiety conservation
+            if formatCorrect == 1,
+                % it has the right format for defining a moiety
+                % conservation => accept it
+                moietyconservations(indexMC).variablename = allVariables{k1};
+                moietyconservations(indexMC).states = listofstates;
+                moietyconservations(indexMC).factors = listoffactors;
+                indexMC = indexMC + 1;
+            end
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CONVERT A NONSINGULAR SYSTEM TO A SINGULAR IN CASE OF MOIETY CONSERVATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% first get the stoichiometric matrix of the system
+% Determine the stoichiometric matrix and the state names
+[N,stateNames] = IQMstoichiometry(iqm,1,1);
+% now differentiate the moietyconservations and add the components defined
+% by variables to the stoichiometric matrix
+for k1 = 1:length(moietyconservations),
+    % construct the row for the stoichiometric matrix, belonging to the variable
+    Nrownew = zeros(1,length(IQMreactions(iqm)));
+    for k2 = 1:length(moietyconservations(k1).states),
+        name = moietyconservations(k1).states{k2};
+        % find the index of the statename
+        stateIndex = strmatchIQM(name,stateNames,'exact');
+        % get its row of the stoichiometric matrix multiplied by the factor
+        % of the state in the moiety conservation and substract from
+        % Nrownew
+        Nrownew = Nrownew - moietyconservations(k1).factors(k2)*N(stateIndex,:);
+    end
+    % add species to stateNames (its not a state in the original model but
+    % in the singular version that is constructed now)
+    stateNames{end+1} = moietyconservations(k1).variablename;
+    % add new row to N
+    N = [N; Nrownew];
+end
+
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/IQMmodel2text/setPartsToCompleteTextBCIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/IQMmodel2text/setPartsToCompleteTextBCIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..0d2b76a43095f5912fe7b006cca2eb8e4d22626f
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/IQMmodel2text/setPartsToCompleteTextBCIQM.m	
@@ -0,0 +1,16 @@
+function [completeTextBC] = setPartsToCompleteTextBCIQM(modelTextStructureBC)
+% setPartsToCompleteTextBCIQM: Sets the different parts of a biochemical
+% oriented text description of an IQMmodel together to the complete text
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+completeTextBC = sprintf('********** MODEL NAME\n%s\n',modelTextStructureBC.name);
+completeTextBC = sprintf('%s\n********** MODEL NOTES\n%s\n',completeTextBC,modelTextStructureBC.notes);
+completeTextBC = sprintf('%s\n********** MODEL STATE INFORMATION\n%s\n',completeTextBC,modelTextStructureBC.states);
+completeTextBC = sprintf('%s\n********** MODEL PARAMETERS\n%s\n',completeTextBC,modelTextStructureBC.parameters);
+completeTextBC = sprintf('%s\n********** MODEL VARIABLES\n%s\n',completeTextBC,modelTextStructureBC.variables);
+completeTextBC = sprintf('%s\n********** MODEL REACTIONS\n%s\n',completeTextBC,modelTextStructureBC.reactions);
+completeTextBC = sprintf('%s\n********** MODEL FUNCTIONS\n%s\n',completeTextBC,modelTextStructureBC.functions);
+completeTextBC = sprintf('%s\n********** MODEL EVENTS\n%s\n',completeTextBC,modelTextStructureBC.events);
+completeTextBC = sprintf('%s\n********** MODEL MATLAB FUNCTIONS\n%s\n',completeTextBC,modelTextStructureBC.functionsMATLAB);
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/IQMmodel2text/setPartsToCompleteTextIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/IQMmodel2text/setPartsToCompleteTextIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..ba1a7ca7630ed75e30d7cc51bb413bd54eefe0eb
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/IQMmodel2text/setPartsToCompleteTextIQM.m	
@@ -0,0 +1,17 @@
+function [completeText] = setPartsToCompleteTextIQM(modelTextStructure)
+% setPartsToCompleteTextIQM: Sets the different parts of a text description
+% of an IQMmodel together to the complete text
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+completeText = sprintf('********** MODEL NAME\n%s\n',modelTextStructure.name);
+completeText = sprintf('%s\n********** MODEL NOTES\n%s\n',completeText,modelTextStructure.notes);
+completeText = sprintf('%s\n********** MODEL STATES\n%s\n',completeText,modelTextStructure.states);
+completeText = sprintf('%s\n********** MODEL PARAMETERS\n%s\n',completeText,modelTextStructure.parameters);
+completeText = sprintf('%s\n********** MODEL VARIABLES\n%s\n',completeText,modelTextStructure.variables);
+completeText = sprintf('%s\n********** MODEL REACTIONS\n%s\n',completeText,modelTextStructure.reactions);
+completeText = sprintf('%s\n********** MODEL FUNCTIONS\n%s\n',completeText,modelTextStructure.functions);
+completeText = sprintf('%s\n********** MODEL EVENTS\n%s\n',completeText,modelTextStructure.events);
+completeText = sprintf('%s\n********** MODEL MATLAB FUNCTIONS\n%s\n',completeText,modelTextStructure.functionsMATLAB);
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/ODEmodel/createEventAssignmentFunctionIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/ODEmodel/createEventAssignmentFunctionIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..06e97709dc67638548e8a9ad6058da0c687e068b
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/ODEmodel/createEventAssignmentFunctionIQM.m	
@@ -0,0 +1,171 @@
+function [] = createEventAssignmentFunctionIQM(iqm,filename,varargin)
+% createEventAssignmentFunctionIQM: writes the event assignments to be
+% performed
+%
+% USAGE:
+% ======
+% [] = createEventFunctionIQM(iqm,filename)
+%
+% iqm: IQMmodel  (ODE file model description is not possible to use)
+% filename: the filename to which wo write the model
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+if nargin == 3,
+    delaybase = varargin{1};
+else
+    delaybase = '';
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF IQMmodel (not really needed but safer)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isIQMmodel(iqm),
+    error('Function only defined for IQMmodels.');
+end
+iqmstruct = struct(iqm);
+
+[PATHSTR,functionName,EXT] = fileparts(filename);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% OPEN FILE FOR WRITING AND WRITE HEADER
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fid = fopen(filename,'w');
+fprintf(fid,'function [newstates,parameterValuesNew] = %s(eventIndex,time_local,statevector,parameterValuesNew)\n',functionName);
+fprintf(fid,'%% This function is used to determine the resulting new states when an event has fired.\n\n');
+fprintf(fid,'global time\n');
+fprintf(fid,'time = time_local;\n\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% WRITE THE MODEL STUFF TO INITIALIZE all eventually needed data
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+fprintf(fid,'%% MODEL DATA\n');
+fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+% PROCESS STATES
+stateNames = IQMstates(iqm);
+for k = 1:length(stateNames),
+    fprintf(fid,'%s = statevector(%d);\n',stateNames{k},k);
+end
+% ALGEBRAIC VARIABLES
+if ~isempty(iqmstruct.algebraic),
+    didWriteStart = 0;
+    algebraicNames = {iqmstruct.algebraic.name};
+    offset = length(stateNames);
+    offset2 = 1;
+    for k = 1:length(algebraicNames),
+        if didWriteStart == 0 && ~isempty(algebraicNames{k}),
+            fprintf(fid,'%% ALGEBRAIC VARIABLES\n');
+            didWriteStart = 1;
+        end
+        if ~isempty(algebraicNames{k}),
+            fprintf(fid,'%s = statevector(%d);\n',algebraicNames{k},offset+offset2);
+            offset2 = offset2+1;
+        end
+    end
+else
+    algebraicNames = {};
+end
+
+% PROCESS PARAMETERS
+[parameterNames,parameterValues] = IQMparameters(iqm);
+fprintf(fid,'if isempty(parameterValuesNew),\n');
+for k = 1:length(parameterNames),
+    fprintf(fid,'\t%s = %g;\n',parameterNames{k},parameterValues(k));
+end
+fprintf(fid,'else\n');
+for k = 1:length(parameterNames),
+    fprintf(fid,'\t%s = parameterValuesNew(%d);\n',parameterNames{k},k);
+end
+fprintf(fid,'end\n');
+% PROCESS VARIABLES
+[variableNames,variableFormulas] = IQMvariables(iqm);
+for k = 1:length(variableNames),
+    delayname = [delaybase '_var_' sprintf('%d',k)];
+    fprintf(fid,'%s = %s;\n',variableNames{k},processFormulaIQM(variableFormulas{k},delayname));
+end
+% PROCESS REACTIONS
+[reactionNames,reactionFormulas] = IQMreactions(iqm);
+for k = 1:length(reactionNames),
+    delayname = [delaybase '_var_' sprintf('%d',k)];
+    fprintf(fid,'%s = %s;\n',reactionNames{k},processFormulaIQM(reactionFormulas{k},delayname));
+end
+% PROCESS EVENT ASSIGNMENTS
+for k = 1:length(iqmstruct.events),
+    for k2 = 1:length(iqmstruct.events(k).assignment),
+        delayname = [delaybase '_eventassign_' sprintf('%d',k) '_' sprintf('%d',k2)];
+        fprintf(fid,'eventassign_%d_%d = %s;\n',k,k2,processFormulaIQM(iqmstruct.events(k).assignment(k2).formula,delayname));
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EXECUTE THE EVENT ASSIGNMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+fprintf(fid,'%% EVENT ASSIGNMENTS\n');
+fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+% assign new states with old states
+for k = 1:length(stateNames),
+    fprintf(fid,'%s_new = %s;\n',stateNames{k},stateNames{k});
+end
+% assign new algebraic with old
+for k = 1:length(algebraicNames),
+    if ~isempty(algebraicNames{k}),
+        fprintf(fid,'%s_new = %s;\n',algebraicNames{k},algebraicNames{k});
+    end
+end
+% assign new parameters with old parameters
+for k = 1:length(parameterNames),
+    fprintf(fid,'%s_new = %s;\n',parameterNames{k},parameterNames{k});
+end
+
+% then do the event assignments
+for k = 1:length(iqmstruct.events),
+    fprintf(fid,'if sum(ismember(eventIndex,%d)) ~= 0,\n',k);
+    for k2 = 1:length(iqmstruct.events(k).assignment),
+        fprintf(fid,'\t%s_new = eventassign_%d_%d;\n',iqmstruct.events(k).assignment(k2).variable,k,k2);
+    end
+    fprintf(fid,'end\n');
+end
+
+% then return the changed new states and new parameters
+for k = 1:length(stateNames),
+    fprintf(fid,'newstates(%d) = %s_new;\n',k,stateNames{k});
+end
+offset = length(stateNames);
+for k = 1:length(algebraicNames),
+    if ~isempty(algebraicNames{k}),
+        fprintf(fid,'newstates(%d) = %s_new;\n',k+offset,algebraicNames{k});
+    end
+end
+for k = 1:length(parameterNames),
+    fprintf(fid,'parameterValuesNew(%d) = %s_new;\n',k,parameterNames{k});
+end
+fprintf(fid,'\n');
+% return
+fprintf(fid,'return\n');
+fprintf(fid,'\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Continue writing model stuff
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% WRITE MODEL FUNCTIONS
+[functionNames,functionFormulas,functionArguments] = IQMfunctions(iqm);
+for k = 1:length(functionNames),
+    fprintf(fid,'function [result] = %s(%s)\n',functionNames{k},functionArguments{k});
+    fprintf(fid,'global time\n');
+    delayname = [delaybase '_func_' sprintf('%d',k)];
+    fprintf(fid,'result = %s;\n',processFormulaIQM(functionFormulas{k},delayname));
+    fprintf(fid,'return\n');
+    fprintf(fid,'\n');
+end
+% WRITE THE MATLAB FUNCTIONS
+functionsMATLAB = IQMfunctionsMATLAB(iqm);
+if ~isempty(functionsMATLAB),
+    delayname = [delaybase '_funcmatlab'];
+    fprintf(fid,'%s',processFormulaIQM(functionsMATLAB,delayname));
+    fprintf(fid,'\n');
+end
+% CLOSE FILE
+fclose(fid);
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/ODEmodel/createEventFunctionIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/ODEmodel/createEventFunctionIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..d7305d2b421cfccc4a437b788ae13fb77337e040
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/ODEmodel/createEventFunctionIQM.m	
@@ -0,0 +1,156 @@
+function [] = createEventFunctionIQM(iqm,filename,varargin)
+% createEventFunctionIQM: writes the event handling function that is
+% necessary to pass to the intergrator in order to be able to deal with
+% discrete state events when doing simulations. This function is called is
+% called by the function IQMcreateODEfile in the case that the event flag is
+% set and at least one event is present in the model.
+%
+% USAGE:
+% ======
+% [] = createEventFunctionIQM(iqm,filename)
+%
+% iqm: IQMmodel  (ODE file model description is not possible to use)
+% filename: the filename to which wo write the model
+
+if nargin == 3,
+    delaybase = varargin{1};
+else
+    delaybase = '';
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF IQMmodel (not really needed but safer)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isIQMmodel(iqm),
+    error('Function only defined for IQMmodels.');
+end
+iqmstruct = struct(iqm);
+
+[PATHSTR,functionName,EXT] = fileparts(filename);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EVENT TRIGGER DATA
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+triggerVector = '';
+for k = 1:length(iqmstruct.events),
+    delayname = [delaybase '_eventtrigger_' sprintf('%d',k)];    
+    trigger = processFormulaIQM(iqmstruct.events(k).trigger,delayname);
+    triggerString = sprintf('double(%s)-0.5',trigger);
+    % add trigger to vector
+    triggerVector = sprintf('%s%s\n',triggerVector,triggerString);
+end
+triggerVector = triggerVector(1:end-1);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% OPEN FILE FOR WRITING AND WRITE HEADER
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fid = fopen(filename,'w');
+fprintf(fid,'function [value,isterminal,direction] = %s(time_local,statevector,varargin)\n',functionName);
+fprintf(fid,'%% This function is passed to the MATLAB integrator in order to detect\n%% events that are present in the model.\n\n');
+fprintf(fid,'global time\n');
+fprintf(fid,'time = time_local;\n\n');
+
+fprintf(fid,'parameterValuesNew = [];\n');
+fprintf(fid,'if nargin == 3,\n');
+fprintf(fid,'    parameterValuesNew = varargin{1};\n');
+fprintf(fid,'end\n\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% WRITE THE MODEL STUFF TO INITIALIZE all eventually needed data
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+fprintf(fid,'%% MODEL DATA\n');
+fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+% PROCESS STATES
+stateNames = IQMstates(iqm);
+for k = 1:length(stateNames),
+   fprintf(fid,'%s = statevector(%d);\n',stateNames{k},k);
+end
+% ALGEBRAIC VARIABLES
+if ~isempty(iqmstruct.algebraic),
+    didWriteStart = 0;
+    algebraicNames = {iqmstruct.algebraic.name};
+    offset = length(stateNames);
+    offset2 = 1;
+    for k = 1:length(algebraicNames),
+        if didWriteStart == 0 && ~isempty(algebraicNames{k}),
+            fprintf(fid,'%% ALGEBRAIC VARIABLES\n');
+            didWriteStart = 1;
+        end
+        if ~isempty(algebraicNames{k}),
+            fprintf(fid,'%s = statevector(%d);\n',algebraicNames{k},offset+offset2);
+            offset2 = offset2+1;
+        end
+    end
+end
+
+
+% PROCESS PARAMETERS
+[parameterNames,parameterValues] = IQMparameters(iqm);
+fprintf(fid,'if isempty(parameterValuesNew),\n');
+for k = 1:length(parameterNames),
+    fprintf(fid,'\t%s = %g;\n',parameterNames{k},parameterValues(k));
+end
+fprintf(fid,'else\n'); 
+for k = 1:length(parameterNames),
+    fprintf(fid,'\t%s = parameterValuesNew(%d);\n',parameterNames{k},k);
+end
+fprintf(fid,'end\n');
+% PROCESS VARIABLES
+[variableNames,variableFormulas] = IQMvariables(iqm);
+for k = 1:length(variableNames),
+   delayname = [delaybase '_var_' sprintf('%d',k)];        
+   fprintf(fid,'%s = %s;\n',variableNames{k},processFormulaIQM(variableFormulas{k},delayname));
+end 
+% PROCESS REACTIONS
+[reactionNames,reactionFormulas] = IQMreactions(iqm);
+for k = 1:length(reactionNames),
+   delayname = [delaybase '_reac_' sprintf('%d',k)];    
+   fprintf(fid,'%s = %s;\n',reactionNames{k},processFormulaIQM(reactionFormulas{k},delayname));
+end
+% PROCESS EVENT ASSIGNMENTS
+for k = 1:length(iqmstruct.events),
+    for k2 = 1:length(iqmstruct.events(k).assignment),
+        delayname = [delaybase '_eventassign_' sprintf('%d',k) '_' sprintf('%d',k2)];
+        fprintf(fid,'eventassign_%d_%d = %s;\n',k,k2,processFormulaIQM(iqmstruct.events(k).assignment(k2).formula,delayname));
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% WRITE THE EVENT DATA
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+fprintf(fid,'%% EVENT DATA\n');
+fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+fprintf(fid,'value = [%s]'';\n',triggerVector);
+fprintf(fid,'isterminal = ones(1,%d);\n',length(iqmstruct.events));
+fprintf(fid,'direction = ones(1,%d);\n',length(iqmstruct.events));
+fprintf(fid,'\n');
+
+% return
+fprintf(fid,'return\n');
+fprintf(fid,'\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Continue writing model stuff
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% WRITE MODEL FUNCTIONS
+[functionNames,functionFormulas,functionArguments] = IQMfunctions(iqm);
+for k = 1:length(functionNames),
+    fprintf(fid,'function [result] = %s(%s)\n',functionNames{k},functionArguments{k});
+    fprintf(fid,'global time\n');
+    delayname = [delaybase '_func_' sprintf('%d',k)];    
+    fprintf(fid,'result = %s;\n',processFormulaIQM(functionFormulas{k},delayname));
+    fprintf(fid,'return\n');
+    fprintf(fid,'\n');
+end
+% WRITE THE MATLAB FUNCTIONS
+functionsMATLAB = IQMfunctionsMATLAB(iqm);
+if ~isempty(functionsMATLAB),
+    delayname = [delaybase '_funcmatlab'];    
+    fprintf(fid,'%s',processFormulaIQM(functionsMATLAB,delayname));
+    fprintf(fid,'\n');
+end
+% CLOSE FILE
+fclose(fid);
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/ODEmodel/createSimulationDataFunctionIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/ODEmodel/createSimulationDataFunctionIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..7cb92d48a885cf6587cdfaa7c4abac32668223f9
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/ODEmodel/createSimulationDataFunctionIQM.m	
@@ -0,0 +1,277 @@
+function [] = createSimulationDataFunctionIQM(iqm,filename,varargin)
+% createSimulationDataFunctionIQM: is called by IQMcreateODEfile to create a
+% function that is able to calculate the values of the variables and
+% parameters for given state or state time series.
+%
+% USAGE:
+% ======
+% [] = createSimulationDataFunctionIQM(iqm, filename)
+%
+% iqm: IQMmodel
+% filename: the name of the file to be created
+
+if nargin == 3,
+    delaybase = varargin{1};
+else
+    delaybase = '';
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF IQMmodel (not really needed but safer)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isIQMmodel(iqm),
+    error('Function only defined for IQMmodels.');
+end
+iqmstruct = struct(iqm);
+
+[PATHSTR,functionName,EXT] = fileparts(filename);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% OPEN FILE FOR WRITING AND WRITE HEADER
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fid = fopen(filename,'w');
+fprintf(fid,'function [output] = %s(varargin)\n',functionName);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% WRITE THE HEADER
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+fprintf(fid,'%% %s\n',iqmstruct.name);
+fprintf(fid,'%% Generated: %s\n',datestr(now));
+fprintf(fid,'%% \n');
+fprintf(fid,'%% [output] = %s(statevector) => time=0\n',functionName);
+fprintf(fid,'%% [output] = %s(time,statevector)\n',functionName);
+fprintf(fid,'%% \n');
+fprintf(fid,'%% output: structure containing information about the values of the variables\n');
+fprintf(fid,'%%         and reaction rates for given time and state information.\n');
+fprintf(fid,'%% \n');
+fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+fprintf(fid,'\n');
+fprintf(fid,'parameterValuesNew_ALL = [];\n\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE VARARGINS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+fprintf(fid,'%% HANDLE VARIABLE INPUT ARGUMENTS\n');
+fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+fprintf(fid,'if nargin == 1,\n');
+
+    fprintf(fid,'\ttime_vector = [0];\n');
+    fprintf(fid,'\tstatevector = varargin{1};\n');
+
+fprintf(fid,'elseif nargin == 2,\n');
+
+    fprintf(fid,'\ttime_vector = varargin{1};\n');
+    fprintf(fid,'\tstatevector = varargin{2};\n');
+
+fprintf(fid,'elseif nargin == 3,\n');
+
+    fprintf(fid,'\ttime_vector = varargin{1};\n');
+    fprintf(fid,'\tstatevector = varargin{2};\n');
+    fprintf(fid,'\tparameterValuesNew_ALL = varargin{3};\n');
+
+fprintf(fid,'else\n');
+    fprintf(fid,'\terror(''Incorrect number of input arguments.'');\n');
+fprintf(fid,'end\n');
+fprintf(fid,'\n');
+
+fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+fprintf(fid,'%% DETERMINE DATA\n');
+fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+fprintf(fid,'variableValuesTotal = [];\n');
+fprintf(fid,'reactionValuesTotal = [];\n');
+fprintf(fid,'if length(time_vector) == 1,\n');
+    fprintf(fid,'\tstatevector = statevector(:)'';\n');
+    fprintf(fid,'\t[variableValuesTotal, reactionValuesTotal] = getValues(time_vector,statevector,parameterValuesNew_ALL);\n');
+fprintf(fid,'else\n');
+    fprintf(fid,'\tfor k = 1:length(time_vector),\n');
+        fprintf(fid,'\t\tif ~isempty(parameterValuesNew_ALL),\n');
+        fprintf(fid,'\t\t\t[variableValues, reactionValues] = getValues(time_vector(k),statevector(k,:),parameterValuesNew_ALL(k,:));\n');
+        fprintf(fid,'\t\telse\n');
+        fprintf(fid,'\t\t\t[variableValues, reactionValues] = getValues(time_vector(k),statevector(k,:),[]);\n');
+        fprintf(fid,'\t\tend\n');    
+        fprintf(fid,'\t\tvariableValuesTotal = [variableValuesTotal; variableValues];\n');
+        fprintf(fid,'\t\treactionValuesTotal = [reactionValuesTotal; reactionValues];\n');
+    fprintf(fid,'\tend\n');
+fprintf(fid,'end\n');
+
+variableNames = IQMvariables(iqm);
+reactionNames = IQMreactions(iqm);
+stateNames = IQMstates(iqm);
+algebraicNames = IQMalgebraic(iqm);
+
+fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+fprintf(fid,'%% CONSTRUCT OUTPUT VARIABLE\n');
+fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+fprintf(fid,'output.time = time_vector;\n');
+fprintf(fid,'output.states = ');
+if ~isempty(stateNames),
+    fprintf(fid,'{');
+    for k = 1:length(stateNames),
+        fprintf(fid,'''%s'',',stateNames{k});
+    end
+    fprintf(fid,'};\n');
+else
+    fprintf(fid,'{};\n');
+end
+fprintf(fid,'output.statevalues = statevector(:,1:%d);\n',length(stateNames));
+
+if ~isempty(algebraicNames),
+    didWriteStart = 0;
+    for k = 1:length(algebraicNames),
+        if didWriteStart == 0 && ~isempty(algebraicNames{k}),
+            fprintf(fid,'output.algebraic = ');
+            fprintf(fid,'{');
+            didWriteStart = 1;
+        end
+        if ~isempty(algebraicNames{k}),
+            fprintf(fid,'''%s'',',algebraicNames{k});
+        end
+    end
+    if didWriteStart == 1,
+        fprintf(fid,'};\n');
+        fprintf(fid,'output.algebraicvalues = statevector(:,%d:end);\n',length(stateNames)+1);
+    end
+end
+
+
+
+
+
+fprintf(fid,'output.variables = ');
+if ~isempty(variableNames),
+    fprintf(fid,'{');
+    for k = 1:length(variableNames),
+        fprintf(fid,'''%s'',',variableNames{k});
+    end
+    fprintf(fid,'};\n');
+else
+    fprintf(fid,'{};\n');
+end
+fprintf(fid,'output.variablevalues = variableValuesTotal;\n');
+fprintf(fid,'output.reactions = ');
+if ~isempty(reactionNames),
+    fprintf(fid,'{');
+    for k = 1:length(reactionNames),
+        fprintf(fid,'''%s'',',reactionNames{k});
+    end
+    fprintf(fid,'};\n');
+else 
+    fprintf(fid,'{};\n');
+end
+fprintf(fid,'output.reactionvalues = reactionValuesTotal;\n');
+
+fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+fprintf(fid,'%% Clear global variables used for delay handling\n');
+fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+fprintf(fid,'clear global %s*\n\n',delaybase);
+
+fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+fprintf(fid,'%% RETURN\n');
+fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+fprintf(fid,'return\n');
+fprintf(fid,'\n');
+fprintf(fid,'\n');
+
+fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+fprintf(fid,'%% getValues FUNCTION\n');
+fprintf(fid,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n');
+fprintf(fid,'function [variableValues, reactionValues] = getValues(time_local,statevector,parameterValuesNew)\n');
+fprintf(fid,'global time\n');
+
+fprintf(fid,'variableValues = [];\n');
+fprintf(fid,'reactionValues = [];\n\n');
+
+fprintf(fid,'time = time_local;\n\n');
+
+% PROCESS STATES
+fprintf(fid,'%% STATES\n');
+stateNames = IQMstates(iqm);
+for k = 1:length(stateNames),
+   fprintf(fid,'%s = statevector(%d);\n',stateNames{k},k);
+end
+
+% PROCESS ALGEBRAIC VARIABLES (IF PRESENT)
+if ~isempty(iqmstruct.algebraic),
+    didWriteStart = 0;
+    algebraicNames = {iqmstruct.algebraic.name};
+    offset = length(stateNames);
+    offset2 = 1;
+    for k = 1:length(algebraicNames),
+        if didWriteStart == 0 && ~isempty(algebraicNames{k}),
+            fprintf(fid,'%% ALGEBRAIC VARIABLES\n');
+            didWriteStart = 1;
+        end
+        if ~isempty(algebraicNames{k}),
+            fprintf(fid,'%s = statevector(%d);\n',algebraicNames{k},offset+offset2);
+            offset2 = offset2+1;
+        end
+    end
+end
+
+% PROCESS PARAMETERS
+fprintf(fid,'%% PARAMETERS\n');
+[parameterNames,parameterValues] = IQMparameters(iqm);
+fprintf(fid,'if isempty(parameterValuesNew),\n');
+for k = 1:length(parameterNames),
+    fprintf(fid,'\t%s = %g;\n',parameterNames{k},parameterValues(k));
+end
+fprintf(fid,'else\n');
+for k = 1:length(parameterNames),
+    fprintf(fid,'\t%s = parameterValuesNew(%d);\n',parameterNames{k},k);
+end
+fprintf(fid,'end\n');
+fprintf(fid,'\n');
+
+% PROCESS VARIABLES
+fprintf(fid,'%% VARIABLES\n');
+[variableNames,variableFormulas] = IQMvariables(iqm);
+for k = 1:length(variableNames),
+   delayname = [delaybase '_var_' sprintf('%d',k)];    
+   fprintf(fid,'%s = %s;\n',variableNames{k},processFormulaIQM(variableFormulas{k},delayname));
+end
+
+% PROCESS REACTIONS
+fprintf(fid,'%% REACTIONS\n');
+[reactionNames,reactionFormulas] = IQMreactions(iqm);
+for k = 1:length(reactionNames),
+   delayname = [delaybase '_reac_' sprintf('%d',k)];
+   fprintf(fid,'%s = %s;\n',reactionNames{k},processFormulaIQM(reactionFormulas{k},delayname));
+end
+
+% WRITE OUTPUT VARIABLES
+fprintf(fid,'%% OUTPUT\n');
+for k = 1:length(variableNames),
+   fprintf(fid,'variableValues(%d) = %s;\n',k,variableNames{k});
+end 
+for k = 1:length(reactionNames),
+   fprintf(fid,'reactionValues(%d) = %s;\n',k,reactionNames{k});
+end 
+fprintf(fid,'return\n');
+fprintf(fid,'\n');
+
+% WRITE MODEL FUNCTIONS
+fprintf(fid,'%% FUNCTIONS\n');
+[filenames,functionFormulas,functionArguments] = IQMfunctions(iqm);
+for k = 1:length(filenames),
+    fprintf(fid,'function [result] = %s(%s)\n',filenames{k},functionArguments{k});
+    fprintf(fid,'global time\n');
+    delayname = [delaybase '_func_' sprintf('%d',k)];
+    fprintf(fid,'result = %s;\n',processFormulaIQM(functionFormulas{k},delayname));
+    fprintf(fid,'return\n');
+    fprintf(fid,'\n');
+end
+
+% WRITE THE MATLAB FUNCTIONS
+fprintf(fid,'%% MATLAB FUNCTIONS\n');
+functionsMATLAB = IQMfunctionsMATLAB(iqm);
+if ~isempty(functionsMATLAB),
+    delayname = [delaybase '_funcmatlab'];
+    fprintf(fid,'%s',processFormulaIQM(functionsMATLAB,delayname));
+    fprintf(fid,'\n');
+end
+
+% CLOSE FILE
+fclose(fid);
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/ODEmodel/processFormulaIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/ODEmodel/processFormulaIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..07f74caf2a36500ba63699af55e5d0bf9447b2a2
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/ODEmodel/processFormulaIQM.m	
@@ -0,0 +1,41 @@
+function [formula] = processFormulaIQM(formula,delaybasename)
+% processFormulaIQM: process different things in formulas for the ODE file
+% export. Right now we only take care of delayIQM functions where some info
+% needs to be added.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+count = 1;
+while 1,
+    index = strfind(formula,'delayIQM(');
+    if length(index) < count,
+        break;
+    end
+    indexstart = index(count)+length('delayIQM(');
+    indexend = indexstart;
+    
+    % search the end of the delay argument definition
+    parOpen = 1;
+    while parOpen ~= 0,
+        if formula(indexend) == '(',
+            parOpen = parOpen + 1;
+        elseif formula(indexend) == ')',
+            parOpen = parOpen - 1;
+        end
+        indexend = indexend + 1;
+    end
+    % check if the delaybasename has to be changed
+    if length(index) > 1,
+        delayname = [delaybasename '_' sprintf('%d', count)];
+    else
+        delayname = delaybasename;
+    end
+    % add info to delayIQM call
+    firstpart = formula(1:indexend-2);
+    lastpart = formula(indexend-1:end);
+    middlepart = sprintf(',time,''%s''',delayname);
+    formula = char([double(firstpart) double(middlepart) double(lastpart)]);
+    % increase counter
+    count = count + 1;
+end
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/exportSBMLcheckIQMmodelIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/exportSBMLcheckIQMmodelIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..87ff6ce6f761ee36b458f661a726242e608a75bf
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/exportSBMLcheckIQMmodelIQM.m	
@@ -0,0 +1,134 @@
+function [] = exportSBMLcheckIQMmodelIQM(iqm)
+% exportSBMLcheckIQMmodelIQM
+% Special function for the SBML export of models. The function checks if
+% the IQMmodel fields "type", "compartment", and "unittype" are all set.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+errorMessage = '';
+
+% get a list of all compartments defined in the species and by
+% isCompartment
+compartmentListSpecies = {};
+compartmentDefinitionList = {};
+for k=1:length(iqm.states),
+    if ~isempty(iqm.states(k).compartment),
+        compartmentListSpecies{end+1} = iqm.states(k).compartment;
+    end
+    if strcmp(iqm.states(k).type,'isCompartment'),
+        compartmentDefinitionList{end+1} = iqm.states(k).name;
+    end
+end
+for k=1:length(iqm.parameters),
+    if ~isempty(iqm.parameters(k).compartment),
+        compartmentListSpecies{end+1} = iqm.parameters(k).compartment;
+    end
+    if strcmp(iqm.parameters(k).type,'isCompartment'),
+        compartmentDefinitionList{end+1} = iqm.parameters(k).name;
+    end
+end
+for k=1:length(iqm.variables),
+    if ~isempty(iqm.variables(k).compartment),
+        compartmentListSpecies{end+1} = iqm.variables(k).compartment;
+    end
+    if strcmp(iqm.variables(k).type,'isCompartment'),
+        compartmentDefinitionList{end+1} = iqm.variables(k).name;
+    end
+end
+compartmentListSpecies = unique(compartmentListSpecies);
+compartmentDefinitionList = unique(compartmentDefinitionList);
+wrongCompartments = union(setdiff(compartmentDefinitionList,compartmentListSpecies),setdiff(compartmentListSpecies,compartmentDefinitionList));
+% wrongCompartments might contain 'default' but thats ok
+if ~(length(wrongCompartments) == 1 && strcmp(wrongCompartments{1},'default'))
+    for k = 1:length(wrongCompartments),
+        errorMessage = sprintf('%sWrongly defined compartment ''%s'' (either ''isCompartment'' missing\n    or compartment defined but no species in it.\n',errorMessage,wrongCompartments{k});
+    end
+end
+compartmentList = compartmentDefinitionList;
+
+% cycle through the IQMmodel structure and check the type, unittype, and
+% compartment field
+% states 
+for k=1:length(iqm.states),
+    typeResult = checkType(iqm.states(k).type);
+    if isempty(typeResult),
+        errorMessage = sprintf('%sUndefined ''type'' field for state ''%s''.\n',errorMessage,iqm.states(k).name);
+    end
+    compartmentResult = checkCompartment(iqm.states(k).compartment, compartmentList, typeResult);
+    if isempty(compartmentResult),
+        errorMessage = sprintf('%sWrongly defined ''compartment'' field for state ''%s''.\n',errorMessage,iqm.states(k).name);
+    end
+    unittypeResult = checkUnittype(iqm.states(k).unittype, typeResult);
+    if isempty(unittypeResult),
+        errorMessage = sprintf('%sWrongly defined ''unittype'' field for state ''%s''.\n',errorMessage,iqm.states(k).name);
+    end   
+end
+
+% parameters
+for k=1:length(iqm.parameters),
+    typeResult = checkType(iqm.parameters(k).type);
+    if isempty(typeResult),
+        errorMessage = sprintf('%sUndefined ''type'' field for parameter ''%s''.\n',errorMessage,iqm.parameters(k).name);
+    end
+    compartmentResult = checkCompartment(iqm.parameters(k).compartment, compartmentList, typeResult);
+    if isempty(compartmentResult),
+        errorMessage = sprintf('%sWrongly defined ''compartment'' field for parameter ''%s''.\n',errorMessage,iqm.parameters(k).name);
+    end
+    unittypeResult = checkUnittype(iqm.parameters(k).unittype, typeResult);
+    if isempty(unittypeResult),
+        errorMessage = sprintf('%sWrongly defined ''unittype'' field for parameter ''%s''.\n',errorMessage,iqm.parameters(k).name);
+    end   
+end
+
+% variables
+for k=1:length(iqm.variables),
+    typeResult = checkType(iqm.variables(k).type);
+    if isempty(typeResult),
+        errorMessage = sprintf('%sUndefined ''type'' field for variable ''%s''.\n',errorMessage,iqm.variables(k).name);
+    end
+    compartmentResult = checkCompartment(iqm.variables(k).compartment, compartmentList, typeResult);
+    if isempty(compartmentResult),
+        errorMessage = sprintf('%sWrongly defined ''compartment'' field for variable ''%s''.\n',errorMessage,iqm.variables(k).name);
+    end
+    unittypeResult = checkUnittype(iqm.variables(k).unittype, typeResult);
+    if isempty(unittypeResult),
+        errorMessage = sprintf('%sWrongly defined ''unittype'' field for variable ''%s''.\n',errorMessage,iqm.variables(k).name);
+    end   
+end
+
+% error message
+if ~isempty(errorMessage),
+    errorMessage = sprintf('%s\nFor information on how to correctly define an IQMmodel prior to SBML export,\nplease type: >> help IQMexportSBML\n',errorMessage);
+    error(errorMessage);
+end
+return
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Help function for type
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [result] = checkType(type),
+result = strmatchIQM(type,{'isSpecie','isParameter','isCompartment'},'exact');
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Help function for compartment
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [result] = checkCompartment(compartment, compartmentList, typeResult),
+    result = 1;
+    if typeResult == 1,
+        % type = isSpecie: check if compartment in compartment List
+        result = strmatchIQM(compartment, compartmentList, 'exact');
+    end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Help function for unittype
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [result] = checkUnittype(unittype, typeResult),
+    result = 1;
+    if typeResult == 1,
+        % type = isSpecie: check if 'concentration' or 'amount'
+        result = strmatchIQM(unittype, {'concentration','amount'}, 'exact');
+    end
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/modeltools/IQMmakeSBMLpresets.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/modeltools/IQMmakeSBMLpresets.m
new file mode 100644
index 0000000000000000000000000000000000000000..fce0073ae4fceca465fe3bef860ac8a9cbc4d3a2
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/modeltools/IQMmakeSBMLpresets.m	
@@ -0,0 +1,859 @@
+function [changedModel] = IQMmakeSBMLpresets(model, varargin)
+% IQMmakeSBMLpresets
+% Special function for the SBML export of models. The function preprocesses
+% IQMmodels to preset the unset "type", "compartment", and "unittype" fields
+% in the structure.
+%
+% USAGE:
+% ======
+% [changedModel] = IQMmakeSBMLpresets(model)
+%
+% model: IQMmodel to preset SBML fields
+% changedModel: IQMmodel with preseted SBML fields
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF IQMmodel
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~strcmp('IQMmodel',class(model)),
+    error('Function only defined for IQMmodels.');
+end
+% get the datastructure of the model
+iqm = IQMstruct(model);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK EXTRA INPUT ARGUMENT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% the first extra input argument is used to force the IQMstoichiometry function
+% not to correct the elements of the stoichiometric matrix for the
+% compartment information in cases where species are given in
+% concentrations. This is needed for model construction (BC type of
+% representation and for other things)
+% the second is used for silent use of the function
+% both flags are not further documented and should not be used by others
+% unless they fully understand their meaning
+
+silentFlag = 0;
+debugFlag = 0;
+if nargin == 2,
+    silentFlag = varargin{1};
+elseif nargin == 3,
+    silentFlag = varargin{1};
+    debugFlag = varargin{2};
+end
+
+% get all reactions from IQMmodel
+reactionNames = {iqm.reactions.name};
+reactionNames = reactionNames(:);
+reversibleFlag = {iqm.reactions.reversible};
+reversibleFlag = reversibleFlag(:);
+reactionCount = length(reactionNames);
+if debugFlag,
+    reactionNames
+end
+% get all States from IQMmodel
+stateNames = { iqm.states.name };
+stateNames = stateNames(:);
+stateCount = length(stateNames);
+if debugFlag,
+    stateNames
+end
+
+% test wehter there are predefined compartments in the model
+compartmentList = [];
+compartmentFrom = [];
+compartmentOrigIndex = [];
+compartmentsPredefined = 0;
+[compartmentList, compartmentFrom, compartmentOrigIndex] = fetchCompartments(model);
+if isempty(compartmentList),
+    compartmentsPredefined=0;
+else
+    compartmentsPredefined=1;
+end
+
+% fallback mechanism for ODEs which are given in concentration
+% if no compartments are predefined we have to check parameter names
+% and variable names, too
+parameterNames = { iqm.parameters.name };
+parameterNames = parameterNames(:);
+variableNames = { iqm.variables.name };
+variableNames = variableNames(:);
+variableCount = length(variableNames);
+
+% begin of extraction of ODE information
+% 2 nested for loops:
+% one for the states and
+% one that searches the ODE for reactions etc.
+
+warnings = {};
+warnIndex = 1;
+errors = {};
+
+% run through states ODEs to look for suitable SBML presets
+for currentStateIndex = 1 : stateCount,
+    doProcessState = true;
+    if strcmp(iqm.states(currentStateIndex).type,'isSpecie') && ~isempty(iqm.states(currentStateIndex).compartment) && (strcmp(iqm.states(currentStateIndex).unittype,'amount') || strcmp(iqm.states(currentStateIndex).unittype,'concentration')),
+        doProcessState = false;
+    end
+    if strcmp(iqm.states(currentStateIndex).type,'isCompartment'),
+        doProcessState = false;
+    end
+    if strcmp(iqm.states(currentStateIndex).type,'isParameter'),
+        doProcessState = false;
+    end
+
+    if doProcessState,
+
+        % get the ODE for the specific specie
+        odeString = iqm.states(currentStateIndex).ODE;
+
+        % only for testing reasons
+        if debugFlag,
+            odeString
+        end
+
+        % test wether reaction contains brackets and if yes test for good bracket expression
+        bracketsDetected = 0;
+        if isBracketstring(odeString),
+            bracketsDetected = 1;
+            if ~isBracketstringWellformed(odeString),
+                % something went wrong in the ODE; ask the user to take care
+                errors{1} = char([double('A mistake concerning brackets within the ODE string of state "'), double(iqm.states(currentStateIndex).name), double('" was detected.\n')]);
+                errors{2} = 'Please correct this on your own!';
+                messageOutput(errors, 1);
+                error('\n');
+            end
+        end
+
+        globalStoichiometry = '';
+        localStoichiometry = '';
+        compartmentExpected = 0;
+        constantFound = 0;
+        reacTermCount = 0;
+        firstReacTermStart = 0;
+        identifierBeginDetected = 0;
+        identifierStart = 0;
+        identifierEnd = 0;
+        bracketIndexForSign = [];
+        lastBracketIndexField = 1;
+        for currentCharIndex = 1 : length(odeString),
+            character = odeString(currentCharIndex);
+            if isspace(character),
+                % blanks do not change anything
+                continue;
+            end
+            if ~identifierBeginDetected && (isSign(character) || isNumber(character)),
+                % some part for the stoichiometry matrix was found
+                % append it to Stoichiometry
+                localStoichiometry = char([double(localStoichiometry), double(character)]);
+                % if the last part of the ODE is a constant
+                if (currentCharIndex == length(odeString)),
+                    constantFound = 1;
+                end
+                continue;
+            end
+            if ~identifierBeginDetected && isLetter2(character),
+                % the beginning of an identifier was found
+                if strcmp(localStoichiometry, '/'),
+                    % we expect definitions of concentration with correct
+                    % parentheses
+                    % dS/dt = R1/Compartment => SBML Specie
+                    % dS/dt = R1 + R2/Compartment => SBML Parameter
+                    if ((reacTermCount == 1) || ( (~isempty(strfind(odeString(1:firstReacTermStart), '('))) && (odeString(currentCharIndex-2)==')'))),
+                        compartmentExpected = 1;
+                    else
+                        iqm.states(currentStateIndex).type = 'isParameter';
+                        iqm.states(currentStateIndex).unittype = '';
+                        iqm.states(currentStateIndex).compartment = '';
+                    end
+                else
+                    if constantFound,
+                        [unimportant, localStoichiometry] = testForConstants(localStoichiometry);
+                    else
+                        [constantFound, localStoichiometry] = testForConstants(localStoichiometry);
+                    end
+                end
+                identifierBeginDetected = 1;
+                identifierStart = currentCharIndex;
+                % for the case that a reactionname consists of only one letter
+                identifierEnd = currentCharIndex;
+                % if detected letter is the last one in an ODE
+                if currentCharIndex == length(odeString),
+                    identifier = odeString(identifierStart : identifierEnd);
+                    % test wether found literal is a reaction
+                    checkIdentifierODE(identifier, currentStateIndex);
+                end
+                continue;
+            end
+            if bracketsDetected,
+                if isOpenedBracket(character),
+                    % if a reaction term is detected in front of a bracket this is assumed to be an error
+                    if identifierBeginDetected,
+                        identifier = odeString(identifierStart : identifierEnd);
+                        if ~isFunctionIdentifier(identifier, model),
+                            warnings{warnIndex} = char([double('A term ("'), double(identifier), double('") that seems not to be a function identifier was detected in front of a bracket, see IQMmodel state "'), double(iqm.states(currentStateIndex).name), double('".')]);
+                            warnIndex = warnIndex + 1;
+                            warnings{warnIndex} = '';
+                            warnIndex = warnIndex + 1;
+                        end
+                    else
+                        if strcmp(localStoichiometry, '/'),
+                            compartmentExpected = 1;
+                        else
+                            if constantFound,
+                                [unimportant, localStoichiometry] = testForConstants(localStoichiometry);
+                            else
+                                [constantFound, localStoichiometry] = testForConstants(localStoichiometry);
+                            end
+                        end
+                    end
+                    bracketIndexForSign(lastBracketIndexField) = length(globalStoichiometry);
+                    globalStoichiometry = char([double(globalStoichiometry), double(localStoichiometry)]);
+                    localStoichiometry = '';
+                    lastBracketIndexField = lastBracketIndexField + 1;
+                    identifierBeginDetected = 0;
+                    continue;
+                end
+                if isClosedBracket(character),
+                    if identifierBeginDetected,
+                        if debugFlag,
+                            fprintf('closing bracketDetected');
+                            localStoichiometry
+                            globalStoichiometry
+                        end
+                        identifier = odeString(identifierStart : identifierEnd);
+                        % if we expect a compartment but know that this will
+                        % not be the last component in the ode string it has to
+                        % be exported as SBML Parameter
+                        if compartmentExpected && (length(odeString)>(currentCharIndex + lastBracketIndexField - 1)),
+                            iqm.states(currentStateIndex).type = 'isParameter';
+                            iqm.states(currentStateIndex).unittype = '';
+                            iqm.states(currentStateIndex).compartment = '';
+                            % because we expect the rest of the ode to be a
+                            % nasty expression we skip parsing it
+                            break;
+                        end
+                        % test identifier origin
+                        checkIdentifierODE(identifier, currentStateIndex);
+                        identifierBeginDetected = 0;
+                    else
+                        if ~isempty(localStoichiometry),
+                            constantFound = 1;
+                        end
+                    end
+                    lastBracketIndexField = lastBracketIndexField - 1;
+                    if lastBracketIndexField > 1,
+                        globalStoichiometry = globalStoichiometry(1:bracketIndexForSign(lastBracketIndexField-1));
+                    else
+                        globalStoichiometry = '';
+                    end
+                    localStoichiometry = '';
+                    continue;
+                end
+            end
+            if identifierBeginDetected,
+                if isLetter2(character) || isNumber(character),
+                    identifierEnd = currentCharIndex;
+                    if currentCharIndex == length(odeString),
+                        identifier = odeString(identifierStart : identifierEnd);
+                        % test identifier origin
+                        checkIdentifierODE(identifier, currentStateIndex);
+                    end
+                else
+                    if debugFlag,
+                        fprintf('identifierBeginDetected');
+                        localStoichiometry
+                        constantFound
+                    end
+                    identifier = odeString(identifierStart : identifierEnd);
+                    % if we expect a compartment but know that this will
+                    % not be the last component in the ode string it has to
+                    % be exported as SBML Parameter
+                    if compartmentExpected && (length(odeString)>currentCharIndex),
+                        iqm.states(currentStateIndex).type = 'isParameter';
+                        iqm.states(currentStateIndex).unittype = '';
+                        iqm.states(currentStateIndex).compartment = '';
+                        % because we expect the rest of the ode to be a
+                        % nasty expression we skip parsing it
+                        break;
+                    end
+                    % test wether found literal is a reaction
+                    checkIdentifierODE(identifier, currentStateIndex);
+                    % if identifier was surrounded by brackets remove
+                    % multiplier from stoichiometry for current pair of
+                    % brackets
+                %{
+                if lastBracketIndexField > 1,
+                    globalStoichiometry = globalStoichiometry(1:bracketIndexForSign(lastBracketIndexField-1));
+                else
+                    globalStoichiometry = '';
+                end
+                %}
+                localStoichiometry = '';
+                localStoichiometry = char([double(localStoichiometry), double(character)]);
+                identifierBeginDetected = 0;
+            end
+        end
+    end % end of parsing ODE string
+
+    % if one or more constant terms have been found in ODE
+    % this state is exported as SBML Parameter
+    if (constantFound && ~strcmp(iqm.states(currentStateIndex).type, 'isCompartment')),
+        iqm.states(currentStateIndex).type = 'isParameter';
+        iqm.states(currentStateIndex).unittype = '';
+        iqm.states(currentStateIndex).compartment = '';
+    end
+
+    % preset fallback for states
+    % if states aren't claimed to be SBML Compartments or SBML
+    % Parameters we assign them to Species
+    type = iqm.states(currentStateIndex).type;
+    if (~strcmp(type, 'isSpecie') && ~strcmp(type, 'isParameter') && ~strcmp(type, 'isCompartment')) || strcmp(type, ''),
+        iqm.states(currentStateIndex).type = 'isSpecie';
+    end
+    % if no SBML unit type assignment was possible
+    unittype = iqm.states(currentStateIndex).unittype;
+    if strcmp(iqm.states(currentStateIndex).type, 'isSpecie') && ~strcmp(unittype, 'concentration'),
+        iqm.states(currentStateIndex).unittype = 'amount';
+    end
+
+end
+end % of run through states
+
+% begin of extraction of formula information
+% 2 nested for loops:
+% one for the variables and
+% one that searches the formulae for reactions etc.
+
+% run through variables formulae to find suitable SBML presets
+for currentVariableIndex = 1 : variableCount,
+    doProcessVariable  = true;
+    if strcmp(iqm.variables(currentVariableIndex).type,'isSpecie') && ~isempty(iqm.variables(currentVariableIndex).compartment) && (strcmp(iqm.variables(currentVariableIndex).unittype,'amount') || strcmp(iqm.variables(currentVariableIndex).unittype,'concentration')),
+        doProcessVariable  = false;
+    end
+    if strcmp(iqm.variables(currentVariableIndex).type,'isCompartment'),
+        doProcessVariable  = false;
+    end
+    if strcmp(iqm.variables(currentVariableIndex).type,'isParameter'),
+        doProcessVariable  = false;
+    end
+    
+    if doProcessVariable ,
+        % get the ODE for the specific specie
+        formulaString = iqm.variables(currentVariableIndex).formula;
+
+        % only for testing reasons
+        if debugFlag,
+            formulaString
+        end
+
+        % test wether reaction contains brackets and if yes test for good bracket expression
+        bracketsDetected = 0;
+        if isBracketstring(formulaString),
+            bracketsDetected = 1;
+            if ~isBracketstringWellformed(formulaString),
+                % something went wrong in the ODE; ask the user to take care
+                errors{1} = char([double('A mistake concerning brackets within the formula string of variable "'), double(iqm.variables(currentVariableIndex).name), double('" was detected.\n')]);
+                errors{2} = 'Please correct this on your own!';
+                messageOutput(errors, 1);
+                error('\n');
+            end
+        end
+        globalFactor = '';
+        localFactor = '';
+        compartmentExpected = 0;
+        constantFound = 0;
+        reacTermCount = 0;
+        firstReacTermStart = 0;
+        identifierBeginDetected = 0;
+        identifierStart = 0;
+        identifierEnd = 0;
+        bracketIndexForSign = [];
+        lastBracketIndexField = 1;
+        for currentCharIndex = 1 : length(formulaString),
+            character = formulaString(currentCharIndex);
+            if isspace(character),
+                % blanks do not change anything
+                continue;
+            end
+            if ~identifierBeginDetected && (isSign(character) || isNumber(character)),
+                % some part of a factor was found append it to localFactor
+                % string
+                localFactor = char([double(localFactor), double(character)]);
+                %stoichiometry = char([double(stoichiometry), double(character)]);
+                % if the last part of the ODE is a constant
+                if (currentCharIndex == length(formulaString)),
+                    constantFound = 1;
+                end
+                continue;
+            end
+            if ~identifierBeginDetected && isLetter2(character),
+                % the beginning of an identifier was found
+                if strcmp(localFactor, '/'),
+                    % we expect definitions of concentration with correct
+                    % parentheses
+                    % formula = R1/Compartment => SBML Specie
+                    % formula = R1 + R2/Compartment => SBML Parameter
+                    if ((reacTermCount == 1) || ( (~isempty(strfind(formulaString(1:firstReacTermStart), '('))) && (formulaString(currentCharIndex-2)==')'))),
+                        compartmentExpected = 1;
+                    else
+                        iqm.variables(currentVariableIndex).type = 'isParameter';
+                        iqm.variables(currentVariableIndex).unittype = '';
+                        iqm.variables(currentVariableIndex).compartment = '';
+                    end
+                else
+                    if constantFound,
+                        [unimportant, localFactor] = testForConstants(localFactor);
+                    else
+                        [constantFound, localFactor] = testForConstants(localFactor);
+                    end
+                end
+                identifierBeginDetected = 1;
+                identifierStart = currentCharIndex;
+                % for the case that a reactionname consists of only one letter
+                identifierEnd = currentCharIndex;
+                % if detected letter is the last one in an ODE
+                if currentCharIndex == length(formulaString),
+                    identifier = formulaString(identifierStart : identifierEnd);
+                    % test wether found literal is a reaction
+                    checkIdentifierFormula(identifier, currentVariableIndex);
+                end
+                continue;
+            end
+            if bracketsDetected,
+                if isOpenedBracket(character),
+                    % if a reaction term is detected in front of a bracket this is assumed to be an error
+                    if identifierBeginDetected,
+                        identifier = formulaString(identifierStart : identifierEnd);
+                        if ~isFunctionIdentifier(identifier, model),
+                            warnings{warnIndex} = char([double('A term ("'), double(identifier), double('") that seems not to be a function identifier was detected in front of a bracket, see IQMmodel variable "'), double(iqm.variables(currentVariableIndex).name), double('".')]);
+                            warnIndex = warnIndex + 1;
+                            warnings{warnIndex} = '';
+                            warnIndex = warnIndex + 1;
+                        end
+                    else
+                        if strcmp(localFactor, '/'),
+                            compartmentExpected = 1;
+                        else
+                            if constantFound,
+                                [unimportant, localFactor] = testForConstants(localFactor);
+                            else
+                                [constantFound, localFactor] = testForConstants(localFactor);
+                            end
+                        end
+                    end
+                    bracketIndexForSign(lastBracketIndexField) = length(globalFactor);
+                    globalFactor = char([double(globalFactor), double(localFactor)]);
+                    localFactor = '';
+                    lastBracketIndexField = lastBracketIndexField + 1;
+                    identifierBeginDetected = 0;
+                    continue;
+                end
+                if isClosedBracket(character),
+                    if identifierBeginDetected,
+                        if debugFlag,
+                            fprintf('closing bracketDetected');
+                            localFactor
+                            globalFactor
+                        end
+                        identifier = formulaString(identifierStart : identifierEnd);
+                        % if we expect a compartment but know that this will
+                        % not be the last component in the ode string it has to
+                        % be exported as SBML Parameter
+                        if compartmentExpected && (length(formulaString)>(currentCharIndex + lastBracketIndexField - 1)),
+                            iqm.variables(currentVariableIndex).type = 'isParameter';
+                            iqm.variables(currentVariableIndex).unittype = '';
+                            iqm.variables(currentVariableIndex).compartment = '';
+                            % because we expect the rest of the ode to be a
+                            % nasty expression we skip parsing it
+                            break;
+                        end
+                        % test identifier origin
+                        checkIdentifierFormula(identifier, currentVariableIndex);
+                        identifierBeginDetected = 0;
+                    else
+                        if ~isempty(localFactor),
+                            constantFound = 1;
+                        end
+                    end
+                    lastBracketIndexField = lastBracketIndexField - 1;
+                    if lastBracketIndexField > 1,
+                        globalFactor = globalFactor(1:bracketIndexForSign(lastBracketIndexField-1));
+                    else
+                        globalFactor = '';
+                    end
+                    localFactor = '';
+                    continue;
+                end
+            end
+            if identifierBeginDetected,
+                if isLetter2(character) || isNumber(character),
+                    identifierEnd = currentCharIndex;
+                    if currentCharIndex == length(formulaString),
+                        identifier = formulaString(identifierStart : identifierEnd);
+                        % test identifier origin
+                        checkIdentifierFormula(identifier, currentVariableIndex);
+                    end
+                else
+                    if debugFlag,
+                        fprintf('identifierBeginDetected');
+                        localFactor
+                        globalFactor
+                    end
+                    identifier = formulaString(identifierStart : identifierEnd);
+                    % if we expect a compartment but know that this will
+                    % not be the last component in the ode string it has to
+                    % be exported as SBML Parameter
+                    if compartmentExpected && (length(formulaString)>currentCharIndex),
+                        iqm.variables(currentVariableIndex).type = 'isParameter';
+                        iqm.variables(currentVariableIndex).unittype = '';
+                        iqm.variables(currentVariableIndex).compartment = '';
+                        % because we expect the rest of the ode to be a
+                        % nasty expression we skip parsing it
+                        break;
+                    end
+                    % test wether found literal is a reaction
+                    checkIdentifierFormula(identifier, currentVariableIndex);
+                    % if identifier was surrounded by brackets remove
+                    % multiplier from stoichiometry for current pair of
+                    % brackets
+                %{
+                if lastBracketIndexField > 1,
+                    globalFactor = globalFactor(1:bracketIndexForSign(lastBracketIndexField-1));
+                else
+                    globalFactor = '';
+                end
+                %}
+                localFactor = '';
+                localFactor = char([double(localFactor), double(character)]);
+                identifierBeginDetected = 0;
+            end
+        end
+    end % end of formula parsing string
+    % if one or more constant terms have been found in ODE
+    % this state is exported as SBML Parameter
+    if (constantFound && ~strcmp(iqm.variables(currentVariableIndex).type, 'isCompartment')),
+        iqm.variables(currentVariableIndex).type = 'isParameter';
+        iqm.variables(currentVariableIndex).unittype = '';
+        iqm.variables(currentVariableIndex).compartment = '';
+    end
+
+    % preset fallback for variables
+    % if variables aren't claimed to be SBML Compartments or SBML
+    % Parameters we assign them to Species
+    type = iqm.variables(currentVariableIndex).type;
+    if (~strcmp(type, 'isSpecie') && ~strcmp(type, 'isParameter') && ~strcmp(type, 'isCompartment')) || strcmp(type, ''),
+        iqm.variables(currentVariableIndex).type = 'isSpecie';
+    end
+    % if no SBML unit type assignment was possible
+    unittype = iqm.variables(currentVariableIndex).unittype;
+    if strcmp(iqm.variables(currentVariableIndex).type, 'isSpecie') && ~strcmp(unittype, 'concentration'),
+        iqm.variables(currentVariableIndex).unittype = 'amount';
+    end
+
+end
+end % of variables run
+
+
+
+
+
+
+
+
+
+
+% run through IQMmodel parameters
+for currentParameterIndex = 1 : length(parameterNames),
+
+doProcessParameter  = true;
+if strcmp(iqm.parameters(currentParameterIndex).type,'isSpecie') && ~isempty(iqm.parameters(currentParameterIndex).compartment) && (strcmp(iqm.parameters(currentParameterIndex).unittype,'amount') || strcmp(iqm.parameters(currentParameterIndex).unittype,'concentration')),
+    doProcessParameter  = false;
+end
+if strcmp(iqm.parameters(currentParameterIndex).type,'isCompartment'),
+    doProcessParameter  = false;
+end
+if strcmp(iqm.parameters(currentParameterIndex).type,'isParameter'),
+    doProcessParameter  = false;
+end
+
+if doProcessParameter,
+    % preset fallback for parameters
+    % if parameters aren't claimed to be SBML Compartments or SBML
+    % Species we assign them to SBML Parameters
+    type = iqm.parameters(currentParameterIndex).type;
+    if (~strcmp(type, 'isSpecie') && ~strcmp(type, 'isParameter') && ~strcmp(type, 'isCompartment')) || strcmp(type, ''),
+        iqm.parameters(currentParameterIndex).type = 'isParameter';
+        iqm.parameters(currentParameterIndex).unittype = '';
+        iqm.parameters(currentParameterIndex).compartment = '';
+    end
+
+end
+end
+
+changedModel = IQMmodel(iqm);
+
+if ~silentFlag && (warnIndex>1),
+    messageOutput(warnings, 2);
+end
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% new code for identifier handling within states ODE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    function checkIdentifierODE(identifier, currentStateIndex)
+
+    if compartmentExpected,
+        % if IQMmodel State is already set to SBML Parameter
+        % a concentration definition is not possible/necessary
+        if strcmp(iqm.states(currentStateIndex).type, 'isParameter'),
+            return;
+        end
+        % check compartments for identifier
+        compaHit = matchStringOnArray(identifier, compartmentList);
+        if (compaHit~=0),
+            % compartment was expected and has been found
+            % check unittype for concentration
+            if ~strcmp(iqm.states(currentStateIndex).unittype, 'concentration'),
+                warnings{warnIndex} = char([double(iqm.states(currentStateIndex).name), double(' seems to be defined as concentration per time by ODE, but unit type is set to "'), double(iqm.states(currentStateIndex).unittype), double('" this will be changed to "concentration"!')]);
+                warnIndex = warnIndex + 1;
+                warnings{warnIndex} = char([double(iqm.states(currentStateIndex).name), double(' is also going to be assigned to compartment: '), double(identifier), double('.')]);
+                warnIndex = warnIndex + 1;
+                warnings{warnIndex} = '';
+                warnIndex = warnIndex + 1;
+                iqm.states(currentStateIndex).unittype = 'concentration';
+                iqm.states(currentStateIndex).compartment = identifier;
+            end
+            return
+        end
+        % check reactions
+        reacHit = matchStringOnArray(identifier, reactionNames);
+        if (reacHit~=0),
+            errors{1} = char([double(identifier), double(' in '), double(iqm.states(currentStateIndex).name), double(' is to be expected a compartment, but was defined as reaction. This is not possible!')]);
+            messageOutput(errors, 1);
+            error('\n');
+        end
+        % check first wether identifier is a reaction (this should be standard
+        % case)
+        stateHit = matchStringOnArray(identifier, stateNames);
+        if (stateHit~=0),
+            warnings{warnIndex} = char([double(identifier), double(' is used as compartment in '), double(iqm.states(currentStateIndex).name), double(' defining concentration per time!')]);
+            warnIndex = warnIndex + 1;
+            warnings{warnIndex} = char([double('SBML type of '), double(iqm.states(stateHit).name), double(' is set to "SBML COMPARTMENT" and unit type of '), double(iqm.states(currentStateIndex).name), double(' is set to "concentration"!')]);
+            warnIndex = warnIndex + 1;
+            warnings{warnIndex} = char([double(iqm.states(currentStateIndex).name), double(' is also going to be assigned to compartment: '), double(identifier), double('.')]);
+            warnIndex = warnIndex + 1;
+            warnings{warnIndex} = '';
+            warnIndex = warnIndex + 1;
+            iqm.states(stateHit).type = 'isCompartment';
+            iqm.states(currentStateIndex).unittype = 'concentration';
+            iqm.states(currentStateIndex).compartment = identifier;
+            % now we update the compartment list to avoid false warnings
+            [compartmentList, compartmentFrom, compartmentOrigIndex] = fetchCompartments(IQMmodel(iqm));
+            return;
+        end
+        paramHit = matchStringOnArray(identifier, parameterNames);
+        if (paramHit~=0),
+            warnings{warnIndex} = char([double(identifier), double(' is used as compartment in '), double(iqm.states(currentStateIndex).name), double(' defining concentration per time!')]);
+            warnIndex = warnIndex + 1;
+            warnings{warnIndex} = char([double('SBML type of '), double(iqm.parameters(paramHit).name), double(' is set to "SBML COMPARTMENT" and unit type of '), double(iqm.states(currentStateIndex).name), double(' is set to "concentration"!')]);
+            warnIndex = warnIndex + 1;
+            warnings{warnIndex} = char([double(iqm.states(currentStateIndex).name), double(' is also going to be assigned to compartment: '), double(identifier), double('.')]);
+            warnIndex = warnIndex + 1;
+            warnings{warnIndex} = '';
+            warnIndex = warnIndex + 1;
+            iqm.parameters(paramHit).type = 'isCompartment';
+            iqm.states(currentStateIndex).unittype = 'concentration';
+            iqm.states(currentStateIndex).compartment = identifier;
+            % now we update the compartment list to avoid false warnings
+            [compartmentList, compartmentFrom, compartmentOrigIndex] = fetchCompartments(IQMmodel(iqm));
+            return;
+        end
+        variaHit = matchStringOnArray(identifier, variableNames);
+        if (variaHit~=0),
+            warnings{warnIndex} = char([double(identifier), double(' is used as compartment in '), double(iqm.states(currentStateIndex).name), double(' defining concentration per time!')]);
+            warnIndex = warnIndex + 1;
+            warnings{warnIndex} = char([double('SBML type of '), double(iqm.variables(variaHit).name), double(' is set to "SBML COMPARTMENT" and unit type of '), double(iqm.states(currentStateIndex).name), double(' is set to "concentration"!')]);
+            warnIndex = warnIndex + 1;
+            warnings{warnIndex} = char([double(iqm.states(currentStateIndex).name), double(' is also going to be assigned to compartment: '), double(identifier), double('.')]);
+            warnIndex = warnIndex + 1;
+            warnings{warnIndex} = '';
+            warnIndex = warnIndex + 1;
+            iqm.variables(variaHit).type = 'isCompartment';
+            iqm.states(currentStateIndex).unittype = 'concentration';
+            iqm.states(currentStateIndex).compartment = identifier;
+            % now we update the compartment list to avoid false warnings
+            [compartmentList, compartmentFrom, compartmentOrigIndex] = fetchCompartments(IQMmodel(iqm));
+            return;
+        end
+        compartmentExpected = 0;
+    else % identifier is not expected to be a compartment
+        % check first wether identifier is a reaction (this should be standard
+        % case)
+        reacHit = matchStringOnArray(identifier, reactionNames);
+        if (reacHit==0),
+            % the current state doesn't consist only of reactions (type -> SBML
+            % Parameter)
+            if ~strcmp(iqm.states(currentStateIndex).type, 'isParameter'),
+                warnings{warnIndex} = char([double(iqm.states(currentStateIndex).name), double(' contains not only reactions therefor the type is changed to "SBML Parameter"!')]);
+                warnIndex = warnIndex + 1;
+                warnings{warnIndex} = '';
+                warnIndex = warnIndex + 1;
+                iqm.states(currentStateIndex).type = 'isParameter';
+                iqm.states(currentStateIndex).unittype = '';
+                iqm.states(currentStateIndex).compartment = '';
+            end
+        else
+            reacTermCount = reacTermCount + 1;
+            % keep position of first reaction occurence
+            % if we have more than one reaction we have to check right
+            % usage of parentheses in case of definition as concentration
+            if (reacTermCount==1),
+                firstReacTermStart = currentCharIndex - length(identifier);
+            end
+        end
+    end
+end % of checkIdentifierODE function
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% new code for identifier handling within variables Formula
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    function checkIdentifierFormula(identifier, currentVariableIndex)
+
+    if compartmentExpected,
+        % if IQMmodel Variable is already set to SBML Parameter
+        % a concentration definition is not possible/necessary
+        if strcmp(iqm.variables(currentVariableIndex).type, 'isParameter'),
+            return;
+        end
+        % check compartments for identifier
+        compaHit = matchStringOnArray(identifier, compartmentList);
+        if (compaHit~=0),
+            % compartment was expected and has been found
+            % check unittype for concentration
+            if ~strcmp(iqm.variables(currentVariableIndex).unittype, 'concentration'),
+                warnings{warnIndex} = char([double(iqm.variables(currentVariableIndex).name), double(' seems to be defined as concentration per time by formula, but unit type is set to "'), double(iqm.variables(currentVariableIndex).unittype), double('" this will be changed to "concentration"!')]);
+                warnIndex = warnIndex + 1;
+                warnings{warnIndex} = char([double(iqm.variables(currentVariableIndex).name), double(' is also going to be assigned to compartment: '), double(identifier), double('.')]);
+                warnIndex = warnIndex + 1;
+                warnings{warnIndex} = '';
+                warnIndex = warnIndex + 1;
+                iqm.variables(currentVariableIndex).unittype = 'concentration';
+                iqm.variables(currentVariableIndex).compartment = identifier;
+            end
+            return
+        end
+        % check reactions
+        reacHit = matchStringOnArray(identifier, reactionNames);
+        if (reacHit~=0),
+            errors{1} = char([double(identifier), double(' in '), double(iqm.variables(currentVariableIndex).name), double(' is to be expected a compartment, but was defined as reaction. This is not possible!')]);
+            messageOutput(errors, 1);
+            error('\n');
+        end
+
+        stateHit = matchStringOnArray(identifier, stateNames);
+        if (stateHit~=0),
+            warnings{warnIndex} = char([double(identifier), double(' is used as compartment in '), double(iqm.variables(currentVariableIndex).name), double(' defining concentration per time!')]);
+            warnIndex = warnIndex + 1;
+            warnings{warnIndex} = char([double('SBML type of '), double(iqm.states(stateHit).name), double(' is set to "SBML COMPARTMENT" and unit type of '), double(iqm.variables(currentVariableIndex).name), double(' is set to "concentration"!')]);
+            warnIndex = warnIndex + 1;
+            warnings{warnIndex} = char([double(iqm.variables(currentVariableIndex).name), double(' is also going to be assigned to compartment: '), double(identifier), double('.')]);
+            warnIndex = warnIndex + 1;
+            warnings{warnIndex} = '';
+            warnIndex = warnIndex + 1;
+            iqm.states(stateHit).type = 'isCompartment';
+            iqm.variables(currentVariableIndex).unittype = 'concentration';
+            iqm.variables(currentVariableIndex).compartment = identifier;
+            % now we update the compartment list to avoid false warnings
+            [compartmentList, compartmentFrom, compartmentOrigIndex] = fetchCompartments(IQMmodel(iqm));
+            return;
+        end
+        paramHit = matchStringOnArray(identifier, parameterNames);
+        if (paramHit~=0),
+            warnings{warnIndex} = char([double(identifier), double(' is used as compartment in '), double(iqm.variables(currentVariableIndex).name), double(' defining concentration per time!')]);
+            warnIndex = warnIndex + 1;
+            warnings{warnIndex} = char([double('SBML type of '), double(iqm.parameters(paramHit).name), double(' is set to "SBML COMPARTMENT" and unit type of '), double(iqm.variables(currentVariableIndex).name), double(' is set to "concentration"!')]);
+            warnIndex = warnIndex + 1;
+            warnings{warnIndex} = char([double(iqm.variables(currentVariableIndex).name), double(' is also going to be assigned to compartment: '), double(identifier), double('.')]);
+            warnIndex = warnIndex + 1;
+            warnings{warnIndex} = '';
+            warnIndex = warnIndex + 1;
+            iqm.parameters(paramHit).type = 'isCompartment';
+            iqm.variables(currentVariableIndex).unittype = 'concentration';
+            iqm.variables(currentVariableIndex).compartment = identifier;
+            % now we update the compartment list to avoid false warnings
+            [compartmentList, compartmentFrom, compartmentOrigIndex] = fetchCompartments(IQMmodel(iqm));
+            return;
+        end
+        variaHit = matchStringOnArray(identifier, variableNames);
+        if (variaHit~=0),
+            warnings{warnIndex} = char([double(identifier), double(' is used as compartment in '), double(iqm.variables(currentVariableIndex).name), double(' defining concentration per time!')]);
+            warnIndex = warnIndex + 1;
+            warnings{warnIndex} = char([double('SBML type of '), double(iqm.variables(variaHit).name), double(' is set to "SBML COMPARTMENT" and unit type of '), double(iqm.variables(currentVariableIndex).name), double(' is set to "concentration"!')]);
+            warnIndex = warnIndex + 1;
+            warnings{warnIndex} = char([double(iqm.variables(currentVariableIndex).name), double(' is also going to be assigned to compartment: '), double(identifier), double('.')]);
+            warnIndex = warnIndex + 1;
+            warnings{warnIndex} = '';
+            warnIndex = warnIndex + 1;
+            iqm.variables(variaHit).type = 'isCompartment';
+            iqm.variables(currentVariableIndex).unittype = 'concentration';
+            iqm.variables(currentVariableIndex).compartment = identifier;
+            % now we update the compartment list to avoid false warnings
+            [compartmentList, compartmentFrom, compartmentOrigIndex] = fetchCompartments(IQMmodel(iqm));
+            return;
+        end
+        compartmentExpected = 0;
+    else % identifier is not expected to be a compartment
+        % check first wether identifier is a reaction (this should be standard
+        % case)
+        reacHit = matchStringOnArray(identifier, reactionNames);
+        if (reacHit==0),
+            % the current variable is best described as parameter
+            % (type -> SBML Parameter)
+            if ~strcmp(iqm.variables(currentVariableIndex).type, 'isParameter'),
+                warnings{warnIndex} = char([double(iqm.variables(currentVariableIndex).name), double(' seems to be best described as "SBML Parameter"!')]);
+                warnIndex = warnIndex + 1;
+                warnings{warnIndex} = '';
+                warnIndex = warnIndex + 1;
+                iqm.variables(currentVariableIndex).type = 'isParameter';
+                iqm.variables(currentVariableIndex).unittype = '';
+                iqm.variables(currentVariableIndex).compartment = '';
+            end
+        else
+            reacTermCount = reacTermCount + 1;
+            % keep position of first reaction occurence
+            % if we have more than one reaction we have to check right
+            % usage of parentheses in case of definition as concentration
+            if (reacTermCount==1),
+                firstReacTermStart = currentCharIndex - length(identifier);
+            end
+        end
+    end
+    end % of checkIdentifierFormula function
+
+    function [constantFound, newExpression] = testForConstants(expression)
+        constantFound = false;
+        newExpression = expression;
+        rhsFactor = false;
+        lastChar = '';
+        for charIndex = 1 : length(expression),
+            if isFOSign(expression(charIndex)),
+                if ~isempty(lastChar) && ~isSOSign(lastChar),
+                    newExpression = expression(charIndex:length(expression));
+                    if rhsFactor,
+                        rhsFactor = false;
+                    else
+                        constantFound = true;
+                    end
+                end
+            elseif ((charIndex==1) && (isSOSign(expression(charIndex)))),
+                rhsFactor = true;
+            end
+            lastChar = expression(charIndex);
+        end
+    end % of testForConstants function
+
+end % of IQMmakeSBMLpresets function
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/modeltools/addDefaultCompartment.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/modeltools/addDefaultCompartment.m
new file mode 100644
index 0000000000000000000000000000000000000000..3867a0912fd35dcbd1da28b16c19af436665f92a
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/modeltools/addDefaultCompartment.m	
@@ -0,0 +1,207 @@
+function [changedModel] = addDefaultCompartment(model, varargin)
+% addDefaultCompartment
+% checks wether a IQMmodel contains any compartments, if not a default
+% compartment (a SBML Parameter with size 1) will be added, so that the
+% model can be exported to SBML
+%
+%
+% USAGE:
+% ======
+% [changedModel] = addDefaultCompartment(model)
+% [changedModel] = addDefaultCompartment(model, compartmentName)
+%
+% model: IQMmodel where a default SBML compartment is to add
+% compartmentName (optional): if you want to provide a name for the
+%                             compartment by yourself
+% 
+% changedModel: IQMmodel with added default (root) compartment
+%
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+modelORIGINAL = model;
+
+compartmentName = '';
+silentFlag = 0;
+if (nargin == 1),
+    silentFlag = 0;
+elseif (nargin == 2),
+    compartmentName = varargin{1};
+    silentFlag = 0;
+elseif (nargin == 3),
+    compartmentName = varargin{1};
+    silentFlag = varargin{2};
+end
+
+if isIQMmodelName(compartmentName),
+    error{1} = char([double('Sorry, but "'), double(compartmentName), double('" is not a valid IQMmodel identifier!')]);
+    error{2} = 'Please provide another compartment name.';
+    messageOutput(error, 1);
+    return
+end
+
+if existsNameInIQMmodel(model, compartmentName),
+    error{1} = char([double('Sorry, but "'), double(compartmentName), double('" is already used as Identifier in the given IQMmodel!')]);
+    error{2} = 'Please provide another compartment name.';
+    messageOutput(error, 1);
+    return;
+end
+    
+
+rootCompartments = 0;
+compartmentCount = 0;
+notCompartmentCount = 0;
+
+boolvalue = false;
+foundError = false;
+errorMessages = [];
+errorNumber = 0;
+
+modelStruct = IQMstruct(model);
+stateCount = length(modelStruct.states);
+parameterCount = length(modelStruct.parameters);
+variableCount = length(modelStruct.variables);
+
+% at first we perform a check for all compartments
+for n = 1 : stateCount
+    if strcmp(modelStruct.states(n).type, 'isCompartment')
+        compartmentCount = compartmentCount + 1;
+        compartmentList{compartmentCount} = modelStruct.states(n).name;
+        if strcmp(modelStruct.states(n).compartment, '')
+            rootCompartments = rootCompartments + 1;
+        end
+    else
+        notCompartmentCount = notCompartmentCount + 1;
+        componentList{notCompartmentCount} = modelStruct.states(n).name;
+    end
+end
+for n = 1 : parameterCount
+    if strcmp(modelStruct.parameters(n).type, 'isCompartment')
+        compartmentCount = compartmentCount + 1;
+        compartmentList{compartmentCount} = modelStruct.parameters(n).name;
+        if strcmp(modelStruct.parameters(n).compartment, '')
+            rootCompartments = rootCompartments + 1;
+        end
+    else
+        notCompartmentCount = notCompartmentCount + 1;
+        componentList{notCompartmentCount} = modelStruct.parameters(n).name;
+    end
+end
+for n = 1 : variableCount
+    if strcmp(modelStruct.variables(n).type, 'isCompartment')
+        compartmentCount = compartmentCount + 1;
+        compartmentList{compartmentCount} = modelStruct.variables(n).name;
+        if strcmp(modelStruct.variables(n).compartment, '')
+            rootCompartments = rootCompartments + 1;
+        end
+    else
+        notCompartmentCount = notCompartmentCount + 1;
+        componentList{notCompartmentCount} = modelStruct.variables(n).name;
+    end
+end
+
+if compartmentCount > 0
+    if ~silentFlag,
+        error{1} = 'This IQMmodel contains already compartments!';
+        error{2} = 'In this case it is not the best way to add a compartment by default. But if you want to, all not assigned components can be added to a default compartment.';
+        messageOutput(error, 1);
+    end
+    while (true),
+        answer = input('Add default compartment to model (needed for export)? [y/n] ?', 's');
+        if (strcmp(answer, 'y') || strcmp(answer, 'Y')),
+            break;
+        elseif (strcmp(answer, 'n') || strcmp(answer, 'N')),
+            disp('Adding of DefaultCompartment aborted.');
+            changedModel = modelORIGINAL;
+            return;
+        end
+    end
+end
+
+% the given IQMmodel matches the requirements of this function
+% now we can check which name can be used
+if isempty(compartmentName),
+    if ~existsNameInIQMmodel(model, 'rootCompartment')
+        compartmentName = 'rootCompartment';
+    elseif ~existsNameInIQMmodel(model, 'defaultCompartment')
+        compartmentName = 'defaultCompartment';
+    else
+        if ~silentFlag,
+            error{1} = 'It was not possible to create a default compartment with the names "rootCompartment" or "defaultCompartment" because they are already in use!';
+            error{2} = 'Please provide a name by your own, with: "addDefaultCompartment(model, compartmentName)"';
+            error{3} = ' ';
+            messageOutput(error, 1);
+        end
+        return;
+    end
+end
+
+% now that we've got the name we can add the other components to the
+% default compartment
+for n = 1 : stateCount
+    if strcmp(modelStruct.states(n).type, 'isSpecie'),
+        if isempty(modelStruct.states(n).compartment),
+            modelStruct.states(n).compartment = compartmentName;
+        end
+    elseif strcmp(modelStruct.states(n).type, 'isCompartment'),
+        if isempty(modelStruct.states(n).compartment),
+            modelStruct.states(n).compartment = compartmentName;
+        end
+    elseif  strcmp(modelStruct.states(n).type, ''),
+        % for testing reasons I have to provide several standard SBML
+        % parameters
+        modelStruct.states(n).type = 'isSpecie';
+        modelStruct.states(n).unittype = 'amount';
+        modelStruct.states(n).compartment = compartmentName;
+    end
+end
+for n = 1 : parameterCount
+    if strcmp(modelStruct.parameters(n).type, 'isSpecie'),
+        if isempty(modelStruct.parameters(n).compartment),
+            modelStruct.parameters(n).compartment = compartmentName;
+        end
+    elseif strcmp(modelStruct.parameters(n).type, 'isCompartment'),
+        if isempty(modelStruct.parameters(n).compartment),
+            modelStruct.parameters(n).compartment = compartmentName;
+        end
+    elseif strcmp(modelStruct.parameters(n).type, ''),
+        % for testing reasons I have to provide several standard SBML
+        % parameters
+        modelStruct.parameters(n).type = 'isParameter';
+        modelStruct.parameters(n).unittype = '';
+        modelStruct.parameters(n).compartment = '';
+    end
+end
+for n = 1 : variableCount
+    if strcmp(modelStruct.variables(n).type, 'isSpecie'),
+        if isempty(modelStruct.variables(n).compartment),
+            modelStruct.variables(n).compartment = compartmentName;
+        end
+    elseif strcmp(modelStruct.variables(n).type, 'isCompartment'),
+        if isempty(modelStruct.variables(n).compartment),
+            modelStruct.variables(n).compartment = compartmentName;
+        end
+    elseif  strcmp(modelStruct.variables(n).type, ''),
+        modelStruct.variables(n).type = 'isParameter';
+        modelStruct.variables(n).unittype = '';
+        modelStruct.variables(n).compartment = '';
+    end
+end
+% now we add the default compartment as IQMmodel parameter with value = 1
+% and type = 'isCompartment'
+modelStruct.parameters(parameterCount+1).name = compartmentName;
+modelStruct.parameters(parameterCount+1).value = 1;
+modelStruct.parameters(parameterCount+1).type = 'isCompartment';
+modelStruct.parameters(parameterCount+1).compartment = '';
+
+if ~silentFlag,
+    message{1} = 'Success!';
+    message{2} = char([double('Default compartment "'), double(compartmentName), double('" has been added to the IQMmodel as:')]);
+    message{3} = char([double('Parameter No.'), double(num2str(parameterCount+1)), double(' value = 1 and type = isCompartment')]);
+    messageOutput(message, 3);
+end
+
+changedModel = IQMmodel(modelStruct);
+
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/modeltools/checkCompartmentsForLoop.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/modeltools/checkCompartmentsForLoop.m
new file mode 100644
index 0000000000000000000000000000000000000000..e569e8bfca7a142a3320b802f7f5acfe73738e8e
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/modeltools/checkCompartmentsForLoop.m	
@@ -0,0 +1,132 @@
+function [loopFound] = checkCompartmentsForLoop(model, varargin)
+% checkCompartmentsForLoop
+% Helper function for the SBML export of models. The function preprocesses
+% IQMmodels compartment definitions and prints out error message if
+% a loop is constructed over outside compartment elements.
+%
+% USAGE:
+% ======
+% [loopFound] = checkCompartmentsForLoop(model)
+%
+% model: IQMmodel with compartment defintions to check
+%
+% loopFound: boolean value, true if loop is detected
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF IQMmodel
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~strcmp('IQMmodel',class(model)),
+    error('Function only defined for IQMmodels.');
+end
+% get the datastructure of the model
+iqm = IQMstruct(model);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK EXTRA INPUT ARGUMENT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+silentFlag = 0;
+if nargin == 2,
+   silentFlag = varargin{1};
+end
+
+loopFound = true;
+
+    [compartmentList, iqmmodelCompartmentKind, iqmmodelKindIndex] = fetchCompartments(model);
+    
+    % try to find way till root Compartment for all defined compartments
+    for startCompartmentIndex = 1 : length(compartmentList),
+        passedCompartments = [];
+        compartmentList(startCompartmentIndex);
+        found = way2RootCompartment(startCompartmentIndex);
+        if ~found,
+            return
+        end
+    end
+    
+    loopFound = false;
+
+
+
+    function [found] = way2RootCompartment(compartmentIndex)
+    
+        found = false;
+        
+        % look wether compartment is defined as state, parameter or
+        % variable
+        switch(iqmmodelCompartmentKind(compartmentIndex))
+            case 0
+                kind = 'state';
+                outsideCompartment = iqm.states(iqmmodelKindIndex(compartmentIndex)).compartment;
+            case 1
+                kind = 'parameter';
+                outsideCompartment = iqm.parameters(iqmmodelKindIndex(compartmentIndex)).compartment;
+            case 2
+                kind = 'variable';
+                outsideCompartment = iqm.variables(iqmmodelKindIndex(compartmentIndex)).compartment;
+        end
+        
+        % determine wether start compartment has been passed already (if
+        % loop is constructed) if yes print error and stop
+        result = find(passedCompartments == startCompartmentIndex);
+        if ~isempty(result),
+            % loop detected construct error message
+            if ~silentFlag,
+                errorIndex = 1;
+                error{errorIndex} = 'On the way to root compartment a loop has been detected for compartment: ';
+                errorIndex = errorIndex + 1;
+                startCompartmentName = char(compartmentList(startCompartmentIndex));
+                iqmmodelCompartmentIndex = num2str(iqmmodelKindIndex(startCompartmentIndex));
+                error{errorIndex} = char([double(startCompartmentName), double(' ('), double(kind), double(' No.'), double(iqmmodelCompartmentIndex), double(')')]);
+                errorIndex = errorIndex + 1;
+                error{errorIndex} =  'Defined relationships:';
+                errorIndex = errorIndex + 1;
+                error{errorIndex} = char(double(startCompartmentName));
+                for index = 1 : length(passedCompartments),
+                    switch(iqmmodelCompartmentKind(passedCompartments(index))),
+                        case 0
+                            kind = 'state';
+                        case 1
+                            kind = 'parameter';
+                        case 2
+                            kind = 'variable';
+                    end
+                    passedCompartmentName = char(compartmentList(passedCompartments(index)));
+                    iqmmodelCompartmentIndex = num2str(iqmmodelKindIndex(passedCompartments(index)));
+                    error{errorIndex} = char([double(error{errorIndex}), double(' -> '), double(passedCompartmentName), double(' ('), double(kind), double(' No.'), double(iqmmodelCompartmentIndex), double(')')]);
+                end
+                messageOutput(error, 1);
+            end
+            return
+        end
+        
+                
+        % recursive abort condition (root compartment found)
+        if isempty(outsideCompartment),
+            found = true;
+            return
+        else % outsideCompartment is not root, test upper level compartment
+            
+            newCompartmentIndex = matchStringOnArray(outsideCompartment, compartmentList);
+            if newCompartmentIndex,
+                passedCompartments((length(passedCompartments)+1)) = newCompartmentIndex;
+                found = way2RootCompartment(newCompartmentIndex);
+            else
+                % found outside compartment is not valid
+                if ~silentFlag,
+                    errorIndex = 1;
+                    error{errorIndex} = 'On the way to root compartment an invalid outside compartment definition has been detected for compartment: ';
+                    errorIndex = errorIndex + 1;
+                    error{errorIndex} = char([double(char(compartmentList(startCompartmentIndex))), double(' ('), double(kind), double(' No.'), double(num2str(iqmmodelKindIndex(startCompartmentIndex))), double(')')]);
+                    errorIndex = 1;
+                    error{errorIndex} = char([double('Invalid outside compartment: '), double(outsideCompartment)]);
+                    messageOutput(error, 1);
+                end
+                return
+            end
+        end
+    end % way2RootCompartment
+
+end % of testSBMLCompartmentSettings
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/modeltools/checkNamesInIQMmodel.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/modeltools/checkNamesInIQMmodel.m
new file mode 100644
index 0000000000000000000000000000000000000000..aa64cc3cc39bcf0bc8963a4fffc71d36e55643a1
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/modeltools/checkNamesInIQMmodel.m	
@@ -0,0 +1,282 @@
+function [namesOK] = checkNamesInIQMmodel(model, varargin)
+% checkNamesInIQMmodel
+% checks the used names in the given IQMmodel (empty name fields and names
+% used more than once)
+%
+%
+% USAGE:
+% ======
+% [namesOK] = checkNamesInIQMmodel(model)
+%
+% model: IQMmodel where names are to test
+% 
+% namesOK: true if no errors in name definitions where found
+%          otherwise false
+%
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+silentFlag = 0;
+if (nargin == 2)
+    silentFlag = varargin{1};
+end
+
+
+namesOK = false;
+emptyNames = {};
+emptyNamesIndex = 1;
+nameError = false;
+errorGroup = {};
+errorName = '';
+nameDoubletError = false;
+modelStruct = IQMstruct(model);
+variableCount = length(modelStruct.variables);
+
+% check names of IQMmodel states 
+stateNames = {};
+index = 1;
+for n = 1 : length(modelStruct.states),
+    name = modelStruct.states(n).name;
+    if strcmp(name, ''),
+        emptyNames{emptyNamesIndex} = char([double('State No. '), double(numstr(n))]);
+        emptyNamesIndex = emptyNamesIndex + 1;
+        nameError = true;
+    else
+        if matchStringOnArray(name, stateNames),
+            errorGroup{1} = 'States';
+            errorGroup{2} = 'States';
+            errorName = name;
+            nameDoubletError = true;
+        else
+            stateNames{index} = name;
+            index = index + 1;
+        end
+    end
+end
+% check names of IQMmodel parameters
+parameterNames = {};
+index = 1;
+if ~nameDoubletError,
+    for n = 1 : length(modelStruct.parameters),
+        name = modelStruct.parameters(n).name;
+        if strcmp(name, ''),
+            emptyNames{emptyNamesIndex} = char([double('Parameter No. '), double(numstr(n))]);
+            emptyNamesIndex = emptyNamesIndex + 1;
+            nameError = true;
+        else
+            if matchStringOnArray(name, stateNames),
+                errorGroup{1} = 'States';
+                errorGroup{2} = 'Parameters';
+                errorName = name;
+                nameDoubletError = true;
+            elseif matchStringOnArray(name, parameterNames),
+                errorGroup{1} = 'Parameters';
+                errorGroup{2} = 'Parameters';
+                errorName = name;
+                nameDoubletError = true;
+            else
+                parameterNames{index} = name;
+                index = index + 1;
+            end
+        end
+    end
+end
+% check names of IQMmodel variables
+variableNames = {};
+index = 1;
+if ~nameDoubletError,
+    for n = 1 : length(modelStruct.variables),
+        name = modelStruct.variables(n).name;
+        if strcmp(name, ''),
+            emptyNames{emptyNamesIndex} = char([double('Variable No. '), double(numstr(n))]);
+            emptyNamesIndex = emptyNamesIndex + 1;
+            nameError = true;
+        else
+            if matchStringOnArray(name, stateNames),
+                errorGroup{1} = 'States';
+                errorGroup{2} = 'Variables';
+                errorName = name;
+                nameDoubletError = true;
+            elseif matchStringOnArray(name, parameterNames),
+                errorGroup{1} = 'Parameters';
+                errorGroup{2} = 'Variables';
+                errorName = name;
+                nameDoubletError = true;
+            elseif matchStringOnArray(name, variableNames),
+                errorGroup{1} = 'Variables';
+                errorGroup{2} = 'Variables';
+                errorName = name;
+                nameDoubletError = true;
+            else
+                variableNames{index} = name;
+                index = index + 1;
+            end
+        end
+    end
+end
+% check names of IQMmodel reactions
+reactionNames = {};
+index = 1;
+if ~nameDoubletError,
+    for n = 1 : length(modelStruct.reactions),
+        name = modelStruct.reactions(n).name;
+        if strcmp(name, ''),
+            emptyNames{emptyNamesIndex} = char([double('Reaction No. '), double(numstr(n))]);
+            emptyNamesIndex = emptyNamesIndex + 1;
+            nameError = true;
+        else
+            if matchStringOnArray(name, stateNames),
+                errorGroup{1} = 'States';
+                errorGroup{2} = 'Reactions';
+                errorName = name;
+                nameDoubletError = true;
+            elseif matchStringOnArray(name, parameterNames),
+                errorGroup{1} = 'Parameters';
+                errorGroup{2} = 'Reactions';
+                errorName = name;
+                nameDoubletError = true;
+            elseif matchStringOnArray(name, variableNames),
+                errorGroup{1} = 'Variables';
+                errorGroup{2} = 'Reactions';
+                errorName = name;
+                nameDoubletError = true;
+            elseif matchStringOnArray(name, reactionNames),
+                errorGroup{1} = 'Reactions';
+                errorGroup{2} = 'Reactions';
+                errorName = name;
+                nameDoubletError = true;
+            else
+                reactionNames{index} = name;
+                index = index + 1;
+            end
+        end
+    end
+end
+% check names of IQMmodel functions
+functionNames = {};
+index = 1;
+if ~nameDoubletError,
+    for n = 1 : length(modelStruct.functions),
+        name = modelStruct.functions(n).name;
+        if strcmp(name, ''),
+            emptyNames{emptyNamesIndex} = char([double('Function No. '), double(numstr(n))]);
+            emptyNamesIndex = emptyNamesIndex + 1;
+            nameError = true;
+        else
+            if matchStringOnArray(name, stateNames),
+                errorGroup{1} = 'States';
+                errorGroup{2} = 'Functions';
+                errorName = name;
+                nameDoubletError = true;
+            elseif matchStringOnArray(name, parameterNames),
+                errorGroup{1} = 'Parameters';
+                errorGroup{2} = 'Functions';
+                errorName = name;
+                nameDoubletError = true;
+            elseif matchStringOnArray(name, variableNames),
+                errorGroup{1} = 'Variables';
+                errorGroup{2} = 'Functions';
+                errorName = name;
+                nameDoubletError = true;
+            elseif matchStringOnArray(name, reactionNames),
+                errorGroup{1} = 'Reactions';
+                errorGroup{2} = 'Functions';
+                errorName = name;
+                nameDoubletError = true;
+            elseif matchStringOnArray(name, functionNames),
+                errorGroup{1} = 'Reactions';
+                errorGroup{2} = 'Functions';
+                errorName = name;
+                nameDoubletError = true;
+            else
+                functionNames{index} = name;
+                index = index + 1;
+            end
+        end
+    end
+end
+% check names of IQMmodel events
+eventNames = {};
+index = 1;
+if ~nameDoubletError,
+    for n = 1 : length(modelStruct.events),
+        name = modelStruct.events(n).name;
+        if strcmp(name, ''),
+            emptyNames{emptyNamesIndex} = char([double('Event No. '), double(numstr(n))]);
+            emptyNamesIndex = emptyNamesIndex + 1;
+            nameError = true;
+        else
+            if matchStringOnArray(name, stateNames),
+                errorGroup{1} = 'States';
+                errorGroup{2} = 'Events';
+                errorName = name;
+                nameDoubletError = true;
+            elseif matchStringOnArray(name, parameterNames),
+                errorGroup{1} = 'Parameters';
+                errorGroup{2} = 'Events';
+                errorName = name;
+                nameDoubletError = true;
+            elseif matchStringOnArray(name, variableNames),
+                errorGroup{1} = 'Variables';
+                errorGroup{2} = 'Events';
+                errorName = name;
+                nameDoubletError = true;
+            elseif matchStringOnArray(name, reactionNames),
+                errorGroup{1} = 'Reactions';
+                errorGroup{2} = 'Events';
+                errorName = name;
+                nameDoubletError = true;
+            elseif matchStringOnArray(name, functionNames),
+                errorGroup{1} = 'Reactions';
+                errorGroup{2} = 'Events';
+                errorName = name;
+                nameDoubletError = true;
+            elseif matchStringOnArray(name, eventNames),
+                errorGroup{1} = 'Events';
+                errorGroup{2} = 'Events';
+                errorName = name;
+                nameDoubletError = true;
+            else
+                eventNames{index} = name;
+                index = index + 1;
+            end
+        end
+    end
+end
+
+errorMessage = {};
+errorIndex = 1;
+if nameError,
+    errorMessage{errorIndex} = 'The following IQMmodel components have no defined name(s):';
+    errorIndex = errorIndex + 1;
+    for n = 1 : length(emptyNames),
+        errorMessage{errorIndex} = emptyNames(n);
+        errorIndex = errorIndex + 1;
+    end
+    errorMessage{errorIndex} = '';
+    errorIndex = errorIndex + 1;
+end
+if nameDoubletError,
+    errorMessage{errorIndex} = char([double('The IQMmodel component "'), double(errorName), double('" has been found ')]);
+    errorIndex = errorIndex + 1;
+    if strcmp(errorGroup{1}, errorGroup{2}),
+        errorMessage{errorIndex} = char([double(' twice in IQMmodel '), double(errorGroup{1}), double('.')]);
+        errorIndex = errorIndex + 1;
+    else
+        errorMessage{errorIndex} = char([double(' in IQMmodel '), double(errorGroup{1}), double('and IQMmodel '), double(errorGroup{2}), double('.')]);
+        errorIndex = errorIndex + 1;
+    end
+    errorMessage{errorIndex} = '';
+    errorIndex = errorIndex + 1;
+end
+
+if (nameError || nameDoubletError),
+    if ~silentFlag,
+        messageOutput(errorMessage, 1);
+    end
+else    
+    namesOK = true;
+end
+
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/modeltools/convert2SBMLNotes.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/modeltools/convert2SBMLNotes.m
new file mode 100644
index 0000000000000000000000000000000000000000..0e948d4da5a9192f7745102c12ae2c8e626ef652
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/modeltools/convert2SBMLNotes.m	
@@ -0,0 +1,47 @@
+function [SBMLNotes] = convert2SBMLNotes(IQMmodelNotes)
+% convert2SBMLNotes
+% converts the notes string given by IQM Tools Lite that they can be used
+% through the SBML Toolbox (conversion to XHTML)
+%
+% USAGE:
+% ======
+% SBMLNotes = convert2SBMLNotes(IQMmodelNotes)
+%
+% IQMmodelNotes: a notes string created manually at the commmand
+%                     window or in one of the GUIs
+% SBMLNotes: a string in XHTML format that can be converted by SBML Toolbox
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+SBMLNotes = '';
+newline = sprintf('\n');
+notesStart = char([double('<html xmlns="http://www.w3.org/1999/xhtml">'), double(newline), double('<body>'), double(newline)]);
+notesEnd = char([double('</body>'), double(newline), double('</html>')]);
+
+% test wether input string is empty
+if (~isempty(IQMmodelNotes)),
+    % test wether notes do already contain xhtml tags
+   if ((~isempty(strfind(IQMmodelNotes, '<html'))) || (~isempty(strfind(IQMmodelNotes, '<body')))), 
+       disp(sprintf('WARNING: "IQMmodelNotes" already contain XHTML tags, conversion aborted!\nNotes are passed through without changes.'));
+       SBMLNotes = IQMmodelNotes;
+   else
+       % test wether notes field contains several lines
+       linebreaks = strfind(IQMmodelNotes, newline);
+       if (isempty(linebreaks)),
+           % build single line SBML notes
+           SBMLNotes = char([double(notesStart), double(IQMmodelNotes), double(notesEnd)]);
+       else
+           % build multiple line SBML notes
+           SBMLNotes = notesStart;
+           startPos = 1;
+           for index = 1 : length(linebreaks),
+               endPos = linebreaks(index)-1;
+               SBMLNotes = char([double(SBMLNotes), double('<p>'), double(IQMmodelNotes(startPos:endPos)), double('</p>'), double(newline)]);
+               startPos = linebreaks(index)+1;
+           end
+           SBMLNotes = char([double(SBMLNotes), double('<p>'), double(IQMmodelNotes(startPos:length(IQMmodelNotes))), double('</p>'), double(newline), double(notesEnd)]);
+       end
+   end
+end
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/modeltools/existsNameInIQMmodel.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/modeltools/existsNameInIQMmodel.m
new file mode 100644
index 0000000000000000000000000000000000000000..b898662fc13ffe09133b41ac697cff2a13b28a08
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/modeltools/existsNameInIQMmodel.m	
@@ -0,0 +1,44 @@
+function [boolvalue] = existsNameInIQMmodel(model, name, varargin)
+% existsNameInIQMmodel
+% checks wether a given name is already used in the given IQMmodel
+%
+%
+% USAGE:
+% ======
+% [boolvalue] = existsNameInIQMmodel(model, name)
+%
+% model: IQMmodel
+% name: string to test model for existence
+% 
+% boolvalue: true if there is already defined a component with the given
+%            name otherwise false
+%
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF IQMmodel
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~strcmp('IQMmodel',class(model)),
+    error('Function only defined for IQMmodels.');
+end
+
+silentFlag = 0;
+if (nargin == 2)
+    silentFlag = 0;
+elseif (nargin == 3)
+    silentFlag = varargin{1};
+end
+
+boolvalue = false;
+
+% fetch all names used within given IQMmodel and test wether given name is
+% already present
+names = getAllNamesFromIQMmodel(model);
+rowPos = matchStringOnArray(name, names);
+if (rowPos > 0)
+    boolvalue = true;
+end
+
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/modeltools/fetchCompartments.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/modeltools/fetchCompartments.m
new file mode 100644
index 0000000000000000000000000000000000000000..2c133dc4990253dd738e2c76716d00ed5ecde750
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/modeltools/fetchCompartments.m	
@@ -0,0 +1,95 @@
+function [compartmentList, origin, origIndex] = fetchCompartments(model)
+% getCompartments
+% looks wether there are predefined compartments in a IQMmodel
+%
+%
+% USAGE:
+% ======
+% [compartmentList, origin, origIndex] = getCompartments(model)
+%
+% model: search for preefined compartments within this IQMmodel
+% 
+% compartmentList: list of predefined compartments found in the model
+%
+% origin: number that indicates where there compartment is defined
+%         0 -> states
+%         1 -> parameters
+%         2 -> variables
+%
+% origIndex: index of the array structure where the compartment is to
+%            find within IQMmodel
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF IQMmodel
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~strcmp('IQMmodel',class(model)),
+    error('Function only defined for IQMmodels.');
+end
+
+componentNames = [];
+compartmentList = [];
+origin = [];
+origIndex = [];
+nameIndex = 1;
+cindex = 1;
+aindex = 1;
+assignedCompartments = [];
+
+% get model structure
+iqm = IQMstruct(model);
+statesCount=length(iqm.states);
+parametersCount=length(iqm.parameters);
+variablesCount=length(iqm.variables);
+
+% search states for compartments
+for k1 = 1 : statesCount,
+    componentNames{nameIndex} = iqm.states(k1).name;
+    nameIndex = nameIndex + 1;
+    if (strcmp(iqm.states(k1).type, 'isCompartment')),
+        compartmentList{cindex} = iqm.states(k1).name;
+        origin(cindex)=0;
+        origIndex(cindex)=k1;
+        cindex = cindex + 1;
+    end
+    if ~strcmp(iqm.states(k1).compartment, ''),
+        assignedCompartments{aindex}=iqm.states(k1).compartment;
+        aindex = aindex + 1;
+    end
+end
+
+% search parameters for compartments
+for k1 = 1 : parametersCount,
+    componentNames{nameIndex} = iqm.parameters(k1).name;
+    nameIndex = nameIndex + 1;
+    if (strcmp(iqm.parameters(k1).type, 'isCompartment')),
+        compartmentList{cindex} = iqm.parameters(k1).name;
+        origin(cindex)=1;
+        origIndex(cindex)=k1;
+        cindex = cindex + 1;
+    end
+    if ~strcmp(iqm.parameters(k1).compartment, ''),
+        assignedCompartments{aindex}=iqm.parameters(k1).compartment;
+        aindex = aindex + 1;
+    end
+end
+
+% search variables for compartments
+for k1 = 1 : variablesCount,
+    componentNames{nameIndex} = iqm.variables(k1).name;
+    nameIndex = nameIndex + 1;
+    if (strcmp(iqm.variables(k1).type, 'isCompartment')),
+        compartmentList{cindex} = iqm.variables(k1).name;
+        origin(cindex)=2;
+        origIndex(cindex)=k1;
+        cindex = cindex + 1;
+    end
+    if ~strcmp(iqm.variables(k1).compartment, ''),
+        assignedCompartments{aindex}=iqm.variables(k1).compartment;
+        aindex = aindex + 1;
+    end
+end
+
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/modeltools/getAllNamesFromIQMmodel.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/modeltools/getAllNamesFromIQMmodel.m
new file mode 100644
index 0000000000000000000000000000000000000000..81a5b5cad130dc9caebecb84ba9ed331a72d00b9
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/modeltools/getAllNamesFromIQMmodel.m	
@@ -0,0 +1,81 @@
+function [nameList] = getAllNamesFromIQMmodel(model, varargin)
+% getAllNamesFromIQMmodel
+% collects the names of all components used in the given IQMmodel
+%
+%
+% USAGE:
+% ======
+% [nameList] = getAllNamesFromIQMmodel(model)
+%
+% model: IQMmodel
+% 
+% nameList: list of component names used in the model
+%
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF IQMmodel
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~strcmp('IQMmodel',class(model)),
+    error('Function only defined for IQMmodels.');
+end
+
+silentFlag = 0;
+if nargin == 1,
+    silentFlag = 0;
+elseif nargin == 2,
+    silentFlag = varargin{1};
+end
+
+componentNames = [];
+nameIndex = 1;
+
+% get model structure and count model components
+iqm = IQMstruct(model);
+statesCount = length(iqm.states);
+parametersCount = length(iqm.parameters);
+variablesCount = length(iqm.variables);
+reactionsCount = length(iqm.reactions);
+eventsCount = length(iqm.events);
+functionsCount = length(iqm.functions);
+
+% fetch state names
+for k1 = 1 : statesCount,
+    componentNames{nameIndex} = iqm.states(k1).name;
+    nameIndex = nameIndex + 1;
+end
+
+% fetch parameter names
+for k1 = 1 : parametersCount,
+    componentNames{nameIndex} = iqm.parameters(k1).name;
+    nameIndex = nameIndex + 1;
+end
+
+% fetch variable names
+for k1 = 1 : variablesCount,
+    componentNames{nameIndex} = iqm.variables(k1).name;
+    nameIndex = nameIndex + 1;
+end
+
+% fetch reaction names
+for k1 = 1 : reactionsCount,
+    componentNames{nameIndex} = iqm.reactions(k1).name;
+    nameIndex = nameIndex + 1;
+end
+
+% fetch event names
+for k1 = 1 : eventsCount,
+    componentNames{nameIndex} = iqm.events(k1).name;
+    nameIndex = nameIndex + 1;
+end
+
+% fetch functions names
+for k1 = 1 : functionsCount,
+    componentNames{nameIndex} = iqm.functions(k1).name;
+    nameIndex = nameIndex + 1;
+end
+
+nameList = componentNames;
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/modeltools/getIQMmodelFunctionNames.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/modeltools/getIQMmodelFunctionNames.m
new file mode 100644
index 0000000000000000000000000000000000000000..26f57e06d40acbb3681adf1b72f0e899cc67bad2
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/modeltools/getIQMmodelFunctionNames.m	
@@ -0,0 +1,30 @@
+function [modelFunctionNames] = getIQMmodelFunctionNames(model)
+% getIQMmodelFunctionNames
+% gives back a structure containing all function names defined
+% in this IQMmodel
+%
+% USAGE:
+% ======
+% [modelFunctionNames] = getIQMmodelFunctionNames(IQMmodel) 
+%
+% IQMmodel: IQMmodel 
+%
+% modelFunctionNames: structure with all function names
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+% CHECK IF IQMmodel
+if ~strcmp('IQMmodel',class(model)),
+    error('Function only defined for IQMmodels.');
+end
+% get the datastructure of the model
+iqm = IQMstruct(model);
+
+modelFunctionNames = {};
+% fetch all names of defined function within given IQMmodel
+for index = 1 : length(iqm.functions),
+    modelFunctionNames{index} = iqm.functions(index).name;
+end
+
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/modeltools/isIQMmodelName.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/modeltools/isIQMmodelName.m
new file mode 100644
index 0000000000000000000000000000000000000000..9950beb2990dc56282984c3d78e0e2e68707a2d7
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/modeltools/isIQMmodelName.m	
@@ -0,0 +1,36 @@
+function [boolvalue] = isIQMmodelName(name, varargin)
+% isIQMmodelName
+% checks wether a given name complies with the used name standard
+% of the IQMmodel
+%
+%
+% USAGE:
+% ======
+% [boolvalue] = isIQMmodelName(name)
+%
+% name: string to test IQMmodel compliance
+% 
+% boolvalue: true if the given name complies with the IQMmodel name
+%            conventions 
+%
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+silentFlag = 0;
+if (nargin == 2)
+    silentFlag = 0;
+elseif (nargin == 3)
+    silentFlag = varargin{1};
+end
+
+boolvalue = false;
+
+%use regular expression to test, wether given name complies with IQMmodel
+%name conventions
+result=regexp(name, '([A-Z]|[a-z]|_)+([A-Z]|[a-z]|[0-9]|_)*');
+if (result == 1)
+    boolvalue = true;
+end
+
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/modeltools/testSBMLsettings.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/modeltools/testSBMLsettings.m
new file mode 100644
index 0000000000000000000000000000000000000000..5cc312485bd0a521da86a6d640ceb87db83d5363
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/modeltools/testSBMLsettings.m	
@@ -0,0 +1,419 @@
+function [sbmlCompliant, onlyDefaultCompartmentError] = testSBMLsettings(model, varargin)
+% testSBMLSettings
+% checks wether all SBML setings in a given IQMmodel are made
+%
+%
+% USAGE:
+% ======
+% [sbmlCompliant, onlyCompartmentError] = testSBMLsettings(model)
+%
+% model: IQMmodel where SBML settings are to test
+% 
+% sbmlCompliant: true if all SBML settings have been made and are correct
+% onlyDefaultCompartmentError: true if only errors concerning a missing default
+%                              compartment have been found
+%
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+silentFlag = 0;
+if (nargin == 2)
+    silentFlag = varargin{1};
+end
+
+rootCompartments = 0;
+compartmentCount = 0;
+compartmentList = {};
+notCompartmentCount = 0;
+componentList = {};
+
+sbmlCompliant = false;
+onlyDefaultCompartmentError = false;
+errorMessages = [];
+errorNumber = 0;
+
+modelStruct = IQMstruct(model);
+stateCount = length(modelStruct.states);
+parameterCount = length(modelStruct.parameters);
+variableCount = length(modelStruct.variables);
+
+% at first we perform a check for all compartments
+for n = 1 : stateCount
+    if strcmp(modelStruct.states(n).type, 'isCompartment')
+        compartmentCount = compartmentCount + 1;
+        compartmentList{compartmentCount} = modelStruct.states(n).name;
+        if strcmp(modelStruct.states(n).compartment, '')
+            rootCompartments = rootCompartments + 1;
+        end
+    else
+        notCompartmentCount = notCompartmentCount + 1;
+        componentList{notCompartmentCount} = modelStruct.states(n).name;
+    end
+end
+for n = 1 : parameterCount
+    if strcmp(modelStruct.parameters(n).type, 'isCompartment')
+        compartmentCount = compartmentCount + 1;
+        compartmentList{compartmentCount} = modelStruct.parameters(n).name;
+        if strcmp(modelStruct.parameters(n).compartment, '')
+            rootCompartments = rootCompartments + 1;
+        end
+    else
+        notCompartmentCount = notCompartmentCount + 1;
+        componentList{notCompartmentCount} = modelStruct.parameters(n).name;
+    end
+end
+for n = 1 : variableCount
+    if strcmp(modelStruct.variables(n).type, 'isCompartment')
+        compartmentCount = compartmentCount + 1;
+        compartmentList{compartmentCount} = modelStruct.variables(n).name;
+        if strcmp(modelStruct.variables(n).compartment, '')
+            rootCompartments = rootCompartments + 1;
+        end
+    else
+        notCompartmentCount = notCompartmentCount + 1;
+        componentList{notCompartmentCount} = modelStruct.variables(n).name;
+    end
+end
+
+if (compartmentCount == 0),
+    if ~silentFlag,
+        compartmentError{1} = 'This IQMmodel contains no compartments!';
+        compartmentError{2} = 'That means that an SBML export is not possible at the moment because at least one compartment is needed that "stores" all components described in your model.';
+        compartmentError{3} = 'If there are no special requirements to the surrounding compartment you can use the "addDefaultCompartment" function.';
+        messageOutput(compartmentError, 1);
+    end
+    onlyDefaultCompartmentError = true;
+elseif (rootCompartments == 0),
+    if ~silentFlag,
+        compartmentError{1} = 'This IQMmodel contains no root compartment!';
+        compartmentError{2} = 'SBML needs one root compartment that "stores" all components described in your model.';
+        messageOutput(compartmentError, 1);
+    end
+    onlyDefaultCompartmentError = true;
+elseif (rootCompartments > 1),
+    if ~silentFlag,
+        compartmentError{1} = 'This IQMmodel contains too many root compartments!';
+        compartmentError{2} = 'SBML supports only one root compartment, to bypass this circumstance give function: "addDefaultCompartment" a try.';
+        messageOutput(compartmentError, 1);
+    end
+    onlyDefaultCompartmentError = true;
+end
+foundLoop = checkCompartmentsForLoop(model, 1);
+if foundLoop,
+    compartmentError{1} = 'A loop has been detected within the compartment definitions. This cannot be fixed automatically.';
+    compartmentError{2} = 'Use "checkCompartmentsForLoop(IQMmodel)" to find out what might be the problem.';
+    compartmentError{3} = 'SBML export would not be possible under that circumstances.';
+    messageOutput(compartmentError, 1);
+    onlyDefaultCompartmentError = false;
+    return
+end
+
+for n = 1 : stateCount
+    name = modelStruct.states(n).name;
+    type = modelStruct.states(n).type;
+    unittype = modelStruct.states(n).unittype;
+    compartment = modelStruct.states(n).compartment;
+    localError = false;
+    if strcmp(type, 'isSpecie')
+        % test wether the unittype definitions match the SBML conventions
+        if ~(strcmp(unittype, 'amount') || strcmp(unittype, 'concentration'))
+            localError = true;
+            errorNumber = errorNumber + 1;
+            errorMessages{errorNumber} = char([double(name), double(' -> IQMmodel state No.: '), double(num2str(n))]);
+            errorNumber = errorNumber + 1;
+            errorMessages{errorNumber} = 'contains a bad unittype definition! ("model.states(no).unittype" can be "amount" or "concentration")';
+        elseif isempty(compartment)
+            localError = true;
+            errorNumber = errorNumber + 1;
+            errorMessages{errorNumber} = char([double(name), double(' -> IQMmodel state No.: '), double(num2str(n))]);
+            errorNumber = errorNumber + 1;
+            errorMessages{errorNumber} = 'this specie is not assigned to a compartment, this is not allowed for a SBML export! ("model.states(no).compartment" has to be filled)';
+        elseif ~isempty(compartment),
+            % test wether the compartment the actual component is located
+            % in is assigned as compartment
+            % afterwards test wether the compartment doesn't exists or
+            % wasn't not assigned to be a compartment
+            if (isempty(compartmentList) || ~matchStringOnArray(compartment, compartmentList))
+                localError = true;
+                if matchStringOnArray(compartment, componentList)
+                    errorNumber = errorNumber + 1;
+                    errorMessages{errorNumber} = char([double(name), double(' -> IQMmodel state No.: '), double(num2str(n))]);
+                    errorNumber = errorNumber + 1;
+                    errorMessages{errorNumber} = char([double('This '), double(type(3:length(type))), double(' is assigned to the compartment "'), double(compartment), double('" which is not marked as one.')]);
+                else
+                    errorNumber = errorNumber + 1;
+                    errorMessages{errorNumber} = char([double(name), double(' -> IQMmodel state No.: '), double(num2str(n))]);
+                    errorNumber = errorNumber + 1;
+                    errorMessages{errorNumber} = char([double('The compartment "'), double(compartment), double('" this '), double(type(3:length(type))), double(' is assigned to, doesn''t exist in this IQMmodel')]);
+                end    
+            end
+        end       
+    elseif strcmp(type, 'isCompartment')
+        if ~isempty(unittype),
+            localError = true;
+            errorNumber = errorNumber + 1;
+            errorMessages{errorNumber} = char([double(name), double(' -> IQMmodel state No.: '), double(num2str(n)), double('  '),double(unittype)]);
+            errorNumber = errorNumber + 1;
+            errorMessages{errorNumber} = 'components marked as SBML Compartments are not allowed to have a unittype (clear "model.states(no).unittype" field)';
+        elseif isempty(compartment),
+            % not needed at the moment, because if number of root
+            % compartments is wrong the functions is stopped in an ealier
+            % state
+        elseif ~isempty(compartment),
+            % test wether the compartment the actual component is located
+            % in is assigned as compartment
+            % afterwards test wether the compartment doesn't exists or
+            % wasn't not assigned to be a compartment
+            if (isempty(compartmentList) || ~matchStringOnArray(compartment, compartmentList))
+                localError = true;
+                if matchStringOnArray(compartment, componentList)
+                    errorNumber = errorNumber + 1;
+                    errorMessages{errorNumber} = char([double(name), double(' -> IQMmodel state No.: '), double(num2str(n))]);
+                    errorNumber = errorNumber + 1;
+                    errorMessages{errorNumber} = char([double('This '), double(type(3:length(type))), double(' is assigned to the compartment "'), double(compartment), double('" which is not marked as one.')]);
+                else
+                    errorNumber = errorNumber + 1;
+                    errorMessages{errorNumber} = char([double(name), double(' -> IQMmodel state No.: '), double(num2str(n))]);
+                    errorNumber = errorNumber + 1;
+                    errorMessages{errorNumber} = char([double('The compartment "'), double(compartment), double('" this '), double(type(3:length(type))), double(' is assigned to, doesn''t exist in this IQMmodel')]);
+                end    
+            end
+        end
+    elseif strcmp(type, 'isParameter')
+        if (length(unittype) ~= 0)
+            localError = true;
+            errorNumber = errorNumber + 1;
+            errorMessages{errorNumber} = char([double(name), double(' -> IQMmodel state No.: '), double(num2str(n))]);
+            errorNumber = errorNumber + 1;
+            errorMessages{errorNumber} = 'components marked as SBML Parameter are not allowed to have a unittype (clear "model.states(no).unittype" field)';
+        elseif ~isempty(compartment),
+            localError = true;
+            errorNumber = errorNumber + 1;
+            errorMessages{errorNumber} = char([double(name), double(' -> IQMmodel state No.: '), double(num2str(n))]);
+            errorNumber = errorNumber + 1;
+            errorMessages{errorNumber} = 'components marked as SBML Parameter are not allowed to be located within a compartment (clear (clear "model.states(no).compartment" field)';
+        end 
+    else
+        localError = true;
+        errorNumber = errorNumber + 1;
+        errorMessages{errorNumber} = char([double(name), double(' -> IQMmodel state No.: '), double(num2str(n))]);
+        errorNumber = errorNumber + 1;
+        errorMessages{errorNumber} = 'no SBML type information found (possibilities for "model.states(no).type" are "isSpecie", "isParameter", "isCompartment")';
+    end
+    if localError,
+        errorNumber = errorNumber + 1;
+        errorMessages{errorNumber} = ' ';
+        localError = false;
+    end
+end
+
+for n = 1 : parameterCount
+    name = modelStruct.parameters(n).name;
+    type = modelStruct.parameters(n).type;
+    unittype = modelStruct.parameters(n).unittype;
+    compartment = modelStruct.parameters(n).compartment;
+    localError = false;
+    if strcmp(type, 'isSpecie')
+        % test wether the unittype definitions match the SBML conventions
+        if ~(strcmp(unittype, 'amount') || strcmp(unittype, 'concentration'))
+            localError = true;
+            errorNumber = errorNumber + 1;
+            errorMessages{errorNumber} = char([double(name), double(' -> IQMmodel parameter No.: '), double(num2str(n))]);
+            errorNumber = errorNumber + 1;
+            errorMessages{errorNumber} = 'contains a bad unittype definition! ("model.parameters(no).unittype" can be "amount" or "concentration")';
+        elseif isempty(compartment),
+            localError = true;
+            errorNumber = errorNumber + 1;
+            errorMessages{errorNumber} = char([double(name), double(' -> IQMmodel parameter No.: '), double(num2str(n))]);
+            errorNumber = errorNumber + 1;
+            errorMessages{errorNumber} = 'this specie is not assigned to a compartment, this is not allowed for a SBML export! ("model.parameters(no).compartment" has to be filled)';
+        elseif ~isempty(compartment),
+            % test wether the compartment the actual component is located
+            % in is assigned as compartment
+            % afterwards test wether the compartment doesn't exists or
+            % wasn't not assigned to be a compartment
+            if (isempty(compartmentList) || ~matchStringOnArray(compartment, compartmentList))
+                localError = true;
+                if matchStringOnArray(compartment, componentList)
+                    errorNumber = errorNumber + 1;
+                    errorMessages{errorNumber} = char([double(name), double(' -> IQMmodel parameter No.: '), double(num2str(n))]);
+                    errorNumber = errorNumber + 1;
+                    errorMessages{errorNumber} = char([double('This '), double(type(3:length(type))), double(' is assigned to the compartment "'), double(compartment), double('" which is not marked as one.')]);
+                else
+                    errorNumber = errorNumber + 1;
+                    errorMessages{errorNumber} = char([double(name), double(' -> IQMmodel parameter No.: '), double(num2str(n))]);
+                    errorNumber = errorNumber + 1;
+                    errorMessages{errorNumber} = char([double('The compartment "'), double(compartment), double('" this '), double(type(3:length(type))), double(' is assigned to, doesn''t exist in this IQMmodel')]);
+                end    
+            end
+        end       
+    elseif strcmp(type, 'isCompartment')
+        if ~isempty(unittype),
+            localError = true;
+            errorNumber = errorNumber + 1;
+            errorMessages{errorNumber} = char([double(name), double(' -> IQMmodel parameter No.: '), double(num2str(n))]);
+            errorNumber = errorNumber + 1;
+            errorMessages{errorNumber} = 'components marked as SBML Compartments are not allowed to have a unittype (clear "model.parameters(no).unittype" field)';
+        elseif isempty(compartment),
+            % not needed at the moment, because if number of root
+            % compartments is wrong the functions is stopped in an ealier
+            % state
+        elseif ~isempty(compartment),
+            % test wether the compartment the actual component is located
+            % in is assigned as compartment
+            % afterwards test wether the compartment doesn't exists or
+            % wasn't not assigned to be a compartment
+            if (isempty(compartmentList) || ~matchStringOnArray(compartment, compartmentList))
+                localError = true;
+                if matchStringOnArray(compartment, componentList)
+                    errorNumber = errorNumber + 1;
+                    errorMessages{errorNumber} = char([double(name), double(' -> IQMmodel parameter No.: '), double(num2str(n))]);
+                    errorNumber = errorNumber + 1;
+                    errorMessages{errorNumber} = char([double('This '), double(type(3:length(type))), double(' is assigned to the compartment "'), double(compartment), double('" which is not marked as one.')]);
+                else
+                    errorNumber = errorNumber + 1;
+                    errorMessages{errorNumber} = char([double(name), double(' -> IQMmodel parameter No.: '), double(num2str(n))]);
+                    errorNumber = errorNumber + 1;
+                    errorMessages{errorNumber} = char([double('The compartment "'), double(compartment), double('" this '), double(type(3:length(type))), double(' is assigned to, doesn''t exist in this IQMmodel')]);
+                end    
+            end
+        end
+    elseif strcmp(type, 'isParameter')
+        if ~isempty(unittype),
+            localError = true;
+            errorNumber = errorNumber + 1;
+            errorMessages{errorNumber} = char([double(name), double(' -> IQMmodel parameter No.: '), double(num2str(n))]);
+            errorNumber = errorNumber + 1;
+            errorMessages{errorNumber} = 'components marked as SBML Parameter are not allowed to have a unittype (clear "model.parameters(no).unittype" field)';
+        elseif ~isempty(compartment),
+            localError = true;
+            errorNumber = errorNumber + 1;
+            errorMessages{errorNumber} = char([double(name), double(' -> IQMmodel parameter No.: '), double(num2str(n))]);
+            errorNumber = errorNumber + 1;
+            errorMessages{errorNumber} = 'components marked as SBML Parameter are not allowed to be located within a compartment (clear (clear "model.parameters(no).compartment" field)';
+        end 
+    else
+        localError = true;
+        errorNumber = errorNumber + 1;
+        errorMessages{errorNumber} = char([double(name), double(' -> IQMmodel parameter No.: '), double(num2str(n))]);
+        errorNumber = errorNumber + 1;
+        errorMessages{errorNumber} = 'no SBML type information found (possibilities for "model.parameters(no).type" are "isSpecie", "isParameter", "isCompartment")';
+    end
+    if localError
+        errorNumber = errorNumber + 1;
+        errorMessages{errorNumber} = ' ';
+        localError = false;
+    end
+end
+
+for n = 1 : variableCount
+    name = modelStruct.variables(n).name;
+    type = modelStruct.variables(n).type;
+    unittype = modelStruct.variables(n).unittype;
+    compartment = modelStruct.variables(n).compartment;
+    localError = false;
+    if strcmp(type, 'isSpecie')
+        % test wether the unittype definitions match the SBML conventions
+        if ~(strcmp(unittype, 'amount') || strcmp(unittype, 'concentration'))
+            localError = true;
+            errorNumber = errorNumber + 1;
+            errorMessages{errorNumber} = char([double(name), double(' -> IQMmodel variable No.: '), double(num2str(n))]);
+            errorNumber = errorNumber + 1;
+            errorMessages{errorNumber} = 'contains a bad unittype definition! ("model.variables(no).unittype" can be "amount" or "concentration")';
+        elseif isempty(compartment),
+            localError = true;
+            errorNumber = errorNumber + 1;
+            errorMessages{errorNumber} = char([double(name), double(' -> IQMmodel variable No.: '), double(num2str(n))]);
+            errorNumber = errorNumber + 1;
+            errorMessages{errorNumber} = 'this specie is not assigned to a compartment, this is not allowed for a SBML export! ("model.variables(no).compartment" has to be filled)';
+        elseif ~isempty(compartment),
+            % test wether the compartment the actual component is located
+            % in is assigned as compartment
+            % afterwards test wether the compartment doesn't exists or
+            % wasn't not assigned to be a compartment
+            if (isempty(compartmentList) || ~matchStringOnArray(compartment, compartmentList))
+                localError = true;
+                if matchStringOnArray(compartment, componentList)
+                    errorNumber = errorNumber + 1;
+                    errorMessages{errorNumber} = char([double(name), double(' -> IQMmodel variable No.: '), double(num2str(n))]);
+                    errorNumber = errorNumber + 1;
+                    errorMessages{errorNumber} = char([double('This '), double(type(3:length(type))), double(' is assigned to the compartment "'), double(compartment), double('" which is not marked as one.')]);
+                else
+                    errorNumber = errorNumber + 1;
+                    errorMessages{errorNumber} = char([double(name), double(' -> IQMmodel variable No.: '), double(num2str(n))]);
+                    errorNumber = errorNumber + 1;
+                    errorMessages{errorNumber} = char([double('The compartment "'), double(compartment), double('" this '), double(type(3:length(type))), double(' is assigned to, doesn''t exist in this IQMmodel')]);
+                end    
+            end
+        end       
+    elseif strcmp(type, 'isCompartment')
+        if ~isempty(unittype),
+            localError = true;
+            errorNumber = errorNumber + 1;
+            errorMessages{errorNumber} = char([double(name), double(' -> IQMmodel variable No.: '), double(num2str(n))]);
+            errorNumber = errorNumber + 1;
+            errorMessages{errorNumber} = 'components marked as SBML Compartments are not allowed to have a unittype (clear "model.variables(no).unittype" field)';
+        elseif isempty(compartment),
+            % not needed at the moment, because if number of root
+            % compartments is wrong the functions is stopped in an ealier
+            % state
+        elseif ~isempty(compartment),
+            % test wether the compartment the actual component is located
+            % in is assigned as compartment
+            % afterwards test wether the compartment doesn't exists or
+            % wasn't not assigned to be a compartment
+            if (isempty(compartmentList) || ~matchStringOnArray(compartment, compartmentList))
+                localError = true;
+                if matchStringOnArray(compartment, componentList)
+                    errorNumber = errorNumber + 1;
+                    errorMessages{errorNumber} = char([double(name), double(' -> IQMmodel variable No.: '), double(num2str(n))]);
+                    errorNumber = errorNumber + 1;
+                    errorMessages{errorNumber} = char([double('This '), double(type(3:length(type))), double(' is assigned to the compartment "'), double(compartment), double('" which is not marked as one.')]);
+                else
+                    errorNumber = errorNumber + 1;
+                    errorMessages{errorNumber} = char([double(name), double(' -> IQMmodel variable No.: '), double(num2str(n))]);
+                    errorNumber = errorNumber + 1;
+                    errorMessages{errorNumber} = char([double('The compartment "'), double(compartment), double('" this '), double(type(3:length(type))), double(' is assigned to, doesn''t exist in this IQMmodel')]);
+                end    
+            end
+        end
+    elseif strcmp(type, 'isParameter')
+        if ~isempty(unittype),
+            localError = true;
+            errorNumber = errorNumber + 1;
+            errorMessages{errorNumber} = char([double(name), double(' -> IQMmodel variable No.: '), double(num2str(n))]);
+            errorNumber = errorNumber + 1;
+            errorMessages{errorNumber} = 'components marked as SBML Parameter are not allowed to have a unittype (clear "model.variables(no).unittype" field)';
+        elseif ~isempty(compartment),
+            localError = true;
+            errorNumber = errorNumber + 1;
+            errorMessages{errorNumber} = char([double(name), double(' -> IQMmodel variable No.: '), double(num2str(n))]);
+            errorNumber = errorNumber + 1;
+            errorMessages{errorNumber} = 'components marked as SBML Parameter are not allowed to be located within a compartment (clear (clear "model.variables(no).compartment" field)';
+        end 
+    else
+        localError = true;
+        errorNumber = errorNumber + 1;
+        errorMessages{errorNumber} = char([double(name), double(' -> IQMmodel variable No.: '), double(num2str(n))]);
+        errorNumber = errorNumber + 1;
+        errorMessages{errorNumber} = 'no SBML type information found (possibilities for "model.variables(no).type" are "isSpecie", "isParameter", "isCompartment")';
+    end
+    if localError
+        errorNumber = errorNumber + 1;
+        errorMessages{errorNumber} = ' ';
+        localError = false;
+    end
+end
+
+if (errorNumber > 0),
+    if (~silentFlag),
+        messageOutput(errorMessages, 1);
+    end
+elseif onlyDefaultCompartmentError,
+    return
+else    
+    sbmlCompliant = true;
+end
+
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/stringtools/isBracketstring.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/stringtools/isBracketstring.m
new file mode 100644
index 0000000000000000000000000000000000000000..7a9a79b76c2df376a013058e6c27578fcf078f87
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/stringtools/isBracketstring.m	
@@ -0,0 +1,44 @@
+function [isBracketstring] = isBracketstring(string)
+%isBracketstring
+% a simple test wether the given string contains squared brackets, curly
+% brackets or parenthesis
+%
+% USAGE:
+% ======
+%
+% [boolean] = isBracketString(string)
+%
+% string: test string
+%
+% boolean: true if string contains (, ), {, }, [ or ]
+%          false otherwise
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+    if strfind(string, '('),
+        isBracketstring = 1;
+        return;
+    end
+    if strfind(string, ')'),
+        isBracketstring = 1;
+        return;
+    end
+    if strfind(string, '['),
+        isBracketstring = 1;
+        return;
+    end
+    if strfind(string, ']'),
+        isBracketstring = 1;
+        return;
+    end
+    if strfind(string, '{'),
+        isBracketstring = 1;
+        return;
+    end
+    if strfind(string, '}'),
+        isBracketstring = 1;
+        return;
+    end
+    isBracketstring = 0;
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/stringtools/isBracketstringWellformed.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/stringtools/isBracketstringWellformed.m
new file mode 100644
index 0000000000000000000000000000000000000000..18ca4e9f45ab5da9fc28c2101a26f656269f4f16
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/stringtools/isBracketstringWellformed.m	
@@ -0,0 +1,43 @@
+function [wellFormed] = isBracketstringWellformed(string)
+%isBracketStringWellformed
+% checks wether the order of opened and closed braces as well as
+% their count is valid
+%
+% USAGE:
+% ======
+%
+% [wellFormed] = isBracketstringWellformed(string)
+%
+% string: i.e. a formula where correct bracketing is to test
+%
+% wellFormed: true or false
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+    wellFormed = 0;
+    openedBrackets={'{','[','('};
+    closedBrackets={'}',']',')'};
+    stack='';
+    index=1;
+    for k = 1 : length(string),
+        if ~isempty(strmatchIQM(string(k), openedBrackets)),
+            stack(index) = string(k);
+            % stack
+            index = index + 1;
+        elseif ~isempty(strmatchIQM(string(k), closedBrackets)),
+            if isempty(stack),
+                return;
+            elseif (int8(string(k))-1 == int8(stack(index-1))) || (int8(string(k))-2 == int8(stack(index-1))),
+                index = index - 1;
+                stack = stack(1:index-1);
+                % stack
+            else
+                return;
+            end
+        end
+    end
+    if isempty(stack),
+        wellFormed = 1;
+    end
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/stringtools/isClosedBracket.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/stringtools/isClosedBracket.m
new file mode 100644
index 0000000000000000000000000000000000000000..8e626fabfeb5c51940ee3c30c760c0f9afe5fb31
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/stringtools/isClosedBracket.m	
@@ -0,0 +1,26 @@
+function [isClosedBracket] = isClosedBracket(character)
+%isClosedBracket
+% checks wether the given character is a closing bracket
+%
+%
+% USAGE:
+% ======
+%
+% boolean = isClosedBracket(character)
+%
+% character: a letter or sign
+%
+% boolean: 1 if character is ']', '}' or ')'
+%          otherwise 0
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+    closedBrackets=['}',']',')'];
+    if strfind(closedBrackets, character),
+        isClosedBracket = 1;
+        return;
+    else
+        isClosedBracket = 0;
+    end
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/stringtools/isFOSign.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/stringtools/isFOSign.m
new file mode 100644
index 0000000000000000000000000000000000000000..3e4826378b5713dc1365e34778fcb7f7030083c7
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/stringtools/isFOSign.m	
@@ -0,0 +1,24 @@
+function [boolean] = isFOSign(character)
+% isFOSign
+% checks, wether character is sign of "First Order" (+ or -)
+%
+% USAGE:
+% ======
+%
+% [boolean] = isFOSign(character)
+%
+% character: test character
+%
+% boolean: true if character is mathematical operator of first order (+ or -)
+%          otherwise false
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+boolean = false;
+
+if (strcmp(character, '+') || strcmp(character, '-')),
+    boolean = true;
+end
+
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/stringtools/isFunctionIdentifier.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/stringtools/isFunctionIdentifier.m
new file mode 100644
index 0000000000000000000000000000000000000000..ced4d0188fbafbbfd0bc0c7725800187f9c08882
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/stringtools/isFunctionIdentifier.m	
@@ -0,0 +1,58 @@
+function [isFunctionIdentifier] = isFunctionIdentifier(identifier, varargin)
+%isFunctionIdentifier
+% checks wether identifier is a reserved function identifier
+%
+% USAGE:
+% ======
+% [boolean] = isFunctionIdentifier(identifier)
+% identifier: test token
+%
+% boolean: true if identifier is a reserved MATLAB function identifier
+%          false otherwise
+%
+% [boolean] = isFunctionIdentifier(identifier, IQMmodel) 
+% identifier: test token
+% IQMmodel: IQMmodel 
+%
+% boolean: true if identifier is a reserved MATLAB function identifier or
+%          if identifier is already used in the supplied IQMmodel
+%          false otherwise
+%
+% For a list of reserved function identifiers take a look at the code,
+% please!
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+modelGiven = false;
+if nargin == 2,
+    % get all function names from given model
+    iqmmodel = varargin{1};
+    modelGiven = true;
+end
+
+    isFunctionIdentifier = false;
+    % Corresponding MATLAB expressions
+    FunctionExpressions = {'acos', 'asin', 'atan', 'ceil', 'log',...
+        'log10', 'power', 'acos', 'acosh', 'acot', 'acoth', 'acsc',...
+        'acsch', 'asec', 'asech', 'asin', 'asinh', 'atan', 'atanh',...
+        'exp', 'logbase', 'piecewise', 'and', 'or', 'gt', 'lt', 'eq',...
+        'ge', 'le', 'mod', 'piecewiseIQM', 'andIQM', 'orIQM'};
+    for index = 1 : length(FunctionExpressions),
+        if strcmp(identifier, FunctionExpressions{index}),
+            isFunctionIdentifier = true;
+            return;
+        end
+    end
+    
+    % if IQMmodel given, test function names there, too
+    if modelGiven,
+        functionNames = getIQMmodelFunctionNames(iqmmodel);
+        for index = 1 : length(functionNames),
+            if strcmp(identifier, functionNames{index}),
+                isFunctionIdentifier = true;
+                return;
+            end
+        end
+    end
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/stringtools/isLetter2.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/stringtools/isLetter2.m
new file mode 100644
index 0000000000000000000000000000000000000000..9da4f9e752b658589de1d0a0e40bb1630a195359
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/stringtools/isLetter2.m	
@@ -0,0 +1,34 @@
+function [isLetter] = isLetter2(character)
+%isLetter2
+% tests wether a given character is a Letter
+% (it's a simpler and faster implementation for stringhandling)
+%
+% USAGE:
+% ======
+%
+% [boolean]= isLetter2(character)
+%
+% character: character to test
+%
+% boolean: true if character is A, ..., Z, a, ..., z, "_"
+%          otherwise false
+%
+% For more details take a look at the code, please!
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+    % Option 1: letterMatrix = ['a':'z','A':'Z','_'];
+    %           if strfind(letterMatrix, character),
+    %
+    % the latter variant could be usefull if reactionnames can consist of
+    % more special characters i.e. ('#', '_', '%', '$', ...)
+    % 
+    %at the moment this one is the fastest
+    if isstrprop(character, 'alpha') || (character == '_'),
+        isLetter = 1;
+    else
+        isLetter = 0;
+    end
+
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/stringtools/isNumber.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/stringtools/isNumber.m
new file mode 100644
index 0000000000000000000000000000000000000000..b790ac461f2a838ce34da441b165baba5925bbe1
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/stringtools/isNumber.m	
@@ -0,0 +1,35 @@
+function [isNumber] = isNumber(character)
+%isNumber
+% tests wether a given character belongs to a digit or float
+% (it's a simpler and faster implementation for stringhandling)
+%
+% USAGE:
+% ======
+%
+% [boolean]= isNumber(character)
+%
+% character: character to test
+%
+% boolean: true if character is 0, ..., 9, "."
+%          otherwise false
+%
+% For more details take a look at the code, please!
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+    % if isstrprop(character, 'digit'),
+    % => slowest implementation for our needs
+    %
+    % if isnumeric(character),
+    % => seems to be fast for it self, but slows down the complete
+    % function!?!
+    % the following one showed the best results in "Profiler" runs
+    numberMatrix = ['0':'9','.'];
+    if strfind(numberMatrix, character),
+        isNumber = 1;
+    else
+        isNumber = 0;
+    end
+
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/stringtools/isOpenedBracket.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/stringtools/isOpenedBracket.m
new file mode 100644
index 0000000000000000000000000000000000000000..cc04e026c52ba36906b9ad6c6f6c687bef75ea02
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/stringtools/isOpenedBracket.m	
@@ -0,0 +1,26 @@
+function [isOpenedBracket] = isOpenedBracket(character)
+%isOpenedBracket
+% checks wether the given character is an opening bracket
+%
+%
+% USAGE:
+% ======
+%
+% boolean = isOpenedBracket(character)
+%
+% character: a letter or sign
+%
+% boolean: 1 if character is '[', '{' or '('
+%          otherwise 0
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+    openedBrackets = ['{','[','('];
+    if strfind(openedBrackets, character),
+        isOpenedBracket = 1;
+        return;
+    else
+        isOpenedBracket = 0;
+    end
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/stringtools/isSOSign.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/stringtools/isSOSign.m
new file mode 100644
index 0000000000000000000000000000000000000000..378a8c58ed8ccd032402ae356f0ac334e87b283d
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/stringtools/isSOSign.m	
@@ -0,0 +1,24 @@
+function [boolean] = isSOSign(character)
+% isSOSign
+% checks, wether character is sign of "Second Order" (* or /)
+%
+% USAGE:
+% ======
+%
+% [boolean] = isSOSign(character)
+%
+% character: test character
+%
+% boolean: true if character is mathematical operator of second order
+%          (* or /) otherwise false
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+boolean = false;
+
+if (strcmp(character, '*') || strcmp(character, '/')),
+    boolean = true;
+end
+
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/stringtools/isSign.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/stringtools/isSign.m
new file mode 100644
index 0000000000000000000000000000000000000000..40bc79c7778004707eb3d4f4d5e3e7530a7f28fb
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/stringtools/isSign.m	
@@ -0,0 +1,26 @@
+function [isSign] = isSign(character)
+%isSign
+% checks wether the given character is an maths operator
+%
+%
+% USAGE:
+% ======
+%
+% boolean = isSign(character)
+%
+% character: a letter or sign
+%
+% boolean: 1 if character is '+', '-', '*', '/' or '^'
+%          otherwise 0
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+    matchMatrix = ['+','-','*','/','^'];
+    if strfind(matchMatrix, character),
+        isSign = 1;
+    else
+        isSign = 0;
+    end
+
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/stringtools/matchStringOnArray.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/stringtools/matchStringOnArray.m
new file mode 100644
index 0000000000000000000000000000000000000000..82e2771e7c53aea46f7aba179dcf61bddc448e82
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/stringtools/matchStringOnArray.m	
@@ -0,0 +1,28 @@
+function [rowPos] = matchStringOnArray(patternString, matchingArray)
+%matchStringOnArray
+% A string match function which gives back the row number of the
+% first occurence of the pattern string within the matching array.
+% (it's a simpler and faster implementation for stringhandling)
+%
+% USAGE:
+% ======
+% [rowPos] = matchStringOnArray(patternString, matchingArray)
+%
+% matchingArray: an array of String
+% patternString: a string to test for occurance in the array
+%
+% rowPos: 0 if string doesn't occur in array
+%         >0 (row number) otherwise -> can be used as boolean value
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+rowPos = 0;
+searchResult = strcmp(patternString, matchingArray);
+for n1 = 1 : length(searchResult),
+    if searchResult(n1),
+        rowPos = n1;
+        break;
+    end
+end
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/stringtools/messageOutput.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/stringtools/messageOutput.m
new file mode 100644
index 0000000000000000000000000000000000000000..55e0b81afb1ed877088268caf4c8801dd7a4512c
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLexport/stringtools/messageOutput.m	
@@ -0,0 +1,116 @@
+function [success] = messageOutput(messages, varargin)
+% messageOutput
+% prints a formated page containing all messages given through the cell
+% array contained in the variable messages
+%
+%
+% USAGE:
+% ======
+% [success] = messageOutput(messages)
+% [success] = messageOutput(messages, type)
+%
+% messages: cell array with output messages
+% type:     kind of messages (1 -> error, 2 -> warning, 3 -> info)
+%           if the user doesn't provide a type variable the messagetype
+%           will be set to info
+% 
+% success: boolean value, false in case that something went wrong
+%
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+%test function parameter
+silentFlag = 0;
+messageType = '';
+if (nargin == 1)
+    silentFlag = 0;
+    messageType = 'Info: ';
+elseif (nargin == 2)
+    switch varargin{1}
+        case 1 
+            messageType = 'Error: ';
+        case 2
+            messageType = 'Warning: ';
+        case 3
+            messageType = 'Info: ';
+        otherwise
+            disp('Sorry, but this message type is not supported!');
+            success = false;
+            return
+    end    
+elseif (nargin == 3)
+    silentFlag = varargin{2};
+end
+
+% prepare line start
+lineStart = [32, 32, 35, 32];
+
+%prepare line end
+lineEnd = [32, 35, 32, 32];
+
+%prepare titleline
+%fetch calling M-file
+[ST, I] = dbstack;
+title = [double(messageType), double(ST(2).name)];
+titleline = [lineStart, title, getBlanks(length(lineStart) + length(title)), lineEnd];
+
+% prepare borderline
+for column = 1 : 90
+    if (column < 3 || column > 88)
+        borderline(column) = 32;
+    else
+        borderline(column) = 35;
+    end
+end
+
+% message output header
+sprintf('\n');
+disp(char(borderline));
+disp(char(titleline));
+disp(char(borderline));
+% message output body
+for lineNo = 1 : length(messages)
+    % build output message line
+    if length(messages{lineNo}) < 82
+        line = [lineStart, double(messages{lineNo}), getBlanks(length(lineStart) + length(messages{lineNo})), lineEnd];
+    else
+        % in case that line exceeds 82 letters split the line at a blank at
+        % the latest possible position in front of column 82
+        help = messages{lineNo};
+        while (length(help) > 82)
+            splitIndices = regexp(help, ' ');
+            lastIndex = 1;
+            for index = 2 : length(splitIndices)
+                if (splitIndices(index) > 82)
+                    text = help(1:splitIndices(lastIndex));
+                    help = help((splitIndices(lastIndex) + 1) : length(help));
+                    break;
+                elseif (index == length(splitIndices))
+                    text = help(1:splitIndices(index));
+                    help = help((splitIndices(index) + 1) : length(help));
+                    break;
+                end
+                lastIndex = index;
+            end
+            line = [lineStart, double(text), getBlanks(length(lineStart) + length(text)), lineEnd];
+            disp(char(line));
+        end
+        line = [lineStart, double(help), getBlanks(length(lineStart) + length(help)), lineEnd];
+    end
+    disp(char(line));
+end
+disp(char(borderline));
+
+success = true;
+return
+
+
+% helper function to get number of blanks
+function [blanks] = getBlanks(start)
+blankscount = 86 - start;
+blanks = [];
+for i = 1 : blankscount
+    blanks(i) = 32;
+end
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLimport/convert2IQMNotes.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLimport/convert2IQMNotes.m
new file mode 100644
index 0000000000000000000000000000000000000000..ab3f08abffc95c725ad887438c11e43c24db91a5
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLimport/convert2IQMNotes.m	
@@ -0,0 +1,31 @@
+function [IQMNotes] = convert2IQMNotes(SBMLmodelNotes,flag)
+% convert2IQMNotes
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+IQMNotes = regexprep(SBMLmodelNotes,'<html xmlns="http://www.w3.org/1999/xhtml">','');
+IQMNotes = regexprep(IQMNotes,'</html>','');
+IQMNotes = regexprep(IQMNotes,'<body xmlns="http://www.w3.org/1999/xhtml">','');
+IQMNotes = regexprep(IQMNotes,'<body>','');
+IQMNotes = regexprep(IQMNotes,'</body>','');
+IQMNotes = regexprep(IQMNotes,'<p>','');
+IQMNotes = regexprep(IQMNotes,'<p/>','');
+IQMNotes = regexprep(IQMNotes,'</p>','');
+IQMNotes = regexprep(IQMNotes,'<br>','');
+IQMNotes = regexprep(IQMNotes,'<br/>','');
+IQMNotes = regexprep(IQMNotes,'</br>','');
+IQMNotes = regexprep(IQMNotes,'<h1>','');
+IQMNotes = regexprep(IQMNotes,'</h1>','');
+IQMNotes = regexprep(IQMNotes,'<h2>','');
+IQMNotes = regexprep(IQMNotes,'</h2>','');
+IQMNotes = regexprep(IQMNotes,'<h3>','');
+IQMNotes = regexprep(IQMNotes,'</h3>','');
+IQMNotes = regexprep(IQMNotes,'<notes>','');
+IQMNotes = regexprep(IQMNotes,'</notes>','');
+IQMNotes = regexprep(IQMNotes,'<p xmlns="http://www.w3.org/1999/xhtml">','');
+IQMNotes = regexprep(IQMNotes,'<br xmlns="http://www.w3.org/1999/xhtml">','');
+IQMNotes = regexprep(IQMNotes,'=','');
+if flag,
+    IQMNotes = regexprep(IQMNotes,'\n','');
+end
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLimport/convertName2IdIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLimport/convertName2IdIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..a470d4cbb1ece3d4335fbd0848dfe77ba8b220ea
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLimport/convertName2IdIQM.m	
@@ -0,0 +1,270 @@
+function [newSBMLmodel] = convertName2IdIQM(SBMLmodel)
+% Convert all ids and corresponding names
+% for compartments, species, parameters, reactions
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+newIds = {};
+oldIds = {};
+names = {};
+
+% COMPARTMENTS
+for k=1:length(SBMLmodel.compartment),
+    if ~isempty(SBMLmodel.compartment(k).name),
+        testid_base = regexprep(SBMLmodel.compartment(k).name,'\W','_');
+        testid = testid_base;
+        % check if testid exists already as new ids
+        ext = 1;
+        while 1,
+            if ~isempty(strmatchIQM(testid,newIds,'exact')),
+                testid = sprintf('%s_%d',testid_base,ext);
+            else
+                break;
+            end
+            ext = ext+1;
+        end
+        % check if numeric or underscore as first character then add something
+        x = double(testid(1));
+        if x == double('_') || (x >= 48 && x <= 57),
+            testid = ['C' testid];
+        end       
+        % go on
+        names{end+1} = SBMLmodel.compartment(k).name;
+        oldIds{end+1} = SBMLmodel.compartment(k).id;
+        newIds{end+1} = testid;
+        SBMLmodel.compartment(k).id = testid;
+    end
+end
+
+% SPECIES
+for k=1:length(SBMLmodel.species),
+    if ~isempty(SBMLmodel.species(k).name),
+        testid_base = regexprep(SBMLmodel.species(k).name,'\W','_');
+        testid = testid_base;
+        % check if testid exists already as new ids
+        ext = 1;
+        while 1,
+            if ~isempty(strmatchIQM(testid,newIds,'exact')),
+                testid = sprintf('%s_%d',testid_base,ext);
+            else
+                break;
+            end
+            ext = ext+1;
+        end
+        % check if numeric or underscore as first character then add something
+        x = double(testid(1));
+        if x == double('_') || (x >= 48 && x <= 57),
+            testid = ['S_' testid];
+        end       
+        % go on        
+        names{end+1} = SBMLmodel.species(k).name;
+        oldIds{end+1} = SBMLmodel.species(k).id;
+        newIds{end+1} = testid;
+        SBMLmodel.species(k).id = testid;        
+    end
+end
+
+% PARAMETERS
+for k=1:length(SBMLmodel.parameter),
+    if ~isempty(SBMLmodel.parameter(k).name),
+        testid_base = regexprep(SBMLmodel.parameter(k).name,'\W','_');
+        testid = testid_base;
+        % check if testid exists already as new ids
+        ext = 1;
+        while 1,
+            if ~isempty(strmatchIQM(testid,newIds,'exact')),
+                testid = sprintf('%s_%d',testid_base,ext);
+            else
+                break;
+            end
+            ext = ext+1;
+        end
+        % check if numeric or underscore as first character then add something
+        x = double(testid(1));
+        if x == double('_') || (x >= 48 && x <= 57),
+            testid = ['P_' testid];
+        end       
+        % go on           
+        names{end+1} = SBMLmodel.parameter(k).name;
+        oldIds{end+1} = SBMLmodel.parameter(k).id;
+        newIds{end+1} = testid;
+        SBMLmodel.parameter(k).id = testid;        
+    end
+end
+
+% REACTIONS
+for k=1:length(SBMLmodel.reaction),
+    if ~isempty(SBMLmodel.reaction(k).name),
+        testid_base = regexprep(SBMLmodel.reaction(k).name,'\W','_');
+        testid = testid_base;
+        % check if testid exists already as new ids
+        ext = 1;
+        while 1,
+            if ~isempty(strmatchIQM(testid,newIds,'exact')),
+                testid = sprintf('%s_%d',testid_base,ext);
+            else
+                break;
+            end
+            ext = ext+1;
+        end
+        % check if numeric or underscore as first character then add something
+        x = double(testid(1));
+        if x == double('_') || (x >= 48 && x <= 57),
+            testid = ['R_' testid];
+        end       
+        % go on            
+        names{end+1} = SBMLmodel.reaction(k).name;
+        oldIds{end+1} = SBMLmodel.reaction(k).id;
+        newIds{end+1} = testid;
+        SBMLmodel.reaction(k).id = testid;                
+    end
+end
+
+% EVENTS
+for k=1:length(SBMLmodel.event),
+    if ~isempty(SBMLmodel.event(k).name),
+        testid_base = regexprep(SBMLmodel.event(k).name,'\W','_');
+        testid = testid_base;
+        % check if testid exists already as new ids
+        ext = 1;
+        while 1,
+            if ~isempty(strmatchIQM(testid,newIds,'exact')),
+                testid = sprintf('%s_%d',testid_base,ext);
+            else
+                break;
+            end
+            ext = ext+1;
+        end
+        % check if numeric or underscore as first character then add something
+        x = double(testid(1));
+        if x == double('_') || (x >= 48 && x <= 57),
+            testid = ['E_' testid];
+        end       
+        % go on                
+        names{end+1} = SBMLmodel.event(k).name;
+        oldIds{end+1} = SBMLmodel.event(k).id;
+        newIds{end+1} = testid;
+        SBMLmodel.event(k).id = testid;                
+    end
+end
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Add regexp logic to oldIds
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for k=1:length(oldIds),
+    oldIds{k} = strcat('\<',oldIds{k},'\>');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Exchange all oldIds agaist new Ids
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Compartment ids in species
+for k=1:length(SBMLmodel.species),
+    SBMLmodel.species(k).compartment = regexprep(SBMLmodel.species(k).compartment,oldIds,newIds);
+end
+
+% Species ids in reactions 
+for k=1:length(SBMLmodel.reaction),
+    % Reactants
+    for k2=1:length(SBMLmodel.reaction(k).reactant)
+        SBMLmodel.reaction(k).reactant(k2).species = regexprep(SBMLmodel.reaction(k).reactant(k2).species,oldIds,newIds);
+    end
+    % Products
+    for k2=1:length(SBMLmodel.reaction(k).product)
+        SBMLmodel.reaction(k).product(k2).species = regexprep(SBMLmodel.reaction(k).product(k2).species,oldIds,newIds);
+    end
+    % Modifiers
+    for k2=1:length(SBMLmodel.reaction(k).modifier)
+        SBMLmodel.reaction(k).modifier(k2).species = regexprep(SBMLmodel.reaction(k).modifier(k2).species,oldIds,newIds);
+    end
+    % Kinetic Law
+    if ~isempty(SBMLmodel.reaction(k).kineticLaw),
+        SBMLmodel.reaction(k).kineticLaw.formula = regexprep(SBMLmodel.reaction(k).kineticLaw.formula,oldIds,newIds);
+        SBMLmodel.reaction(k).kineticLaw.math = regexprep(SBMLmodel.reaction(k).kineticLaw.math,oldIds,newIds);
+    end
+end
+
+% Ids in rule definitions
+for k=1:length(SBMLmodel.rule),
+    % variable
+    SBMLmodel.rule(k).variable = regexprep(SBMLmodel.rule(k).variable,oldIds,newIds);
+    % species
+    SBMLmodel.rule(k).species = regexprep(SBMLmodel.rule(k).species,oldIds,newIds);
+    % compartment
+    SBMLmodel.rule(k).compartment = regexprep(SBMLmodel.rule(k).compartment,oldIds,newIds);
+    % formula
+    SBMLmodel.rule(k).formula = regexprep(SBMLmodel.rule(k).formula,oldIds,newIds);    
+end
+
+% Ids in event definitions
+for k=1:length(SBMLmodel.event),
+    % variable
+    if isstruct(SBMLmodel.event(k).trigger),
+        SBMLmodel.event(k).trigger = regexprep(SBMLmodel.event(k).trigger.math,oldIds,newIds);
+    else
+        SBMLmodel.event(k).trigger = regexprep(SBMLmodel.event(k).trigger,oldIds,newIds);
+    end
+    % assignments
+    for k2=1:length(SBMLmodel.event(k).eventAssignment),
+        SBMLmodel.event(k).eventAssignment(k2).variable = regexprep(SBMLmodel.event(k).eventAssignment(k2).variable,oldIds,newIds);
+        SBMLmodel.event(k).eventAssignment(k2).math = regexprep(SBMLmodel.event(k).eventAssignment(k2).math,oldIds,newIds);
+    end
+end
+
+% Compartment ids in species
+if isfield(SBMLmodel,'initialAssignment'),
+    for k=1:length(SBMLmodel.initialAssignment),
+        SBMLmodel.initialAssignment(k).symbol = regexprep(SBMLmodel.initialAssignment(k).symbol,oldIds,newIds);
+        SBMLmodel.initialAssignment(k).math = regexprep(SBMLmodel.initialAssignment(k).math,oldIds,newIds);
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE LOCAL PARAMETERS IN REACTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% LOCAL PARAMETERS IN REACTIONS
+for k=1:length(SBMLmodel.reaction),
+    if ~isempty(SBMLmodel.reaction(k).kineticLaw),
+        newIds = {};
+        oldIds = {};
+        names = {};
+        for k2 = 1:length(SBMLmodel.reaction(k).kineticLaw.parameter)
+            if ~isempty(SBMLmodel.reaction(k).kineticLaw.parameter(k2).name),
+                testid_base = regexprep(SBMLmodel.reaction(k).kineticLaw.parameter(k2).name,'\W','_');
+                testid = testid_base;
+                % check if correct first character and fix it eventually
+                if double(testid(1))>=48 && double(testid(1))<=57,
+                    testid = sprintf('para_%s',testid);
+                end
+                % check if testid exists already as new ids
+                ext = 1;
+                while 1,
+                    if ~isempty(strmatchIQM(testid,newIds,'exact')),
+                        testid = sprintf('%s_%d',testid_base,ext);
+                    else
+                        break;
+                    end
+                    ext = ext+1;
+                end
+                names{end+1} = SBMLmodel.reaction(k).kineticLaw.parameter(k2).name;
+                oldIds{end+1} = SBMLmodel.reaction(k).kineticLaw.parameter(k2).id;
+                newIds{end+1} = testid;
+                SBMLmodel.reaction(k).kineticLaw.parameter(k2).id = testid;
+            end
+        end
+        for k2=1:length(oldIds),
+            oldIds{k2} = strcat('\<',oldIds{k2},'\>');
+        end
+        SBMLmodel.reaction(k).kineticLaw.formula = regexprep(SBMLmodel.reaction(k).kineticLaw.formula,oldIds,newIds);
+        SBMLmodel.reaction(k).kineticLaw.math = regexprep(SBMLmodel.reaction(k).kineticLaw.math,oldIds,newIds);
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% RETURN result
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+newSBMLmodel = SBMLmodel;
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLimport/convertSBML2IQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLimport/convertSBML2IQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..f11932ee0756526ce0c6c9f6ee8386d066785c10
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLimport/convertSBML2IQM.m	
@@ -0,0 +1,1555 @@
+function [IQMstructure,errorMsg] = convertSBML2IQM(SBMLmodel,SBMLmodelFile)
+% convertSBML2IQM
+% Converting a SBML Level 2 MATLAB structure to the object model structure
+% used in the toolbox
+%
+% Private method 
+%
+% [IQMstructure,errorMsg] = convertSBML2IQM(SBMLmodel);
+%
+% Simple error checking is provided. In the case of an error an empty
+% structure is returned.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INITIALIZE ERROR MESSAGES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+errorMsg = '';
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Do some checks if supported or not
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+contents = fileread(SBMLmodelFile);
+
+% Stoichiometry math wrongly handeled in libSBML
+if ~isempty(strfind(contents,'<stoichiometryMath>')),
+    errorMsg = sprintf('%s\nStoichiometry math construct is wrongly handeled in libSBML and thus not supported currently in IQM Tools.\n',errorMsg);
+end
+
+% Do not consider delay things in the model
+if ~isempty(strfind(contents,'<delay>')),
+    errorMsg = sprintf('%s\nDelays in SBML models are not supported in IQM Tools.\n',errorMsg);
+end
+
+% Do not consider delay things in the model
+if ~isempty(strfind(contents,'symbols/delay')),
+    errorMsg = sprintf('%s\nDelays in SBML models are not supported in IQM Tools.\n',errorMsg);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Start conversion
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+global SBMLtimesymbol
+
+% additional global variable to record species that have amount initial
+% units but are converted to concentration ... and the corresponding
+% compartment
+global amount2concentration
+amount2concentration = [];
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CREATE AN EMPTY IQMSTRUCTURE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+IQMstructure = struct(IQMmodel());
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK TIME SYMBOL
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% From SBML Toolbobx 2.0.2 on a time_symbol field exists in the
+% SBMLmodel. We need to get the time symbol if it is there and replace
+% all occurrences in the model with 'time'.
+if isfield(SBMLmodel,'time_symbol'),
+    SBMLtimesymbol = SBMLmodel.time_symbol;
+else
+    SBMLtimesymbol = '';
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% NAME AND NOTES (INCLUDE IN STRUCTURE)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~strcmp(SBMLmodel.name,''),
+    IQMstructure.name = SBMLmodel.name;
+elseif ~strcmp(SBMLmodel.id,''),
+    IQMstructure.name = SBMLmodel.id;
+else
+    IQMstructure.name = 'Unknown model';
+end
+% Indicate in notes that the model has been created by import from SBML.
+IQMstructure.notes = strtrim(convert2IQMNotes(SBMLmodel.notes,0));
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% FUNCTIONS (INCLUDE IN STRUCTURE)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for k = 1:length(SBMLmodel.functionDefinition),
+    functionName = SBMLmodel.functionDefinition(k).id;
+    functionMath = SBMLmodel.functionDefinition(k).math;
+    % take away the lambda( ... ) and only leave the ...
+    expression = removeWhiteSpace(functionMath(8:length(functionMath)-1));
+    % take away power functions
+    expression = exchangepowerexp(expression);
+    % explode at the comma (not within parentheses)
+    [elements] = explodePCIQM(expression);
+    % last element is the formula, the others are the arguments
+    functionFormula = elements{end};
+    functionArguments = expression(1:end-length(functionFormula)-1);
+    % replace eventual MathML expressions by MATLAB expressions
+    [functionFormula] = replaceMathMLexpressions(functionFormula);
+    % include function into structure
+    
+    IQMstructure.functions(k).name = functionName;
+    IQMstructure.functions(k).arguments = functionArguments;
+    IQMstructure.functions(k).formula = functionFormula;
+    IQMstructure.functions(k).notes = convert2IQMNotes(SBMLmodel.functionDefinition(k).notes,1);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% SOME COUNTER DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% States and parameters are included in the structure in their order of
+% appearance. For variables no counters are needed, since their order 
+% is defined by the ordering of the scalar rules and not by their order of 
+% appearance (see below)
+numberStates = 1;
+numberParameters = 1;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% ORDERING OF VARIABLES (SCALAR RULES)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Scalar rules lead always to the definition of variables. The order of
+% appearance of the rules is important and thus the order of appearance of
+% the variables should reflect the ordering of the rules. We determine an
+% array in which the the index i determines the priority of the scalar rule, and
+% the i-th array element the index of the corresponding scalar rule. Rate
+% rules do not have to be considered since they are evaluated at last
+% anyway
+orderScalarRules = strmatchIQM('SBML_ASSIGNMENT_RULE',{SBMLmodel.rule.typecode});
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% SPECIES (INCLUDE IN STRUCTURE)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Species of the model are included in the structure as follows:
+%
+% Non-boundary species:
+%   - rate rule: as state
+%   - scalar rule: as variable
+%   - no rule: as state
+%
+% Boundary species:
+%   - rate rule: as states
+%   - scalar rule: as variable
+%   - no rule: as parameter
+%
+% If initial values of species given as concentrations:
+%   - They will be treated as concentrations, this means the ODE will be
+%     adjusted by diving the amount rate with the corresponding compartment
+%     volume.
+%
+% If initial values of species given as amounts:
+%   - They will be treated as amounts, this means the ODE will NOT be
+%     adjusted!
+%
+% The rate formulas in the kinetic laws are just taken as they are. This
+% means a mix of concentration and amount species might occur - the user 
+% has him/herself to take care to have the correct rate laws!
+%
+% Species that have amount units will be divided with their compartment volume in each expression later on
+speciesAmount_SAVEnames = {};
+speciesAmount_SAVEcompartments = {};
+%
+% Species that are defined by rate rules need this rate rule to be multiplied by the compartment the species is in.
+
+%
+speciesODElist = [];
+speciesODElistIndex = 1;
+% Check if there are any species. 
+if isempty(SBMLmodel.species),
+%    errorMsg = sprintf('%s\n%s\n',errorMsg,'No species are defined in the SBML model');
+%     warning('No species are defined in the SBML model - uncertain if model conversion will lead to a working IQMmodel!');
+end
+% Cycle through all the species and determine how they are to be included
+% in the model structure
+for k1 = 1:length(SBMLmodel.species),
+%%
+    speciesName = SBMLmodel.species(k1).id;
+    speciesCompartmentName = SBMLmodel.species(k1).compartment;
+    speciesNotes = convert2IQMNotes(SBMLmodel.species(k1).notes,1);
+    % get the compartment size for this species
+    makeItAmountAnyway = 0;
+    for k2 = 1:length(SBMLmodel.compartment),
+        if strcmp(speciesCompartmentName, SBMLmodel.compartment(k2).id),
+            compartmentSize = SBMLmodel.compartment(k2).size;
+            if isempty(compartmentSize),
+                errorMsg = sprintf('%s\nNo compartment size defined for compartment ''%s''\n',errorMsg,speciesCompartmentName);
+                compartmentSize = 1; % set to whatever, error will still occurr!
+            end
+            spatialDimensions = SBMLmodel.compartment(k2).spatialDimensions;
+            if spatialDimensions == 0 || compartmentSize == 0,
+                makeItAmountAnyway = 1;
+            end
+            break;
+        end
+    end
+    % determine the initial value for species
+    % if hasOnlySubstanceUnits is true then it is amount, otherwise it is concentration
+    initialCondition = [];
+    if SBMLmodel.species(k1).hasOnlySubstanceUnits || makeItAmountAnyway || (SBMLmodel.species(k1).isSetInitialAmount && ~SBMLmodel.species(k1).hasOnlySubstanceUnits ),% && ~isempty(SBMLmodel.species(k1).substanceUnits)),
+        % It is amount ... need to calculate if needed
+        % Only if substanceunits is not substance
+%         if ~strcmp(SBMLmodel.species(k1).substanceUnits,'substance') && ~SBMLmodel.species(k1).hasOnlySubstanceUnits,
+            speciesAmount_SAVEnames{end+1} = SBMLmodel.species(k1).id;
+            speciesAmount_SAVEcompartments{end+1} = SBMLmodel.species(k1).compartment;
+%         end
+
+        speciesUnits = 'amount';
+        if SBMLmodel.species(k1).isSetInitialAmount,
+            initialCondition = SBMLmodel.species(k1).initialAmount;
+        elseif SBMLmodel.species(k1).isSetInitialConcentration,
+            initialCondition = SBMLmodel.species(k1).initialConcentration*compartmentSize;
+        else 
+            initialCondition = NaN;
+        end
+    else
+        % It is concentration
+        speciesUnits = 'concentration';
+        if SBMLmodel.species(k1).isSetInitialAmount,
+            initialCondition = SBMLmodel.species(k1).initialAmount/compartmentSize;
+        elseif SBMLmodel.species(k1).isSetInitialConcentration,
+            initialCondition = SBMLmodel.species(k1).initialConcentration;
+        else 
+            initialCondition = NaN;
+        end
+    end
+% initialCondition
+% speciesUnits
+    %%
+    % Check the number of rules the species is in and get the index
+    % of the last rule the species is used in together with its type
+    % ('rate' or 'scalar') and the right hand side expression 'formula'
+    [numberRulesSpecies,lastRuleIndex,lastRuleType,lastRuleFormula,errorMsg] = getRules(speciesName,SBMLmodel,errorMsg);
+    if numberRulesSpecies > 1,
+        % Species defined by more than one rule => error
+        errorMsg = sprintf('%s\nSpecies ''%s'' defined by more than one rule\n',errorMsg,speciesName);
+    end
+    % Process all the species that DO NOT have a boundary condition
+    % In case the species is non-constant it is included as for Level 1
+    % In case the species is constant it is included as ODE with RHS 0 and initial condition as value
+    if SBMLmodel.species(k1).constant == 0,
+        if SBMLmodel.species(k1).boundaryCondition == 0,
+            if numberRulesSpecies == 0,
+                % add species to the ODE list (for use below in ODE
+                % construction)
+                speciesODElist(speciesODElistIndex).name = speciesName;
+                speciesODElist(speciesODElistIndex).stateIndex = numberStates;
+                speciesODElist(speciesODElistIndex).units = speciesUnits;
+                speciesODElistIndex = speciesODElistIndex + 1;
+                % Include species as state
+                IQMstructure.states(numberStates).name = speciesName;
+                % Check if an initial value is set for a species
+                if isempty(initialCondition),
+%                     errorMsg = sprintf('%s\nNo initial value defined for species ''%s''\n',errorMsg,speciesName);
+                    initialCondition = 0;
+                end
+                IQMstructure.states(numberStates).initialCondition = initialCondition;
+                % Note that this state is a 'species'
+                % Notes are not used by the toolbox for other things as
+                % documentation
+                IQMstructure.states(numberStates).notes = speciesNotes;
+                IQMstructure.states(numberStates).type = 'isSpecie';
+                IQMstructure.states(numberStates).compartment = SBMLmodel.species(k1).compartment;
+                IQMstructure.states(numberStates).unittype = speciesUnits;                
+                % Initialize the ODE field for this state
+                IQMstructure.states(numberStates).ODE = '';
+                % Increment
+                numberStates = numberStates+1;
+            elseif numberRulesSpecies == 1,
+                % Before including the species in the model structure we have
+                % to check if this species is also used in reactions as product
+                % or reactant. In this case an error message will be issued,
+                % since non-boundary species are not allowed to appear in
+                % reactions and rules.
+                reactionSpeciesPresent = checkReactionsForSpecies(speciesName,SBMLmodel);
+                if reactionSpeciesPresent,
+                    % Species is also present in a reaction. This means the SBML
+                    % model is inconsistent. => error
+                    errorMsg = sprintf('%s\nSpecies ''%s'' defined by rule and altered by reactions\n',errorMsg,speciesName);
+                end
+                % Even in the case of an error we continue here with the
+                % processing - The error message will take care of returning
+                % an empty model structure at the end
+                if strcmp(lastRuleType,'rate'),
+                    % Species added as a state, since rule of type 'rate'
+                    IQMstructure.states(numberStates).name = speciesName;
+                    % check if an initial value is set for a species
+                    if isempty(initialCondition),
+%                         errorMsg = sprintf('%s\nNo initial value defined for species ''%s''\n',errorMsg,speciesName);
+                        initialCondition = 0;
+                    end
+                    % Include initial value into structure
+                    IQMstructure.states(numberStates).initialCondition = initialCondition;
+                    % Include the RHS formula as the ODE for this species state
+                    % in case of speciesUnits='concentration' keep as is the rule.
+                    % But in case of amount then multiply by compartment.
+                    
+                    formula_use = lastRuleFormula;
+                    if strcmp(speciesUnits,'amount'),
+                        formula_use = ['(' lastRuleFormula ')*' SBMLmodel.species(k1).compartment];
+                    end
+                    IQMstructure.states(numberStates).ODE = formula_use;
+                    
+                    % Set a note that type of state is 'species'
+                    IQMstructure.states(numberStates).notes = speciesNotes;
+                    % initialize type, compartment, and unittype fields
+                    IQMstructure.states(numberStates).type = 'isSpecie';
+                    IQMstructure.states(numberStates).compartment = SBMLmodel.species(k1).compartment;
+                    IQMstructure.states(numberStates).unittype = speciesUnits;                
+                    % Increment
+                    numberStates = numberStates+1;
+                else
+                    % Species added as a variable, since rule of type 'scalar'
+                    % Determine the index where to include the variable (based
+                    % on the ordering of the scalar rules)
+                    
+                    formula_use = lastRuleFormula;
+                    if sum([SBMLmodel.species.isSetInitialConcentration]) == 0,
+                        formula_use = ['(' lastRuleFormula ')*' SBMLmodel.species(k1).compartment];
+                    end
+                    
+                    indexVariable = find(orderScalarRules==lastRuleIndex);
+                    IQMstructure.variables(indexVariable).name = speciesName;
+                    IQMstructure.variables(indexVariable).formula = formula_use;
+                    IQMstructure.variables(indexVariable).notes = speciesNotes;
+                    % initialize type, compartment, and unittype fields
+                    IQMstructure.variables(indexVariable).type = 'isSpecie';
+                    IQMstructure.variables(indexVariable).compartment = SBMLmodel.species(k1).compartment;
+                    IQMstructure.variables(indexVariable).unittype = speciesUnits;
+                end
+            end
+            % The case where numberRulesSpecies > 1 does not have to be treated
+            % here since already an error message is set above. This error
+            % message will lead to an empty model structure at the end. Even
+            % if the error is set the rest of the model will be processed.
+            % This has the advantage that all errors can be
+            % detected at once and makes the control structure of this script
+            % simpler.
+        else
+            % Process all the species that DO have a boundary condition
+            if numberRulesSpecies == 0,
+                % Include boundary species as a parameter
+                IQMstructure.parameters(numberParameters).name = speciesName;
+                % Check if an initial amount is set for a species
+                if isempty(initialCondition),
+%                     errorMsg = sprintf('%s\nNo initial value defined for species ''%s''\n',errorMsg,speciesName);
+                    initialCondition = 0;
+                end
+                % Include initial value
+                IQMstructure.parameters(numberParameters).value = initialCondition;
+                % Set note that type of the parameter is 'boundaey species'
+                IQMstructure.parameters(numberParameters).notes = speciesNotes;
+                % initialize type, compartment, and unittype fields
+                IQMstructure.parameters(numberParameters).type = 'isSpecie';
+                IQMstructure.parameters(numberParameters).compartment = SBMLmodel.species(k1).compartment;
+                IQMstructure.parameters(numberParameters).unittype = speciesUnits;
+                % Increment
+                numberParameters = numberParameters+1;
+            elseif numberRulesSpecies == 1,
+                % Boundary species may appear as products and reactants in
+                % reactions.
+                if strcmp(lastRuleType,'rate'),
+                    % Boundary species added as a state, since rule of type 'rate'
+                    IQMstructure.states(numberStates).name = speciesName;
+                    % check if an initial amount is set for a species
+                    if isempty(initialCondition),
+%                         errorMsg = sprintf('%s\nNo initial value defined for species ''%s''\n',errorMsg,speciesName);
+                        initialCondition = 0;
+                    end
+                    % Include initial value in structure
+                    IQMstructure.states(numberStates).initialCondition = initialCondition;
+                    % Include the RHS formula as the ODE for this species state
+                    IQMstructure.states(numberStates).ODE = lastRuleFormula;
+                    % Set note that type of the state is 'boundary species'
+                    IQMstructure.states(numberStates).notes = speciesNotes;
+                    % initialize type, compartment, and unittype fields
+                    IQMstructure.states(numberStates).type = 'isSpecie';
+                    IQMstructure.states(numberStates).compartment = SBMLmodel.species(k1).compartment;
+                    IQMstructure.states(numberStates).unittype = speciesUnits;
+                    % Increment
+                    numberStates = numberStates+1;
+                else
+                    % Boundary species added as a variable, since rule of type 'scalar'
+                    % Determine the index where to include the variable (based
+                    % on the ordering of the scalar rules)
+                    indexVariable = find(orderScalarRules==lastRuleIndex);
+                    IQMstructure.variables(indexVariable).name = speciesName;
+                    IQMstructure.variables(indexVariable).formula = lastRuleFormula;
+                    IQMstructure.variables(indexVariable).notes = speciesNotes;
+                    % initialize type, compartment, and unittype fields
+                    IQMstructure.variables(indexVariable).type = 'isSpecie';
+                    IQMstructure.variables(indexVariable).compartment = SBMLmodel.species(k1).compartment;
+                    IQMstructure.variables(indexVariable).unittype = speciesUnits;
+                end
+            end
+        end
+    else
+        % Species defined as being constant!
+        % Thus include it as state with ODE RHS 0
+        IQMstructure.states(numberStates).name = speciesName;
+        % check if an initial amount is set for a species
+        if isempty(initialCondition),
+            %                         errorMsg = sprintf('%s\nNo initial value defined for species ''%s''\n',errorMsg,speciesName);
+            initialCondition = 0;
+        end
+        % Include initial value in structure
+        IQMstructure.states(numberStates).initialCondition = initialCondition;
+        % 0 RHS since constant
+        IQMstructure.states(numberStates).ODE = '0';
+        % Set note that type of the state is 'boundary species'
+        IQMstructure.states(numberStates).notes = speciesNotes;
+        % initialize type, compartment, and unittype fields
+        IQMstructure.states(numberStates).type = 'isSpecie';
+        IQMstructure.states(numberStates).compartment = SBMLmodel.species(k1).compartment;
+        IQMstructure.states(numberStates).unittype = speciesUnits;
+        % Increment
+        numberStates = numberStates+1;
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PARAMETERS (INCLUDE IN STRUCTURE)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% First process the global parameters and check if rules exist for them
+%   - rate rule: as state
+%   - scalar rule: as variable
+%   - no rule: as parameter
+%
+% Then process the local parameters. They can only be parameters, no 
+% rules can exist for them. In case of collisions:
+%
+% parameter-parameter: colliding parameters are prefixed by their reaction 
+%                      names (global parameters are not prefixed)
+%
+% parameter-species: are prefixed by reaction name
+%
+% parameter-compartment: are prefixed by reactio name
+%
+% Start with global parameters
+for k = 1:length(SBMLmodel.parameter),
+    parameterName = SBMLmodel.parameter(k).id;
+    parameterValue = SBMLmodel.parameter(k).value;
+    parameterNotes = convert2IQMNotes(SBMLmodel.parameter(k).notes,1);
+    % Check the number of rules the parameter is in and get the index
+    % of the last rule the parameter is used in together with its type
+    % ('rate' or 'scalar') and the right hand side expression 'formula'
+    [numberRulesParameter,lastRuleIndex,lastRuleType,lastRuleFormula,errorMsg] = getRules(parameterName,SBMLmodel,errorMsg);
+    if numberRulesParameter > 1,
+        % Parameter defined by more than one rule => error
+        errorMsg = sprintf('%s\nParameter ''%s'' defined by more than one rule\n',errorMsg,parameterName);
+    end
+    if numberRulesParameter == 0 || SBMLmodel.parameter(k).constant,
+        % Include parameter as parameter
+        IQMstructure.parameters(numberParameters).name = parameterName;
+        % Check if a value is set for the parameter
+        if length(parameterValue)==0,
+            errorMsg = sprintf('%s\nNo value defined defined for parameter ''%s''\n',errorMsg,parameterName);
+        end
+        % Include value in IQMstructure
+        IQMstructure.parameters(numberParameters).value = parameterValue;
+        % Set note that type of the parameter is 'global'
+        IQMstructure.parameters(numberParameters).notes = parameterNotes; 
+        % initialize type, compartment, and unittype fields
+        IQMstructure.parameters(numberParameters).type = 'isParameter';
+        IQMstructure.parameters(numberParameters).compartment = '';
+        IQMstructure.parameters(numberParameters).unittype = '';                
+        % Increment
+        numberParameters = numberParameters+1;
+    elseif numberRulesParameter == 1,
+        % One rule has been detected for this parameter
+        if strcmp(lastRuleType,'rate'),
+            % Parameter added as a state, since rule of type 'rate'
+            IQMstructure.states(numberStates).name = parameterName;
+            % check if an initial amount is set for the parameter
+            if length(parameterValue)==0,
+                errorMsg = sprintf('%s\nNo value defined for parameter ''%s''\n',errorMsg,parameterName);
+            end
+            % Include value as initial value in IQMstructure
+            IQMstructure.states(numberStates).initialCondition = parameterValue;
+            % Include the RHS formula as the ODE for this parameter state
+            IQMstructure.states(numberStates).ODE = lastRuleFormula;
+            % Set note that type of the state is 'parameter rule'
+            IQMstructure.states(numberStates).notes = parameterNotes;
+            % initialize type, compartment, and unittype fields
+            IQMstructure.states(numberStates).type = 'isParameter';
+            IQMstructure.states(numberStates).compartment = '';
+            IQMstructure.states(numberStates).unittype = '';                
+            % Increment
+            numberStates = numberStates+1;
+        else
+            % Parameter added as a variable, since rule of type 'scalar'
+            % Determine the index where to include the variable (based
+            % on the ordering of the scalar rules)
+            indexVariable = find(orderScalarRules==lastRuleIndex);
+            IQMstructure.variables(indexVariable).name = parameterName;
+            IQMstructure.variables(indexVariable).formula = lastRuleFormula;
+            IQMstructure.variables(indexVariable).notes = parameterNotes;
+            % initialize type, compartment, and unittype fields
+            IQMstructure.variables(indexVariable).type = 'isParameter';
+            IQMstructure.variables(indexVariable).compartment = '';
+            IQMstructure.variables(indexVariable).unittype = '';               
+        end
+    end
+end
+% Then include the local parameters within the different reactions
+% Name collisions are avoided by adding the reaction name in front of each
+% local parameter.
+for k1 = 1:length(SBMLmodel.reaction),
+    % get the current reaction name
+    reactionName = SBMLmodel.reaction(k1).id;
+    if ~isempty(SBMLmodel.reaction(k1).kineticLaw),
+        for k2 = 1:length(SBMLmodel.reaction(k1).kineticLaw.parameter),
+            % get the current local parameter in reaction reactionName
+            parameterName = SBMLmodel.reaction(k1).kineticLaw.parameter(k2).id;
+            parameterValue = SBMLmodel.reaction(k1).kineticLaw.parameter(k2).value;
+            parameterNotes = convert2IQMNotes(SBMLmodel.reaction(k1).kineticLaw.parameter(k2).notes,1);
+            % check if a value is set for the parameter
+            if length(parameterValue)==0,
+                errorMsg = sprintf('%s\nNo value defined for parameter ''%s'' in reaction ''%s''\n',errorMsg,parameterName,reactionName);
+            end
+            % add the reaction name to the parameter and update the kinetic rate law
+            parameterName = char([double(reactionName) double('_') double(parameterName)]);  % fastest strcat ;)
+            % Include parameter in the structure
+            IQMstructure.parameters(numberParameters).name = parameterName;
+            IQMstructure.parameters(numberParameters).value = parameterValue;
+            IQMstructure.parameters(numberParameters).notes = parameterNotes;
+            % initialize type, compartment, and unittype fields
+            IQMstructure.parameters(numberParameters).type = 'isParameter';
+            IQMstructure.parameters(numberParameters).compartment = '';
+            IQMstructure.parameters(numberParameters).unittype = '';
+            numberParameters = numberParameters+1;
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% COMPARTMENTS (INCLUDE IN STRUCTURE)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Include compartments
+% No rule => as parameters
+%
+% Scalar rule => as variables
+%       
+% Rate rule => as states
+%
+for k = 1:length(SBMLmodel.compartment),
+    compartmentName = SBMLmodel.compartment(k).id;
+    compartmentValue = SBMLmodel.compartment(k).size;
+    compartmentNotes = convert2IQMNotes(SBMLmodel.compartment(k).notes,1);
+    % Check the number of rules the compartment is in and get the index
+    % of the last rule the compartment is used in together with its type
+    % ('rate' or 'scalar') and the right hand side expression 'formula'
+    [numberRulesCompartment,lastRuleIndex,lastRuleType,lastRuleFormula,errorMsg] = getRules(compartmentName,SBMLmodel,errorMsg);
+    if numberRulesCompartment > 1,
+        % Compartment defined by more than one rule => error
+        errorMsg = sprintf('%s\nCompartment ''%s'' defined by more than one rule\n',errorMsg,compartmentName);
+    end
+    if numberRulesCompartment == 1 && SBMLmodel.compartment(k).constant,
+        % compartment defined as constant, but rule defined for it
+        errorMsg = sprintf('%s\nCompartment ''%s'' defined as having constant size but rule exists for it.\n',errorMsg,compartmentName);
+    end
+    if numberRulesCompartment == 0 || SBMLmodel.compartment(k).constant,
+        % check compartment size and return an error in case it is "NaN"
+        if isnan(compartmentValue),
+%            errorMsg = sprintf('%s\nNo size for compartment ''%s'' given\n',errorMsg,compartmentName);
+             compartmentValue = 1;   
+        end
+        % Include compartment as parameter
+        IQMstructure.parameters(numberParameters).name = compartmentName;
+        % Check if a value is set for the parameter
+        if isempty(compartmentValue),
+%             errorMsg = sprintf('%s\nNo value defined defined for compartment ''%s''\n',errorMsg,compartmentName);
+            compartmentValue = 1;
+        end
+        % Include value in IQMstructure
+        IQMstructure.parameters(numberParameters).value = compartmentValue;
+        % Set note that type of the parameter is 'compartment size'
+        IQMstructure.parameters(numberParameters).notes = compartmentNotes;
+        % initialize type, compartment, and unittype fields
+        IQMstructure.parameters(numberParameters).type = 'isCompartment';
+        IQMstructure.parameters(numberParameters).compartment = SBMLmodel.compartment(k).outside;
+        IQMstructure.parameters(numberParameters).unittype = '';
+        % Increment
+        numberParameters = numberParameters+1;
+    elseif numberRulesCompartment == 1,
+        % One rule has been detected for this compartment
+        if strcmp(lastRuleType,'rate'),
+            % check compartment size and return an error in case it is "NaN"
+            if isnan(compartmentValue),
+%                 errorMsg = sprintf('%s\nNo size for compartment ''%s'' given\n',errorMsg,compartmentName);
+                compartmentValue = 1;
+            end
+            % Compartment added as a state, since rule of type 'rate'
+            IQMstructure.states(numberStates).name = compartmentName;
+            % check if an initial amount is set for the compartment
+            if isempty(compartmentValue),
+%                 errorMsg = sprintf('%s\nNo value defined for compartment ''%s''\n',errorMsg,compartmentName);
+                compartmentValue = 1;
+            end
+            % Include value as initial value in IQMstructure
+            IQMstructure.states(numberStates).initialCondition = compartmentValue;
+            % Include the RHS formula as the ODE for this compartment state
+            IQMstructure.states(numberStates).ODE = lastRuleFormula;
+            % Set note that type of the state is 'compartment size'
+            IQMstructure.states(numberStates).notes = compartmentNotes;
+            % initialize type, compartment, and unittype fields
+            IQMstructure.states(numberStates).type = 'isCompartment';
+            IQMstructure.states(numberStates).compartment = SBMLmodel.compartment(k).outside;
+            IQMstructure.states(numberStates).unittype = '';
+            % Increment
+            numberStates = numberStates+1;
+            % compartment_rate variable right hand side
+            compartmentDotRHS = lastRuleFormula;
+        else
+            % Compartment added as a variable, since rule of type 'scalar'
+            % Determine the index where to include the variable (based
+            % on the ordering of the scalar rules)
+            indexVariable = find(orderScalarRules==lastRuleIndex);
+            IQMstructure.variables(indexVariable).name = compartmentName;
+            IQMstructure.variables(indexVariable).formula = lastRuleFormula;
+            IQMstructure.variables(indexVariable).notes = compartmentNotes;
+            % initialize type, compartment, and unittype fields
+            IQMstructure.variables(indexVariable).type = 'isCompartment';
+            IQMstructure.variables(indexVariable).compartment = SBMLmodel.compartment(k).outside;
+            IQMstructure.variables(indexVariable).unittype = '';
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% REACTIONS (INCLUDE IN STRUCTURE)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Read in reaction information into the model structure. Replace colliding 
+% parameter names with their prefixed versions (reaction name). Reactions 
+% are included into the model structure in the 'reactions' field. This leads 
+% to shorter ODE definitions for the specie states, which then contain the 
+% reaction names with the correct stoichiometries. The 'reactions' field
+% contains three fields: 'name', 'formula', 'notes'
+%
+% We differentiate the case where:
+%   - single compartment model with constant compartment size = 1
+%     (nothing is done additionally)
+%   - multi compartment model or single compartment model with compartment 
+%     size different from one. In this case all species names in the
+%     reactions are exchanged agains speciesname/speciesCompartmentSize
+%
+% Cycle through all reactions
+for k1 = 1:length(SBMLmodel.reaction),
+    reactionName = SBMLmodel.reaction(k1).id;
+    kineticLaw = SBMLmodel.reaction(k1).kineticLaw;
+    % check if a kineticLaw is given
+    if isempty(kineticLaw),
+        errorMsg = sprintf('%s\nNo kinetic law is given for reaction ''%s''\n',errorMsg,reactionName);
+    elseif isempty(kineticLaw.formula) || isempty(kineticLaw.math),
+        errorMsg = sprintf('%s\nNo kinetic formula law given for reaction ''%s''\n',errorMsg,reactionName);
+    end
+    % Process the kineticLaw formula by replacing the local parameter names
+    % by reactionname_parameternames and replace the mathml expressions
+    if ~isempty(kineticLaw),
+        if length(kineticLaw.formula) >= length(kineticLaw.math),
+            formula = kineticLaw.formula;
+        else
+            formula = kineticLaw.math;
+        end
+        if ~isempty(kineticLaw.parameter),
+            % SBML 2 can have formula in formula or math. Check which string is
+            % longer and use this one (quick and dirty fix - since it has been
+            % observer that TranslateSBML can return strange stuff in the math
+            % field sometimes)
+            for k2 = 1:length(kineticLaw.parameter),
+                parameterName = kineticLaw.parameter(k2).id;
+                newParameterName = char([double(reactionName) double('_') double(parameterName)]); % fastest strcat
+                formula = exchangeStringInString(formula,parameterName,newParameterName);
+            end
+        end
+    else
+        formula = '';
+    end
+    % replace MathML expressions in formula against MATLAB expressions
+    [formula] = replaceMathMLexpressions(formula);
+    % Include reaction information in the structure
+    IQMstructure.reactions(k1).name = reactionName;
+    IQMstructure.reactions(k1).formula = formula;
+    IQMstructure.reactions(k1).notes = convert2IQMNotes(SBMLmodel.reaction(k1).notes,1);
+    IQMstructure.reactions(k1).reversible = SBMLmodel.reaction(k1).reversible;    
+    if (SBMLmodel.reaction(k1).isSetFast == 1) && (SBMLmodel.reaction(k1).fast == 1),
+        IQMstructure.reactions(k1).fast = 1;    
+    else
+        IQMstructure.reactions(k1).fast = 0;
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS REACTION ODES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Add the reaction variable names with correct stoichiometries to the 'ODE' field
+% for the correct species. The 'correct' species are only non-boundary and 
+% non-constant species for which no rules exist. These are listed in
+% the 'speciesODElist'
+%
+for k1 = 1:length(speciesODElist),
+    % get name of species and the index of the corresponding state
+    speciesName = speciesODElist(k1).name;
+    stateIndex = speciesODElist(k1).stateIndex;
+    % cycle through all the reactions and look in which reactions the
+    % species is changed
+    for k2 = 1:length(IQMstructure.reactions),
+        % get reaction name for inclusion in ODEstring
+        reactionName = IQMstructure.reactions(k2).name;
+        % cycle through the reactants of the current reaction
+        % (ordering of reactions in IQMstructure and SBMLmodel are equal)
+        for k3 = 1:length(SBMLmodel.reaction(k2).reactant),
+            % Handle missing stoichiomety definition in L2V>1 - then set to 1
+            if isnan(SBMLmodel.reaction(k2).reactant(k3).stoichiometry),
+                SBMLmodel.reaction(k2).reactant(k3).stoichiometry = 1;
+            end
+            % Handle missing denominator definition in L2V>1 - then set to 1
+            if ~isfield(SBMLmodel.reaction(k2).reactant(k3),'denominator'),
+                SBMLmodel.reaction(k2).reactant(k3).denominator = 1;
+            else
+                if isempty(SBMLmodel.reaction(k2).reactant(k3).denominator),
+                    SBMLmodel.reaction(k2).reactant(k3).denominator = 1;
+                end
+            end
+            
+            reactantName = SBMLmodel.reaction(k2).reactant(k3).species;
+            if ~isempty(SBMLmodel.reaction(k2).reactant(k3).stoichiometryMath),
+                reactantStoichiometry = SBMLmodel.reaction(k2).reactant(k3).stoichiometryMath; 
+                if isstruct(reactantStoichiometry),
+                    reactantStoichiometry = reactantStoichiometry.math;
+                end                
+                isunitystoich = 0;
+            else
+                reactantStoichiometry_num = abs(double(SBMLmodel.reaction(k2).reactant(k3).stoichiometry) / double(SBMLmodel.reaction(k2).reactant(k3).denominator));
+                isunitystoich = reactantStoichiometry_num == 1;
+                reactantStoichiometry = num2str(reactantStoichiometry_num);
+            end
+            % If species name and reactant name are equal then add reaction
+            % to species ODE
+            if strcmp(reactantName,speciesName),
+                % construct the string to add to the ODE of the current reactant
+                if isunitystoich == 0,
+                    ODEstringAdd = char([double('-') double(reactantStoichiometry) double('*') double(reactionName)]); % fastest strcat
+                else
+                    ODEstringAdd = char([double('-') double(reactionName)]); % fastest strcat
+                end
+                % add the ODEstringAdd to the 'ODE' field of this species
+                IQMstructure.states(stateIndex).ODE = char([double(IQMstructure.states(stateIndex).ODE) double(ODEstringAdd)]); % fastest strcat
+                break;
+            end
+        end
+        % cycle through the products of the current reaction
+        % (ordering of reactions in IQMstructure and SBMLmodel are equal)
+        for k3 = 1:length(SBMLmodel.reaction(k2).product),
+            % Handle missing stoichiomety definition in L2V>1 - then set to 1
+            if isnan(SBMLmodel.reaction(k2).product(k3).stoichiometry),
+                SBMLmodel.reaction(k2).product(k3).stoichiometry = 1;
+            end
+            % Handle missing denominator definition in L2V>1 - then set to 1
+            if ~isfield(SBMLmodel.reaction(k2).product(k3),'denominator'),
+                SBMLmodel.reaction(k2).product(k3).denominator = 1;
+            else
+                if isempty(SBMLmodel.reaction(k2).product(k3).denominator),
+                    SBMLmodel.reaction(k2).product(k3).denominator = 1;
+                end
+            end
+            
+            productName = SBMLmodel.reaction(k2).product(k3).species;
+            if ~isempty(SBMLmodel.reaction(k2).product(k3).stoichiometryMath),
+                productStoichiometry = SBMLmodel.reaction(k2).product(k3).stoichiometryMath; 
+                if isstruct(productStoichiometry),
+                    productStoichiometry = productStoichiometry.math;
+                end
+                isunitystoich = 0;
+            else
+                productStoichiometry_num = abs(double(SBMLmodel.reaction(k2).product(k3).stoichiometry) / double(SBMLmodel.reaction(k2).product(k3).denominator));
+                isunitystoich = productStoichiometry_num == 1;
+                productStoichiometry = num2str(productStoichiometry_num);
+            end
+            % If species name and product name are equal then add reaction
+            % to species ODE
+            if strcmp(productName,speciesName),
+                % construct the string to add to the ODE of the current product
+                if isunitystoich == 0,
+                    ODEstringAdd = char([double('+') double(productStoichiometry) double('*') double(reactionName)]); % fastest strcat
+                else
+                    ODEstringAdd = char([double('+') double(reactionName)]); % fastest strcat
+                end
+                % add the ODEstringAdd to the 'ODE' field of this species
+                IQMstructure.states(stateIndex).ODE = char([double(IQMstructure.states(stateIndex).ODE) double(ODEstringAdd)]); % fastest strcat
+                break;
+            end
+        end
+    end
+end
+% Now all ODEs should be defined - check if everything is correct!
+% Finally cycle through all the states and check if all ODEs have been defined
+for k = 1:length(IQMstructure.states),
+    stateName = IQMstructure.states(k).name;
+    stateODE = IQMstructure.states(k).ODE;
+    if isempty(stateODE),
+%         % Issue a warning only and set ODE to 0
+%         disp(sprintf('No ODE defined for state ''%s''',stateName));
+        IQMstructure.states(k).ODE = '0';
+    end
+end
+% After initial construction of the ODEs their units need to be changed (or
+% not) since the rate laws are assumed to have amount/time units.
+%
+% - species defined as 'amount' => no change necessary!
+% - species defined as 'concentration' => divide the ode expression by the
+%   compartment size the species is in.
+%
+% We differentiate the case where:
+%   - single compartment model with constant compartment size = 1
+%     (nothing is done additionally)
+%   - multi compartment model or single compartment model with compartment 
+%     size different from one. In this case the conversion is done for the
+%     concentration species.
+%
+compartmentddtdonelist = {};
+for k1 = 1:length(speciesODElist),
+    % get name of species and the index of the corresponding state
+    speciesName = speciesODElist(k1).name;
+    speciesUnits = speciesODElist(k1).units;
+    stateIndex = speciesODElist(k1).stateIndex;
+    % only do the conversion if species in concentration units!
+    if strcmp(speciesUnits,'concentration'),
+        % check if the model has only one compartment with volume 1 and
+        % constant volume => if yes then leave ODE as it is.
+        convertODE = 1;
+%         if length(SBMLmodel.compartment) == 1,
+%             % only one compartment
+%             if SBMLmodel.compartment(1).size == 1,
+%                 % size of compartment is 1
+%                 for k = 1:length(IQMstructure.parameters),
+%                     % check if compartment size is constant (then it is defined as
+%                     % a parameter)
+%                     if strcmp(SBMLmodel.compartment(1).id,IQMstructure.parameters(k).name),
+%                         % compartment defined as a parameter and thus no species
+%                         % names need to be exchanged
+%                         convertODE = 0;
+%                         % return directly to the main function
+%                     end
+%                 end
+%             end
+%         end
+        if convertODE,
+            % convert the ODE expression
+            % get compartment name for species
+            compartmentName = getCompartmentNameSpecies(speciesName,SBMLmodel);
+            ODEstring = IQMstructure.states(stateIndex).ODE;
+            if ~strcmp(ODEstring,'0')
+                % construct new ODE string
+                newODEstring = char([double('(') double(ODEstring) double(')/') double(compartmentName)]); % fastest strcat 
+                % include the new ODE string in structure
+                IQMstructure.states(stateIndex).ODE = newODEstring;
+            end
+            
+            
+% HANDLE TIME VARYING COMPARTMENT SIZES
+            [changingFlag,ddtCompartment] = getCompartmentInfoChanging(compartmentName,IQMstructure,compartmentddtdonelist);
+            if changingFlag,
+                % append the second derivative term
+                IQMstructure.states(stateIndex).ODE = sprintf('%s - %s*ddt_%s/%s',IQMstructure.states(stateIndex).ODE,speciesName,compartmentName,compartmentName);
+                
+                % add the time derivative of the compartment to variables
+                % (if not done already)
+                if isempty(strmatchIQM(compartmentName,compartmentddtdonelist,'exact')),
+                    IQMstructure.variables(end+1).name = ['ddt_' compartmentName];
+                    IQMstructure.variables(end).formula = ddtCompartment;
+                    IQMstructure.variables(end).type = 'isParameter';
+                    IQMstructure.variables(end).compartment = '';
+                    IQMstructure.variables(end).unittype = '';
+                    IQMstructure.variables(end).notes = 'Time derivative of compartment';
+                    compartmentddtdonelist{end+1} = compartmentName;
+                end
+            end
+
+            
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EVENTS (INCLUDE IN STRUCTURE)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for k1 = 1:length(SBMLmodel.event),
+    % get the name of the event
+    if ~isempty(SBMLmodel.event(k1).id),
+        eventName = SBMLmodel.event(k1).id;
+    else 
+        eventName = sprintf('Event_%d',k1);
+    end
+    % check event trigger is present
+    if isempty(SBMLmodel.event(k1).trigger),
+        errorMsg = sprintf('%s\nNo trigger condition defined for event ''%s''.',errorMsg,eventName);
+    end
+    % get delay and check if it is not given or given
+    delay = SBMLmodel.event(k1).delay;
+    if isstruct(delay) && ~isempty(delay),
+        delay = delay.math;
+    end
+    if isempty(delay),
+        delay = '0';
+    end
+    delay = replaceMathMLexpressions(delay);
+    % fill structure with basic event information
+    IQMstructure.events(k1).name = eventName;
+    % check the trigger expression and handle delay if present
+    trigger = SBMLmodel.event(k1).trigger;
+    if isstruct(trigger),
+        % Happens in L2 V3 or definitly 4
+        trigger = trigger.math;
+    end
+        
+
+    trigger = removeWhiteSpace(trigger);
+    trigger = replaceMathMLexpressions(trigger);
+    if ~strcmp(delay,'0'),
+        trigger = ['delayIQM(' trigger ',' delay ')'];
+    end
+    IQMstructure.events(k1).trigger = trigger;
+    IQMstructure.events(k1).notes = convert2IQMNotes(SBMLmodel.event(k1).notes,1);
+    % fill in data for event assignments
+    for k2 = 1:length(SBMLmodel.event(k1).eventAssignment),
+        variableName = SBMLmodel.event(k1).eventAssignment(k2).variable;
+        variableValue = SBMLmodel.event(k1).eventAssignment(k2).math;
+        % check that the name is the name of a state in the model
+        nameFound = 0;
+        for k3 = 1:length(IQMstructure.states),
+            if strcmp(variableName,IQMstructure.states(k3).name),
+                nameFound = 1;
+                break;
+            end
+        end
+        if nameFound == 0,
+            % events on parameters are now allowed
+            %errorMsg = sprintf('%s\nThe variable affected by event ''%s'' is not a state.',errorMsg,eventName);
+        end
+        % check that the variable value is set
+        if isempty(variableValue),
+            errorMsg = sprintf('%s\nNo math element given for event ''%s''.',errorMsg,eventName);
+        end
+        % update IQMstructure
+        IQMstructure.events(k1).assignment(k2).variable = variableName;
+        assignformula = replaceMathMLexpressions(variableValue);
+        % if delay not 0 then add delay information
+        if ~strcmp(delay,'0'),
+            assignformula = ['delayIQM(' assignformula ',' delay ')'];
+        end
+        IQMstructure.events(k1).assignment(k2).formula = assignformula;
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EXCHANGE NaN VALUES AGAINST 0
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for k=1:length(IQMstructure.states),
+    if isnan(IQMstructure.states(k).initialCondition),
+        IQMstructure.states(k).initialCondition = 0;
+    end
+end
+for k=1:length(IQMstructure.parameters),
+    if isnan(IQMstructure.parameters(k).value),
+        IQMstructure.parameters(k).value = 0;
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% IMPORT ALGEBRAIC RULES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% prepare the import
+% 1)need to find all species, compartments, and (global) parameters that are
+% NOT constant. These are the candidates for the determination by an
+% algebraic rule (in this order of priority)
+nonConstantSpecies = {};
+nonConstantParameters = {};
+nonConstantCompartments = {};
+for k=1:length(SBMLmodel.species),
+    if SBMLmodel.species(k).constant == 0,
+        nonConstantSpecies{end+1} = SBMLmodel.species(k).id;
+    end
+end
+for k=1:length(SBMLmodel.parameter),
+    if SBMLmodel.parameter(k).constant == 0,
+        nonConstantParameters{end+1} = SBMLmodel.parameter(k).id;
+    end
+end
+for k=1:length(SBMLmodel.compartment),
+    if SBMLmodel.compartment(k).constant == 0,
+        nonConstantCompartments{end+1} = SBMLmodel.compartment(k).id;
+    end
+end
+% 2) now we need to make a list of all states determined by ODEs and
+% variables determined by formulas. 
+allStates = {};
+for k=1:length(IQMstructure.states),
+    if IQMstructure.states(k).ODE ~= '0',
+        % Only non constant states (would also require the check of event 
+        % assignments ... but in my opinion, SBML should simply define the
+        % variable which is affected by an algebraic rule ... so much
+        % cleaner!
+        allStates{end+1} = IQMstructure.states(k).name;
+    end
+end
+allVariables = {};
+for k=1:length(IQMstructure.variables),
+    if ~isnan(str2double(IQMstructure.variables(k).formula)),
+        % If variable has not a numeric assignment ... 
+        allVariables{end+1} = IQMstructure.variables(k).name;
+    end
+end
+% 3) The names of the states and variables need to be deleted from the
+% nonConstantSpecies, nonConstantCompartments, and nonConstantParameters,
+% because only the remaining ones can be determined by algebraic rules
+possibleSpecies = setdiff(nonConstantSpecies,allStates);
+possibleSpecies = setdiff(possibleSpecies,allVariables);
+possibleParameters = setdiff(nonConstantParameters,allStates);
+possibleParameters = setdiff(possibleParameters,allVariables);
+possibleCompartments = setdiff(nonConstantCompartments,allStates);
+possibleCompartments = setdiff(possibleCompartments,allVariables);
+% 4) now we check if at least as many possibilities as there are ARs
+% (otherwise certainly overdetermined).
+ARindices = strmatchIQM('SBML_ALGEBRAIC_RULE',{SBMLmodel.rule.typecode},'exact');
+nrARs = length(ARindices);
+if length(possibleSpecies) + length(possibleParameters) + length(possibleCompartments) < nrARs,
+    error('The model is certainly overdetermined. To many algebraic rules!');
+end
+% 5) Now check which of the possible elements appear in the ARs. If at
+% least a number of nrARs do appear there its fine ... if not put out a
+% warning and select whatever.
+ARs = SBMLmodel.rule(ARindices);
+ReallyPossibleSpecies = {};
+ReallyPossibleParameters = {};
+ReallyPossibleCompartments = {};
+for k=1:nrARs,
+    species = regexp(ARs(k).formula,possibleSpecies,'match');
+    for k2=1:length(species),
+        if ~isempty(species{k2}),
+            ReallyPossibleSpecies{end+1} = species{k2}{1};
+        end
+    end
+    parameters = regexp(ARs(k).formula,possibleParameters,'match');
+    for k2=1:length(parameters),
+        if ~isempty(parameters{k2}),
+            ReallyPossibleParameters{end+1} = parameters{k2}{1};
+        end
+    end
+    compartments = regexp(ARs(k).formula,possibleCompartments,'match');
+    for k2=1:length(compartments),
+        if ~isempty(compartments{k2}),
+            ReallyPossibleCompartments{end+1} = compartments{k2}{1};
+        end
+    end
+end
+% make unique (it might not be)
+ReallyPossibleSpecies = unique(ReallyPossibleSpecies);
+ReallyPossibleParameters = unique(ReallyPossibleParameters);
+ReallyPossibleCompartments = unique(ReallyPossibleCompartments);
+nrPossible = length(ReallyPossibleSpecies) + length(ReallyPossibleParameters) + length(ReallyPossibleCompartments);
+if nrPossible < nrARs,
+    error('The model is overdetermined or at least it is unclear which variables are to be determined using the algebraic rules.');
+end
+% get the indices in the SBML model for the really possible ones
+indexspecies = [];
+indexparameters = [];
+indexcompartments = [];
+for k=1:length(ReallyPossibleSpecies),
+    indexspecies(end+1) = strmatchIQM(ReallyPossibleSpecies{k},{SBMLmodel.species.id},'exact');
+end
+for k=1:length(ReallyPossibleParameters),
+    indexparameters(end+1) = strmatchIQM(ReallyPossibleParameters{k},{SBMLmodel.parameter.id},'exact');
+end
+for k=1:length(ReallyPossibleCompartments),
+    indexcompartments(end+1) = strmatchIQM(ReallyPossibleCompartments{k},{SBMLmodel.compartment.id},'exact');
+end
+% 6) Add the algebraic rules and delete the corresponding parameters from
+% the IQMmodel structure
+for k=1:length(ARindices),
+    rule = SBMLmodel.rule(ARindices);
+    % determine the name (it needs to be one of the elements in
+    % indexspecies, indexparameters, or indexcompartments
+    if ~isempty(indexspecies),      
+        index = indexspecies(1);
+        name = SBMLmodel.species(index).id;
+        type = 'isSpecie';
+        compartment = SBMLmodel.species(index).compartment;
+        if SBMLmodel.species(index).isSetInitialAmount,
+            if SBMLmodel.species(index).hasOnlySubstanceUnits,
+                unittype = 'amount';        
+            else
+                unittype = 'concentration';
+                amount2concentration(end+1).species = name;
+                amount2concentration(end).compartment = compartment;                
+            end
+        else
+            unittype = 'concentration';
+        end
+        % remove the used species
+        indexspecies(1) = [];             
+    elseif ~isempty(indexparameters),
+        index = indexparameters(1);
+        name = SBMLmodel.parameter(index).id;
+        type = 'isParameter';
+        compartment = '';
+        unittype = '';
+        % remove the used parameter
+        indexparameters(1) = [];      
+    elseif ~isempty(indexcompartments),
+        index = indexcompartments(1);
+        name = SBMLmodel.compartment(index).id;
+        type = 'isCompartment';
+        compartment = SBMLmodel.compartment(index).outside;
+        unittype = '';        
+        % remove the used compartment
+        indexcompartments(1) = [];      
+    else
+        error('Should not get to this :)');
+    end
+    % get initial condition (can be state, parameter, or variable .... YEEEESSS!)
+    % and delete the corresponding component from the model (now determined
+    % by algebraic rule).
+    allStates = {IQMstructure.states.name};    
+    allParams = {IQMstructure.parameters.name};
+    allVars = {IQMstructure.variables.name};
+    indexstate = strmatchIQM(name,allStates,'exact');
+    indexparam = strmatchIQM(name,allParams,'exact');
+    indexvar = strmatchIQM(name,allVars,'exact');
+    if ~isempty(indexstate),
+        initialCondition = IQMstructure.states(indexstate).initialCondition;    
+        IQMstructure.states(indexstate) = [];
+    elseif ~isempty(indexparam),
+        initialCondition = IQMstructure.parameters(indexparam).value;
+        IQMstructure.parameters(indexparam) = [];
+    elseif ~isempty(indexvar),
+        initialCondition = str2double(IQMstructure.variables(indexvar).formula);    
+        IQMstructure.variables(indexvar) = [];
+    else
+        error('Should not get to this :) ... 2');
+    end
+    % add algebraic rule
+    IQMstructure.algebraic(k).name = name;
+    IQMstructure.algebraic(k).formula = rule(k).formula;
+    IQMstructure.algebraic(k).initialCondition = initialCondition;
+    IQMstructure.algebraic(k).type = type;
+    IQMstructure.algebraic(k).compartment = compartment;
+    IQMstructure.algebraic(k).unittype = unittype;
+    IQMstructure.algebraic(k).notes = rule(k).notes;
+end
+% 7) Its DONE!
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK ALL COMPONENTNAMES AND REMOVE TRAILING "_"
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% get names to exchange
+oldnames = {};
+newnames = {};
+% states
+for k=1:length(IQMstructure.states),
+    [oldnames,newnames,changed,IQMstructure.states(k).name] = removeUnderscores(oldnames,newnames,IQMstructure.states(k).name);    
+end
+% algebraic
+for k=1:length(IQMstructure.algebraic),
+    [oldnames,newnames,changed,IQMstructure.algebraic(k).name] = removeUnderscores(oldnames,newnames,IQMstructure.algebraic(k).name);    
+end
+% parameters
+for k=1:length(IQMstructure.parameters),
+    [oldnames,newnames,changed,IQMstructure.parameters(k).name] = removeUnderscores(oldnames,newnames,IQMstructure.parameters(k).name);
+end
+% variables
+for k=1:length(IQMstructure.variables),
+    [oldnames,newnames,changed,IQMstructure.variables(k).name] = removeUnderscores(oldnames,newnames,IQMstructure.variables(k).name);
+end
+% reactions
+for k=1:length(IQMstructure.reactions),
+    [oldnames,newnames,changed,IQMstructure.reactions(k).name] = removeUnderscores(oldnames,newnames,IQMstructure.reactions(k).name);   
+end
+% functions
+for k=1:length(IQMstructure.functions),
+    [oldnames,newnames,changed,IQMstructure.functions(k).name] = removeUnderscores(oldnames,newnames,IQMstructure.functions(k).name);   
+end
+% ok, if names changed then handle formulas
+if ~isempty(oldnames),
+    % states
+    for k=1:length(IQMstructure.states),
+        IQMstructure.states(k).ODE = regexprep(IQMstructure.states(k).ODE,oldnames,newnames);
+        IQMstructure.states(k).compartment = regexprep(IQMstructure.states(k).compartment,oldnames,newnames);
+    end
+    % algebraic
+    for k=1:length(IQMstructure.algebraic),
+        IQMstructure.algebraic(k).formula = regexprep(IQMstructure.algebraic(k).formula,oldnames,newnames);    
+        IQMstructure.algebraic(k).compartment = regexprep(IQMstructure.algebraic(k).compartment,oldnames,newnames);
+    end
+    % parameters
+    for k=1:length(IQMstructure.parameters),
+        IQMstructure.parameters(k).compartment = regexprep(IQMstructure.parameters(k).compartment,oldnames,newnames);
+    end    
+    % variables
+    for k=1:length(IQMstructure.variables),
+        IQMstructure.variables(k).formula = regexprep(IQMstructure.variables(k).formula,oldnames,newnames);
+        IQMstructure.variables(k).compartment = regexprep(IQMstructure.variables(k).compartment,oldnames,newnames);
+    end
+    % reactions
+    for k=1:length(IQMstructure.reactions),
+        IQMstructure.reactions(k).formula = regexprep(IQMstructure.reactions(k).formula,oldnames,newnames);
+    end
+    % functions
+    for k=1:length(IQMstructure.functions),
+        IQMstructure.functions(k).formula = regexprep(IQMstructure.functions(k).formula,oldnames,newnames);
+    end
+    % events
+    for k=1:length(IQMstructure.events),
+        IQMstructure.events(k).trigger = regexprep(IQMstructure.events(k).trigger,oldnames,newnames);
+        for k2=1:length(IQMstructure.events(k).assignment),
+            IQMstructure.events(k).assignment(k2).variable = regexprep(IQMstructure.events(k).assignment(k2).variable,oldnames,newnames);
+            IQMstructure.events(k).assignment(k2).formula = regexprep(IQMstructure.events(k).assignment(k2).formula,oldnames,newnames);
+        end
+    end
+end
+
+%% Here handle initial assignments
+% Idea: 
+% - get the name of the element that has an initial assignment.
+% - for states implement as initial condition
+% - for variables as new formula (valid until time=0?)
+% - for parameters: make variables out of parameters and handle as variables
+
+if ~isfield(SBMLmodel,'initialAssignment'),
+    % Add field if not present
+    SBMLmodel.initialAssignment = [];
+end
+
+% Cycle through all initial assignments
+for k=1:length(SBMLmodel.initialAssignment),
+    symbol = SBMLmodel.initialAssignment(k).symbol;
+    math = replaceMathMLexpressions(SBMLmodel.initialAssignment(k).math);
+    % Adjust math if species and in amount 
+    ix = strmatchIQM(symbol,speciesAmount_SAVEnames,'exact');
+    if ~isempty(ix),
+        math = ['(' math ')*' speciesAmount_SAVEcompartments{ix}];
+    end
+    % Handle states
+    ix = strmatchIQM(symbol,{IQMstructure.states.name},'exact');
+    if ~isempty(ix),
+        IQMstructure.states(ix).initialCondition = math;
+    end
+    % Handle variables
+    ix = strmatchIQM(symbol,{IQMstructure.variables.name},'exact');
+    if ~isempty(ix),
+        IQMstructure.variables(ix).formula = math;
+    end    
+    % Handle parameters
+    ix = strmatchIQM(symbol,{IQMstructure.parameters.name},'exact');
+    if ~isempty(ix),
+        paramsave = IQMstructure.parameters(ix);
+        % Remove parameter from model
+        IQMstructure.parameters(ix) = [];
+        % Create variable
+        variablenew = [];
+        variablenew.name        = paramsave.name;
+        variablenew.formula     = math;
+        variablenew.type        = paramsave.type;
+        variablenew.compartment = paramsave.compartment;
+        variablenew.unittype    = paramsave.unittype;
+        variablenew.notes       = paramsave.notes;
+        % Add variable
+        IQMstructure.variables(end+1) = variablenew;
+    end    
+    % Handle reactions
+    ix = strmatchIQM(symbol,{IQMstructure.reactions.name},'exact');
+    if ~isempty(ix),
+        error('Initial Assignments on Reactions do not make sense.');
+    end    
+end
+
+%% Handle species that are in amount but in expressions in concentration
+for k0=1:length(speciesAmount_SAVEnames),
+    name = speciesAmount_SAVEnames{k0};
+    comp = speciesAmount_SAVEcompartments{k0};
+    replacename = ['(' name '/' comp ')'];
+    % In ODEs
+    for k=1:length(IQMstructure.states),
+        IQMstructure.states(k).ODE = regexprep(IQMstructure.states(k).ODE,['\<' name '\>'],replacename);
+    end
+    % In initial conditions of ODEs
+    for k=1:length(IQMstructure.states),
+        if ~isnumeric(IQMstructure.states(k).initialCondition),
+            IQMstructure.states(k).initialCondition = regexprep(IQMstructure.states(k).initialCondition,['\<' name '\>'],replacename);
+        end
+    end
+    % In variables
+    for k=1:length(IQMstructure.variables),
+        IQMstructure.variables(k).formula = regexprep(IQMstructure.variables(k).formula,['\<' name '\>'],replacename);
+    end
+    % In reactions
+    for k=1:length(IQMstructure.reactions),
+        IQMstructure.reactions(k).formula = regexprep(IQMstructure.reactions(k).formula,['\<' name '\>'],replacename);
+    end
+    % In event triggers
+    for k=1:length(IQMstructure.events),
+        IQMstructure.events(k).trigger = regexprep(IQMstructure.events(k).trigger,['\<' name '\>'],replacename);
+        % Adjust event assignments
+        for k2=1:length(IQMstructure.events(k).assignment),
+            if strcmp(IQMstructure.events(k).assignment(k2).variable,name),
+                IQMstructure.events(k).assignment(k2).formula = ['(' IQMstructure.events(k).assignment(k2).formula ')*' comp];
+            end
+        end
+    end    
+end
+    
+%% Handle parameters that are changed by an event ... call these parameters differently and create a variable
+% with the parameter name ... important to get the test suite to work for few models
+parChangeNames = {};
+for k=1:length(IQMstructure.events),
+    for k2=1:length(IQMstructure.events(k).assignment),
+        name = IQMstructure.events(k).assignment(k2).variable;
+        % check if parameter
+        ix = strmatchIQM(name,{IQMstructure.parameters.name},'exact');
+        if ~isempty(ix),
+            parChangeNames{end+1} = name;
+        end
+    end
+end
+parChangeNames = unique(parChangeNames);
+
+for k=1:length(parChangeNames),
+    name                    = parChangeNames{k};
+    % Get param info and change its name to "name"_par
+    ix                      = strmatchIQM(name,{IQMstructure.parameters.name},'exact');
+    parstruct               = IQMstructure.parameters(ix);
+    IQMstructure.parameters(ix).name = [name '_par'];
+    % Create a variabe "name" = "name"_par
+    variablenew             = [];
+    variablenew.name        = name;
+    variablenew.formula     = [name '_par'];
+    variablenew.type        = parstruct.type;
+    variablenew.compartment = parstruct.compartment;
+    variablenew.unittype    = parstruct.unittype;
+    variablenew.notes       = parstruct.notes;
+    % Add variable as first into the model structure
+    allVariables            = IQMstructure.variables;    
+    if isempty(allVariables),
+        variableall         = variablenew;
+    else
+        % Create a dummy first and shift the present ones to start at index 2
+        variableall         = allVariables([1 1:length(allVariables)]);
+        % Add the new variable
+        variableall(1)      = variablenew;
+    end
+    IQMstructure.variables  = variableall;
+    % Change event assignment par names
+    for k2=1:length(IQMstructure.events),
+        for k3=1:length(IQMstructure.events(k2).assignment),
+            IQMstructure.events(k2).assignment(k3).variable = regexprep(IQMstructure.events(k2).assignment(k3).variable, ['\<' name '\>'],[name '_par']);
+        end
+    end
+end
+
+%% return from main function
+return
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE TIME VARYING COMPARTMENTS ... get changing flag and the
+% time-derivative of the compartment size.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [changingFlag,ddtCompartment] = getCompartmentInfoChanging(compartmentName,IQMstructure,compartmentddtdonelist)
+changingFlag = 0; 
+ddtCompartment = '';
+% go through states and variables to check if the compartment name appears
+% there ... then just do it
+indexState = strmatchIQM(compartmentName,{IQMstructure.states.name},'exact');
+indexVariable = strmatchIQM(compartmentName,{IQMstructure.variables.name},'exact');
+indexAlgebraic = strmatchIQM(compartmentName,{IQMstructure.algebraic.name},'exact');
+if ~isempty(indexState),
+    changingFlag = 1; 
+    ddtCompartment = IQMstructure.states(indexState).ODE;
+elseif ~isempty(indexVariable),
+    changingFlag = 1;
+    Compartment = IQMstructure.variables(indexVariable).formula;
+    % ddtCompartment needs only to be determined once for each compartment.
+    % So not per species in this compartment. We make it simple here (since
+    % it mainly matters when determining and adding it manually):
+    if isempty(strmatchIQM(compartmentName,compartmentddtdonelist,'exact')),
+        if isSymbolicpresentIQM(),
+            ddtCompartment = char(diff(Compartment,'time'));
+        else
+            disp('For the handling of time varying compartments the time derivative of the');
+            disp('compartment size needs to be determined. Since the symbolic toolbox is not');
+            disp('present you need to do that manually.');
+            disp(' ');
+            disp(sprintf('C(time) = %s',Compartment));
+            disp(' ');
+            ddtCompartment = input('d/dtime(C(time)) = ','s');
+        end
+    end
+elseif ~isempty(indexAlgebraic),
+    error(sprintf('Size of compartment ''%s'' defined by an algebraic rule! Cant determine\nthe analytic rate of change of the size.',compartmentName));
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HELP FUNCTION TO REMOVE __ at the start of element names
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [oldnames,newnames,changed,newname] = removeUnderscores(oldnames,newnames,name)
+changed = 0;
+newname = regexprep(name,'^([_]?)','underscore_');
+if length(name) ~= length(newname),
+    changed = 1;
+    oldnames{end+1} = sprintf('\\<%s\\>',name);
+    newnames{end+1} = newname;
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% FIND RULES FOR A CERTAIN VARIABLE NAME
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Cycle through all the rules and check if the given variable name
+% (species or parameter or compartment) appears as left hand side (LHS) in a rule
+%
+% numberRulesVariable: number of rules the name appears in as LHS
+% lastRuleIndex: the index of the rule the name was last detected
+% lastRuleType: 'scalar' or 'rate'
+% lastRuleFormula: the RHS expression for the variable
+%
+% We assume that the name of the variable can appear in the
+% 'variable' field, in the 'species' field, in the 'compartment' field,
+% or in the 'name' field of the 'rule' field. 
+% Some SBML example models had species in the 'variable' field!
+%
+function [numberRulesVariable,lastRuleIndex,lastRuleType,lastRuleFormula,errorMsg] = getRules(variableName,SBMLmodel,errorMsg)
+% Initialize return values
+numberRulesVariable = 0;
+lastRuleIndex = [];
+lastRuleType = '';
+lastRuleFormula = '';
+for k = 1:length(SBMLmodel.rule),
+    % DO NOT PROCESS ALGEBRAIC RULES HERE ... WE DO THAT AT A DIFFERENT PLACE
+    if isempty(strfind(SBMLmodel.rule(k).typecode,'ALGEBRAIC')),
+        if strcmp(variableName,SBMLmodel.rule(k).variable) || strcmp(variableName,SBMLmodel.rule(k).species) || strcmp(variableName,SBMLmodel.rule(k).name) || strcmp(variableName,SBMLmodel.rule(k).compartment),
+            % The name was found as LHS in a rule
+            numberRulesVariable = numberRulesVariable+1;
+            lastRuleIndex = k;
+            if isempty(strfind(SBMLmodel.rule(k).typecode,'RATE')),
+                % Rule is a scalar rule
+                lastRuleType = 'scalar';
+            else
+                % Rule is a rate rule
+                lastRuleType = 'rate';
+            end
+            % get the RHS expression of the rule
+            lastRuleFormula = SBMLmodel.rule(k).formula;
+        end
+    end
+end
+% replace MathML expressions against MATLAB expressions
+[lastRuleFormula] = replaceMathMLexpressions(lastRuleFormula);
+% return
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF A CERTAIN SPECIES APPEARS AS PRODUCT AND/OR REACTANT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% In the case that a non-boundary species is defined by a rule
+% we need to check if it is also present as product or reactant in any
+% reaction. In this case the SBML model is not correctly defined and
+% reactionSpeciesPresent = 1
+function [reactionSpeciesPresent] = checkReactionsForSpecies(speciesName,SBMLmodel)
+% Initialize return value
+reactionSpeciesPresent = 0;
+reactionComponents = {};
+for k = 1:length(SBMLmodel.reaction),
+    reactionComponents = {reactionComponents{:},SBMLmodel.reaction(k).reactant.species,SBMLmodel.reaction(k).product.species};
+end
+if ~isempty(strmatchIQM(speciesName,reactionComponents,'exact')),
+    reactionSpeciesPresent = 1;
+end
+return
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DELETE WHITESPACES IN STRINGS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Useful for taking away whitespaces in kineticLaw formulas, as
+% seen in some example models
+function [outputString] = removeWhiteSpace(inputString)
+outputString = strrep(inputString,' ','');
+% return
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET COMPARTMENT NAME FOR SPECIES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [compartmentName] = getCompartmentNameSpecies(species,SBMLmodel)
+compartmentName = SBMLmodel.species(strmatchIQM(species,{SBMLmodel.species.id},'exact')).compartment;
+% return
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EXCHANGE STRING IN STRING - WITH CHECK OF ALLOWED CHARACTERS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% find occurrences of stringOld in fullString and exchange it with
+% stringNew. 
+function [processedString] = exchangeStringInString(fullString,stringOld,stringNew);
+% really simple!!!
+exprString = char([double('\<') double(stringOld) double('\>')]);
+processedString = regexprep(fullString, exprString, stringNew);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EXCHANGE MATHML FUNCTION NAMES IN ALL FORMULAS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% MathML functions can have different names than MATLAB function names
+% we need to exchange them in the formula strings. The term 'MathML
+% expression' relates to what is returned by TranslateSBML!
+function [newFormula] = replaceMathMLexpressions(formula)
+% MathML expressions that need simple exchange with corresponding MATLAB
+% expressions:
+MathMLexpressions = {'\<multiply\>','\<delay\>','\<piecewise\>','\<and\>','\<or\>','\<arccos\>','\<arcsin\>','\<arctan\>','\<ceiling\>','\<ln\>',...
+    '\<pow\>','\<arccos\>','\<arccosh\>','\<arccot\>','\<arccoth\>','\<arccsc\>','\<arccsch\>',...
+    '\<arcsec\>','\<arcsech\>','\<arcsin\>','\<arcsinh\>','\<arctan\>','\<arctanh\>',...
+    '\<exponentiale','\<geq\>','\<leq\>','\<xor\>','\<multiply\>'};
+MATLABexpressions = {'multiplyIQM','delayIQM','piecewiseIQM','andIQM','orIQM','acos','asin','atan','ceil','log', ...
+    'power','acos','acosh','acot','acoth','acsc','acsch',...
+    'asec','asech','asin','asinh','atan','atanh'...
+    'exp(1)','ge','le','xorIQM','multiplyIQM'};
+% find indices
+newFormula = regexprep(formula,MathMLexpressions,MATLABexpressions);
+% replace the time_symbol with 'time' if a time_symbol is defined and not
+% 'time'.
+newFormula = exchangeTimeSymbol(newFormula);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% exchange time symbol if needed
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [expression] = exchangeTimeSymbol(expression)
+global SBMLtimesymbol
+if ~isempty(SBMLtimesymbol) && ~strcmp(SBMLtimesymbol,'time'),
+    expression = regexprep(expression,strcat('\<',SBMLtimesymbol,'\>'),'time');
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% regexprep command doing the replacement
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [formula] = exchangepowerexp(formula)
+global changeFlag
+oldformula = formula;
+formula = regexprep(['#' formula],'([\W]+)',' $1 ');
+formula = regexprep(formula,'[\s]power[\s]*\(([^,]+),([^,]+)\)','($1)^($2)');
+formula = regexprep(formula,'\s','');
+formula = formula(2:end);
+if ~strcmp(oldformula,formula),
+    changeFlag = 1;
+end
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLimport/importSBMLIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLimport/importSBMLIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..699f778104f0fe787abec31f20a634042a5f9031
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/SBMLimport/importSBMLIQM.m	
@@ -0,0 +1,50 @@
+function [IQMstructure,errorMsg] = importSBMLIQM(SBMLmodelFile,useSBMLnames)
+% importSBMLIQM 
+% imports a SBML model using the TranslateSBML function from libSBML
+% Supported SBML levels: 1  (V1,2) and 2 (V1-4)
+%
+% SBMLmodelFile: SBMLmodelfilename.xml (string)
+%
+% IQMstructure: empty if error occurred
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INITIALIZATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+errorMsg = '';
+IQMstructure = [];
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% SBML -> MATLAB
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Use the TranslateSBML function from libSBML
+try
+    SBMLmodel = TranslateSBML(SBMLmodelFile);
+catch
+    errTxt = sprintf('An error during the SBML import using the SBML Toolbox occurred.\n\nLast error message:\n\n%s',lasterr);
+    error(errTxt);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CONVERT INTO OWN IQM STRUCTURE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~strcmp(SBMLmodel.typecode,'SBML_MODEL'),
+    errorMsg = 'Model is not an SBML model';
+    return;
+end
+if SBMLmodel.SBML_level == 2 && SBMLmodel.SBML_version <= 4,
+    if useSBMLnames,
+        % Convert names to ids if requested
+        SBMLmodel = convertName2IdIQM(SBMLmodel);
+    end
+
+    % Convert level 2 V1-4
+    [IQMstructure,errorMsg] = convertSBML2IQM(SBMLmodel,SBMLmodelFile);
+else
+    % Not supported SBML level
+    error('IQM Tools only support SBML L2. Please convert your model to SBML L2 and reload.');
+end
+
+
+
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/addparameterIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/addparameterIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..15ae41e73bc5fcfe4fec93c139d361d5fa3bf0ea
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/addparameterIQM.m	
@@ -0,0 +1,60 @@
+function [output] = addparameterIQM(model,parametername,parametervalue,varargin)
+% addparameterIQM: Adds a parameter with given name and given value to the 
+% IQMmodel. New parameters are appended at the end of the list.
+%
+% USAGE:
+% ======
+% [output] = addparameterIQM(model,parametername,parametervalue)
+% [output] = addparameterIQM(model,parametername,parametervalue,parameternotes)
+%
+% model: IQMmodel to add the parameter to
+% parametername: name of the parameter to add (check is done to ensure that
+%   the name is not already used).
+% parametervalue: value of the new parameter
+% parameternotes: optional comment about the parameter
+%
+% Output Arguments:
+% =================
+% output: changed model with new parameter included
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK model
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isIQMmodel(model),
+    error('First input argument is not an IQMmodel.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle variable input arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+parameternotes = '';
+if nargin == 4,
+    parameternotes = varargin{1};
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK if parametername already exists in the model
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+modelparamnames = IQMparameters(model);
+if ~isempty(strmatchIQM(parametername,modelparamnames,'exact')),
+    error('The parameter "%s" does already exist in the model and can not be added again.',parametername);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Add the new parameter
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ms = struct(model);
+ms.parameters(end+1).name = parametername;
+ms.parameters(end).value = parametervalue;
+ms.parameters(end).notes = parameternotes;
+ms.parameters(end).type = '';
+ms.parameters(end).compartment = '';
+ms.parameters(end).unittype = '';
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Construct and return new model
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+output = IQMmodel(ms);
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/addpiecewiseeventsIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/addpiecewiseeventsIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..12490329475effb8cbd3cf449e9fb9b25fc0f65a
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/addpiecewiseeventsIQM.m	
@@ -0,0 +1,179 @@
+function [modelout] = addpiecewiseeventsIQM(model)
+% addpiecewiseeventsIQM: In order to switch piecewiseIQM constructs at
+% precisely the right instants the trigger functions of all piecewise
+% statements in a model are additionally implemented as events with dummy
+% assignments.
+%
+% USAGE:
+% ======
+% [modelout] = addpiecewiseeventsIQM(model)       
+%
+% model: IQMmodel
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+if ~isIQMmodel(model),
+    error('Function only defined for IQMmodels.');
+end
+ms = struct(model);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% FIND ALL PIECEWISE TRIGGERS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+triggers = {};
+% Check in ODEs
+for k=1:length(ms.states),
+    addtriggers = gettrigger(ms.states(k).ODE);
+    triggers = {triggers{:}, addtriggers{:}};
+end
+% Check in variables
+for k=1:length(ms.variables),
+    addtriggers = gettrigger(ms.variables(k).formula);
+    triggers = {triggers{:}, addtriggers{:}};
+end
+% Check in reactions
+for k=1:length(ms.reactions),
+    addtriggers = gettrigger(ms.reactions(k).formula);
+    triggers = {triggers{:}, addtriggers{:}};
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CYCLE THROUGH TRIGGERS AND FIND SOME WITH A SPECIAL FORMAT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Format: and(ge/gt(time, xyz),lt/le(time, abc))
+% These triggers are used to implement BOLUS inputs in the IQMdosing
+% framework. These event-pulses can be so short that they are not detected
+% by the integrator. Therefor we need to split them up into two events:
+% event1:   ge(time, xyz)
+% event2:   ge(time, abc)    => change from lt(time, abc) to fire correctly
+triggers = handlePulsePiecewiseExpressions(triggers,'andIQM<ge<time,(.*)>,lt<time,(.*)>>');
+triggers = handlePulsePiecewiseExpressions(triggers,'andIQM<ge<time,(.*)>,le<time,(.*)>>');
+triggers = handlePulsePiecewiseExpressions(triggers,'andIQM<gt<time,(.*)>,lt<time,(.*)>>');
+triggers = handlePulsePiecewiseExpressions(triggers,'andIQM<gt<time,(.*)>,le<time,(.*)>>');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% ADD EVENTS WITH ABOVE TRIGGERS 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(triggers),
+    if ~isempty(ms.states),
+        sn = ms.states(1).name; % used for dummy assignments
+    else
+        sn = ms.parameters(1).name;
+    end
+    for k=1:length(triggers),
+        ms.events(end+1).name = sprintf('piecewise_event_%d',k);
+        ms.events(end).trigger = triggers{k};
+        ms.events(end).assignment(1).variable = sn;
+        ms.events(end).assignment(1).formula = sn;
+        ms.events(end).notes = 'Just a dummy assignment for correct piecewise timing';
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Run through all event triggers and remove double definitions (if same assignments)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get events structure to modify
+eventsOriginal = ms.events;
+% Get all trigger strings
+triggers = {eventsOriginal.trigger};
+% Derive unique trigger strings (ix_unique are the indices of the unique ones that are going to be kept)
+[triggers_unique,ix_unique,J] = unique(triggers);
+% Remove multiple events from the eventsReduced structure
+eventsReduced = eventsOriginal(ix_unique);
+eventsRemoved = eventsOriginal(setdiff(1:length(eventsOriginal),ix_unique));
+% Run through all the eventsReduced triggers and find the event in eventsRemoved and add assignments in eventsRemoved to eventsReduced
+for k=1:length(eventsReduced),
+    assignmentsWhere2Add = eventsReduced(k).assignment;
+    ix = strmatchIQM(eventsReduced(k).trigger,{eventsRemoved.trigger},'exact');
+    if ~isempty(ix),
+        assignments2add = eventsRemoved(ix).assignment;
+        % Check if assignments already present (same variable and same formula)
+        ix_assignments2add = [];
+        for k2=1:length(assignments2add),
+            variable = assignments2add(k2).variable;
+            formula  = assignments2add(k2).formula;
+            % Find indices in assignmentsWhere2Add of same variable
+            ix2 = strmatchIQM(variable,{assignmentsWhere2Add.variable},'exact');
+            if isempty(ix2),
+                % Not the same variable => add the assignment
+                ix_assignments2add(end+1) = k2;
+            else
+                % If same variable in the assignment then check if same formula. 
+                % If same formula then do not add, if different formula, then error.
+                for k3=1:length(ix2),
+                    % Check if different formula, then error
+                    if ~strcmp(formula,assignmentsWhere2Add(ix2).variable),
+                        error('Different events with same triggers and same assignment variables but different assignment formulas present in the model.');
+                    else
+                        % Do nothing (do not add assignment)
+                    end
+                end
+            end
+        end
+        % Select the assignments to add
+        assignments2add = assignments2add(ix_assignments2add);
+        % Add them
+        eventsReduced(k).assignment = [assignmentsWhere2Add assignments2add];
+    end
+end
+% Add modified events to ms structure
+ms.events = eventsReduced;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% FINISH IT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+modelout = IQMmodel(ms);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Helpfunction to get the trigger expressions
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [triggers] = handlePulsePiecewiseExpressions(triggers,syntax)
+usetriggers = {};
+for k=1:length(triggers),
+    trigger = triggers{k};
+    % replace parentheses by "<" and ">" to use regexp for tokens
+    x = strrep(trigger,'(','<');
+    x = strrep(x,')','>');
+    y = regexp(x,syntax,'tokens');
+    if ~isempty(y),
+        % trigger of special format => replace it by two triggers as shown above
+        trigger1 = y{1}{1};
+        trigger2 = y{1}{2};
+        usetriggers{end+1} = ['ge(time,' trigger1 ')'];
+        usetriggers{end+1} = ['ge(time,' trigger2 ')'];
+    else
+        % if trigger not of special format then just keep the previous trigger
+        usetriggers{end+1} = trigger;
+    end
+end
+% copy back the triggers to right 
+triggers = usetriggers;
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Helpfunction to get the trigger expressions
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [trigger] = gettrigger(input)
+trigger = {};
+% find the start indices 
+index = strfind(input,'piecewiseIQM');
+% get the triggers
+for k=1:length(index),
+    work = input;
+    work = work(index(k)+length('piecewiseIQM')+1:end);
+    popen = 1; offset = 1;
+    while popen ~= 0,
+        if work(offset) == '(',
+            popen = popen + 1;
+        elseif work(offset) == ')',
+            popen = popen - 1;
+        end
+        offset = offset + 1;
+    end
+    work = work(1:offset-2);
+    % explode elements
+    terms = explodePCIQM(work);
+    trigger = {trigger{:} terms{2:2:end}};
+end
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/addreactionrateIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/addreactionrateIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..934891e6fac2cc2da6bb7fb7984dd3771073b16e
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/addreactionrateIQM.m	
@@ -0,0 +1,54 @@
+function [output] = addreactionrateIQM(model, name, formula, notes, reversibleFlag, fastFlag)
+% addreactionrateIQM: Allows to add a reaction rate expression to an IQMmodel. Only
+% the reaction rate expression is added, the ODE right hand sides are not
+% changed. It is checked if the given reaction rate name already exists
+% and an error is returned if it does.
+%
+% USAGE:
+% ======
+% [output] = addreactionrateIQM(model, name, formula, notes, reversibleFlag, fastFlag)
+%
+% model: IQMmodel to add the reaction rate to
+% name: name of the reaction rate (string)
+% formula: reaction rate expression (string)
+% notes: eventual notes about the reaction (string)
+% reversibleFlag: 0 = irreversible, 1 = reversible
+% fastFlag: 0 = slow, 1 = fast
+%
+% Output Arguments:
+% =================
+% output: changed model reaction rate added.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS IQMMODEL OR ODE FILE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~strcmp('IQMmodel',class(model)),
+    error('A reaction rate can not be added to an ODE file.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF reaction name ALREADY EXISTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+reactionsModel = IQMreactions(model);
+for k = 1:length(reactionsModel),
+    if strcmp(strtrim(name), strtrim(reactionsModel{k})),
+        error('The reaction rate name %s exists already in the model',name);
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DO THE ADDING
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+modelstruct = IQMstruct(model);
+reactionsstruct = modelstruct.reactions;
+reactionIndex = length(reactionsstruct)+1;
+reactionsstruct(reactionIndex).name = name;
+reactionsstruct(reactionIndex).formula = formula;
+reactionsstruct(reactionIndex).notes = notes;
+reactionsstruct(reactionIndex).reversible = reversibleFlag;
+reactionsstruct(reactionIndex).fast = fastFlag;
+modelstruct.reactions = reactionsstruct;
+output = IQMmodel(modelstruct);
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/check functions/hasmoietyconservationsIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/check functions/hasmoietyconservationsIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..5aa9281bafee448ac1f15bff6d2bf18fb5092fa2
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/check functions/hasmoietyconservationsIQM.m	
@@ -0,0 +1,23 @@
+function [output] = hasmoietyconservationsIQM(model)
+% hasmoietyconservationsIQM: Checks if the model contains moiety
+% conservations.
+%
+% Output Arguments:
+% =================
+% output: =1 if MCs present, =0 if not
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+if ~isIQMmodel(model),
+    error('Given model is not an IQMmodel.');
+end
+
+% default setting
+output = 0; % no MCs present
+% check/determine MCs
+[depVarIndex, depVarConstant, depVarFactor, message] = IQMmoietyconservations(model);
+if ~isempty(depVarIndex),
+    % the model seems to contain moiety conservations
+    output = 1;
+end
+
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/check functions/hasonlynumericICsIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/check functions/hasonlynumericICsIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..7c37421a7039d15b610e5587a329c2c9ae45023c
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/check functions/hasonlynumericICsIQM.m	
@@ -0,0 +1,29 @@
+function [output] = hasonlynumericICsIQM(model)
+% hasonlynumericICsIQM: Checks if the model contains only numeric initial
+% conditions. The model can be an IQMmodel or an ODE or MEX file model.
+%
+% Output Arguments:
+% =================
+% output: =1 if only numeric ICs, =0 if not
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+% default setting
+output = 1; % no non-numeric ICs present
+
+if isIQMmodel(model),
+    ms = struct(model);
+    for k=1:length(ms.states),
+        if ~isnumeric(ms.states(k).initialCondition),
+            output = 0; % non-numeric ICs present
+            break
+        end
+    end
+else
+    ICs = feval(model);
+    if ~isnumeric(ICs),
+        output = 0;
+    end
+end
+return
+    
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/check functions/isparameterIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/check functions/isparameterIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..90a54a35a69dddf0df9fadb9840c6d9ea40e6bff
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/check functions/isparameterIQM.m	
@@ -0,0 +1,24 @@
+function [output] = isparameterIQM(model,name)
+% isparameterIQM: checks if "name" is a parameter in the provided model.
+% This function works both for IQMmodels and ODE files. The check is of
+% course case sensitive
+%
+% Output Arguments:
+% =================
+% output: =1 if "name" is a parameter, =0 if not
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+% get all parameters of the model
+allParameters = IQMparameters(model);
+
+% check if "name" is a parameter.
+output = 0;
+for k = 1:length(allParameters),
+    if strcmp(strtrim(name),allParameters{k}),
+        output = 1;
+        break;
+    end
+end
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/check functions/isreactionIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/check functions/isreactionIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..797fe1c82ae994cd937d75f6639db17a347b8243
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/check functions/isreactionIQM.m	
@@ -0,0 +1,28 @@
+function [output] = isreactionIQM(model,name)
+% isreactionIQM: checks if "name" is a reaction in the provided model.
+% This function works only for IQMmodels. The check is of
+% course case sensitive
+%
+% Output Arguments:
+% =================
+% output: =1 if "name" is a reaction, =0 if not
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+if ~strcmp(class(model),'IQMmodel'),
+    error('Given model is not an IQMmodel.');
+end
+
+% get all reactions of the model
+allReactions = IQMreactions(model);
+
+% check if "name" is a reaction.
+output = 0;
+for k = 1:length(allReactions),
+    if strcmp(strtrim(name),allReactions{k}),
+        output = 1;
+        break;
+    end
+end
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/check functions/isstateIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/check functions/isstateIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..d0a1ecf5b29f9ff5500f2400c4d3d5ed57c20f39
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/check functions/isstateIQM.m	
@@ -0,0 +1,24 @@
+function [output] = isstateIQM(model,name)
+% isstateIQM: checks if "name" is a state in the provided model.
+% This function works both for IQMmodels and ODE files. The check is of
+% course case sensitive
+%
+% Output Arguments:
+% =================
+% output: =1 if "name" is a state, =0 if not
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+% get all states of the model
+allStates = IQMstates(model);
+
+% check if "name" is a state.
+output = 0;
+for k = 1:length(allStates),
+    if strcmp(strtrim(name),allStates{k}),
+        output = 1;
+        break;
+    end
+end
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/check functions/isvariableIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/check functions/isvariableIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..2164d8d67d4b041dbe153b808d95ce7ca6aa8dd3
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/check functions/isvariableIQM.m	
@@ -0,0 +1,28 @@
+function [output] = isvariableIQM(model,name)
+% isvariableIQM: checks if "name" is a variable in the provided model.
+% This function works only for IQMmodels. The check is of
+% course case sensitive
+%
+% Output Arguments:
+% =================
+% output: =1 if "name" is a variable, =0 if not
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+if ~strcmp(class(model),'IQMmodel'),
+    error('Given model is not an IQMmodel.');
+end
+
+% get all variables of the model
+allVariables = IQMvariables(model);
+
+% check if "name" is a variable.
+output = 0;
+for k = 1:length(allVariables),
+    if strcmp(strtrim(name),allVariables{k}),
+        output = 1;
+        break;
+    end
+end
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/check functions/usealgebraicIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/check functions/usealgebraicIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..a1ab56b4089bbb1985d4f8ef964eb8c7746249d7
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/check functions/usealgebraicIQM.m	
@@ -0,0 +1,23 @@
+function [output] = usealgebraicIQM(model)
+% usealgebraicIQM: checks if an IQMmodel contains algebraic rules.
+%
+% Output Arguments:
+% =================
+% output: =1 if algebraic rules are used, =0 if not
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+if ~isIQMmodel(model),
+    error('Given model is not an IQMmodel.');
+end
+
+% default setting
+output = 0; % no algebraic rule present
+
+% get model structure
+ms = struct(model);
+
+% check algebraic rules
+if ~isempty(ms.algebraic),
+    output = 1;
+end
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/check functions/usedelayIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/check functions/usedelayIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..2a34941bc4d4b4e54691b72c5dd6a941d6b384b3
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/check functions/usedelayIQM.m	
@@ -0,0 +1,81 @@
+function [output] = usedelayIQM(model)
+% usedelayIQM: checks if an IQMmodel contains the delayIQM function.
+%
+% Output Arguments:
+% =================
+% output: =1 if "delayIQM" function is present in the model, =0 if not
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+if ~isIQMmodel(model),
+    error('Given model is not an IQMmodel.');
+end
+
+% default setting
+output = 0; % no delay present
+
+% get model structure
+ms = struct(model);
+
+% check all ODEs
+for k=1:length(ms.states),
+    output = delayPresent(ms.states(k).ODE);
+    if output,
+        return
+    end
+end
+    
+% check all variables
+for k=1:length(ms.variables),
+    output = delayPresent(ms.variables(k).formula);
+    if output,
+        return
+    end
+end
+
+% check all reactions
+for k=1:length(ms.reactions),
+    output = delayPresent(ms.reactions(k).formula);
+    if output,
+        return
+    end
+end
+
+% check all event triggers
+for k=1:length(ms.events),
+    output = delayPresent(ms.events(k).trigger);
+    if output,
+        return
+    end
+end
+
+% check all event assignments
+for k=1:length(ms.events),
+    for k2=1:length(ms.events(k).assignment),
+        output = delayPresent(ms.events(k).assignment(k2).formula);
+        if output,
+            return
+        end
+    end
+end
+
+% check all functions
+for k=1:length(ms.functions),
+    output = delayPresent(ms.functions(k).formula);
+    if output,
+        return
+    end
+end
+
+% check MATLAB functions
+output = delayPresent(ms.functionsMATLAB);
+return
+
+% help function not to have to write it to often
+function [result] = delayPresent(text)
+    if ~isempty(strfind(text,'delayIQM')),
+        result = 1;
+    else
+        result = 0;
+    end
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/check functions/useeventIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/check functions/useeventIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..16c674e17f96aefb5301904e3fc3e389550c5dae
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/check functions/useeventIQM.m	
@@ -0,0 +1,23 @@
+function [output] = useeventIQM(model)
+% useeventIQM: checks if an IQMmodel contains events.
+%
+% Output Arguments:
+% =================
+% output: =1 if events are used, =0 if not
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+if ~isIQMmodel(model),
+    error('Given model is not an IQMmodel.');
+end
+
+% default setting
+output = 0; % no event present
+
+% get model structure
+ms = struct(model);
+
+% check events
+if ~isempty(ms.events),
+    output = 1;
+end
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/check functions/usefastIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/check functions/usefastIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..a28df55d1964ab5778a198ee7afddb4eb681f638
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/check functions/usefastIQM.m	
@@ -0,0 +1,16 @@
+function [output] = usefastIQM(model)
+% usefastIQM: checks if an IQMmodel contains "fast" reactions.
+%
+% Output Arguments:
+% =================
+% output: =1 if reactions with the "fast" flag set are present, =0 if not
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+if ~isIQMmodel(model),
+    error('Given model is not an IQMmodel.');
+end
+
+ms = struct(model);
+output = ~isempty(find([ms.reactions.fast]==1, 1));
+
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/cleanmodelIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/cleanmodelIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..f14302ef60de74d58f65ad7bd897102d23337ed3
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/cleanmodelIQM.m	
@@ -0,0 +1,118 @@
+function [model] = cleanmodelIQM(model,varargin)
+% cleanmodelIQM: Remove unused reactions, variables and parameters from a model
+%
+% USAGE:
+% ======
+% model = cleanmodelIQM(model)
+% model = cleanmodelIQM(model,silentflag)
+%
+% model: IQMmodel to be cleaned
+% silentflag: =0 stats output on console (default) 
+%             =1 no output on console
+%
+% Output Arguments:
+% =================
+% model:   cleaned IQMmodel
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+if nargin == 1,
+    silentflag = 0;
+elseif nargin == 2,
+    silentflag = varargin{1};
+else
+    error('Incorrect number of input arguments.');
+end
+
+removedReactions = {};
+removedVariables = {};
+removedParameters = {};
+
+doclean = 1;
+while doclean,
+    % Creates structure and extracts necessary data
+    iqms = IQMstruct(model);
+
+    % extracts information from model
+    [sName, sFormula] = IQMstates(model);
+    [vName, vFormula] = IQMvariables(model);
+    [rName, rFormula] = IQMreactions(model);
+    [pName] = IQMparameters(model);
+
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Check ODEs and remove all reactions that do not appear in the ODEs
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    elements = {};
+    for k = 1:length(sFormula)
+        elements = unique(union(elements,regexp(sFormula{k},'\w+','match')));
+    end
+    ism = ismember(rName, elements)';
+removedReactions = {removedReactions{:}, iqms.reactions(~ism).name};
+    iqms.reactions(~ism) = '';
+    nrreactions = sum(ism==0);
+
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Check ODEs, variables, events, and reactions and remove all variables that do not appear
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    elements = {};
+    for k = 1:length(sFormula)
+        elements = unique(union(elements,regexp(sFormula{k},'\w+','match')));
+    end
+    for k = 1:length(vFormula)
+        elements = unique(union(elements,regexp(vFormula{k},'\w+','match')));
+    end
+    for k = 1:length(rFormula)
+        elements = unique(union(elements,regexp(rFormula{k},'\w+','match')));
+    end
+    for k = 1:length(iqms.events),
+        elements = unique(union(elements,regexp(iqms.events(k).trigger,'\w+','match')));
+        for k2 = 1:length(iqms.events(k).assignment),
+            elements = unique(union(elements,regexp(iqms.events(k).assignment(k2).formula,'\w+','match')));
+        end
+    end
+    ism = ismember(vName, elements)';
+removedVariables = {removedVariables{:}, iqms.variables(~ism).name};    
+    iqms.variables(~ism) = '';
+    nrvariables = sum(ism==0);
+
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Check ODEs, variables, events, and reactions and remove all parameters that do not appear
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    ism = ismember(pName, elements)';
+removedParameters = {removedParameters{:}, iqms.parameters(~ism).name};        
+    iqms.parameters(~ism) = '';
+    nrparameters = sum(ism==0);
+
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % decide if to clean again
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    if nrparameters+nrvariables+nrreactions == 0,
+        doclean = 0;
+    end
+    model = IQMmodel(iqms);
+end
+
+if ~silentflag,
+    if ~isempty({removedParameters{:} removedVariables{:} removedReactions{:}}),
+        if ~isempty(removedParameters),
+            disp(sprintf('Removed Parameters: %d',length(removedParameters)));
+            disp('==================');
+            disp(cell2wraptextIQM(removedParameters,10));
+            disp(' ');
+        end
+        if ~isempty(removedVariables),
+            disp(sprintf('Removed Variables: %d',length(removedVariables)));
+            disp('=================');
+            disp(cell2wraptextIQM(removedVariables,10));
+            disp(' ');
+        end
+        if ~isempty(removedReactions),
+            disp(sprintf('Removed Reactions: %d',length(removedReactions)));
+            disp('=================');
+            disp(cell2wraptextIQM(removedReactions,10));
+            disp(' ');
+        end
+    else
+        disp('No unused components in the model');
+    end
+end
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/deleteparametersIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/deleteparametersIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..d92ad4e9d7f63d653f7fe478917d1fb3a7240c39
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/deleteparametersIQM.m	
@@ -0,0 +1,61 @@
+function [output] = deleteparametersIQM(model,parameters)
+% deleteparametersIQM: Deletes the given parameters from the model. Will 
+% keep the parameters in the equations.
+%
+% USAGE:
+% ======
+% [output] = deleteparametersIQM(model,parameters)
+%
+% model: IQMmodel to delete the parameters from 
+% parameters: single parameter (string) or multiple parameters (cell-array)
+%   to delete from model
+%
+% Output Arguments:
+% =================
+% output: changed model without parameter definitions for given parameters
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS IQMMODEL OR ODE FILE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~strcmp('IQMmodel',class(model)),
+    error('Parameters can not be deleted from ODE file.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF parameters GIVEN AS CELL ARRAY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ischar(parameters),
+    parameters = {parameters};
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DO THE DELETIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+modelstruct = IQMstruct(model);
+oldparametersstruct = modelstruct.parameters;
+newparametersstruct = struct('name',{},'value',{},'type',{},'compartment',{},'unittype',{},'notes',{});%[];
+parameterIndex = 1;
+for k1 = 1:length(oldparametersstruct),
+    keepParameter = 1;
+    for k2 = 1:length(parameters),
+        if strcmp(oldparametersstruct(k1).name,parameters{k2}),
+            keepParameter = 0;
+            break;
+        end
+    end
+    if keepParameter == 1,
+        newparametersstruct(parameterIndex).name = oldparametersstruct(k1).name;
+        newparametersstruct(parameterIndex).value = oldparametersstruct(k1).value;
+        newparametersstruct(parameterIndex).type = oldparametersstruct(k1).type;
+        newparametersstruct(parameterIndex).compartment = oldparametersstruct(k1).compartment;
+        newparametersstruct(parameterIndex).unittype = oldparametersstruct(k1).unittype;
+        newparametersstruct(parameterIndex).notes = oldparametersstruct(k1).notes;
+        parameterIndex = parameterIndex + 1;
+    end
+end
+modelstruct.parameters = newparametersstruct;
+output = IQMmodel(modelstruct);
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/deletereactionratesIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/deletereactionratesIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..ea540d1feb71b54b59ae0127713c70ae747bb987
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/deletereactionratesIQM.m	
@@ -0,0 +1,61 @@
+function [output] = deletereactionratesIQM(model,reactions)
+% deletereactionratesIQM: Deletes the given reactions rate expression from
+% an IQMmodel. Will keep the names of the reactions in the right hand sides
+% of the ODEs. 
+%
+% USAGE:
+% ======
+% [output] = deletereactionratesIQM(model,reactions)
+%
+% model: IQMmodel to delete the reactions from 
+% reactions: single reaction name (string) or multiple reaction names (cell-array)
+%   to delete from model
+%
+% Output Arguments:
+% =================
+% output: changed model without reaction definitions for given reactions
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS IQMMODEL OR ODE FILE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~strcmp('IQMmodel',class(model)),
+    error('Reactions can not be deleted from ODE file.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF reactions GIVEN AS CELL ARRAY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ischar(reactions),
+    reactions = {reactions};
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DO THE DELETIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+modelstruct = IQMstruct(model);
+oldreactionsstruct = modelstruct.reactions;
+newreactionsstruct = [];
+reactionIndex = 1;
+for k1 = 1:length(oldreactionsstruct),
+    keepReaction = 1;
+    for k2 = 1:length(reactions),
+        if strcmp(oldreactionsstruct(k1).name,reactions{k2}),
+            keepReaction = 0;
+            break;
+        end
+    end
+    if keepReaction == 1,
+        newreactionsstruct(reactionIndex).name = oldreactionsstruct(k1).name;
+        newreactionsstruct(reactionIndex).formula = oldreactionsstruct(k1).formula;
+        newreactionsstruct(reactionIndex).notes = oldreactionsstruct(k1).notes;
+        newreactionsstruct(reactionIndex).reversible = oldreactionsstruct(k1).reversible;
+        newreactionsstruct(reactionIndex).fast = oldreactionsstruct(k1).fast;
+        reactionIndex = reactionIndex + 1;
+    end
+end
+modelstruct.reactions = newreactionsstruct;
+output = IQMmodel(modelstruct);
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/depowerIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/depowerIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..5436871c664e3349d712a65d2521a7bd127c4714
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/depowerIQM.m	
@@ -0,0 +1,60 @@
+function [model,changeFlag] = depowerIQM(model)
+% depowerIQM: simple function that replaces power(x,y) expressions in models
+% to (x)^(y)
+%
+% USAGE:
+% ======
+% model = depowerIQM(model)
+%
+% Output Arguments:
+% =================
+% model:        IQMmodel with replaced power expressions
+% changeFlag:   =0 => no changes, =1 => changes made
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+global changeFlag
+changeFlag = 0;
+iqmstruct = IQMstruct(model);
+% states
+for k = 1:length(iqmstruct.states),
+    iqmstruct.states(k).ODE = exchangepowerexp(iqmstruct.states(k).ODE);
+end
+% variables
+for k = 1:length(iqmstruct.variables),
+    iqmstruct.variables(k).formula = exchangepowerexp(iqmstruct.variables(k).formula);
+end
+% reactions
+for k = 1:length(iqmstruct.reactions),
+    iqmstruct.reactions(k).formula = exchangepowerexp(iqmstruct.reactions(k).formula);
+end
+% events
+for k = 1:length(iqmstruct.events),
+    iqmstruct.events(k).trigger = exchangepowerexp(iqmstruct.events(k).trigger);
+    for k2 = 1:length(iqmstruct.events(k).assignment),
+        iqmstruct.events(k).assignment(k2).formula = exchangepowerexp(iqmstruct.events(k).assignment(k2).formula);
+    end        
+end
+% functions
+for k = 1:length(iqmstruct.functions),
+    iqmstruct.functions(k).formula = exchangepowerexp(iqmstruct.functions(k).formula);
+end
+model = IQMmodel(iqmstruct);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% regexprep command doing the replacement
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [formula] = exchangepowerexp(formula)
+global changeFlag
+oldformula = formula;
+formula = regexprep(['#' formula],'([\W]+)',' $1 ');
+formula = regexprep(formula,'[\s]power[\s]*\(([^,]+),([^,]+)\)','($1)^($2)');
+formula = regexprep(formula,'\s','');
+formula = formula(2:end);
+if ~strcmp(oldformula,formula),
+    changeFlag = 1;
+end
+return
+    
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/getnumberoftypeIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/getnumberoftypeIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..31f5f395b5c1ce805a3d549a45b7ec5e9d4335a5
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/getnumberoftypeIQM.m	
@@ -0,0 +1,41 @@
+function n = getnumberoftypeIQM(model,type)
+% getnumberoftypeIQM: retrieve the number counts from IQM model
+%
+% USAGE:
+% ======
+% n = getnumberoftypeIQM(model,type)
+%
+% model: IQMmodel
+% type:  instance type of which the number is to be known (possible values:
+%                       'functions','states:','algebraic','parameters',
+%                       'variables','reactions','events','inputs','outputs')
+%
+% Output Arguments:
+% =================
+% n:	number of instances for the type given
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+% inputs: - model IQMmodel
+%         - typestring: string identifying which type to be counted;
+%         allowed =
+%         {'functions','states:','algebraic','parameters','variables','reac
+%         tions','events','inputs','outputs'}
+
+possibletypes = {'functions','states','algebraic','parameters','variables','reactions','events','inputs','outputs'};
+
+
+if class(model) == 'IQMmodel'
+    model_struct = IQMstruct(model);
+else
+    error('getnumberoftypeIQM:WrongClassOfModel', 'Model not IQMmodel.')
+end
+
+type = lower(type);
+if ~ismember(type,possibletypes)
+    error('getnumberoftypeIQM:WrongType', 'Type string does not match possible types.')
+end
+    
+    
+eval(['n = length(model_struct.',type,');']);
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/nonnumericICserrorIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/nonnumericICserrorIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..36921d5ebbf88e58f70dd695559af984004088be
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/nonnumericICserrorIQM.m	
@@ -0,0 +1,14 @@
+function [] = nonnumericICserrorIQM(model)
+% nonnumericICserrorIQM: returns an error if the model contains
+% non-numeric ICs
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+if ~isIQMmodel(model),
+    error('Given model is not an IQMmodel.');
+end
+
+% check
+if ~hasonlynumericICsIQM(model),
+    error('The model contains non-numeric initial conditions. These are not supported by this function.');
+end
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/reactionindexIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/reactionindexIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..726c74004d4d720554cd6a3623f02521d92cf468
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/reactionindexIQM.m	
@@ -0,0 +1,34 @@
+function [output] = reactionindexIQM(model,reactionname)
+% reactionindexIQM: returns the number of the reaction 'reactionname' in model
+% 'model'. If the reaction does not exist then [] is returned.
+%
+% Output Arguments:
+% =================
+% output = index of the reaction 'reactionname' in the model.
+%          If 'reactionname' is not a reaction in the model, [] is returned.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+if ischar(reactionname),
+    reactionname = {reactionname};
+end
+
+allreactions = IQMreactions(model);
+
+if length(reactionname) == 1,
+    output = strmatchIQM(reactionname,allreactions,'exact');
+    if isempty(output),
+        output = [];
+    end
+else    
+    output = [];
+    for k = 1:length(reactionname),
+        index = strmatchIQM(reactionname{k},allreactions,'exact');
+        if isempty(index),
+            output(k) = -1;
+        else
+            output(k) = index;
+        end
+    end
+end
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/removedelayIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/removedelayIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..5a423c3aaf34a0461c3fa70b12ac224a5985e456
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/removedelayIQM.m	
@@ -0,0 +1,94 @@
+function [modelnew] = removedelayIQM(model)
+% removedelayIQM: removes the delay function from the model.
+% This is for example necessary for the determination of the 
+% steady-state. Thus this function is called, e.g., from IQMsteadystate
+% in the case that delay functions have been detected in the model.
+%
+% Output Arguments:
+% =================
+% modelnew: model with removed delay function
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+if ~isIQMmodel(model),
+    error('Given model is not an IQMmodel.');
+end
+
+% get model structure
+ms = struct(model);
+
+% check all ODEs
+for k=1:length(ms.states),
+    ms.states(k).ODE = removeDelay(ms.states(k).ODE);
+end
+    
+% check all variables
+for k=1:length(ms.variables),
+    ms.variables(k).formula = removeDelay(ms.variables(k).formula);
+end
+
+% check all reactions
+for k=1:length(ms.reactions),
+    ms.reactions(k).formula = removeDelay(ms.reactions(k).formula);
+end
+
+% check all event triggers
+for k=1:length(ms.events),
+    ms.events(k).trigger = removeDelay(ms.events(k).trigger);
+end
+
+% check all event assignments
+for k=1:length(ms.events),
+    for k2=1:length(ms.events(k).assignment),
+        ms.events(k).assignment(k2).formula = removeDelay(ms.events(k).assignment(k2).formula);
+    end
+end
+
+% check all functions
+for k=1:length(ms.functions),
+    ms.functions(k).formula = removeDelay(ms.functions(k).formula);
+end
+
+% check MATLAB functions
+ms.functionsMATLAB = removeDelay(ms.functionsMATLAB);
+
+% return new model
+modelnew = IQMmodel(ms);
+return
+
+% remove the delayIQM function
+function [formula] = removeDelay(formula)
+% first remove the second input argument to delayIQM
+count = 1;
+while 1,
+    index = strfind(formula,'delayIQM(');
+    if length(index) < count,
+        break;
+    end
+    indexstart = index(count)+length('delayIQM(');
+    indexend = indexstart;
+    % search the end of the delay argument definition
+    parOpen = 1;
+    while parOpen ~= 0,
+        if formula(indexend) == '(',
+            parOpen = parOpen + 1;
+        elseif formula(indexend) == ')',
+            parOpen = parOpen - 1;
+        end
+        indexend = indexend + 1;
+    end
+    argument = formula(indexstart:indexend-2);
+    % we only need the first argument
+    terms = explodePCIQM(argument,',');
+    argument = terms{1};
+    % reconstruct formula
+    firstpart = formula(1:indexstart-1);
+    lastpart = formula(indexend-1:end);
+    middlepart = argument;
+    formula = char([double(firstpart) double(middlepart) double(lastpart)]);
+    % increase counters
+    count = count + 1;
+end
+% finally remove the delayIQM call
+formula = regexprep(formula,'\<delayIQM\>','');
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/replaceelementIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/replaceelementIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..26a538d6fc7d7db8f3dc74918bd07e958ed72f5f
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/replaceelementIQM.m	
@@ -0,0 +1,68 @@
+function [output] = replaceelementIQM(model,oldelements,newelements)
+% replaceelementIQM: Replaces a given string by a new string. Replacing is
+% only done in cases where the previous and next character in the code is
+% not a text element (a-z, A-Z, 0-9, _). Elements should ONLY be
+% statenames, reactionnames, variablenames, parameternames.
+%
+% USAGE:
+% ======
+% [output] = replaceelementIQM(model,oldelement,newelement)
+%
+% model: IQMmodel to replace an element in 
+% oldelements: string containing the name of a parameter, variable,
+%   reaction, state, function, etc. to replace
+%   alternatively a cell array with different old elements can be specified
+% newelements: string containing the new text
+%   alternatively a cell array with different new elements can be specified
+%
+% Output Arguments:
+% =================
+% output: changed model 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS IQMMODEL OR ODE FILE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~strcmp('IQMmodel',class(model)),
+    error('In ODE files nothing can be replaced using this function.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK INPUT DATA
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ischar(oldelements),
+    oldelements = {oldelements};
+end
+if ischar(newelements),
+    newelements = {newelements};
+end
+if length(oldelements) ~= length(newelements),
+    error('Same number of old and new elements is required.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CONVERT MODEL TO TEXT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+modelTextStructure = convertModelToTextIQM(model);
+modelText = setPartsToCompleteTextIQM(modelTextStructure);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CONSTRUCT REPLACE EXPRESSION AND DO REPLACE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+replaceexpression = {};
+for k = 1:length(oldelements),
+    replaceexpression{k} = char([double('\<') double(oldelements{k}) double('\>')]);
+end
+modelText = regexprep(modelText,replaceexpression,newelements);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CONVERT TEXT TO MODEL
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[IQMstructure,errorMsg] = convertTextToModelIQM(modelText);
+if ~isempty(errorMsg),
+    error(errorMsg);
+end
+output = IQMmodel(IQMstructure);
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/stateindexIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/stateindexIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..9f867e93de97548aa388a474f7aedfb107785ae7
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/stateindexIQM.m	
@@ -0,0 +1,34 @@
+function [output] = stateindexIQM(model,statename)
+% stateindexIQM: returns the number of the state 'statename' in model
+% 'model'. If the state does not exist then [] is returned.
+%
+% Output Arguments:
+% =================
+% output = index of the state 'statename' in the model.
+%          If 'statename' is not a state in the model, [] is returned.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+if ischar(statename),
+    statename = {statename};
+end
+
+allstates = IQMstates(model);
+
+if length(statename) == 1,
+    output = strmatchIQM(statename,allstates,'exact');
+    if isempty(output),
+        output = [];
+    end
+else    
+    output = [];
+    for k = 1:length(statename),
+        index = strmatchIQM(statename{k},allstates,'exact');
+        if isempty(index),
+            output(k) = -1;
+        else
+            output(k) = index;
+        end
+    end
+end
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/text2IQMmodel/convertTEXTArrayDefIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/text2IQMmodel/convertTEXTArrayDefIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..28c9889f79882ecc59dad6f4c1b5d6740e36cab8
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/text2IQMmodel/convertTEXTArrayDefIQM.m	
@@ -0,0 +1,378 @@
+function [msnew] = convertTEXTArrayDefIQM(ms)
+
+% global variable for passing array state initial conditions from
+% convertTextToModelIQM.m
+global arrayInitialConditions_qayxsw
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF MODEL CONTAINS ARRAYS, OTHERWISE RETURN
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+containsArrays = 0;
+for k=1:length(ms.states),
+    if ~isempty(strfind(ms.states(k).name,'<')),
+        containsArrays = 1;
+        break;
+    end
+end
+if containsArrays == 0,
+    for k=1:length(ms.variables),
+        if ~isempty(strfind(ms.variables(k).name,'<')),
+            containsArrays = 1;
+            break;
+        end
+    end
+end
+if containsArrays == 0,
+    for k=1:length(ms.reactions),
+        if ~isempty(strfind(ms.reactions(k).name,'<')),
+            containsArrays = 1;
+            break;
+        end
+    end
+end
+if containsArrays == 0,
+    msnew = ms;
+    return
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CREATE NEW MODELSTRUCT AND COPY UNCHANGED
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+msnew = struct(IQMmodel);
+msnew.name              = ms.name;
+msnew.notes             = ms.notes;
+msnew.functions         = ms.functions;
+msnew.algebraic         = ms.algebraic;
+msnew.parameters        = ms.parameters;
+msnew.events            = ms.events;
+msnew.functionsMATLAB   = ms.functionsMATLAB;
+msnew.inputs            = ms.inputs;
+msnew.outputs           = ms.outputs;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE SPECIAL ARRAY FUNCTIONS 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Currently there is a single function that can be used: 'arraysumIQM'.
+% However, there might be more in the future.
+% These functions can ONLY be used in the variable formulas. All other uses
+% are leading to errors.
+% Check all parts of the model first
+% States
+for k=1:length(ms.states),
+    if ~isempty(strfind(ms.states(k).ODE,'arraysumIQM')),
+        error('arraysumIQM is only allowed in the MODEL VARIABLES definition.');
+    end
+end
+% Reactions
+for k=1:length(ms.reactions),
+    if ~isempty(strfind(ms.reactions(k).formula,'arraysumIQM')),
+        error('arraysumIQM is only allowed in the MODEL VARIABLES definition.');
+    end
+end
+% Now check the variables
+for k=1:length(ms.variables),
+    if ~isempty(strfind(ms.variables(k).formula,'arraysumIQM')),
+        ms.variables(k).formula = handleArraySumIQM(ms.variables(k).name,ms.variables(k).formula,ms.parameters);
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE STATES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for k=1:length(ms.states),
+    % Check if array definition (<index,arrayrange>) by checking the name
+    arraydef = regexp(ms.states(k).name,'<[^<>]+>','match');
+    if isempty(arraydef),
+        % Just a normal state definition. Need to copy it and 
+        % deal with array elements that might appear on the RHS
+        msnew.states(end+1) = ms.states(k);
+        msnew.states(end).ODE = handleRHSs(msnew.states(end).ODE,msnew.parameters,[],[],'noeval');
+    else
+        % Its an array state. Need to handle the RHS as above and expand
+        % the array definition into single states. The LHS gives
+        % information about range and indexvariable.
+        arraydef = arraydef{1};
+        [indexvariable,range] = handleLHSs(arraydef,msnew.parameters,ms.states(k).name,'state');
+        % Get the base name of the state, etc.
+        basename = ms.states(k).name(1:end-length(arraydef));
+        ODEbase = ms.states(k).ODE;
+        % Expand the array
+        for k2=range,
+            if k2 >= 0,
+                newstate.name = sprintf('%s%d',basename,k2);
+            else
+                newstate.name = sprintf('%s_%d',basename,abs(k2));
+            end                
+            newstate.initialCondition = ms.states(k).initialCondition;
+            newstate.ODE = handleRHSs(ODEbase,ms.parameters,indexvariable,k2,'noeval');
+            newstate.type = ms.states(k).type;
+            newstate.compartment = ms.states(k).compartment;
+            newstate.unittype = ms.states(k).unittype;
+            newstate.notes = ms.states(k).notes;
+            msnew.states(end+1) = newstate;
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE REACTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for k=1:length(ms.reactions),
+    % Check if array definition (<index,arrayrange>) by checking the name
+    arraydef = regexp(ms.reactions(k).name,'<[^<>]+>','match');
+    if isempty(arraydef),
+        % Just a normal reaction definition. Need to copy it and 
+        % deal with array elements that might appear on the RHS
+        msnew.reactions(end+1) = ms.reactions(k);
+        msnew.reactions(end).formula = handleRHSs(msnew.reactions(end).formula,msnew.parameters,[],[],'noeval');
+    else
+        % Its an array reaction. Need to handle the RHS as above and expand
+        % the array definition into single reactions. The LHS gives
+        % information about range and indexvariable.
+        arraydef = arraydef{1};
+        [indexvariable,range] = handleLHSs(arraydef,msnew.parameters,ms.reactions(k).name,'reaction');
+        % Get the base name of the reaction, etc.
+        basename = ms.reactions(k).name(1:end-length(arraydef));
+        formulabase = ms.reactions(k).formula;
+        % Expand the array
+        for k2=range,
+            if k2 >= 0,
+                newreaction.name = sprintf('%s%d',basename,k2);
+            else
+                newreaction.name = sprintf('%s_%d',basename,abs(k2));
+            end                
+            newreaction.formula = handleRHSs(formulabase,ms.parameters,indexvariable,k2,'noeval');
+            newreaction.notes = ms.reactions(k).notes;
+            newreaction.reversible = ms.reactions(k).reversible;
+            newreaction.fast = ms.reactions(k).fast;
+            msnew.reactions(end+1) = newreaction;
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE VARIABLES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for k=1:length(ms.variables),
+    % Check if array definition (<index,arrayrange>) by checking the name
+    arraydef = regexp(ms.variables(k).name,'<[^<>]+>','match');
+    if isempty(arraydef),
+        % Just a normal variable definition. Need to copy it and 
+        % deal with array elements that might appear on the RHS
+        msnew.variables(end+1) = ms.variables(k);
+        msnew.variables(end).formula = handleRHSs(msnew.variables(end).formula,msnew.parameters,[],[],'noeval');
+    else
+        % Its an array variable. Need to handle the RHS as above and expand
+        % the array definition into single variables. The LHS gives
+        % information about range and indexvariable.
+        arraydef = arraydef{1};
+        [indexvariable,range] = handleLHSs(arraydef,msnew.parameters,ms.variables(k).name,'variable');
+        % Get the base name of the variable, etc.
+        basename = ms.variables(k).name(1:end-length(arraydef));
+        formulabase = ms.variables(k).formula;
+        % Expand the array
+        for k2=range,
+            if k2 >= 0,
+                newvariable.name = sprintf('%s%d',basename,k2);
+            else
+                newvariable.name = sprintf('%s_%d',basename,abs(k2));
+            end                
+            newvariable.formula = handleRHSs(formulabase,ms.parameters,indexvariable,k2,'noeval');
+            newvariable.type = ms.variables(k).type;
+            newvariable.compartment = ms.variables(k).compartment;
+            newvariable.unittype = ms.variables(k).unittype;
+            newvariable.notes = ms.variables(k).notes;
+            msnew.variables(end+1) = newvariable;
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE INITIAL CONDITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(arrayInitialConditions_qayxsw),
+    % There are initial conditions we need to take care of
+    ICdata = arrayInitialConditions_qayxsw;
+    icnames = {};
+    icvalues = [];
+    for k=1:length(ICdata),
+        name = ICdata(k).name;
+        ic = ICdata(k).ic;
+        % Check if array definition (<index,arrayrange>) by checking the name
+        arraydef = regexp(name,'<[^<>]+>','match');
+        if isempty(arraydef),
+            % There must have been an error
+            error('There seems to be a problem with the definition of the initial condition ''%''',name);
+        else
+            % Its an array IC. Need to handle the RHS as above and expand
+            % the array definition into single ICs. The LHS gives
+            % information about range and indexvariable. Then the data is
+            % added to the states.
+            arraydef = arraydef{1};
+            [indexvariable,range] = handleLHSs(arraydef,msnew.parameters,name,'IC');
+        end
+        % Get the base name of the ICstates, etc.
+        basename = name(1:end-length(arraydef));
+        formulabase = ic;
+        % Expand the array and build the icnames and the icvalues
+        for k2=range,
+            if k2 >= 0,
+                icnames{end+1} = sprintf('%s%d',basename,k2);
+            else
+                icnames{end+1} = sprintf('%s_%d',basename,abs(k2));
+            end
+            icvalues(end+1) = handleRHSs(formulabase,ms.parameters,indexvariable,k2,'eval');
+        end       
+        % Finally fit the ICs into the states structure
+        for k2=1:length(icnames),
+            stateindex = strmatchIQM(icnames{k2},{msnew.states.name},'exact');
+            if isempty(stateindex),
+                error('The state ''%s'' for which an array-type initial condition is defined is not present in the model.',icnames{k2});
+            end
+            msnew.states(stateindex).initialCondition = icvalues(k2);
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% FINISHED
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+return
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE ARRAY SUM
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [newformula] = handleArraySumIQM(name,formula,parameters)
+    newformula = formula;
+    % Allow only one call to arraysumIQM per formula
+    index = strfind(newformula,'arraysumIQM');
+    if length(index)>1,
+        error('Only one call to ''arraysumIQM'' allowed per variable definition.');
+    end
+    % Split formula in three parts: before arraysumIQM, the arguments of arraysumIQM, and
+    % after arraysumIQM
+    formulabefore = newformula(1:index-1);
+    help = newformula(index+length('arraysumIQM('):end);
+    indexend = 0;
+    popen = 1;
+    while popen ~= 0,
+        indexend = indexend + 1;
+        if help(indexend) == '(',
+            popen = popen + 1;
+        end
+        if help(indexend) == ')',
+            popen = popen - 1;
+        end
+    end
+    formulaas = help(1:indexend-1);
+    formulaafter = help(indexend+1:end);
+    % Get the array information
+    arraydef = regexp(formulaas,'<[^<>]+>','match');
+    arraydef = arraydef{1};
+    [indexvariable,range] = handleLHSs(arraydef,parameters,name,'arraysumIQM');
+    % Expand the expression
+    expression = '';
+    for k=range,
+        expressionk = formulaas;
+        % Replace index
+        if k>=0,
+            repindex = num2str(k);
+        else
+            repindex = ['_',num2str(abs(k))];
+        end
+        expressionk = strrep(expressionk,arraydef,repindex);
+        % Replace the index variable
+        regsearch = ['\<' indexvariable '\>'];
+        expressionk = regexprep(expressionk,regsearch,num2str(k));        
+        % Add to overall expression
+        if k==range(1),
+            expression = ['(' expressionk ')'];
+        else
+            expression = [expression '+' '(' expressionk ')'];
+        end
+    end
+    % put together the new forumla
+    newformula = [formulabefore expression formulaafter];
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE ARRAY <> THINGS IN LHSs
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [indexvariable_qayxsw,range_qayxsw] = handleLHSs(arraydef_qayxsw,parameters_qayxsw,name_qayxsw,type_qayxsw)
+    % Get the index variable and its range
+    terms_qayxsw = explodePCIQM(arraydef_qayxsw(2:end-1),',','[',']');
+    if length(terms_qayxsw)~=2,
+        error('Incorrect %s-array definition for %s ''%s''.',type_qayxsw,type_qayxsw,name_qayxsw);
+    end
+    indexvariable_qayxsw = terms_qayxsw{1};
+    range_qayxsw = terms_qayxsw{2};
+    if isempty(indexvariable_qayxsw) || isempty(range_qayxsw),
+        error('Incorrect %s-array definition for %s ''%s''.',type_qayxsw,type_qayxsw,name_qayxsw);
+    end
+    % Define all model parameters locally in this function (needed for the
+    % evaluation of the range)
+    for k_qayxsw=1:length(parameters_qayxsw),
+        eval(sprintf('%s = %g;',parameters_qayxsw(k_qayxsw).name,parameters_qayxsw(k_qayxsw).value));
+    end
+    % Evaluate the range variable
+    try
+        range_qayxsw = eval(range_qayxsw);
+    catch
+        error('Incorrect definition of the range for %s ''%s''.',type_qayxsw,name_qayxsw);
+    end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE ARRAY <> THINGS IN RHSs
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [newRHS_qayxsw] = handleRHSs(RHS,parameters_qayxsw,indexvariable_qayxsw,indexvalue_qayxsw,eval_qayxsw)
+    newRHS_qayxsw = RHS;
+    % Get all the elements in <> and evaluate them
+    elements_qayxsw = unique(regexp(newRHS_qayxsw,'<[^<>]+>','match'));
+    % Define all model parameters locally in this function
+    for k_qayxsw=1:length(parameters_qayxsw),
+        eval(sprintf('%s = %g;',parameters_qayxsw(k_qayxsw).name,parameters_qayxsw(k_qayxsw).value));
+    end
+    % Handle and define indexvariable
+    if ~isempty(indexvariable_qayxsw),
+        % Check if indexvariable already exists (in the model) ... would be an error
+        errorIndexvariable_qayxsw = 0;
+        try 
+            eval(indexvariable_qayxsw);
+            errorIndexvariable_qayxsw = 1;
+        catch
+        end
+        if errorIndexvariable_qayxsw,
+            error('The index variable ''%s'' is defined as model parameter. This is not allowed.',indexvariable_qayxsw);
+        end
+        % Define the index variable
+        eval(sprintf('%s = %d;',indexvariable_qayxsw,indexvalue_qayxsw));
+    end
+    % Evaluate the contents of the brackets (they are indices for the array)
+    elements_values_qayxsw = [];
+    for k_qayxsw=1:length(elements_qayxsw),
+        elements_values_qayxsw(k_qayxsw) = eval(sprintf('%s;',elements_qayxsw{k_qayxsw}(2:end-1)));
+    end
+    % Replace the brackets with the values
+    for k_qayxsw=1:length(elements_qayxsw),
+        if elements_values_qayxsw(k_qayxsw) >= 0,
+            newRHS_qayxsw = strrep(newRHS_qayxsw,elements_qayxsw{k_qayxsw},sprintf('%d',elements_values_qayxsw(k_qayxsw)));
+        else
+            newRHS_qayxsw = strrep(newRHS_qayxsw,elements_qayxsw{k_qayxsw},sprintf('_%d',abs(elements_values_qayxsw(k_qayxsw))));
+        end
+    end    
+    % Replace the indexvariable in a second step
+    if ~isempty(indexvariable_qayxsw),
+        regsearch_qayxsw = ['\<' indexvariable_qayxsw '\>'];
+        newRHS_qayxsw = regexprep(newRHS_qayxsw,regsearch_qayxsw,num2str(indexvalue_qayxsw));
+    end
+    % Evaluate the RHS is desired
+    if length(eval_qayxsw) == 4,  % ('eval')
+        try
+            newRHS_qayxsw = eval(newRHS_qayxsw);
+        catch
+            error('Error evaluating the RHS (needs to lead to a numeric value): ''%s''',newRHS_qayxsw);
+        end
+    end
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/text2IQMmodel/convertTextBCToModelIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/text2IQMmodel/convertTextBCToModelIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..e7f0b4a5f912030a05a8fbd64c6a71c385463d06
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/text2IQMmodel/convertTextBCToModelIQM.m	
@@ -0,0 +1,1095 @@
+function [IQMstructure,errorMsg] = convertTextBCToModelIQM(modelTextBC)
+% convertTextBCToModelIQM: Converts a biochemiccaly oriented text description 
+% of an IQMmodel to the internal data structure representation.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+% initialize variables
+errorMsg = '';
+errorFunctions = '';
+errorStates = '';
+errorParameters = '';
+errorVariables = '';
+errorReactions = '';
+errorEvents = '';
+
+IQMstructure = struct(IQMmodel());
+
+% cut text into pieces
+modelTextBCStructure = getPartsFromCompleteTextBCIQM(modelTextBC);
+
+% First the standard parts are parsed and put into the model structure.
+% This means: name, notes, functions, parameters, events, and MATLAB functions
+% State information and reactions need to be considered together and need
+% the information about parameters and variables to handle boundary
+% species, constant species, etc.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%% Name
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+IQMstructure.name = removeCharacters(modelTextBCStructure.name);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%% Notes
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+IQMstructure.notes = strtrim(removeCharacters2(modelTextBCStructure.notes));
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%% Functions
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try
+    [IQMfunctions, errorFunctions] = getFunctions(modelTextBCStructure.functions);
+catch
+    error('%sPlease check the syntax of the ''Functions'' definitions.\n',errorMsg);
+end
+if ~isempty(errorFunctions),
+    errorMsg = sprintf('%s%s\n',errorMsg,errorFunctions);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%% Parameters
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try
+    [IQMparameters, errorParameters] = getParameters(modelTextBCStructure.parameters);
+catch
+    error('%sPlease check the syntax of the ''Parameter'' definitions (No "=" characters allowed in comment).\n',errorMsg);
+end
+if ~isempty(errorParameters),
+    errorMsg = sprintf('%s%s\n',errorMsg,errorParameters);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%% Variables
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try
+    [IQMvariables, errorVariables] = getVariables(modelTextBCStructure.variables);
+catch
+    error('%sPlease check the syntax of the ''Variables'' definitions.\n',errorMsg);
+end
+if ~isempty(errorVariables),
+    errorMsg = sprintf('%s%s\n',errorMsg,errorVariables);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%% Events
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try
+    [IQMevents, errorEvents] = getEvents(modelTextBCStructure.events);
+catch
+    error('%sPlease check the syntax of the ''Events'' definitions.\n',errorMsg);
+end
+if ~isempty(errorEvents),
+    errorMsg = sprintf('%s%s\n',errorMsg,errorEvents);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%% MATLAB functions
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+IQMfunctionsMATLAB = modelTextBCStructure.functionsMATLAB;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PARSING OF REACTIONS 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% parse reaction expressions and make a list of all species and reaction
+% information to be used to construct the ODEs
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% 1) parse reaction expressions, use ':' as indicator of reactions. this
+% means then that ':' is not allowed in any comment
+% use vf= and vr= for indicators of reaction rate expressions
+reactions = modelTextBCStructure.reactions;
+IQMreactions = struct('name',{},'formula',{},'notes',{},'reversible',{},'fast',{});
+% get the starting indices for the reactions by finding the index
+% of the last '\n' before the ':' for each reaction
+reactionsStart = [];
+temp = strfind(reactions,':');
+for k = 1:length(temp),
+    % add a line break in the beginning since the first reaction might
+    % not have one in front of it
+    temp2 = [10 double(reactions(1:temp(k)))];
+    temp3 = find(temp2==10);
+    reactionsStart = [reactionsStart temp3(end)];
+end
+
+% run through the reactions and process them (+1 since endindex = end-1)
+% make a structure with all reaction information
+% additionally determine a list of all species in the model
+allReactions = [];
+allReactions.name = [];
+allReactions.substratenames = [];
+allReactions.substratefactors = [];
+allReactions.productnames = [];
+allReactions.productfactors = [];
+allSpecies = {};
+numberReactions = 1;
+reactionsStart = [reactionsStart length(reactions)+1];
+for k = 1:length(reactionsStart)-1,
+    reactionString = reactions(reactionsStart(k):reactionsStart(k+1)-1);
+    % check and get notes
+    indexCommentSign = strfind(reactionString,'%');
+    if isempty(indexCommentSign),
+        reactionComment = '';
+    elseif length(indexCommentSign) > 1,
+        errorMsg = sprintf('%s\nSyntax error in a reaction equation.\nThe ''%%'' sign is only allowed once to separate the comment.',errorMsg);
+    else
+        x = double(reactionString);
+        indexCommentEnd = find(x==10);
+        reactionComment = strtrim(reactionString(indexCommentSign+1:indexCommentEnd(1)-1));
+        reactionString = [reactionString(1:indexCommentSign-1) reactionString(indexCommentEnd(1):end)];
+    end
+    reactionString = removeCharacters(reactionString);
+    % check fast flag
+    temp = strfind(lower(reactionString),'{fast}');
+    if ~isempty(temp),
+        % fast identifier is present - take it away and 
+        % set the flag to one, otherwise leave the expression untouched and
+        % set it to 0
+        reactionString = strrep(reactionString,'{fast}','');
+        fastFlag = 1;
+    else
+        fastFlag = 0;
+    end    
+    % check location of separator ':'
+    indexSeparator = strfind(reactionString,':');
+    if isempty(indexSeparator), 
+        errorMsg = sprintf('%s\nSyntax error in reaction equation #%d (or one earlier).\nThe char '':'' is only allowed as name separator! Not within a comment!',errorMsg, k);
+    end
+    % check start of forward rate
+    indexForwardRate = strfind(reactionString,'vf=');
+    % check start of reverse rate
+    indexReverseRate = strfind(reactionString,'vr=');
+    % check if '<=>' is present
+    indexReversibleIdentifier = strfind(reactionString,'<=>');
+    % check if '=>' is present (only if '<=>' is not present)
+    if isempty(indexReversibleIdentifier),
+        indexIrreversibleIdentifier = strfind(reactionString,'=>');
+    else 
+        indexIrreversibleIdentifier = [];
+    end
+    % get reaction equation
+    reactionEquation = reactionString(1:indexSeparator-1);
+    % do a bit of syntax check
+    if length(indexForwardRate) > 1 || length(indexReverseRate) > 1,
+        errorMsg = sprintf('%s\nSyntax error in reaction equation #%d.\nAt least one reaction name is not defined. Or you might have written ''vf='' twice for a reaction:\n%s',errorMsg,k,reactionString);
+    end
+    if ~isempty(indexForwardRate) && ~isempty(indexReverseRate) && ~isempty(indexIrreversibleIdentifier),
+        errorMsg = sprintf('%s\nSyntax error in reaction equation #%d.\nDefined as irreversible but forward and reverse rate are defined.\n%s',errorMsg,k,reactionString);
+    end
+    if (isempty(indexForwardRate) || isempty(indexReverseRate)) && ~isempty(indexReversibleIdentifier),
+        errorMsg = sprintf('%s\nSyntax error in reaction equation #%d.\nDefined as reversible but at least one rate is missing.\n%s',errorMsg,k,reactionString);
+    end
+    if isempty(indexForwardRate) && isempty(indexReverseRate),
+        errorMsg = sprintf('%s\nSyntax error in reaction equation #%d.\nNo rates are defined.\n%s',errorMsg,k,reactionString);
+    end
+    if isempty(indexForwardRate) && ~isempty(indexReverseRate),
+        errorMsg = sprintf('%s\nSyntax error in reaction equation #%d.\nOnly a reverse rate is defined.\n%s',errorMsg,k,reactionString);
+    end
+    if indexForwardRate > indexReverseRate,
+       errorMsg = sprintf('%s\nSyntax error in reaction equation #%d.\nForward rate has to be defined before reverse rate.\n%s',errorMsg,k,reactionString);
+    end 
+    % get the reaction name
+    reactionName = reactionString(indexSeparator+1:indexForwardRate-1);
+    % check reaction name
+    if isempty(reactionName),
+        errorMsg = sprintf('%s\nSyntax error in reaction #%d.\nNor reaction name specified.\n%s',errorMsg,k,reactionString);
+    end
+    % get the forward rate and eventually also the reverse rate
+    if isempty(indexReverseRate),
+        reactionForwardRate = reactionString(indexForwardRate+3:end);
+        reactionReverseRate = '';
+        if isempty(reactionForwardRate),
+            errorMsg = sprintf('%s\nNo forward reaction rate defined for reaction ''%s''',errorMsg,reactionName);
+        end
+    else
+        reactionForwardRate = reactionString(indexForwardRate+3:indexReverseRate-1);
+        reactionReverseRate = reactionString(indexReverseRate+3:end);
+        if isempty(reactionForwardRate),
+            errorMsg = sprintf('%s\nNo forward reaction rate defined for reaction ''%s''',errorMsg,reactionName);
+        end
+        if isempty(reactionReverseRate),
+            errorMsg = sprintf('%s\nNo reverse reaction rate defined for reaction ''%s''',errorMsg,reactionName);
+        end
+    end
+    % parse reaction equation
+    if ~isempty(indexReversibleIdentifier),
+        substratePart = reactionEquation(1:indexReversibleIdentifier-1);
+        productPart = reactionEquation(indexReversibleIdentifier+3:end);
+    else
+        substratePart = reactionEquation(1:indexIrreversibleIdentifier-1);
+        productPart = reactionEquation(indexIrreversibleIdentifier+2:end);
+    end
+    % define reversible flag
+    reactionReversible = ~isempty(reactionReverseRate);
+    % parse the substrate and product parts
+    try
+        substrateTerms = getReactionTerms(substratePart);
+        productTerms = getReactionTerms(productPart);
+    catch
+        errorMsg = sprintf('%sPlease check the syntax of the reaction ''%s''.\n',errorMsg,reactionName);
+    end
+    % add all information into the reaction structure
+    allReactions(numberReactions).name = reactionName;
+    allReactions(numberReactions).substratenames = substrateTerms.names;
+    allReactions(numberReactions).substratefactors = substrateTerms.factors;
+    allReactions(numberReactions).productnames = productTerms.names;
+    allReactions(numberReactions).productfactors = productTerms.factors;
+    numberReactions = numberReactions + 1;
+    % add products and species to allSpecies list (unique entries)
+    allSpecies = unique({allSpecies{:} substrateTerms.names{:} productTerms.names{:}});
+    % add reaction to model structure
+    IQMreactions(k).name = reactionName;
+    if reactionReversible,
+        IQMreactions(k).formula = strcat(reactionForwardRate,'- (',reactionReverseRate,')');
+        IQMreactions(k).reversible = 1;
+    else
+        IQMreactions(k).formula = reactionForwardRate;
+        IQMreactions(k).reversible = 0;
+    end
+    IQMreactions(k).notes = reactionComment;
+    IQMreactions(k).fast = fastFlag;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PARSING OF STATE INFORMATION AND CONSTRUCTING STATES AND ODES
+% ALSO TAKE CARE OF DIFFERENTIAL EQUATIONS THAT ARE DEFINED IN THE TEXT!!!
+% Additionally, handle algebraic rules
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% 2) check the list of species against variables and parameters to
+%    determine the states. 
+% 4) check unittypes ........ BIG THING!!!
+% define the state substructure
+IQMstates = struct('name',{},'initialCondition',{},'ODE',{},'type',{},'compartment',{},'unittype',{},'notes',{});
+IQMalgebraic = struct('name',{},'formula',{},'initialCondition',{},'type',{},'compartment',{},'unittype',{},'notes',{});
+% run through allSpecies and check which ones are defined by variables or
+% parameters. 
+allSpeciesStates = {};
+for k = 1:length(allSpecies),
+    if ~isempty(allSpecies{k}),
+        parameterIndex = strmatchIQM(allSpecies{k},{IQMparameters.name},'exact');
+        variableIndex = strmatchIQM(allSpecies{k},{IQMvariables.name},'exact');
+        if isempty(parameterIndex) && isempty(variableIndex) && ~isempty(allSpecies{k}),
+            allSpeciesStates{end+1} = allSpecies{k};
+        end
+    end
+end
+% now add all species that are states to the structure. add default initial
+% condition, add ODE, default notes, default information
+for k = 1:length(allSpeciesStates),
+    IQMstates(k).name = allSpeciesStates{k};
+    IQMstates(k).initialCondition = 0;
+    IQMstates(k).ODE = '';
+    IQMstates(k).type = '';          % default: empty
+    IQMstates(k).compartment = '';   % default: empty
+    IQMstates(k).unittype = '';      % default: empty
+    IQMstates(k).notes = '';
+end
+% now run throught the reaction structure and update the state informations (ODE)
+for k1 = 1:length(allReactions),
+    reactionname = allReactions(k1).name;
+    substratenames = allReactions(k1).substratenames;
+    substratefactors = allReactions(k1).substratefactors;
+    productnames = allReactions(k1).productnames;
+    productfactors = allReactions(k1).productfactors;
+    % go through all substrate names
+    for k2 = 1:length(substratenames),
+        substrate = substratenames{k2};
+        % find substrate in species states structure
+        stateIndex = strmatchIQM(substrate,{IQMstates.name},'exact');
+        % add reaction name to state ODE if substrate found
+        if ~isempty(stateIndex),
+            if substratefactors(k2) == 1,
+                IQMstates(stateIndex).ODE = strcat(IQMstates(stateIndex).ODE,'-',reactionname);
+            else
+                IQMstates(stateIndex).ODE = strcat(IQMstates(stateIndex).ODE,'-',num2str(substratefactors(k2)),'*',reactionname);
+            end
+        end
+    end
+    % go through all product names
+    for k2 = 1:length(productnames),
+        product = productnames{k2};
+        % find product in species states structure
+        stateIndex = strmatchIQM(product,{IQMstates.name},'exact');
+        % add reaction name to state ODE if substrate found
+        if ~isempty(stateIndex),
+            if productfactors(k2) == 1,
+                IQMstates(stateIndex).ODE = strcat(IQMstates(stateIndex).ODE,'+',reactionname);
+            else
+                IQMstates(stateIndex).ODE = strcat(IQMstates(stateIndex).ODE,'+',num2str(productfactors(k2)),'*',reactionname);
+            end
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PARSE STATE INFORMATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%
+% ODEs are updated now. last thing is to parse the state information in
+% order to update the fields initialCondition, type, compartment, unittype,
+% and notes
+% get the stateinformation text and trim it
+states = strtrim(modelTextBCStructure.states);
+states = char([10 double(states) 10]);
+% START OF THE ODEs
+ODEsStart = strfind(states,'d/dt(');
+% START OF THE ALGEBRAIC RULES
+ARsStart = regexp(states,'\n0')+1;
+% START OF THE INITIAL CONDITIONS
+% (finding the index of the last '\n' before the '(0)' for each initial condition)
+initialConditionsStart = [];
+temp = strfind(states,'(0)');
+for k = 1:length(temp),
+    temp2 = double(states(1:temp(k)));
+    temp3 = find(temp2==10);
+    initialConditionsStart = [initialConditionsStart temp3(end)+1];
+end
+
+%%%%%%%%%%%%%
+% PARSE ODEs
+%%%%%%%%%%%%%
+
+%%%
+stateConstraintInfo = [];
+
+
+% run through the ODEs and process them
+if isempty(ARsStart) && isempty(initialConditionsStart),
+    % if no initial conditions are present then use end of states
+    % string as end index (+1)
+    ODEsStart = [ODEsStart length(states)+1];
+elseif isempty(ARsStart)
+    ODEsStart = [ODEsStart initialConditionsStart(1)];
+else
+    ODEsStart = [ODEsStart ARsStart(1)];
+end
+% process ODEs
+for k = 1:length(ODEsStart)-1,
+    stateString = removeCharacters(states(ODEsStart(k):ODEsStart(k+1)-1));
+    % check if additional information and/or comment is present => error
+    if ~isempty(strfind(stateString,'{')) || ~isempty(strfind(stateString,'%')),
+        errorMsg = sprintf('Additional information and comment should be added behind initial conditions.');
+    end
+    % get name and ODE
+    % extract the state name
+    temp = strfind(stateString,')');
+    test = stateString(6:temp(1)-1);
+    % check if state name given
+    if isempty(test),
+        errorMsg = sprintf('At least on state name in\nODE definition is not given.');
+        return
+    end
+    IQMstates(end+1).name = removeWhiteSpace(test);
+    % extract the state ODE
+    temp = strfind(stateString,'=');
+    test = stateString(temp+1:end);
+    % check if state ODE given
+    if isempty(test),
+        errorMsg = sprintf('At least one RHS of an ODE is not given.');
+        return
+    end
+    % The test string contains now the ODE
+    ODE = removeWhiteSpace(test);
+    IQMstates(end).ODE = ODE;
+    IQMstates(end).notes = '';
+    % add default value for initial condition
+    IQMstates(end).initialCondition = 0;
+    % add information to state
+    IQMstates(end).type = '';
+    IQMstates(end).compartment = '';
+    IQMstates(end).unittype = '';
+end
+
+%%%%%%%%%%%%%
+% PARSE ARs
+%%%%%%%%%%%%%
+if isempty(initialConditionsStart),
+    ARsStart = [ARsStart length(states)+1];
+else
+    ARsStart = [ARsStart initialConditionsStart(1)];
+end
+for k=1:length(ARsStart)-1,
+    % get each single AR
+    ARk = strtrim(states(ARsStart(k):ARsStart(k+1)-1));
+    % separate comment from AR definition
+    index1 = strfind(ARk,'=');
+    index2 = strfind(ARk,'%');
+    if ~isempty(index2),
+        ARformulak = strtrim(ARk(index1(1)+1:index2(1)-1));
+        ARnotek = strtrim(ARk(index2(1)+1:end));
+    else
+        ARformulak = strtrim(ARk(index1(1)+1:end));
+        ARnotek = '';
+    end        
+    % split rhs in formula and variable name
+    terms = explodePCIQM(ARformulak,':');
+    if length(terms) ~= 2,
+        ARformulak = strtrim(terms{1});
+        ARnamek = '';
+        ARick = [];
+    else
+        ARformulak = strtrim(terms{1});
+        ARnamek = strtrim(terms{2});
+        ARick = 0; % default setting (determined by the integrator)
+    end
+    % update structure
+    IQMalgebraic(k).name = ARnamek;
+    IQMalgebraic(k).formula = ARformulak;
+    IQMalgebraic(k).initialCondition = ARick; 
+    IQMalgebraic(end).type = '';
+    IQMalgebraic(end).compartment = '';
+    IQMalgebraic(end).unittype = '';
+    IQMalgebraic(k).notes = ARnotek;
+end
+
+%%%%%%%%%%%%%
+% PARSE ICs
+%%%%%%%%%%%%%
+definedICs4Ordering = {};
+% remove ODEs and ARs from the text
+states = states(initialConditionsStart:end);
+% get the starting indices for the initial conditions by finding the index
+% of the last '\n' before the '(0)' for each initial condition
+statesStart = [];
+temp = strfind(states,'(0)');
+for k = 1:length(temp),
+    temp2 = [10 double(states(1:temp(k)))];
+    temp3 = find(temp2==10);
+    statesStart = [statesStart temp3(end)];
+end
+if ~isempty(statesStart),
+    statesStart = [statesStart length(states)+1];
+end
+% run through each state information and update state structure
+for k1 = 1:length(statesStart)-1,
+    stateText = strtrim(states(statesStart(k1):statesStart(k1+1)-1));
+    
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle possible constraints on state variables in the IQMmodel
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check if constraint information is present on a state. Syntax: {constraints:[min,max]}
+stateConstraints = {};
+infoStartConstraints = strfind(stateText,'{constraints:');
+if ~isempty(infoStartConstraints),
+    % find the end of the constraint information
+    offset = 11; po = 1;
+    while 1,
+        if stateText(infoStartConstraints+offset) == '}',
+            break;
+        end
+        offset = offset + 1;
+    end
+    constraintsString = stateText(infoStartConstraints:infoStartConstraints+offset);
+    % remove constraint information from stateString
+    stateText = stateText([1:infoStartConstraints-1 infoStartConstraints+offset+1:end]);
+    % parse the constraints string
+    constraintsString = strrep(constraintsString,' ',''); % remove spaces
+    constraintsString = constraintsString(15:end-2);
+    stateConstraints = explodePCIQM(constraintsString,',');
+    if length(stateConstraints) ~= 2,
+        error('A state-constraint information seems to be wrongly defined');
+    end
+    % convert numeric bounds to numbers
+    for k2=1:2,
+        try
+            temp = eval(stateConstraints{k2});
+            stateConstraints{k2} = temp;
+        catch
+        end
+    end
+end    
+    
+    % find index of '(0)'
+    indexIdentifier = strfind(stateText,'(0)');
+    % find '='
+    indexEqualSign = strfind(stateText,'=');
+    % find start of additional information
+    indexInfoStart = strfind(stateText,'{');
+    % find end of additional information
+    indexInfoEnd = strfind(stateText,'}');
+    % find comment start
+    indexComment = strfind(stateText,'%');
+    % get the state name
+    stateName = stateText(1:indexIdentifier(1)-1);
+    % Save the stateName in the "definedICs4Ordering" list
+    definedICs4Ordering{end+1} = stateName;
+    % do some error checking
+    if (isempty(indexInfoStart) && ~isempty(indexInfoEnd)) || (isempty(indexInfoStart) && ~isempty(indexInfoEnd)),
+        errorMsg = sprintf('%s\nSyntax error in state information for state ''%s''.',errorMsg,stateName);
+    end
+    % get all the pieces
+    stateComment = '';
+    if isempty(indexInfoStart) && isempty(indexComment),
+        stateICx = (stateText(indexEqualSign(1)+1:end));
+        stateInfo = '';
+        stateComment = '';
+    elseif isempty(indexInfoStart) && ~isempty(indexComment),
+        stateICx = (stateText(indexEqualSign(1)+1:indexComment(1)-1));
+        stateInfo = '';
+        stateComment = stateText(indexComment(1)+1:end);
+    elseif ~isempty(indexInfoStart) && isempty(indexComment),
+        stateICx = (stateText(indexEqualSign(1)+1:indexInfoStart(1)-1));
+        stateInfo = stateText(indexInfoStart+1:indexInfoEnd-1);
+        stateComment = '';
+    elseif ~isempty(indexInfoStart) && ~isempty(indexComment),
+        stateICx = (stateText(indexEqualSign(1)+1:indexInfoStart(1)-1));
+        stateInfo = stateText(indexInfoStart+1:indexInfoEnd-1);
+        stateComment = stateText(indexComment+1:end);
+    end
+    stateIC = str2double(stateICx);
+    if isnan(stateIC),
+%         disp(sprintf('At least one initial condition has a non-numerical value assigned.\nThis might lead to problems with certain toolbox functions.'));
+        stateIC = strtrim(stateICx);
+    end
+    % process state information
+    type = '';
+    compartment = '';
+    unittype = '';
+    % Handle additional information for species states
+    if ~isempty(strmatchIQM(stateName,allSpeciesStates)),
+        if ~isempty(stateInfo),
+            terms = explodePCIQM(stateInfo,':');
+            if length(terms) ~= 3,
+                errorMsg = sprintf('%s\nError in a state information.',errorMsg);
+            elseif strcmpi(terms{1},'isspecie'),
+                type = terms{1};
+                compartment = terms{2};
+                unittype = terms{3};
+            else
+                errorMsg = sprintf('%s\nError in a state information.',errorMsg);
+            end
+        end
+    else
+        % handle additional information for ODE state
+        if ~isempty(stateInfo),
+            % explode the information text with ':'
+            terms = explodePCIQM(stateInfo,':');
+            if length(terms) == 1 && ~isempty(strfind(lower(terms{1}),'parameter')),
+                type = strtrim(terms{1});
+                compartment = '';
+                unittype = '';
+            elseif length(terms) == 2 && ~isempty(strfind(lower(terms{1}),'compartment')),
+                type = strtrim(terms{1});
+                compartment = strtrim(terms{2});
+                unittype = '';
+            elseif length(terms) == 3 && ~isempty(strfind(lower(terms{1}),'specie')),
+                type = strtrim(terms{1});
+                compartment = strtrim(terms{2});
+                unittype = strtrim(terms{3});
+            else
+                errorMsg = 'Error in a state information';
+                return
+            end
+        end
+    end
+    % update state structure with state information
+    % state or algebraic variable !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+    % first find the index of the state where to add it to
+    stateIndex = strmatchIQM(stateName,{IQMstates.name},'exact');
+    if ~isempty(stateIndex),
+        IQMstates(stateIndex).initialCondition = stateIC;
+        IQMstates(stateIndex).notes = stateComment;
+        if ~isempty(type),
+            IQMstates(stateIndex).type = type;
+        end
+        IQMstates(stateIndex).compartment = compartment;
+        if ~isempty(unittype),
+            IQMstates(stateIndex).unittype = unittype;
+        end
+        
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle possible constraints on state variables in the IQMmodel
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%    
+if ~isempty(stateConstraints),
+    % ok, state constraints have been defined for this state
+    % save some information to be able to add it later to the model
+    stateConstraintInfo(end+1).statename = stateName;
+    stateConstraintInfo(end).stateindex = stateIndex;
+    stateConstraintInfo(end).lowbound = stateConstraints{1};
+    stateConstraintInfo(end).highbound = stateConstraints{2};
+    stateConstraintInfo(end).ODE = IQMstates(stateIndex).ODE;
+end
+    else
+        % if not state found then it should be an algebraic variable!
+        algebraicIndex = strmatchIQM(stateName,{IQMalgebraic.name},'exact');
+        if ~isempty(algebraicIndex),
+            IQMalgebraic(algebraicIndex).initialCondition = stateIC;
+            IQMalgebraic(algebraicIndex).notes = stateComment;
+            if ~isempty(type),
+                IQMalgebraic(algebraicIndex).type = type;
+            end
+            IQMalgebraic(algebraicIndex).compartment = compartment;
+            if ~isempty(unittype),
+                IQMalgebraic(algebraicIndex).unittype = unittype;
+            end
+        else
+            errorMsg = sprintf('An initial condition is defined for which not state exists: ''%s''',stateName);
+            return
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CORRECT ODES WITH COMPARTMENT INFORMATION TO CONVERT RATE TYPES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for k = 1:length(IQMstates),
+    type = IQMstates(k).type;
+    compartment = IQMstates(k).compartment;
+    unittype = IQMstates(k).unittype;
+    % check if state is a specie and compartment given and in concentration
+    if strcmp(lower(type),'isspecie') && ~isempty(compartment) && strcmp(lower(unittype),'concentration'),
+        addCompartmentText = strcat('/',compartment);
+        IQMstates(k).ODE = strcat('(',IQMstates(k).ODE,')',addCompartmentText);
+    end
+end
+
+% Combining the parts of the IQMmodel structure (name and notes are already
+% added)
+IQMstructure.functions = IQMfunctions;
+IQMstructure.states = IQMstates;
+IQMstructure.algebraic = IQMalgebraic;
+IQMstructure.parameters = IQMparameters;
+IQMstructure.variables = IQMvariables;
+IQMstructure.reactions = IQMreactions;
+IQMstructure.events = IQMevents;
+IQMstructure.functionsMATLAB = IQMfunctionsMATLAB;
+
+% Finally we need to reorder the states in the order given by the list of
+% initial conditions in the model. Non defined initial conditions come
+% first, followed by the ones defined in the same order ... this is
+% important only for the handling of non-numeric ICs.
+allStateNames = {IQMstructure.states.name};
+orderedStateNames = definedICs4Ordering;
+% get the indices of the ordered states in the current structure
+currentIndex = [];
+for k=1:length(orderedStateNames),
+    currentIndex(end+1) = strmatchIQM(orderedStateNames{k},allStateNames,'exact');
+end
+% get permutation vector
+allIndex = [1:length(allStateNames)];
+notOrder = setdiff(allIndex,currentIndex);
+permutvec = [notOrder currentIndex];
+% do permutation
+IQMstructure.states(1:length(allIndex)) = IQMstructure.states(permutvec);
+% It's done ... enjoy!
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%% State Constraints
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% First, since states can have been reordered we need to get the correct
+% indices in the stateConstraintInfo stucture:
+for k=1:length(stateConstraintInfo),
+    sname = stateConstraintInfo(k).statename;
+    stateConstraintInfo(k).stateindex = strmatchIQM(sname,{IQMstructure.states.name},'exact');
+end
+% Handle possible constraints on state variables in the IQMmodel:
+% add the needed piecewise expressions and the factors on the ODEs
+% as last reactions in the model. We need to add it as reactions in order
+% to evaluate these as last elements before evaluating the ODEs.
+for k=1:length(stateConstraintInfo),
+    statename = stateConstraintInfo(k).statename;
+    stateindex = stateConstraintInfo(k).stateindex;
+    lowbound = stateConstraintInfo(k).lowbound;
+    highbound = stateConstraintInfo(k).highbound;
+    ODE = stateConstraintInfo(k).ODE;
+    % add a factor "constraints_factor_statename" to the ODE for the state
+    IQMstructure.states(stateindex).ODE = ['constraints_factor_' statename ' * (' ODE ')'];
+    % define the "constraints_factor_statename" in the reactions
+    IQMstructure.reactions(end+1).name = ['constraints_factor_' statename];
+    % construct the piecewise expression
+    if ~checkboundIsInf(lowbound) && ~checkboundIsInf(highbound),
+        pwtext = sprintf('piecewiseIQM(0,orIQM(andIQM(ge(%s,%s),gt(%s,0)),andIQM(le(%s,%s),lt(%s,0))),1)',statename,num2str(highbound,20),ODE,statename,num2str(lowbound,20),ODE);
+    elseif checkboundIsInf(lowbound) && ~checkboundIsInf(highbound),
+        pwtext = sprintf('piecewiseIQM(0,andIQM(ge(%s,%s),gt(%s,0)),1)',statename,num2str(highbound,20),ODE);
+    elseif checkboundIsInf(lowbound) && ~checkboundIsInf(highbound),
+        pwtext = sprintf('piecewiseIQM(0,andIQM(le(%s,%s),lt(%s,0)),1)',statename,num2str(lowbound,20),ODE);
+    else
+        pwtext = '1'; % always unconstrained
+    end
+    % add the piecewise expression as last reaction and do the rest
+    IQMstructure.reactions(end).formula = pwtext;
+    IQMstructure.reactions(end).notes = sprintf('Implementation of constraints on state %s',statename);
+    IQMstructure.reactions(end).reversible = 0;
+    IQMstructure.reactions(end).fast = 0;
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [output] = checkboundIsInf(bound)
+if ischar(bound),
+    output = 0;
+    return
+end
+if isnumeric(bound),
+    output = isinf(bound);
+    return
+end
+error('Problem with constraints - bound definition.');
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET SPECIES AND STOICHIOMETRIC COEFFICIENTS FROM REACTION PARTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [reactionterms,errorMsg] = getReactionTerms(reactionPart,errorMsg)
+% explode the substrate and product parts into species and
+% stoichiometric coefficients
+% expect the terms to be of the format:
+% factor*species + factor*species + ...
+allTerms = explodePCIQM(reactionPart,'+');
+% check the syntax of the single terms (name or numeric*name)
+reactionterms = [];
+reactionterms.names = {};
+reactionterms.factors = [];
+for k = 1:length(allTerms),
+    checkTerms = explodePCIQM(allTerms{k},'*');
+    % only accept lengths 1 or 2 (possibly with or without
+    % factor) otherwise error
+    if length(checkTerms) == 1,
+        reactionterms.names{end+1} = checkTerms{1};
+        reactionterms.factors(end+1) = 1;
+    elseif length(checkTerms) == 2 && ~isnan(str2double(checkTerms{1})),
+        % first term needs to be numeric
+        reactionterms.names{end+1} = checkTerms{2};
+        reactionterms.factors(end+1) = str2double(checkTerms{1});
+    else
+        errorMsg = sprintf('Syntax error in a reaction equation.');
+    end
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [IQMparameters, error] = getParameters(parameters)
+error = '';
+%    parameters = removeWhiteSpace(parameters);
+IQMparameters = struct('name',{},'value',{},'type',{},'compartment',{},'unittype',{},'notes',{});
+
+% get the starting indices for the parameters by finding the index
+% of the last '\n' before the '=' for each parameter
+parametersStart = regexp([10 parameters],['\n[^\n=]*=']);
+% run through the parameters and process them (+1 since endindex = end-1)
+parametersStart = [parametersStart length(parameters)+1];
+
+parNAN = 0;
+for k = 1:length(parametersStart)-1,
+%    parameterString = removeCharacters(parameters(parametersStart(k):parametersStart(k+1)-1));
+    parameterString = strtrim(parameters(parametersStart(k):parametersStart(k+1)-1));
+    % check if additional information is present ... if yes, cut it out
+    infoStart = strfind(parameterString,'{');
+    infoEnd = strfind(parameterString,'}');
+    informationText = '';
+    if length(infoStart) + length(infoEnd) > 2,
+        error = 'To many square parentheses in a parameter definition';
+        return
+    end
+    if length(infoStart) ~= length(infoEnd),
+        error = 'At least one parameter information not properly defined';
+        return
+    end
+    if length(infoStart) == 1,
+        informationText = parameterString(infoStart+1:infoEnd-1);
+        parameterString = parameterString([1:infoStart-1, infoEnd+1:end]);
+    end
+    if ~isempty(informationText),
+        % explode the information text with ':'
+        terms = explodePCIQM(informationText,':');
+        if length(terms) == 1 && ~isempty(strfind(lower(terms{1}),'parameter')),
+            type = strtrim(terms{1});
+            compartment = '';
+            unittype = '';
+        elseif length(terms) == 2 && ~isempty(strfind(lower(terms{1}),'compartment')),
+            type = strtrim(terms{1});
+            compartment = strtrim(terms{2});
+            unittype = '';
+        elseif length(terms) == 3 && ~isempty(strfind(lower(terms{1}),'specie')),
+            type = strtrim(terms{1});
+            compartment = strtrim(terms{2});
+            unittype = strtrim(terms{3});
+        else
+            error = sprintf('Error in a parameter information (Do not use ''{'' and/or ''}'' in state, parameter or variable comments).');
+            return           
+        end
+    else 
+        type = '';
+        compartment = '';
+        unittype = '';
+    end
+    % extract the parameter name
+    temp = strfind(parameterString,'=');
+    test = parameterString(1:temp(1)-1);
+    % check if parameter name given
+    if isempty(test),
+        error = sprintf('At least one parameter name not given.');
+        return
+    end
+    IQMparameters(k).name = removeWhiteSpace(test);
+    % extract the parameter value
+    % check if it has a numerical value
+    test = parameterString(temp+1:end);
+    % The test string contains now the parameter value and eventually also a
+    % comment that should be written into notes.
+    % check if a comment is present
+    temp = strfind(test,'%');
+    if ~isempty(temp),
+        value = str2double(removeWhiteSpace(test(1:temp(1)-1)));
+        notes = strtrim(test(temp(1)+1:end));
+    else
+        value = str2double(removeWhiteSpace(test));
+        notes = '';
+    end
+    if isnan(value),
+        % initial condition was not a numerical value
+        parNAN = 1;
+    else
+        IQMparameters(k).value = value;
+    end
+    % add default notes to parameter
+    IQMparameters(k).notes = notes;
+    % add information to parameter
+    IQMparameters(k).type = type;
+    IQMparameters(k).compartment = compartment;
+    IQMparameters(k).unittype = unittype;
+end
+if parNAN,
+    error = sprintf('At least one parameter has a\nnon-numerical value assigned');
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [IQMvariables, error] = getVariables(variables)
+error = '';
+IQMvariables = struct('name',{},'formula',{},'type',{},'compartment',{},'unittype',{},'notes',{});
+
+% get the starting indices for the variables by finding the index
+% of the last '\n' before the '=' for each variable
+variablesStart = regexp([10 variables],['\n[^\n=]*=']);
+% run through the variables and process them (+1 since endindex = end-1)
+variablesStart = [variablesStart length(variables)+1];
+
+for k = 1:length(variablesStart)-1,
+%     variableString = removeCharacters(variables(variablesStart(k):variablesStart(k+1)-1));
+    variableString = strtrim(variables(variablesStart(k):variablesStart(k+1)-1));
+    % check if additional information is present ... if yes, cut it out
+    infoStart = strfind(variableString,'{');
+    infoEnd = strfind(variableString,'}');
+    informationText = '';
+    if length(infoStart) + length(infoEnd) > 2,
+        error = 'To many square parentheses in a variable definition';
+        return
+    end
+    if length(infoStart) ~= length(infoEnd),
+        error = 'At least one variable information not properly defined';
+        return
+    end
+    if length(infoStart) == 1,
+        informationText = variableString(infoStart+1:infoEnd-1);
+        variableString = variableString([1:infoStart-1, infoEnd+1:end]);
+    end
+    if ~isempty(informationText),
+        % explode the information text with ':'
+        terms = explodePCIQM(informationText,':');
+        if length(terms) == 1 && ~isempty(strfind(lower(terms{1}),'parameter')),
+            type = strtrim(terms{1});
+            compartment = '';
+            unittype = '';
+        elseif length(terms) == 2 && ~isempty(strfind(lower(terms{1}),'compartment')),
+            type = strtrim(terms{1});
+            compartment = strtrim(terms{2});
+            unittype = '';
+        elseif length(terms) == 3 && ~isempty(strfind(lower(terms{1}),'specie')),
+            type = strtrim(terms{1});
+            compartment = strtrim(terms{2});
+            unittype = strtrim(terms{3});
+        else
+            error = 'Error in a variable information';
+            return           
+        end
+    else 
+        type = '';
+        compartment = '';
+        unittype = '';
+    end
+    % extract the variable name
+    temp = strfind(variableString,'=');
+    test = variableString(1:temp(1)-1);
+    % check if variable name given
+    if isempty(test),
+        error = sprintf('At least one variable name not given.');
+        return
+    end
+    IQMvariables(k).name = removeWhiteSpace(test);
+    % extract the variable value
+    test = variableString(temp+1:end);
+    % The test string contains now the variable expression and
+    % eventually also a comment that should be written into notes.
+    % check if a comment is present
+    temp = strfind(test,'%');
+    if ~isempty(temp),
+        formula = removeWhiteSpace(test(1:temp(1)-1));
+        notes = strtrim(test(temp(1)+1:end));
+    else
+        formula = removeWhiteSpace(test);
+        notes = '';
+    end
+    % check if variable expression given
+    if isempty(formula),
+        error = sprintf('At least one variable definition not given.');
+        return
+    end
+    IQMvariables(k).formula = formula;
+    % add default notes to variable
+    IQMvariables(k).notes = notes;
+    % add information to parameter
+    IQMvariables(k).type = type;
+    IQMvariables(k).compartment = compartment;
+    IQMvariables(k).unittype = unittype;    
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [IQMfunctions, error] = getFunctions(functions)
+error = '';
+%    functions = removeWhiteSpace(functions);
+IQMfunctions = struct('name',{},'arguments',{},'formula',{},'notes',{});
+
+% get the starting indices for the functions by finding the index
+% of the last '\n' before the '=' for each function
+functionsStart = regexp([10 functions],['\n[^\n=]*=']);
+% run through the functions and process them (+1 since endindex = end-1)
+functionsStart = [functionsStart length(functions)+1];
+
+for k = 1:length(functionsStart)-1,
+%    functionString = removeCharacters(functions(functionsStart(k):functionsStart(k+1)-1));
+    functionString = strtrim(functions(functionsStart(k):functionsStart(k+1)-1));
+    % extract the function name
+    temp = strfind(functionString,'(');
+    test = functionString(1:temp(1)-1);
+    % check if function name given
+    if isempty(test),
+        error = sprintf('At least one function name not given.');
+        return
+    end
+    IQMfunctions(k).name = removeWhiteSpace(test);
+    % extract the arguments
+    temp2 = strfind(functionString,')');
+    test = functionString(temp+1:temp2-1);
+    % check if function arguments given
+    if isempty(test),
+        error = sprintf('At least for one function no arguments given.');
+        return
+    end
+    IQMfunctions(k).arguments = removeWhiteSpace(test);
+    % extract the formula
+    temp3 = strfind(functionString,'=');
+    test = functionString(temp3+1:end);
+    % The test string contains now the formula and
+    % eventually also a comment that should be written into notes.
+    % check if a comment is present
+    temp = strfind(test,'%');
+    if ~isempty(temp),
+        formula = removeWhiteSpace(test(1:temp(1)-1));
+        notes = strtrim(test(temp(1)+1:end));
+    else
+        formula = removeWhiteSpace(test);
+        notes = '';
+    end
+    % check if function formula given
+    if isempty(formula),
+        error = sprintf('At least for one function no formula given.');
+        return
+    end
+    IQMfunctions(k).formula = formula;
+    % add default notes to function
+    IQMfunctions(k).notes = notes;
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [IQMevents, error] = getEvents(events)
+error = '';
+% event substructure
+eventassignmentStruct = struct('variable',{},'formula',{});
+IQMevents = struct('name',{},'trigger',{},'assignment',eventassignmentStruct,'notes',{});
+
+% get the starting indices for the events by finding the index
+% of the last '\n' before the '=' for each event
+eventsStart = regexp([10 events],['\n[^\n=]*=']);
+% run through the events and process them (+1 since endindex = end-1)
+eventsStart = [eventsStart length(events)+1];
+
+for k = 1:length(eventsStart)-1,
+%     eventString = removeCharacters(events(eventsStart(k):eventsStart(k+1)-1));
+    eventString = strtrim(events(eventsStart(k):eventsStart(k+1)-1));
+    % check if comment present
+    startNotes = strfind(eventString,'%');
+    notes = '';
+    if ~isempty(startNotes),
+        notes = eventString(startNotes(1)+1:end);
+        eventString = eventString(1:startNotes(1)-1);
+    end
+    IQMevents(k).notes = notes;
+    % extract the event name
+    temp = strfind(eventString,'=');
+    test = strtrim(eventString(1:temp(1)-1));
+    % check if event name given
+    if isempty(test),
+        error = sprintf('At least one event has no name given.');
+        return
+    end
+    IQMevents(k).name = removeWhiteSpace(test);
+    % get the right hand side
+    eventRHS = eventString(temp(1)+1:end);
+    % decompose the eventRHS into its comma separated elements
+    % taking into account parentheses
+    elementsRHS = explodePCIQM(eventRHS);
+    % check number of elements
+    if length(elementsRHS) < 3 || mod(length(elementsRHS),2) == 0,
+        error = sprintf('At least one event has no full information given.');
+        return
+    end
+    % first element is assumed to be the trigger function
+    IQMevents(k).trigger = removeWhiteSpace(elementsRHS{1});
+    % add the event assignments
+    indexAssignment = 1;
+    for k2 = 2:2:length(elementsRHS),
+        IQMevents(k).assignment(indexAssignment).variable = removeWhiteSpace(elementsRHS{k2});
+        IQMevents(k).assignment(indexAssignment).formula = removeWhiteSpace(elementsRHS{k2+1});
+        indexAssignment = indexAssignment + 1;
+    end
+
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DELETE WHITESPACES IN STRINGS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Useful for taking away whitespaces in kineticLaw formulas, as
+% seen in some example models
+function [outputString] = removeWhiteSpace(inputString)
+outputString = strrep(inputString,' ','');
+% return
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [output] = removeCharacters(input)
+% delete all line breaks and tabs from the input string
+temp = double(input);
+temp(find(temp==13)) = 32;  % replace '\cr' by white space
+temp(find(temp==10)) = 32;  % replace '\n' by white space
+temp(find(temp==9)) = 32;   % replace '\t' by white space
+output = char(temp);
+output = strrep(output,' ','');
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [output] = removeCharacters2(input)
+% delete all line breaks and tabs from the input string
+temp = double(input);
+temp(find(temp==13)) = 32;  % replace '\cr' by white space
+output = char(temp);
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/text2IQMmodel/convertTextToModelIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/text2IQMmodel/convertTextToModelIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..aa5dbe8bc52e35232bdfa6f5c60eb51e31bd9976
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/text2IQMmodel/convertTextToModelIQM.m	
@@ -0,0 +1,944 @@
+function [IQMstructure,errorMsg] = convertTextToModelIQM(modelText)
+% convertTextToModelIQM: Converts a text description of an IQMmodel to 
+% the internal data structure representation.r
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+% global variable for passing array state initial conditions to
+% convertTEXTArrayDefIQM.m
+global arrayInitialConditions_qayxsw
+arrayInitialConditions_qayxsw = [];
+
+% initialize variables
+errorMsg = '';
+errorFunctions = '';
+errorStates = '';
+errorParameters = '';
+errorVariables = '';
+errorReactions = '';
+errorEvents = '';
+
+IQMstructure = struct(IQMmodel());
+
+% cut text into pieces
+modelTextStructure = getPartsFromCompleteTextIQM(modelText);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%% Name
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+IQMstructure.name = removeCharacters(modelTextStructure.name);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%% Notes
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+IQMstructure.notes = strtrim(modelTextStructure.notes);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%% Functions
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try
+    [IQMstructure.functions, errorFunctions] = getFunctions(modelTextStructure.functions);
+catch
+    errorMsg = sprintf('%sPlease check the syntax of the ''Functions'' definitions.\n',errorMsg);
+end
+if ~isempty(errorFunctions),
+    errorMsg = sprintf('%s%s\n',errorMsg,errorFunctions);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%% States and algebraic rules
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try
+    [IQMstructure.states, IQMstructure.algebraic, stateConstraintInfo, errorStates] = getStates(modelTextStructure.states);
+catch
+    errorMsg = sprintf('%sPlease check the syntax of the ''ODE'' and\n''initial condition'' definitions.\n',errorMsg);
+end
+if ~isempty(errorStates),
+    errorMsg = sprintf('%s%s\n',errorMsg,errorStates);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%% Parameters
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try
+    [IQMstructure.parameters, errorParameters] = getParameters(modelTextStructure.parameters);
+catch
+    errorMsg = sprintf('%sPlease check the syntax of the ''Parameter'' definitions.\n',errorMsg);
+end
+if ~isempty(errorParameters),
+    errorMsg = sprintf('%s%s\n',errorMsg,errorParameters);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%% Variables
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try
+    [IQMstructure.variables, errorVariables] = getVariables(modelTextStructure.variables);
+catch
+    errorMsg = sprintf('%sPlease check the syntax of the ''Variables'' definitions.\n',errorMsg);
+end
+if ~isempty(errorVariables),
+    errorMsg = sprintf('%s%s\n',errorMsg,errorVariables);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%% Reactions
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try
+    [IQMstructure.reactions, errorReactions] = getReactions(modelTextStructure.reactions);
+catch
+    errorMsg = sprintf('%sPlease check the syntax of the ''Reactions'' definitions.\n',errorMsg);
+end
+if ~isempty(errorReactions),
+    errorMsg = sprintf('%s%s\n',errorMsg,errorReactions);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%% Events
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try
+    [IQMstructure.events, errorEvents] = getEvents(modelTextStructure.events);
+catch
+    errorMsg = sprintf('%sPlease check the syntax of the ''Events'' definitions.\n',errorMsg);
+end
+if ~isempty(errorEvents),
+    errorMsg = sprintf('%s%s\n',errorMsg,errorEvents);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%% MATLAB functions
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+IQMstructure.functionsMATLAB = modelTextStructure.functionsMATLAB;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%% Check errorMessage
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(errorMsg),
+    IQMstructure = [];
+    return
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%% State Constraints
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle possible constraints on state variables in the IQMmodel:
+% add the needed piecewise expressions and the factors on the ODEs
+% as last reactions in the model. We need to add it as reactions in order
+% to evaluate these as last elements before evaluating the ODEs.
+for k=1:length(stateConstraintInfo),
+    statename = stateConstraintInfo(k).statename;
+    stateindex = stateConstraintInfo(k).stateindex;
+    lowbound = stateConstraintInfo(k).lowbound;
+    highbound = stateConstraintInfo(k).highbound;
+    ODE = stateConstraintInfo(k).ODE;
+    % add a factor "constraints_factor_statename" to the ODE for the state
+    IQMstructure.states(stateindex).ODE = ['constraints_factor_' statename ' * (' ODE ')'];
+    % define the "constraints_factor_statename" in the reactions
+    IQMstructure.reactions(end+1).name = ['constraints_factor_' statename];
+    % construct the piecewise expression
+    if ~checkboundIsInf(lowbound) && ~checkboundIsInf(highbound),
+        pwtext = sprintf('piecewiseIQM(0,orIQM(andIQM(ge(%s,%s),gt(%s,0)),andIQM(le(%s,%s),lt(%s,0))),1)',statename,num2str(highbound,20),ODE,statename,num2str(lowbound,20),ODE);
+    elseif checkboundIsInf(lowbound) && ~checkboundIsInf(highbound),
+        pwtext = sprintf('piecewiseIQM(0,andIQM(ge(%s,%s),gt(%s,0)),1)',statename,num2str(highbound,20),ODE);
+    elseif checkboundIsInf(lowbound) && ~checkboundIsInf(highbound),
+        pwtext = sprintf('piecewiseIQM(0,andIQM(le(%s,%s),lt(%s,0)),1)',statename,num2str(lowbound,20),ODE);
+    else
+        pwtext = '1'; % always unconstrained
+    end
+    % add the piecewise expression as last reaction and do the rest
+    IQMstructure.reactions(end).formula = pwtext;
+    IQMstructure.reactions(end).notes = sprintf('Implementation of constraints on state %s',statename);
+    IQMstructure.reactions(end).reversible = 0;
+    IQMstructure.reactions(end).fast = 0;
+end
+
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [output] = checkboundIsInf(bound)
+if ischar(bound),
+    output = 0;
+    return
+end
+if isnumeric(bound),
+    output = isinf(bound);
+    return
+end
+error('Problem with constraints - bound definition.');
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [IQMstates, IQMalgebraic, stateConstraintInfo, error] = getStates(states)
+global arrayInitialConditions_qayxsw
+error = '';
+%    states = removeWhiteSpace(states);
+IQMstates = struct('name',{},'initialCondition',{},'ODE',{},'type',{},'compartment',{},'unittype',{},'notes',{});
+IQMalgebraic = struct('name',{},'formula',{},'initialCondition',{},'type',{},'compartment',{},'unittype',{},'notes',{});
+% check if ode definitions are present
+if isempty(strfind(states,'d/dt(')),
+    error = 'The model does not contain any states';
+    return
+end
+% get start of ODEs, ARs, and ICs
+ODEtest = strfind(states,'d/dt(');
+ARtest = strfind(states,'0 = ');
+ICtest = strfind(states,'(0)');
+% check if they come subsequently
+if ~isempty(ICtest),
+    if max(ODEtest)>min(ICtest),
+        error = sprintf('Initial conditions have to be defined\nafter the definition of the ODEs.');
+        return
+    end
+end
+if ~isempty(ARtest),
+    if max(ODEtest)>min(ARtest),
+        error = sprintf('Algebraic rules have to be defined\nafter the definition of the ODEs.');
+        return
+    end
+end
+if ~isempty(ARtest) && ~isempty(ICtest),
+    if max(ARtest)>min(ICtest),
+        error = sprintf('Initial conditions have to be defined\nafter the definition of the algebraic rules.');
+        return
+    end
+end
+% START OF THE ODEs
+ODEsStart = strfind(states,'d/dt(');
+% START OF THE ALGEBRAIC RULES
+ARsStart = regexp(states,'\n0')+1;
+% START OF THE INITIAL CONDITIONS
+% (finding the index of the last '\n' before the '(0)' for each initial condition)
+initialConditionsStart = [];
+temp = strfind(states,'(0)');
+for k = 1:length(temp),
+    temp2 = double(states(1:temp(k)));
+    temp3 = find(temp2==10);
+    initialConditionsStart = [initialConditionsStart temp3(end)+1];
+end
+
+%%%%%%%%%%%%%%%%%%%
+% PROCESS ODEs
+%%%%%%%%%%%%%%%%%%%
+stateConstraintInfo = [];
+
+% run through the ODEs and process them
+if isempty(ARsStart) && isempty(initialConditionsStart),
+    % if no initial conditions are present then use end of states
+    % string as end index (+1)
+    ODEsStart = [ODEsStart length(states)+1];
+elseif isempty(ARsStart)
+    ODEsStart = [ODEsStart initialConditionsStart(1)];
+else
+    ODEsStart = [ODEsStart ARsStart(1)];
+end
+for k = 1:length(ODEsStart)-1,
+    stateString = removeCharacters(states(ODEsStart(k):ODEsStart(k+1)-1));
+
+    
+
+    
+    
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle possible constraints on state variables in the IQMmodel
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check if constraint information is present on a state. Syntax: {constraints:[min,max]}
+stateConstraints = {};
+infoStartConstraints = strfind(stateString,'{constraints:');
+if ~isempty(infoStartConstraints),
+    % find the end of the constraint information
+    offset = 11; po = 1;
+    while 1,
+        if stateString(infoStartConstraints+offset) == '}',
+            break;
+        end
+        offset = offset + 1;
+    end
+    constraintsString = stateString(infoStartConstraints:infoStartConstraints+offset);
+    % remove constraint information from stateString
+    stateString = stateString([1:infoStartConstraints-1 infoStartConstraints+offset+1:end]);
+    % parse the constraints string
+    constraintsString = strrep(constraintsString,' ',''); % remove spaces
+    constraintsString = constraintsString(15:end-2);
+    stateConstraints = explodePCIQM(constraintsString,',');
+    if length(stateConstraints) ~= 2,
+        error('A state-constraint information seems to be wrongly defined');
+    end
+    % convert numeric bounds to numbers
+    for k2=1:2,
+        try
+            temp = eval(stateConstraints{k2});
+            stateConstraints{k2} = temp;
+        catch
+        end
+    end
+end
+    
+
+
+    % check if additional information is present ... if yes, cut it out
+    infoStart = strfind(stateString,'{');
+    infoEnd = strfind(stateString,'}');
+    informationText = '';
+    if length(infoStart) + length(infoEnd) > 2,
+        error = 'To many curly parentheses in a state definition';
+        return
+    end
+    if length(infoStart) ~= length(infoEnd),
+        error = 'At least one state information not properly defined';
+        return
+    end
+    if length(infoStart) == 1,
+        informationText = stateString(infoStart+1:infoEnd-1);
+        stateString = stateString([1:infoStart-1, infoEnd+1:end]);
+    end
+    if ~isempty(informationText),
+        % explode the information text with ':'
+        terms = explodePCIQM(informationText,':');
+        if length(terms) == 1 && ~isempty(strfind(lower(terms{1}),'parameter')),
+            type = strtrim(terms{1});
+            compartment = '';
+            unittype = '';
+        elseif length(terms) == 2 && ~isempty(strfind(lower(terms{1}),'compartment')),
+            type = strtrim(terms{1});
+            compartment = strtrim(terms{2});
+            unittype = '';
+        elseif length(terms) == 3 && ~isempty(strfind(lower(terms{1}),'specie')),
+            type = strtrim(terms{1});
+            compartment = strtrim(terms{2});
+            unittype = strtrim(terms{3});
+        else
+            error = 'Error in a state information';
+            return           
+        end
+    else 
+        type = '';
+        compartment = '';
+        unittype = '';
+    end
+    % extract the state name
+    temp = strfind(stateString,')');
+    test = stateString(6:temp(1)-1);
+    % check if state name given
+    if isempty(test),
+        error = sprintf('At least on state name in\nODE definition is not given.');
+        return
+    end
+    IQMstates(k).name = removeWhiteSpace(test);
+    % extract the state ODE
+    temp = strfind(stateString,'=');
+    test = stateString(temp+1:end);
+    % check if state ODE given
+    if isempty(test),
+        error = sprintf('At least one RHS of an ODE is not given.');
+        return
+    end
+    % The test string contains now the ODE and eventually also a
+    % comment that should be written into notes.
+    % check if a comment is present
+    temp = strfind(test,'%');
+    if ~isempty(temp),
+        ODE = removeWhiteSpace(test(1:temp(1)-1));
+        notes = strtrim(test(temp(1)+1:end));
+    else
+        ODE = removeWhiteSpace(test);
+        notes = '';
+    end
+    IQMstates(k).ODE = ODE;
+    IQMstates(k).notes = notes;
+    % add default value for initial condition
+    IQMstates(k).initialCondition = 0;
+    % add information to state
+    IQMstates(k).type = type;
+    IQMstates(k).compartment = compartment;
+    IQMstates(k).unittype = unittype;
+    
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle possible constraints on state variables in the IQMmodel
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%    
+if ~isempty(stateConstraints),
+    % ok, state constraints have been defined for this state
+    % save some information to be able to add it later to the model
+    stateConstraintInfo(end+1).statename = IQMstates(k).name;
+    stateConstraintInfo(end).stateindex = k;
+    stateConstraintInfo(end).lowbound = stateConstraints{1};
+    stateConstraintInfo(end).highbound = stateConstraints{2};
+    stateConstraintInfo(end).ODE = IQMstates(k).ODE;
+end
+
+end
+
+%%%%%%%%%%%%%%%%%%%
+% PROCESS ARs
+%%%%%%%%%%%%%%%%%%%
+if isempty(initialConditionsStart),
+    ARsStart = [ARsStart length(states)+1];
+else
+    ARsStart = [ARsStart initialConditionsStart(1)];
+end
+for k=1:length(ARsStart)-1,
+    % get each single AR
+    ARk = strtrim(states(ARsStart(k):ARsStart(k+1)-1));
+    % check if additional information is present ... if yes, cut it out
+    infoStart = strfind(ARk,'{');
+    infoEnd = strfind(ARk,'}');
+    informationText = '';
+    if length(infoStart) + length(infoEnd) > 2,
+        error = 'To many curly parentheses in an algebraic rule definition';
+        return
+    end
+    if length(infoStart) ~= length(infoEnd),
+        error = 'At least one algebraic rule not properly defined';
+        return
+    end
+    if length(infoStart) == 1,
+        informationText = ARk(infoStart+1:infoEnd-1);
+        ARk = ARk([1:infoStart-1, infoEnd+1:end]);
+    end
+    if ~isempty(informationText),
+        % explode the information text with ':'
+        terms = explodePCIQM(informationText,':');
+        if length(terms) == 1 && ~isempty(strfind(lower(terms{1}),'parameter')),
+            type = strtrim(terms{1});
+            compartment = '';
+            unittype = '';
+        elseif length(terms) == 2 && ~isempty(strfind(lower(terms{1}),'compartment')),
+            type = strtrim(terms{1});
+            compartment = strtrim(terms{2});
+            unittype = '';
+        elseif length(terms) == 3 && ~isempty(strfind(lower(terms{1}),'specie')),
+            type = strtrim(terms{1});
+            compartment = strtrim(terms{2});
+            unittype = strtrim(terms{3});
+        else
+            error = 'Error in an algebraic rule information';
+            return           
+        end
+    else 
+        type = '';
+        compartment = '';
+        unittype = '';
+    end
+    % separate comment from AR definition
+    index1 = strfind(ARk,'=');
+    index2 = strfind(ARk,'%');
+    if ~isempty(index2),
+        ARformulak = strtrim(ARk(index1(1)+1:index2(1)-1));
+        ARnotek = strtrim(ARk(index2(1)+1:end));
+    else
+        ARformulak = strtrim(ARk(index1(1)+1:end));
+        ARnotek = '';
+    end        
+    % split rhs in formula and variable name
+    terms = explodePCIQM(ARformulak,':');
+    if length(terms) ~= 2,
+        ARformulak = terms{1};
+        ARnamek = ''; % keep it empty
+        ARick = [];
+    else
+        ARformulak = strtrim(terms{1});
+        ARnamek = strtrim(terms{2});
+        ARick = 0; % default setting (determined by the integrator)
+    end
+    % update structure
+    IQMalgebraic(k).name = ARnamek;
+    IQMalgebraic(k).formula = ARformulak;
+    IQMalgebraic(k).initialCondition = ARick; % default setting (determined by the integrator)
+    IQMalgebraic(k).type = type;
+    IQMalgebraic(k).compartment = compartment;
+    IQMalgebraic(k).unittype = unittype;
+    IQMalgebraic(k).notes = ARnotek;
+end
+
+%%%%%%%%%%%%%%%%%%%
+% PROCESS ICs
+%%%%%%%%%%%%%%%%%%%
+% run through the initial conditions and add them
+% they can have a different order than the odes. if an initial
+% condition is not defined for a certain state then it is set to zero
+% by default
+% First check if any initial conditions are given - if not then don't
+% execute this part!
+if ~isempty(strfind(states,'(0)')),
+    initialConditionsStart = [initialConditionsStart length(states)+1];
+    for k1 = 1:length(initialConditionsStart)-1,
+        ICString = removeWhiteSpace(removeCharacters(states(initialConditionsStart(k1):initialConditionsStart(k1+1)-1)));
+        % extract the state name
+        temp = strfind(ICString,'(0)');
+        stateName = ICString(1:temp(1)-1);
+        % extract the states' initial condition
+        temp = strfind(ICString,'=');
+        stateIC = ICString(temp+1:end);
+        % cycle through the states in the IQMstructure and add the initial
+        % condition at the correct state
+        statefound = 0;
+        for k2 = 1:length(IQMstates),
+            if strcmp(stateName,IQMstates(k2).name),
+                statefound = 1;
+                test = str2double(stateIC);
+                if isnan(test),
+                    % initial condition was not a numerical value
+%                     disp(sprintf('At least one initial condition has a non-numerical value assigned.\nThis might lead to problems with certain toolbox functions.'));
+                    IQMstates(k2).initialCondition = strtrim(stateIC);
+                else
+                    IQMstates(k2).initialCondition = test;
+                end
+                break;
+            end
+        end
+        % add initial conditions to the algebraic variables if defined
+        for k2 = 1:length(IQMalgebraic),
+            if strcmp(stateName,IQMalgebraic(k2).name),
+                statefound = 1;
+                test = str2double(stateIC);
+                if isnan(test),
+                    % initial condition was not a numerical value
+                    error = sprintf('At least one initial condition for an algebraic state has a non-numerical value assigned');
+                    return;
+                else
+                    IQMalgebraic(k2).initialCondition = test;
+                end
+                break;
+            end
+        end
+        if ~statefound,
+            % check if the state IC stems from an array definition
+            if isempty(strfind(stateName,'<')),
+                % no it doesn't
+                error = sprintf('At least one initial condition given\nfor a statename that does not appear\nin the ODE definitions.');
+                return;
+            else
+                % yes it does! so don't output an error but do something
+                % different. I will for now pass the IC information for
+                % array states using a global variable. Not nice but it
+                % should do the trick.
+                arrayInitialConditions_qayxsw(end+1).name = stateName;
+                arrayInitialConditions_qayxsw(end).ic = stateIC;
+            end
+        else
+            % state could have been found but it still is an array thing
+            % check it here
+            if ~isempty(strfind(stateName,'<')),
+                arrayInitialConditions_qayxsw(end+1).name = stateName;
+                arrayInitialConditions_qayxsw(end).ic = stateIC;    
+            end
+        end
+    end
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [IQMparameters, error] = getParameters(parameters)
+error = '';
+%    parameters = removeWhiteSpace(parameters);
+IQMparameters = struct('name',{},'value',{},'type',{},'compartment',{},'unittype',{},'notes',{});
+% get the starting indices for the parameters by finding the index
+% of the last '\n' before the '=' for each parameter
+parametersStart = regexp([10 parameters],['\n[^\n=]*=']);
+% run through the parameters and process them (+1 since endindex = end-1)
+parametersStart = [parametersStart length(parameters)+1];
+parNAN = 0;
+for k = 1:length(parametersStart)-1,
+    parameterString = removeCharacters(parameters(parametersStart(k):parametersStart(k+1)-1));
+    % check if additional information is present ... if yes, cut it out
+    infoStart = strfind(parameterString,'{');
+    infoEnd = strfind(parameterString,'}');
+    informationText = '';
+    if length(infoStart) + length(infoEnd) > 2,
+        error = 'To many curly parentheses in a parameter definition';
+        return
+    end
+    if length(infoStart) ~= length(infoEnd),
+        error = 'At least one parameter information not properly defined';
+        return
+    end
+    if length(infoStart) == 1,
+        informationText = parameterString(infoStart+1:infoEnd-1);
+        parameterString = parameterString([1:infoStart-1, infoEnd+1:end]);
+    end
+    if ~isempty(informationText),
+        % explode the information text with ':'
+        terms = explodePCIQM(informationText,':');
+        if length(terms) == 1 && ~isempty(strfind(lower(terms{1}),'parameter')),
+            type = strtrim(terms{1});
+            compartment = '';
+            unittype = '';
+        elseif length(terms) == 2 && ~isempty(strfind(lower(terms{1}),'compartment')),
+            type = strtrim(terms{1});
+            compartment = strtrim(terms{2});
+            unittype = '';
+        elseif length(terms) == 3 && ~isempty(strfind(lower(terms{1}),'specie')),
+            type = strtrim(terms{1});
+            compartment = strtrim(terms{2});
+            unittype = strtrim(terms{3});
+        else
+            error = 'Error in a parameter information';
+            return           
+        end
+    else 
+        type = '';
+        compartment = '';
+        unittype = '';
+    end
+    % extract the parameter name
+    temp = strfind(parameterString,'=');
+    test = parameterString(1:temp(1)-1);
+    % check if parameter name given
+    if isempty(test),
+        error = sprintf('At least one parameter name not given.');
+        return
+    end
+    IQMparameters(k).name = removeWhiteSpace(test);
+    % extract the parameter value
+    % check if it has a numerical value
+    test = parameterString(temp+1:end);
+    % The test string contains now the parameter value and eventually also a
+    % comment that should be written into notes.
+    % check if a comment is present
+    temp = strfind(test,'%');
+    if ~isempty(temp),
+        value = str2double(removeWhiteSpace(test(1:temp(1)-1)));
+        notes = strtrim(test(temp(1)+1:end));
+    else
+        value = str2double(removeWhiteSpace(test));
+        notes = '';
+    end
+    if isnan(value),
+        % initial condition was not a numerical value
+        parNAN = 1;
+    else
+        IQMparameters(k).value = value;
+    end
+    % add default notes to parameter
+    IQMparameters(k).notes = notes;
+    % add information to parameter
+    IQMparameters(k).type = type;
+    IQMparameters(k).compartment = compartment;
+    IQMparameters(k).unittype = unittype;
+end
+if parNAN,
+    error = sprintf('At least one parameter has a\nnon-numerical value assigned');
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [IQMvariables, error] = getVariables(variables)
+error = '';
+%    variables = removeWhiteSpace(variables);
+IQMvariables = struct('name',{},'formula',{},'type',{},'compartment',{},'unittype',{},'notes',{});
+% get the starting indices for the variables by finding the index
+% of the last '\n' before the '=' for each variable
+variablesStart = regexp([10 variables],['\n[^\n=]*=']);
+% run through the variables and process them (+1 since endindex = end-1)
+variablesStart = [variablesStart length(variables)+1];
+for k = 1:length(variablesStart)-1,
+    variableString = removeCharacters(variables(variablesStart(k):variablesStart(k+1)-1));
+    % check if additional information is present ... if yes, cut it out
+    infoStart = strfind(variableString,'{');
+    infoEnd = strfind(variableString,'}');
+    informationText = '';
+    if length(infoStart) + length(infoEnd) > 2,
+        error = 'To many curly parentheses in a variable definition';
+        return
+    end
+    if length(infoStart) ~= length(infoEnd),
+        error = 'At least one variable information not properly defined';
+        return
+    end
+    if length(infoStart) == 1,
+        informationText = variableString(infoStart+1:infoEnd-1);
+        variableString = variableString([1:infoStart-1, infoEnd+1:end]);
+    end
+    if ~isempty(informationText),
+        % explode the information text with ':'
+        terms = explodePCIQM(informationText,':');
+        if length(terms) == 1 && ~isempty(strfind(lower(terms{1}),'parameter')),
+            type = strtrim(terms{1});
+            compartment = '';
+            unittype = '';
+        elseif length(terms) == 2 && ~isempty(strfind(lower(terms{1}),'compartment')),
+            type = strtrim(terms{1});
+            compartment = strtrim(terms{2});
+            unittype = '';
+        elseif length(terms) == 3 && ~isempty(strfind(lower(terms{1}),'specie')),
+            type = strtrim(terms{1});
+            compartment = strtrim(terms{2});
+            unittype = strtrim(terms{3});
+        else
+            error = 'Error in a variable information';
+            return           
+        end
+    else 
+        type = '';
+        compartment = '';
+        unittype = '';
+    end
+    % extract the variable name
+    temp = strfind(variableString,'=');
+    test = variableString(1:temp(1)-1);
+    % check if variable name given
+    if isempty(test),
+        error = sprintf('At least one variable name not given.');
+        return
+    end
+    IQMvariables(k).name = removeWhiteSpace(test);
+    % extract the variable value
+    test = variableString(temp+1:end);
+    % The test string contains now the variable expression and
+    % eventually also a comment that should be written into notes.
+    % check if a comment is present
+    temp = strfind(test,'%');
+    if ~isempty(temp),
+        formula = removeWhiteSpace(test(1:temp(1)-1));
+        notes = strtrim(test(temp(1)+1:end));
+    else
+        formula = removeWhiteSpace(test);
+        notes = '';
+    end
+    % check if variable expression given
+    if isempty(formula),
+        error = sprintf('At least one variable definition not given.');
+        return
+    end
+    IQMvariables(k).formula = formula;
+    % add default notes to variable
+    IQMvariables(k).notes = notes;
+    % add information to parameter
+    IQMvariables(k).type = type;
+    IQMvariables(k).compartment = compartment;
+    IQMvariables(k).unittype = unittype;    
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [IQMreactions, error] = getReactions(reactions)
+error = '';
+%    reactions = removeWhiteSpace(reactions);
+IQMreactions = struct('name',{},'formula',{},'notes',{},'reversible',{},'fast',{});
+% get the starting indices for the reactions by finding the index
+% of the last '\n' before the '=' for each reaction
+reactionsStart = regexp([10 reactions],['\n[^\n=]*=']);
+% run through the reactions and process them (+1 since endindex = end-1)
+reactionsStart = [reactionsStart length(reactions)+1];
+for k = 1:length(reactionsStart)-1,
+    reactionString = removeCharacters(reactions(reactionsStart(k):reactionsStart(k+1)-1));
+    % extract the reaction name
+    temp = strfind(reactionString,'=');
+    test = reactionString(1:temp(1)-1);
+    % check if reaction name given
+    if isempty(test),
+        error = sprintf('At least one reaction name not given.');
+        return
+    end
+    IQMreactions(k).name = removeWhiteSpace(test);
+    % extract the reaction value
+    test = reactionString(temp+1:end);
+    % The test string contains now the reaction expression, an optional
+    % "[reversible]" identifier and eventually also a comment that should be
+    % written into notes. 
+    % check if a comment is present
+    temp = strfind(test,'%');
+    if ~isempty(temp),
+        reaction = removeWhiteSpace(test(1:temp(1)-1));
+        notes = strtrim(test(temp(1)+1:end));
+    else
+        reaction = removeWhiteSpace(test);
+        notes = '';
+    end
+    % finally check if the "{reversible}" identifier is present.
+    temp = strfind(lower(reaction),'{reversible}');
+    if ~isempty(temp),
+        % reversible identifier is present - take it away and 
+        % set the flag to one, otherwise leave the expression untouched and
+        % set it to 0
+        reaction = strrep(reaction,'{reversible}','');
+        reversibleFlag = 1;
+    else
+        reversibleFlag = 0;
+    end
+    % finally finally check if the "{fast}" identifier is present.
+    temp = strfind(lower(reaction),'{fast}');
+    if ~isempty(temp),
+        % fast identifier is present - take it away and 
+        % set the flag to one, otherwise leave the expression untouched and
+        % set it to 0
+        reaction = strrep(reaction,'{fast}','');
+        fastFlag = 1;
+    else
+        fastFlag = 0;
+    end
+    % check if reaction expression given
+    reaction = removeWhiteSpace(reaction);
+    if isempty(reaction),
+        error = sprintf('At least one reaction definition not given.');
+        return
+    end
+    IQMreactions(k).formula = reaction;
+    % add default notes to reaction
+    IQMreactions(k).notes = notes;
+    % add the reversible flag
+    IQMreactions(k).reversible = reversibleFlag;
+    % add the fast flag
+    IQMreactions(k).fast = fastFlag;
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [IQMfunctions, error] = getFunctions(functions)
+error = '';
+%    functions = removeWhiteSpace(functions);
+IQMfunctions = struct('name',{},'arguments',{},'formula',{},'notes',{});
+% % get the starting indices for the function by finding the index
+% % of the last '\n' before the '=' for each function
+% functionsStart = [];
+% temp = strfind(functions,'=');
+% for k = 1:length(temp),
+%     % add a line break in the beginning since the first function might
+%     % not have one in front of it
+%     temp2 = [10 double(functions(1:temp(k)))];
+%     temp3 = find(temp2==10);
+%     functionsStart = [functionsStart temp3(end)];
+% end
+% % run through the reactions and process them (+1 since endindex = end-1)
+% functionsStart = [functionsStart length(functions)+1];
+
+% get the starting indices for the functions by finding the index
+% of the last '\n' before the '=' for each function
+functionsStart = regexp([10 functions],['\n[^\n=]*=']);
+% run through the functions and process them (+1 since endindex = end-1)
+functionsStart = [functionsStart length(functions)+1];
+
+for k = 1:length(functionsStart)-1,
+    functionString = removeCharacters(functions(functionsStart(k):functionsStart(k+1)-1));
+    % extract the function name
+    temp = strfind(functionString,'(');
+    test = functionString(1:temp(1)-1);
+    % check if function name given
+    if isempty(test),
+        error = sprintf('At least one function name not given.');
+        return
+    end
+    IQMfunctions(k).name = removeWhiteSpace(test);
+    % extract the arguments
+    temp2 = strfind(functionString,')');
+    test = functionString(temp+1:temp2-1);
+    % check if function arguments given
+    if isempty(test),
+        error = sprintf('At least for one function no arguments given.');
+        return
+    end
+    IQMfunctions(k).arguments = removeWhiteSpace(test);
+    % extract the formula
+    temp3 = strfind(functionString,'=');
+    test = functionString(temp3+1:end);
+    % The test string contains now the formula and
+    % eventually also a comment that should be written into notes.
+    % check if a comment is present
+    temp = strfind(test,'%');
+    if ~isempty(temp),
+        formula = removeWhiteSpace(test(1:temp(1)-1));
+        notes = strtrim(test(temp(1)+1:end));
+    else
+        formula = removeWhiteSpace(test);
+        notes = '';
+    end
+    % check if function formula given
+    if isempty(formula),
+        error = sprintf('At least for one function no formula given.');
+        return
+    end
+    IQMfunctions(k).formula = formula;
+    % add default notes to function
+    IQMfunctions(k).notes = notes;
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [IQMevents, error] = getEvents(events)
+error = '';
+% event substructure
+eventassignmentStruct = struct('variable',{},'formula',{});
+IQMevents = struct('name',{},'trigger',{},'assignment',eventassignmentStruct,'notes',{});
+
+% % get the starting indices for the events by finding the index
+% % of the last '\n' before the '=' for each event
+% eventsStart = [];
+% temp = strfind(events,'=');
+% for k = 1:length(temp),
+%     % add a line break in the beginning since the first event might
+%     % not have one in front of it
+%     temp2 = [10 double(events(1:temp(k)))];
+%     temp3 = find(temp2==10);
+%     eventsStart = [eventsStart temp3(end)];
+% end
+% eventsStart = [eventsStart length(events)+1];
+
+% get the starting indices for the events by finding the index
+% of the last '\n' before the '=' for each event
+eventsStart = regexp([10 events],['\n[^\n=]*=']);
+% run through the events and process them (+1 since endindex = end-1)
+eventsStart = [eventsStart length(events)+1];
+
+for k = 1:length(eventsStart)-1,
+    eventString = removeCharacters(events(eventsStart(k):eventsStart(k+1)-1));
+    % check if comment present
+    startNotes = strfind(eventString,'%');
+    notes = '';
+    if ~isempty(startNotes),
+        notes = eventString(startNotes(1)+1:end);
+        eventString = eventString(1:startNotes(1)-1);
+    end
+    IQMevents(k).notes = notes;
+    % extract the event name
+    temp = strfind(eventString,'=');
+    test = strtrim(eventString(1:temp(1)-1));
+    % check if event name given
+    if isempty(test),
+        error = sprintf('At least one event has no name given.');
+        return
+    end
+    IQMevents(k).name = removeWhiteSpace(test);
+    % get the right hand side
+    eventRHS = eventString(temp(1)+1:end);
+    % decompose the eventRHS into its comma separated elements
+    % taking into account parentheses
+    elementsRHS = explodePCIQM(eventRHS);
+    % check number of elements
+    if length(elementsRHS) < 3 || mod(length(elementsRHS),2) == 0,
+        error = sprintf('At least one event has no full information given.');
+        return
+    end
+    % first element is assumed to be the trigger function
+    IQMevents(k).trigger = removeWhiteSpace(elementsRHS{1});
+    % add the event assignments
+    indexAssignment = 1;
+    for k2 = 2:2:length(elementsRHS),
+        IQMevents(k).assignment(indexAssignment).variable = removeWhiteSpace(elementsRHS{k2});
+        IQMevents(k).assignment(indexAssignment).formula = removeWhiteSpace(elementsRHS{k2+1});
+        indexAssignment = indexAssignment + 1;
+    end
+
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DELETE WHITESPACES IN STRINGS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Useful for taking away whitespaces in kineticLaw formulas, as
+% seen in some example models
+function [outputString] = removeWhiteSpace(inputString)
+outputString = strrep(inputString,' ','');
+% return
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [output] = removeCharacters(input)
+% delete all line breaks and tabs from the input string
+temp = double(input);
+temp(find(temp==13)) = 32;  % replace '\cr' by white space
+temp(find(temp==10)) = 32;  % replace '\n' by white space
+temp(find(temp==9)) = 32;   % replace '\t' by white space
+output = char(temp);
+return
+
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/text2IQMmodel/getPartsFromCompleteTextBCIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/text2IQMmodel/getPartsFromCompleteTextBCIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..e4b34564ee0e13af5631a45a15593d6d42dd10a6
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/text2IQMmodel/getPartsFromCompleteTextBCIQM.m	
@@ -0,0 +1,31 @@
+function [modelTextStructure] = getPartsFromCompleteTextIQM(modelText)
+% getPartsFromCompleteTextIQM: Cuts a text description of an IQMmodel
+% into the different parts and returns them in a structure
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+% take commented lines out of the model description
+modelText = regexprep(modelText,'\n%[^\n]*','');
+
+% Find the starts of the different view data
+nameStart = strfind(modelText,'********** MODEL NAME');
+notesStart = strfind(modelText,'********** MODEL NOTES');
+statesStart = strfind(modelText,'********** MODEL STATE INFORMATION');
+parametersStart = strfind(modelText,'********** MODEL PARAMETERS');
+variablesStart = strfind(modelText,'********** MODEL VARIABLES');
+reactionsStart = strfind(modelText,'********** MODEL REACTIONS');
+functionsStart = strfind(modelText,'********** MODEL FUNCTIONS');
+eventsStart = strfind(modelText,'********** MODEL EVENTS');
+functionsMATLABStart = strfind(modelText,'********** MODEL MATLAB FUNCTIONS');
+% Cut out the different pieces and assign them to the modelTextStructure structure
+modelTextStructure.name = strtrim(modelText(nameStart+length('********** MODEL NAME'):notesStart-1));
+modelTextStructure.notes = strtrim(modelText(notesStart+length('********** MODEL NOTES'):statesStart-1));
+modelTextStructure.states = strtrim(modelText(statesStart+length('********** MODEL STATE INFORMATION'):parametersStart-1));
+modelTextStructure.parameters = strtrim(modelText(parametersStart+length('********** MODEL PARAMETERS'):variablesStart-1));
+modelTextStructure.variables = strtrim(modelText(variablesStart+length('********** MODEL VARIABLES'):reactionsStart-1));
+modelTextStructure.reactions = strtrim(modelText(reactionsStart+length('********** MODEL REACTIONS'):functionsStart-1));
+modelTextStructure.functions = strtrim(modelText(functionsStart+length('********** MODEL FUNCTIONS'):eventsStart-1));
+modelTextStructure.events = strtrim(modelText(eventsStart+length('********** MODEL EVENTS'):functionsMATLABStart-1));
+modelTextStructure.functionsMATLAB = strtrim(modelText(functionsMATLABStart+length('********** MODEL MATLAB FUNCTIONS'):end));
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/text2IQMmodel/getPartsFromCompleteTextIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/text2IQMmodel/getPartsFromCompleteTextIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..1188b4c383d2c0a8a05aeb2a62cf0ec2a5d73e42
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/text2IQMmodel/getPartsFromCompleteTextIQM.m	
@@ -0,0 +1,31 @@
+function [modelTextStructure] = getPartsFromCompleteTextExpIQM(modelText)
+% getPartsFromCompleteTextIQM: Cuts a text description of an IQMmodel object
+% into the different parts and returns them in a structure
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+% take commented lines out of the model description
+modelText = regexprep(modelText,'\n%[^\n]*','');
+
+% Find the starts of the different view data
+nameStart = strfind(modelText,'********** MODEL NAME');
+notesStart = strfind(modelText,'********** MODEL NOTES');
+statesStart = strfind(modelText,'********** MODEL STATES');
+parametersStart = strfind(modelText,'********** MODEL PARAMETERS');
+variablesStart = strfind(modelText,'********** MODEL VARIABLES');
+reactionsStart = strfind(modelText,'********** MODEL REACTIONS');
+functionsStart = strfind(modelText,'********** MODEL FUNCTIONS');
+eventsStart = strfind(modelText,'********** MODEL EVENTS');
+functionsMATLABStart = strfind(modelText,'********** MODEL MATLAB FUNCTIONS');
+% Cut out the different pieces and assign them to the modelTextStructure structure
+modelTextStructure.name = strtrim(modelText(nameStart+length('********** MODEL NAME'):notesStart-1));
+modelTextStructure.notes = strtrim(modelText(notesStart+length('********** MODEL NOTES'):statesStart-1));
+modelTextStructure.states = strtrim(modelText(statesStart+length('********** MODEL STATES'):parametersStart-1));
+modelTextStructure.parameters = strtrim(modelText(parametersStart+length('********** MODEL PARAMETERS'):variablesStart-1));
+modelTextStructure.variables = strtrim(modelText(variablesStart+length('********** MODEL VARIABLES'):reactionsStart-1));
+modelTextStructure.reactions = strtrim(modelText(reactionsStart+length('********** MODEL REACTIONS'):functionsStart-1));
+modelTextStructure.functions = strtrim(modelText(functionsStart+length('********** MODEL FUNCTIONS'):eventsStart-1));
+modelTextStructure.events = strtrim(modelText(eventsStart+length('********** MODEL EVENTS'):functionsMATLABStart-1));
+modelTextStructure.functionsMATLAB = strtrim(modelText(functionsMATLABStart+length('********** MODEL MATLAB FUNCTIONS'):end));
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/variableindexIQM.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/variableindexIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..065365af9d7e49912ebcd00b8382fd42da86da3c
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/auxiliary/variableindexIQM.m	
@@ -0,0 +1,34 @@
+function [output] = variableindexIQM(model,variablename)
+% variableindexIQM: returns the number of the variable 'variablename' in model
+% 'model'. If the variable does not exist then [] is returned.
+%
+% Output Arguments:
+% =================
+% output = index of the variable 'variablename' in the model.
+%          If 'variablename' is not a variable in the model, [] is returned.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+if ischar(variablename),
+    variablename = {variablename};
+end
+
+allvariables = IQMvariables(model);
+
+if length(variablename) == 1,
+    output = strmatchIQM(variablename,allvariables,'exact');
+    if isempty(output),
+        output = [];
+    end
+else    
+    output = [];
+    for k = 1:length(variablename),
+        index = strmatchIQM(variablename{k},allvariables,'exact');
+        if isempty(index),
+            output(k) = -1;
+        else
+            output(k) = index;
+        end
+    end
+end
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/isIQMmodel.m b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/isIQMmodel.m
new file mode 100644
index 0000000000000000000000000000000000000000..8fa749e8a5b26f756ab56a1806ffc9d0930cf233
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/classeshandling/modelhandling/isIQMmodel.m	
@@ -0,0 +1,6 @@
+function [output] = isIQMmodel(model)
+% isIQMmodel: check if input argument is an IQMmodel.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+output = strcmp(class(model),'IQMmodel');
diff --git a/IQMtools V1.2.2.2/IQMlite/installIQMlite.m b/IQMtools V1.2.2.2/IQMlite/installIQMlite.m
new file mode 100644
index 0000000000000000000000000000000000000000..e2395052d1037d845fd269c05e101feaab4285e1
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/installIQMlite.m	
@@ -0,0 +1,104 @@
+function [] = installIQMlite()
+% installIQMlite
+% This script installs the LITE version of the IQM Suite of modeling tools.
+%
+%       installIQMlite
+%
+% The function will check for a previous version of IQM Lite installed and
+% in this case it will remove this previous version from the path and
+% install the desired version.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+% Check correct starting folder
+currentDir      = pwd;
+installIQMliteDir    = fileparts(which('installIQMlite.m'));
+if ~strcmp(currentDir,installIQMliteDir),
+    error('Run the ''installIQMlite'' script from the folder where it is located.');
+end
+
+% Check that correct local path (network paths are not allowed)
+if strcmp(currentDir(1:2),'\\'),
+    error(sprintf('The installation can not be run from a network path (\\\\...).\nPlease run the installation from a local path.'));
+end
+
+% Check if IQM Lite already installed
+IGMLiteVer = ver('IQMlite');
+if length(IGMLiteVer) >= 1,
+    % Reset the path
+    restoredefaultpath();
+end
+
+% Add IQM Lite to the path 
+addpath(genpath(pwd));
+addpath(tempdirIQM)
+
+% Compile and install the needed packages 
+% Compilation is done for Unix AND Windows systems
+PATH_IQMLITE = pwd();
+try
+    % interpcseIQM
+    cd(fileparts(which('interpcseIQM.m')));
+    mex interpcseIQM.c
+    mex interpcseSlopeIQM.c
+catch, end
+cd(PATH_IQMLITE)
+try
+    % isrsort
+    cd(fileparts(which('isrsort.c')));
+    mex isrsort.c
+catch, end
+cd(PATH_IQMLITE)
+
+% Install SBML tools if path defined
+if isunix,
+    % Get path definitions
+    SETUP_PATHS_TOOLS_IQMLITE
+    if ~isempty(PATH_SYSTEM_SBML_UNIX),
+        try
+            oldpath = pwd();
+            cd(PATH_SYSTEM_SBML_UNIX);           
+            addpath(genpath(pwd));
+            cd(oldpath);
+        catch
+            disp('Problems detected with path to SBML tools. Please have a look at the file "SETUP_PATHS_TOOLS_IQMLITE.m".');
+        end
+    end
+end
+
+% Message
+disp(' ');
+disp('IQM Tools Lite');
+disp('	- Developer: IntiQuan GmbH (info@intiquan.com)');
+disp('	- Installation completed');
+disp(' ');
+disp(' ');
+
+% Output license information, etc.
+disp('License IQM Tools Lite:');
+disp(' ');
+disp(sprintf('This program is Free Open Source Software: you can redistribute it and/or modify '));
+disp(sprintf('it under the terms of the GNU General Public License as published by '));
+disp(sprintf('the Free Software Foundation, either version 3 of the License, or '));
+disp(sprintf('(at your option) any later version. '));
+disp(sprintf(' '));
+disp(sprintf('This program is distributed in the hope that it will be useful, '));
+disp(sprintf('but WITHOUT ANY WARRANTY; without even the implied warranty of '));
+disp(sprintf('MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the '));
+disp(sprintf('GNU General Public License for more details. '));
+disp(sprintf(' '));
+disp(sprintf('You should have received a copy of the GNU General Public License '));
+disp(sprintf('along with this program. If not, see <http://www.gnu.org/licenses/>.'));
+disp(sprintf(' '));
+disp(sprintf(' '));
+disp(sprintf(' '));
+
+
+try
+    % Check version number (>=R2013B required)
+    if verLessThan('matlab','8.2.0'),
+        warning('The dataset import/export functions in IQM Tools Lite require >=MATLAB R2013B.');
+    end
+end
+
+
diff --git a/IQMtools V1.2.2.2/IQMlite/installation.txt b/IQMtools V1.2.2.2/IQMlite/installation.txt
new file mode 100644
index 0000000000000000000000000000000000000000..a3c25e91209bb9ebcfa89dd50ae622dbb6ed21ec
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/installation.txt	
@@ -0,0 +1,17 @@
+Installation of IQM Tools Lite
+==============================
+
+When you are reading this document, you already have successfully obtained IQM Tools Lite from somewhere.
+Please perform the following steps to install it:
+
+- Move the IQMlite folder to a location on your computer where you would like to store it
+- Start MATLAB 
+- Type "mex -setup" to check if you have a C compiler installed for MATLAB. If not, please read the information from this command and install a C compiler.
+- Change into the IQMlite folder
+- Open the file "SETUP_PATHS_TOOLS_IQMLITE.m" in the editor, read its documentation and modify setup accordingly (if needed). Then save and close the file
+- Run "installIQMlite.m" script
+- If you have the parallel toolbox for MATLAB, please do the following setting
+    - Home->parallel->parallel preferences deselect the checkbox "Automatically create a parallel pool" 
+
+Note: The installation of IQM Tools Lite does not save the MATLAB path. This means that everytime you start MATLAB you will need to 
+      execute the "installIQMlite" script. This procedure has been chosen on purpose, for compliance and reproducibility reasons.
diff --git a/IQMtools V1.2.2.2/IQMlite/license.txt b/IQMtools V1.2.2.2/IQMlite/license.txt
new file mode 100644
index 0000000000000000000000000000000000000000..9cecc1d4669ee8af2ca727a5d8cde10cd8b2d7cc
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/license.txt	
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    {one line to give the program's name and a brief idea of what it does.}
+    Copyright (C) {year}  {name of author}
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    {project}  Copyright (C) {year}  {fullname}
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/IQMtools V1.2.2.2/IQMlite/release.txt b/IQMtools V1.2.2.2/IQMlite/release.txt
new file mode 100644
index 0000000000000000000000000000000000000000..4144d8a335062e61f86d1351a4a7e3cbbaa8d779
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/release.txt	
@@ -0,0 +1,39 @@
+Release Notes IQM Tools Lite
+============================
+
+Version 1.2.2 (02.01.2017)
+--------------------------
+- Minor big fixes
+- Improved graphical output
+- Survival analysis functions
+
+Version 1.2.1 (30.04.2016)
+------------------------
+- Minor big fixes
+
+Version 1.2 (13.04.2016)
+------------------------
+- Allow non-numeric lag time definitions in IQMdosing schemes
+- Ensured compatibility with MONOLIX 4.3.3 
+- Ensured better compatibility with Mac computers
+- Added "bubble plots" function to allow for correlation assesment of categorical variables
+- Added loess/lowess/etc. smoother
+
+Version 1.1 (10.02.2016)
+------------------------
+- Minor bug fixes
+- Update of IQMdosing to fix automatically lenght of the parameter field
+- Added functionality in dosing scenarios to allow estimation of 0th order absorption time
+
+Version 1.0 (09.11.2015)
+------------------------
+- First full release of IQM Lite - the follow-up of SBPOP and SBTOOLBOX2
+- Many improvements with respect to SBPOP (stability, usability, documentation, functionality)
+- Where SBPOP used the "dataset" type, IQM Tools uses the "table" type
+- IQM Tools does not require the presence of the stats toolbox 
+- Parallel computation is used in several functions if the parallel toolbox is available
+- Recommended use of MATLAB >= R2015b (>=R2013B is required)
+- Removed support of SBML Level 1
+- Added support of SBML Level 2, Version 2,3, and 4
+- Implemented "compliance mode" for time and information stamps on figures, tables, text
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/analysis/IQMjacobian.m b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/IQMjacobian.m
new file mode 100644
index 0000000000000000000000000000000000000000..f4a215d1490e8380fda5df258b893fe28a58f80c
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/IQMjacobian.m	
@@ -0,0 +1,125 @@
+function [jacobian,statenames] = IQMjacobian(varargin)
+% IQMjacobian: determines the Jacobian of a given IQMmodel or an ODE file 
+% description. This function should only be used for time-invariant systems.
+% If used for time-variant systems an error will occur.
+%
+% USAGE:
+% ======
+% [jacobian] = IQMjacobian(model,state)         
+% [jacobian] = IQMjacobian(model,state,delta)         
+% [jacobian,statenames] = IQMjacobian(model,state)         
+% [jacobian,statenames] = IQMjacobian(model,state,delta)         
+%
+% model: IQMmodel or ODE file model description
+% state: state at which to determine the Jacobian
+% delta: stepsize used for numerical differentiation. in case of nonzero
+%        states the applied change is relative, in case of a zero value the
+%        applied change is absolute.
+%
+% DEFAULT VALUES:
+% ===============
+% delta: 1e-4
+%
+% Output Arguments:
+% =================
+% jacobian: Jacobian of the model at the given state
+% statenames: cell-array with the names of the states of the model
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GLOBAL VARIABLE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+global ODEfctname
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PARAMETERS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Default stepsize for numerical differentiation
+DEFAULT_DELTA = 1e-4;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF IQMMODEL OR FILENAME
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isIQMmodel(varargin{1}),
+    % IQMmodel
+    iqm = varargin{1};
+    % check delays and events
+    if usedelayIQM(iqm),
+        error('The model contains delays. These can not be handled by this function.');
+    end
+    % Create temporary ODE file
+    [ODEfctname, ODEfilefullpath] = IQMcreateTempODEfile(iqm);    
+else
+    % ODEfctname of ODE file
+    ODEfctname = varargin{1};
+    % Check if file exists
+    if exist(strcat(ODEfctname,'.m')) ~= 2,
+        error('ODE file could not be found.');
+    end
+end
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin == 2,
+    state = varargin{2};
+    delta = DEFAULT_DELTA;
+elseif nargin == 3,
+    state = varargin{2};
+    delta = varargin{3};
+else
+    error('Wrong number of input arguments');
+end
+% Check if correct number of elements in "state".
+teststate = feval(ODEfctname);
+if length(state) ~= length(teststate),
+    error('Number of elements in provided state-vector does not match the number of states in the model.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET JACOBIAN AT GIVEN STATE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+jacobian = calculateJacobian(state,delta);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET THE STATE NAMES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+statenames = feval(ODEfctname,'states');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DELETE FILE IF IQMMODEL
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if strcmp('IQMmodel',class(varargin{1})),
+    IQMdeleteTempODEfile(ODEfilefullpath);
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Calculate Jacobian 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [jacobian] = calculateJacobian(state,delta)
+n = length(state);          % size of system
+jacobian = zeros(n,n);      % initialize jacobian variable
+% determine the Jacobian by numerical differentiation
+for k = 1:n,                
+    statedn = state;
+    stateup = state; 
+    if stateup(k) == 0,
+        stateup(k) = stateup(k) + delta;
+        jacobian(:,k) = (model(stateup)'-model(statedn)')/delta;
+    else
+        stateup(k) = stateup(k)*(1+delta);
+        jacobian(:,k) = (model(stateup)'-model(statedn)')/(delta*stateup(k));
+    end
+end
+return 
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% MODEL
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [xdot] = model(x)
+    global ODEfctname
+    xdot = feval(ODEfctname,0,x);
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/analysis/IQMmakeirreversible.m b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/IQMmakeirreversible.m
new file mode 100644
index 0000000000000000000000000000000000000000..fca50c44afcc36dd965692d03483cca77ae208eb
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/IQMmakeirreversible.m	
@@ -0,0 +1,286 @@
+function [output] = IQMmakeirreversible(model)
+% IQMmakeirreversible
+% For certain analysis methods it is useful that all reaction rate
+% expressions in a model are irreversible. This function takes an IQMmodel
+% as input and replaces all reversible reactions by irreversible ones. This
+% is done by splitting up reversible reaction rates into one forward and one
+% backward rate. For this to be possible it is IMPORTANT that the reaction
+% rate expressions that are marked as reversible in the model are defined
+% in the following format:
+%
+%     ReactionRate = RateForward - RateReverse
+%
+% where "ReactionRate" can be any reaction rate name, and the terms
+% "RateForward" and "RateReverse" can be any mathematical expressions,
+% involving parameters, states, functions, and/or variables.
+% However, it is IMPORTANT that there is only one minus sign in the top
+% level of the formula. Minus signs in eventual parentheses are not taken
+% into account for the parsing and are therefor, of course, allowed to be
+% present.
+%
+% Examples: R1 = Rf1 - Rr1
+%           R2 = k1*A - k2*B
+%           R3 = (k1-k2*A) - (k3+k4*B)
+%
+% This function requires that each reaction only appears once in each ODE.
+% Example:    d/dt(A) = -R1 + R2        is OK
+%             d/dt(B) = -R1 + R2 + R1   is not OK 
+% 
+% Replace last ODE by:    d/dt(B) = R2   or do the irreversible making manually.
+%
+% USAGE:
+% ======
+% [output] = IQMmakeirreversible(model)
+%
+% model: IQMmodel for which to convert reversible reactions to irreversible ones.
+%
+% Output Arguments:
+% =================
+% output: converted model
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF IQMmodel
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~strcmp('IQMmodel',class(model)),
+    error('Function only defined for IQMmodels.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% SAVE ORIGINAL MODEL FOR LATER USE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+originalmodel = model;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK THAT ALL ODE EXPRESSIONS ARE DEFINED VIA REACTION TERMS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[Ntest,componentsTest] = IQMstoichiometry(model,1);  % set rawFlag to 1 
+componentsModel = IQMstates(model);
+if length(componentsTest) ~= length(componentsModel),
+    error('Not all ODEs seem to be constructed by reaction terms. Therefor the full stoichiometric information is not possible to determine.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET NAMES AND DATA OF REVERSIBLE REACTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[names,formulas,reversibleFlag,fastFlag] = IQMreactions(model);
+reversibleReactionsAll = reversibleFlag;
+% check if reversible reactions are present
+if sum(reversibleFlag) == 0,
+    output = model;
+    disp('The model does not contain any reversible reactions.');
+    return
+end
+% get indices of reversible reactions
+reversibleIndices = find(reversibleFlag ~= 0);
+reactionsStore = [];
+for k = 1:length(reversibleIndices),
+    reactionsStore(k).name = names{reversibleIndices(k)};
+    reactionsStore(k).formula = formulas{reversibleIndices(k)};
+    reactionsStore(k).fastFlag = fastFlag(reversibleIndices(k));
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK SYNTAX OF REACTION RATES (R = Rf-Rr)
+% AND SPLIT THEM UP INTO Rf and Rr
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+errorReversibleRateDefinitions = '';
+for k = 1:length(reactionsStore),
+    irreversibleRates = explodePCIQM(reactionsStore(k).formula,'-');
+    if length(irreversibleRates) ~= 2,
+        % Need to have two parts that are separated by a '-' sign. (Forward
+        % first, then reverse reaction kinetics).
+        errorReversibleRateDefinitions = sprintf('%sError in rate definition of reaction rate ''%s''. It does not seem to be reversible.\n', errorReversibleRateDefinitions, reactionsStore(k).name);
+    else
+        % Seems fine ... save the different parts
+        reactionsStore(k).forwardRate = irreversibleRates{1};
+        reactionsStore(k).reverseRate = irreversibleRates{2};        
+    end
+end
+if ~isempty(errorReversibleRateDefinitions),
+    error(errorReversibleRateDefinitions);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DELETE REVERSIBLE RATES AND ADD IRREVERSIBLE ONES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for k = 1:length(reactionsStore),
+    model = deletereactionratesIQM(model, reactionsStore(k).name);
+    forwardReactionName = strcat(reactionsStore(k).name,'_forward');
+    reverseReactionName = strcat(reactionsStore(k).name,'_reverse');
+    reversibleFlag = 0;
+    notes = '';
+    model = addreactionrateIQM(model, forwardReactionName, reactionsStore(k).forwardRate, notes, reversibleFlag, reactionsStore(k).fastFlag);
+    model = addreactionrateIQM(model, reverseReactionName, reactionsStore(k).reverseRate, notes, reversibleFlag, reactionsStore(k).fastFlag);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET AND SAVE COMPARTMENT INFORMATION (original model)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[allComponentNames,allODEs] = IQMstates(originalmodel);
+compartmentInformation = {}; % Strings ordered in the same way as states in the model
+% check if a scaling by the compartment volume is done.
+% in this case the expected syntax is 
+% ODE = ("reactionterms")/compartmentvolume
+% the compartment information is saved and used later to restore the ODEs
+for k = 1:length(allODEs),     
+    ODE = strtrim(allODEs{k});
+    numberOpenParentheses = length(find(ODE == '('));
+    numberClosedParentheses = length(find(ODE == ')'));
+    % all eventual errorneous cases are caught in the beginning of this
+    % function by calling IQMstoichiometry
+    if ODE(1) == '(',
+        % if the first character is an open parenthesis then assume that 
+        % this is due to a adjustement to compartment sizes. here we only
+        % need to keep the compartment information.
+        % cut out the content of the parentheses
+        closeParenthesis = find(ODE == ')');
+        compartmentInformation{k} = ODE(closeParenthesis+1:end);
+    else
+        compartmentInformation{k} = '';
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% UPDATE RIGHT HAND SIDE OF THE ODES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% get model structure
+modelstruct = IQMstruct(model);
+% determine stoichiometric information of original model to 
+% see where and with which stoichiometric coefficient the reversible
+% reactions come into play. The stoichiometry function takes care of
+% compartment factors by itself 
+N = IQMstoichiometry(originalmodel,1); % set rawFlag to 1
+% get info about non elementary reactions and delete them from the
+% stoichiometric matrix (will be taken care off later)
+L = IQMreactantstoichiometry(originalmodel,1); % reactant stoichiometry
+Lnone = L+N.*(N<0);
+if sum(sum(abs(Lnone))) ~= 0,
+    error('Same reaction appears in at least one ODE more than once. Please see the help text to IQMmakeirreversible.');
+end
+% Rnone = N.*(Lnone~=0)+L.*(Lnone>0);
+% % now delete
+% N = N.*(Lnone == 0).*(Rnone == 0);
+
+% get the submatrix of N corresponding only to the irreversible reactions
+% reversibleIndices is same as determined above and irreversibleIndices can
+% be determined by
+irreversibleIndices = setdiff(1:length(IQMreactions(originalmodel)),reversibleIndices);
+Nirrev = N(:,irreversibleIndices);
+% get the submatrix of N corresponding only to the reversible reactions
+% reversibleIndices is same as determined above
+Nrev = N(:,reversibleIndices);
+% clear all ODEs
+for k = 1:length(modelstruct.states),
+    modelstruct.states(k).ODE = '';
+end
+% cycle through the columns of Nirrev (irreversible reaction rates) and
+% construct the corresponding ODEs
+reactionNamesOriginal = IQMreactions(originalmodel);
+irrevReactionNames = reactionNamesOriginal(irreversibleIndices);
+for k1 = 1:size(Nirrev,2),
+    % get indices of state number where to add the terms
+    addTermsIndices = find(Nirrev(:,k1) ~= 0);
+    for k2 = 1:length(addTermsIndices),
+        % construct expression
+        stoichCoeff = Nirrev(addTermsIndices(k2),k1);
+        if stoichCoeff > 0,
+            if stoichCoeff ~= 1,
+                addTerm = sprintf('+%g*%s',abs(stoichCoeff),irrevReactionNames{k1});
+            else
+                addTerm = sprintf('+%s',irrevReactionNames{k1});
+            end
+        elseif stoichCoeff < 0,
+            if stoichCoeff ~= -1,
+                addTerm = sprintf('-%g*%s',abs(stoichCoeff),irrevReactionNames{k1});
+            else
+                addTerm = sprintf('-%s',irrevReactionNames{k1});
+            end
+        else
+            error('This can not happen :)');
+        end
+        % add the new term to the corresponding ODE
+        modelstruct.states(addTermsIndices(k2)).ODE = strcat(modelstruct.states(addTermsIndices(k2)).ODE, addTerm);
+    end
+end
+% cycle trough the columns of Nrev (reversible reaction rates) and add the
+% corresponding terms to the corresponding ODE expressions
+for k1 = 1:size(Nrev,2),
+    % get indices of state number where to add the terms
+    addTermsIndices = find(Nrev(:,k1) ~= 0);
+    for k2 = 1:length(addTermsIndices),
+        % construct expression
+        stoichCoeff = Nrev(addTermsIndices(k2),k1);
+        if stoichCoeff > 0,
+            if stoichCoeff ~= 1,
+                addTerm = sprintf('+%g*%s_forward-%g*%s_reverse',abs(stoichCoeff),reactionsStore(k1).name,abs(stoichCoeff),reactionsStore(k1).name);
+            else
+                addTerm = sprintf('+%s_forward-%s_reverse',reactionsStore(k1).name,reactionsStore(k1).name);
+            end                
+        elseif stoichCoeff < 0,
+            if stoichCoeff ~= -1,
+                addTerm = sprintf('-%g*%s_forward+%g*%s_reverse',abs(stoichCoeff),reactionsStore(k1).name,abs(stoichCoeff),reactionsStore(k1).name);
+            else
+                addTerm = sprintf('-%s_forward+%s_reverse',reactionsStore(k1).name,reactionsStore(k1).name);
+            end
+        else
+            error('This can not happen :)');
+        end
+        % add the new term to the corresponding ODE
+        modelstruct.states(addTermsIndices(k2)).ODE = strcat(modelstruct.states(addTermsIndices(k2)).ODE, addTerm);
+    end
+end
+
+% % handle non elementary reactions
+% if sum(sum(abs(Lnone))) ~= 0,
+%     % non elementary reactions are present ... need to add those reactions
+%     % to the ODEs
+%     for k = 1:size(N,1),
+%         Lrow = Lnone(k,:);
+%         Rrow = Rnone(k,:);
+%         if sum(Lrow) ~= 0,
+%             for k2 = 1:length(Lrow),
+%                 if Lrow(k2) ~= 0,
+%                     if ~reversibleReactionsAll(k2),
+%                         modelstruct.states(k).ODE = sprintf('%s-%g*%s',modelstruct.states(k).ODE, Lrow(k2), reactionNamesOriginal{k2});
+%                     else
+%                         addTerm = sprintf('-%g*%s_forward+%g*%s_reverse',Lrow(k2),reactionNamesOriginal{k2},Rrow(k2),reactionNamesOriginal{k2});
+%                         modelstruct.states(k).ODE = sprintf('%s%s',modelstruct.states(k).ODE, addTerm);
+%                     end
+%                 end
+%             end
+%         end
+%         if sum(Rrow) ~= 0,
+%             for k2 = 1:length(Rrow),
+%                 if Rrow(k2) ~= 0,
+%                     if ~reversibleReactionsAll(k2),
+%                         modelstruct.states(k).ODE = sprintf('%s+%g*%s',modelstruct.states(k).ODE, Rrow(k2), reactionNamesOriginal{k2});
+%                     else
+%                         addTerm = sprintf('-%g*%s_forward+%g*%s_reverse',Rrow(k2),reactionNamesOriginal{k2},Lrow(k2),reactionNamesOriginal{k2});
+%                         modelstruct.states(k).ODE = sprintf('%s%s',modelstruct.states(k).ODE, addTerm);
+%                     end
+%                 end
+%             end
+%         end
+%     end
+% end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% ADD EVENTUAL COMPARTMENT INFORMATION TO ODEs
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for k = 1:length(compartmentInformation),
+    if ~isempty(compartmentInformation{k}),
+        modelstruct.states(k).ODE = strcat('(',modelstruct.states(k).ODE,')',compartmentInformation{k});
+    end
+end
+
+% convert structure to model again
+model = IQMmodel(modelstruct);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% OUTPUT THE MODEL
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+output = model;
+return
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/analysis/IQMmoietyconservations.m b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/IQMmoietyconservations.m
new file mode 100644
index 0000000000000000000000000000000000000000..980ec5dc2d60fc2d19aaa23fd5a2e1ca7ec55b70
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/IQMmoietyconservations.m	
@@ -0,0 +1,251 @@
+function [varargout] = IQMmoietyconservations(varargin)
+% IQMmoietyconservations: determines the moitey conservations that are
+% present in a model. The model can be specified as IQMmodel or as ODE file.
+%
+% USAGE:
+% ======
+% [] = IQMmoietyconservations(model)         
+% [] = IQMmoietyconservations(model,stateValues)         
+% [] = IQMmoietyconservations(model,stateValues,tol)         
+% [formulas,constants] = IQMmoietyconservations(model,stateValues,tol)         
+% [depVarIndex, depVarConstant, depVarFactor, message] = IQMmoietyconservations(model)         
+% [depVarIndex, depVarConstant, depVarFactor, message] = IQMmoietyconservations(model,stateValues)         
+% [depVarIndex, depVarConstant, depVarFactor, message] = IQMmoietyconservations(model,stateValues,tol)         
+%
+% model: IQMmodel or ODE file model description
+% stateValues: values of the state variables for which to perform the
+%   analysis
+% tol: Tolerance for the determination of the number of algebraic
+% 	relationships in the model. If the method fails than this
+%   might be due to a wrong rank computation and in this case
+%   the tolerance should be increased. If set, the same tolerance
+%   setting is used when determining the indices of the
+%   dependent variables.
+%
+%
+% DEFAULT VALUES:
+% ===============
+% stateValues: if not given, the state stored in the model is used to
+%   determine the moiety conservations. It is a good idea to a systems
+%   steady-state for the computation of the conservations
+%
+% Output Arguments:
+% =================
+% depVarIndex: index of dependent states
+% depVarConstant: Sum of states taking part in conservation
+% depVarFactor: Factor for states - non-zero values for the ones that take
+%   part in conservation
+% message: Any message that otherwise is printed to the MATLAB window
+% formulas: A cell-array containing the equations of the found algebraic
+%           relations
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+global message
+message = '';
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF IQMMODEL OR FILENAME
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if strcmp('IQMmodel',class(varargin{1})),
+    % IQMmodel
+    iqm = varargin{1};
+    % Create temporary ODE file
+    [ODEfctname, ODEfilefullpath] = IQMcreateTempODEfile(iqm);    
+else
+    % ODEfctname of ODE file
+    ODEfctname = varargin{1};
+    % set iqm to empty!
+    iqm = [];
+    % Check if file exists
+    if exist(strcat(ODEfctname,'.m')) ~= 2,
+        error('ODE file could not be found.');
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin == 1,
+    % handle numeric and non-numeric ICs
+    stateValues = IQMcalcICvector(ODEfctname);
+    tol = 0;
+elseif nargin == 2,
+    stateValues = varargin{2};
+    stateValues = stateValues(:);
+    tol = 0;
+elseif nargin == 3,
+    stateValues = varargin{2};
+    stateValues = stateValues(:);
+    tol = varargin{3};
+else
+    error('Incorrect number of input arguments.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DETERMINE THE MOIETY CONSERVATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[depVarIndex, depVarConstant, depVarFactor] = getMoietyConservations(iqm,ODEfctname,stateValues,tol);
+% invert order of moiety conservations (to be able to evaluate them
+% sequentially in case of model reduction)
+depVarIndex(1:end) = depVarIndex(end:-1:1);
+depVarConstant(1:end) = depVarConstant(end:-1:1);
+depVarFactor(1:end,:) = depVarFactor(end:-1:1,:);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CONSTRUCT RESULT MESSAGE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+MCarray = {};
+MCconstants = [];
+if ~isempty(depVarIndex),
+    message = sprintf('%s\nFollowing moitey conservations have been found:\n',message);
+    variableNames = feval(ODEfctname,'states');
+    for k1 = 1:length(depVarIndex),
+        MCarray{k1} = sprintf('%s = moietyConserv_%d',variableNames{depVarIndex(k1)},k1);
+        MCconstants(k1) = depVarConstant(k1);
+        message = sprintf('%s\n%s = %g',message,variableNames{depVarIndex(k1)},depVarConstant(k1));
+        for k2 = 1:length(depVarFactor(k1,:)),
+            if abs(depVarFactor(k1,k2)) > 0,
+                % Here a check against 0 can be done since zerocheck
+                % already done and small values set to identically zero.
+                if depVarFactor(k1,k2) > 0
+                    element = sprintf('+%g*',depVarFactor(k1,k2));
+                else
+                    element = sprintf('-%g*',abs(depVarFactor(k1,k2)));
+                end
+                MCarray{k1} = sprintf('%s%s%s',MCarray{k1},element,variableNames{k2});
+                message = sprintf('%s%s%s',message,element,variableNames{k2});
+            end
+        end
+    end
+    message = sprintf('%s\n',message);
+else
+    message = sprintf('%sNo moiety conservations have been found.\n',message);
+end
+message = sprintf('%s\nIf this result does not seem correct, do the analysis\nusing a different initial condition and/or tolerance setting.',message);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS VARIABLE OUTPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargout == 0,
+    % no output argument => simply display the results
+    disp(message);
+elseif nargout == 2,
+    varargout{1} = MCarray;
+    varargout{2} = MCconstants;
+elseif nargout == 4,
+    varargout{1} = depVarIndex;
+    varargout{2} = depVarConstant;
+    varargout{3} = depVarFactor;
+    varargout{4} = message;
+else
+    error('Incorrect number of output arguments');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DELETE FILE IF IQMMODEL
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if strcmp('IQMmodel',class(varargin{1})),
+    IQMdeleteTempODEfile(ODEfilefullpath);
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET THE MOIETY CONSERVATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% the function works either based on the jacobian or if it is possible on
+% the stoichiometric matrix. the latter is only possible if the model is
+% given as IQMmodel and the odes are fully described in terms of reaction
+% rates.
+function [depVarIndex, depVarConstant, depVarFactor] = getMoietyConservations(iqm,ODEfctname,stateValues,tol)
+global message;
+% initialize return variables
+depVarIndex = [];
+depVarConstant = [];
+depVarFactor = [];
+% get initial condition 
+initialCondition = stateValues;
+% check if model given as IQMmodel:
+if ~isempty(iqm),
+    % check if stoichiometric matrix gives full information
+    N = IQMstoichiometry(iqm,0,1); % no rawFlag but silentFlag!
+    if length(initialCondition) == size(N,1),
+        % yes, full information available
+        useStoich = 1;
+    else
+        useStoich = 0;
+    end
+else
+    useStoich = 0;
+end
+% handle stoich and jac differently
+if useStoich == 0,
+    % use Jacobian!
+    % Get jacobian and determine its rankdeficiency - use default deltaX for
+    % numerical differentiation
+    J = IQMjacobian(ODEfctname,initialCondition);
+
+% handle ARs by reducing J
+nrARs = length(feval(ODEfctname,'algebraic'));
+J = J(1:end-nrARs, 1:end-nrARs);
+  
+    if tol == 0,
+        d = length(J) - rank(J);        
+    else
+        d = length(J) - rank(J,tol);
+    end
+else
+    % use stoichiometry
+    if tol == 0,
+        X = rref([N,eye(size(N,1))]);
+    else
+        X = rref([N,eye(size(N,1))],tol);
+    end        
+    Nx = X(:,1:size(N,2));
+    d = length(find(sum(abs(Nx)')'==0));
+end
+if d > 0,
+    % print out a message
+    message = sprintf('%sThe system has a rank deficiency of %d. This might be due to moiety or\nother conservations in the model, to the excessive use of zero initial\nconditions and/or integrating behavior of the system. If this does\nnot seem to be correct, please check the initial conditions and/or\nset a different value for the tolerance "tol" in the options.\n',message,d);
+    % The systems contains algebraic relationships (moiety conservations)
+    % Handle stoich and jac differently
+    if useStoich == 0,
+        message = sprintf('%s\nThe algebraic relationships are determined using the Jacobian.\nThis is numerically not very stable and you need eventually\nto change tolerance "tol" settings.\n',message);
+        % Use the singular value decomposition of the Jacobian to determine
+        % the algebraic relationships
+        [U,S,V] = svd(J);
+        U0 = U(:,length(J)-d+1:length(J));
+        if tol == 0,
+            factors = rref(U0');
+        else
+            factors = rref(U0',tol);
+        end
+    else
+        message = sprintf('%s\nThe algebraic relationships are determined using the Stoichiometric matrix.\n',message);
+        % Use rref of the Stoichiometric Matrix
+        factors = X(end-d+1:end,size(N,2)+1:end);
+    end    
+    % set smaller values than tolerance to zero
+    factors(find(abs(factors)<tol)) = 0;
+% handle ARs by reducing initialConditions
+nrARs = length(feval(ODEfctname,'algebraic'));
+iCs = initialCondition(1:end-nrARs);    
+    constantValues = factors*iCs;
+    % Process the result and get the algebraic equations
+    for k = 1:size(factors,1),
+        relation = [factors(k,:) constantValues(k)];
+        % find largest element (abs) in the first n-1 elements
+        [value,index] = max(abs(relation(1:length(relation)-1)));
+        % normalize the relation
+        relation = relation./relation(index);
+        % the index of the largest element is the index of a dependent variable
+        depVarIndex = [depVarIndex index];
+        % the constant value is given by the last element in relation
+        depVarConstant = [depVarConstant; relation(length(relation))];
+        % the factor vector is constructed as follows:
+        factorVector = -relation(1:length(relation)-1); factorVector(index) = 0;
+        depVarFactor = [depVarFactor; factorVector];
+    end
+end
+return
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/analysis/IQMreactantstoichiometry.m b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/IQMreactantstoichiometry.m
new file mode 100644
index 0000000000000000000000000000000000000000..3098f389017dd3e43dee814c0560caa337bba70e
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/IQMreactantstoichiometry.m	
@@ -0,0 +1,245 @@
+function [L] = IQMreactantstoichiometry(model,varargin)
+% IQMreactantstoichiometry
+% Determines the stoichiometric coefficients of only the reactants. 
+% Non-elementary reactions are taken into account ... otherwise this 
+% function would not really make sense.
+%
+% USAGE:
+% ======
+% [L] = IQMreactantstoichiometry(model)
+%
+% model: IQMmodel to determine the reactant stoichiometric matrix for
+%
+% DEFAULT VALUES:
+% ===============
+%
+% Output Arguments:
+% =================
+% L: stoichiometric matrix with coefficients only for the reactants
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF IQMmodel
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~strcmp('IQMmodel',class(model)),
+    error('Function only defined for IQMmodels.');
+end
+% get the datastructure of the model
+modelstruct = IQMstruct(model);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK EXTRA INPUT ARGUMENT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% the first extra input argument is used to force the IQMstoichiometry function 
+% not to correct the elements of the stoichiometric matrix for the
+% compartment information in cases where species are given in
+% concentrations. This is needed for model construction (BC type of
+% representation and for other things)
+% the second is used for silent use of the function
+% both flags are not further documented and should not be used by others
+% unless they fully understand their meaning
+
+rawFlag = 0;
+silentFlag = 0;
+if nargin == 2,
+    rawFlag = varargin{1};
+elseif nargin == 3,
+    rawFlag = varargin{1};
+    silentFlag = varargin{2};
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get all reaction names
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[reactionNames, dummy, reversibleFlag]  = IQMreactions(model);
+if isempty(reactionNames),
+    if silentFlag == 0,
+        error('No reactions present in the model');
+    else
+        N = [];
+        componentNames = {};
+        reactionNames = {};
+        reversibleFlag = [];
+        return
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Go trough all ODEs and check reactions ...
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% go through all ODEs and check for which components the ODEs only
+% consist of reaction terms - this returns already positive and negative
+% terms and coefficients
+componentNames = {};
+[parameterNames, parameterValues] = IQMparameters(model);
+N = [];
+for k = 1:length(modelstruct.states),
+    ODE = modelstruct.states(k).ODE;
+    % check if ODE contains only reaction terms - otherwise do not 
+    % consider the current state as component for the stoichiometric matrix
+    Nrow = getStoichiometryInformation(ODE,reactionNames,parameterNames,parameterValues,rawFlag,silentFlag);
+    if ~isempty(Nrow),
+        N = [N; Nrow];
+        componentNames{size(N,1)} = modelstruct.states(k).name;
+    end
+end
+% check for zero rows in N and take them away both from N and from the
+% list of component names
+%useIndices = find(sum(abs(N')) ~= 0);
+%notUseIndices = find(sum(abs(N')) == 0);
+
+nonReactionStates = setdiff(IQMstates(model),componentNames);
+if ~isempty(nonReactionStates) && silentFlag == 0,
+    disp('For the following components no stoichiometries could be determined.');
+    disp('This is due to the syntax of the corresponding ODEs.');
+    text = '';
+    for k = 1:length(nonReactionStates),
+        text = sprintf('%s %s\n',text,nonReactionStates{k});
+    end
+    disp(text);
+end
+%componentNames = componentNames(useIndices);
+%N = N(useIndices,:);
+L = N;
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK ODEs for reactions
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% check if given ODE expression contains only reaction terms - then return
+% the stoichiometry for this ODE. Otherwise if not only reactions are
+% present, return an empty vector.
+% in cases that the reaction rate is adjustet by the compartment volume
+% (happens especially in cases of import of SBML models containing species
+% with concentration rates and compartment volumes different from one) the
+% adjustment term and the needed parentheses should be detected and
+% neglected.
+function [Nrow] = getStoichiometryInformation(ODE,reactionNames,parameterNames,parameterValues,rawFlag,silentFlag)
+errorFlag = 0;
+% delete all white spaces from the ODE
+ODE = regexprep(ODE,'\s*','');
+% first of all check if a scaling by the compartment volume is done.
+% in this case the expected syntax is 
+% ODE = ("reactionterms")/compartmentvolume
+numberOpenParentheses = length(find(ODE == '('));
+numberClosedParentheses = length(find(ODE == ')'));
+compartmentSize = 1;
+if numberOpenParentheses ~= numberClosedParentheses,
+    % parentheses need to appear in pairs - otherwise error
+    errorFlag = 1;
+elseif numberOpenParentheses > 1,
+    % if there is more than one pair of parentheses, then error
+    errorFlag = 1;
+elseif numberOpenParentheses == 0,
+    errorFlag = 0;
+elseif ODE(1) == '(',
+    % if the first character is an open parenthesis then assume that 
+    % this is due to a adjustement to compartment sizes
+    % cut out the content of the parentheses
+    closeParenthesis = find(ODE == ')');
+    ODERHS = ODE;
+    ODE = ODERHS(2:closeParenthesis-1);
+    % check part outside parenthesis
+    rest = ODERHS(closeParenthesis+1:end);
+    % first character needs to be a '/'
+    if rest(1) ~= '/',
+        errorFlag = 1;
+    else
+        rest = rest(2:end);
+        % check if this rest corresponds to a parameter name and if yes get
+        % its value
+        index = strmatchIQM(rest,parameterNames,'exact');
+        if ~isempty(index),
+            compartmentSize = parameterValues(index);
+            errorFlag = 0;
+        else
+            if silentFlag == 0,
+                error('The stoichimetric matrix can not be computed. A compartment size seems not to be given as a parameter.');
+            else 
+                errorFlag = 1;
+            end
+        end
+    end
+else
+    % parentheses is expected as first non white space character in
+    % reaction string ... therefor an error.
+    errorFlag = 1;
+end
+% continue with the algorithm if no error occurred
+if errorFlag == 0,
+    ODE = char([double(ODE) double('+')]);  % fastest strcat
+    % first explode the ODE in additive terms
+    terms = [];
+    termIndex = 1;
+    % check the sign of the first term (first character in string)
+    if ODE(1) == '-',
+        signCurrent = -1;
+        lastIndex = 2;
+    elseif ODE(1) == '+',
+        signCurrent = +1;
+        lastIndex = 2;
+    else
+        signCurrent = +1;
+        lastIndex = 1;
+    end
+    % explode in terms, check if term has the right format and if the
+    % second term features a reactionname. then construct the row of the
+    % stoichiometric matrix
+    Nrow = zeros(1,length(reactionNames));
+    startk = lastIndex;
+    for k = startk:length(ODE),
+        % check for positive term
+        if ODE(k) == '+' || ODE(k) == '-',
+            element = ODE(lastIndex:k-1);
+            % check the element if composed of term in the right format
+            multIndex = find(element == '*');
+            if length(multIndex) == 0,
+                stoichiometry = signCurrent*1;
+                reactionterm = element;
+            elseif length(multIndex) == 1,
+                absStoichiometry = str2double(element(1:multIndex-1));
+                if isempty(absStoichiometry),
+                    errorFlag = 1;
+                    break;
+                end
+                stoichiometry = signCurrent*absStoichiometry;
+                reactionterm = element(multIndex+1:end);
+            else
+                % to many multiplication signs (only one allowed)
+                errorFlag = 1;
+                break;
+            end
+            % find the index of the reaction name and add the
+            % stoichiometric information to Nrow
+            indexReaction = strmatchIQM(reactionterm,reactionNames,'exact');
+            if isempty(indexReaction),
+                errorFlag = 1;
+                break;
+            end
+            % only add the coefficient if sign is negative (reactant)
+            if signCurrent == -1,
+                Nrow(indexReaction) = Nrow(indexReaction) + abs(stoichiometry);
+            end
+            % increment
+            termIndex = termIndex + 1;
+            lastIndex = k+1;
+            if ODE(k) == '+',
+                signCurrent = +1;
+            else
+                signCurrent = -1;
+            end
+        end
+    end
+end
+% if an error occurred for the current ODE the Nrow is set to zero
+if errorFlag == 1,
+    Nrow = [];
+end
+% adjust stoichiometries with compartment size
+if rawFlag == 0,
+    Nrow = Nrow / compartmentSize;
+end
+return
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/analysis/IQMreducemodel.m b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/IQMreducemodel.m
new file mode 100644
index 0000000000000000000000000000000000000000..3a7e3986d3f5ad46b417965859e36d398ad158c8
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/IQMreducemodel.m	
@@ -0,0 +1,343 @@
+function [reducedmodel] = IQMreducemodel(varargin)
+% IQMreducemodel: Reduces an IQMmodel by identifying algebraic relations 
+% between time dependent variable, defined by differential equations, and 
+% deleting the dependent variables. This function first checks if the 
+% IQMmodel contains algebraic relations between the state variables. If 
+% there are, it lets the user decide which variables to choose as dependent
+% ones and to replace the ODEs by algebraic relations.
+%
+% Due to moiety conservations algebraic relations are often present in 
+% biological systems. However, for several analysis methods models are 
+% required to be non-singular. This function helps to avoid this problem.
+%
+% USAGE:
+% ======
+% [reducedmodel] = IQMreducemodel(model)         
+% [reducedmodel] = IQMreducemodel(model,tol)         
+%
+% model: IQMmodel model to reduce
+% tol: tolerance to be used to determine moiety conservations
+%
+% DEFAULT VALUES:
+% ===============
+% tol: same as for IQMmoietyconservations
+%
+% Output Arguments:
+% =================
+% reducedmodel: Reduced IQMmodel. If no algebraic relations were present in
+%       the model, the initial model is returned unchanged.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% NEEDED GLOBAL VARIABLES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+global ODEfctname 
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF IQMMODEL OR FILENAME
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if strcmp('IQMmodel',class(varargin{1})),
+    % IQMmodel
+    iqm = varargin{1};
+    % Create temporary ODE file
+    [ODEfctname, ODEfilefullpath] = IQMcreateTempODEfile(iqm);    
+else
+    error('This function can not be applied to ODE files.');
+end
+
+if nargin == 1,
+    tol = 0;
+elseif nargin == 2,
+    tol = varargin{2};
+else
+    error('Incorrect number of input arguments.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK AND REDUCE THE MODEL
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+reducedmodel = reduceModel(iqm,tol);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DELETE FILE 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+IQMdeleteTempODEfile(ODEfilefullpath);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK AND REDUCE THE MODEL
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [iqmReduced] = reduceModel(iqm,tol)
+% needed global variables
+global ODEfctname
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DETERMINE THE MOIETY CONSERVATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get initial conditions (numeric and non-numeric ICs)
+initialCondition = IQMcalcICvector(ODEfctname);
+[depVarIndex, depVarConstant, depVarFactor, message] = IQMmoietyconservations(iqm,initialCondition,tol);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF REDUCTION NECESSARY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(depVarIndex),
+    % System is non-singular - return the original system
+    disp('Model is non-singular. Nothing is done.');
+    iqmReduced = iqm; 
+    return
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% REMOVE NON-NUMERIC ICs (if present)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% print a warning if non-numeric initial conditions (reduction will be
+% correct but non-numeric ICs have been replaced by numeric ones).
+if ~hasonlynumericICsIQM(iqm),
+    numICs = IQMcalcICvector(iqm);
+    ms = struct(iqm);
+    for k=1:length(ms.states),
+        ms.states(k).initialCondition = numICs(k);
+    end
+    iqm = IQMmodel(ms);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK THE CONSERVATION EQUATIONS 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% To be able to include them as variables in an IQMmodel it is important
+% that the moietyconservations are independent of each other. No algebraic
+% loop is allowed.
+% for k1 = 1:size(depVarFactor,1),
+%     for k2 = 1:size(depVarFactor,1),
+%         if k1 ~= k2,
+%            if ~isempty(intersect(find(depVarFactor(k1,:)~=0),find(depVarFactor(k2,:)~=0))),
+%                error(sprintf('The model can not be reduced due to dependency among the conservations.\nIn the future the toolbox will support these kind of things, but not today.\nSorry!'));
+%            end
+%         end
+%     end
+% end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CONVERSION OF THE MOIETY CONSERVATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% need to convert these results to a different format.
+% result format: dependentVariable = constantTerm + factor1*variable1 + ... + factorn*variablen
+% needed format: constantTerm = dependentVariable + NewFactor1*variable1 -
+% ... + NewFactorn*variablen
+% => change sign in depVarFactor and add a 1 in the places corresponding to
+% the dependent variables.
+depVarFactor = -depVarFactor;
+for k = 1:length(depVarIndex),
+    depVarFactor(k,depVarIndex(k)) = 1;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS SYSTEM
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% System is singular - process the algebraic relations
+d = length(depVarIndex);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DISPLAY ALL ALGEBRAIC RELATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+disp(message);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DECIDE WHICH STATES TO REMOVE (USER)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+text = sprintf('You need to decide, for each algebraic relation, which state to remove from the model.\n');
+disp(text);
+% handle the case when events are present in the model (the states that are
+% changed by events can not be removed). If this leads to no reducable
+% states an error message will be displayed.
+iqms = struct(iqm);
+eventvariables = {};
+eventstateindices = [];
+if ~isempty(iqms.events),
+    for k=1:length(iqms.events),
+        eventvariables = {eventvariables{:} iqms.events(k).assignment(1:end).variable};
+    end
+    eventvariables = unique(eventvariables);
+    % check which of these eventvariables are states 
+    eventstateindices = stateindexIQM(iqm,eventvariables); 
+    % remove the elements that are -1 (no states) ... the rest are indices
+    % of states that are changed by events
+    eventstateindices(eventstateindices<0) = [];
+    % mark the elements that correspond to state variables that have
+    % a zero right hand side of the ODE (these become parameters and thus
+    % can be changed by events).
+    for k=1:length(eventstateindices),
+        if iqms.states(eventstateindices(k)).ODE == '0',
+            eventstateindices(k) = -1;
+        end
+    end
+    % and remove them
+    eventstateindices(eventstateindices<0) = [];
+    % eventstateindices now contains the indices of the states that are not
+    % allowed to be removed from the set of ODEs. simply because these can
+    % be changed by events and this is only possible if they are kept as
+    % states.
+end
+statesRemove = [];
+variableNames = feval(ODEfctname,'states');
+% cycle through all the algebraic relations, display them and let the
+% user decide which state to remove.
+for k1 = 1:length(depVarConstant),
+    % delete the eventstateindices states from the states that are removable
+    removableStates = setdiff(find(depVarFactor(k1,:) ~= 0), eventstateindices);
+    % remove the already removed states
+    indices = setdiff(removableStates,statesRemove);
+    % check if at least one state removable
+    if isempty(indices),
+        error(sprintf('There is a moiety conservation but none of the states can be removed.\nThis is most certainly due to the fact that at least one event is present\nin the model that changes the states involved in this moiety conservation.\nDeleting the states would lead to an incorrect event behavior.'));
+    end
+    text = sprintf('Relation %d: %s',k1,getTextAlgebraicRelation(depVarConstant(k1),depVarFactor(k1,:)));
+    disp(text);
+    text = sprintf('Choose the number of the state that should be removed (1-%d).',length(indices));
+    disp(text);
+    text = '';
+    for k2 = 1:length(indices),
+        text = sprintf('%s (%d)%s  ',text,k2,variableNames{indices(k2)});
+    end
+    disp(text);
+    indexRemove = input('State to remove: ');
+    if indexRemove > length(indices) || indexRemove < 1,
+        error('Wrong input!');
+    end
+    statesRemove = [statesRemove indices(indexRemove)];
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CONSTRUCT REDUCED MODEL
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% get the structure of the IQMmodel
+modelStructure = IQMstruct(iqm); % will contain the reduced information
+fullModelStructure = IQMstruct(iqm); % contains the full information (needed only for updating the additional information fields of the variables)
+% create new "states" entry and copy only the states that are not
+% deleted into it
+states = [];
+statesCount = 1;
+for k1 = 1:length(modelStructure.states),
+    if sum(ismember(statesRemove,k1)) == 0,
+        % copy this state information to new model
+        states(statesCount).name = modelStructure.states(k1).name;
+        states(statesCount).initialCondition = modelStructure.states(k1).initialCondition;
+        states(statesCount).ODE = modelStructure.states(k1).ODE;
+        states(statesCount).type = modelStructure.states(k1).type;
+        states(statesCount).compartment = modelStructure.states(k1).compartment;
+        states(statesCount).unittype = modelStructure.states(k1).unittype;
+        states(statesCount).notes = modelStructure.states(k1).notes;
+        statesCount = statesCount + 1;
+    end
+end
+% Include the state information in the model structure
+modelStructure.states = states;
+% Now add the algebraic relations as variables.
+% It is important to add the relations before all other variables!
+% Since they might be used in the other variables!
+variables = [];
+variableCount = 1;
+parameterCount = length(modelStructure.parameters)+1;
+% First add the algebraic relations
+for k1 = 1:length(depVarConstant),
+    % Construct variable formula corresponding to algebraic relation
+    % Get the constant term
+    constantTerm = depVarConstant(k1);
+    % Scale the factor vector with -1 and set reduced element to zero
+    factor = depVarFactor(k1,:);
+    scaleFactor = 1/abs(factor(statesRemove(k1)));
+    factor = -factor*scaleFactor;
+    factor(statesRemove(k1)) = 0;
+    % Scale the constant term
+    constantTerm = constantTerm*scaleFactor;
+    % get the variableName
+    variable = variableNames{statesRemove(k1)};
+    % Construct the formula string
+    moietyConservationName = sprintf('conserv%d',k1);
+    formula = sprintf('%s',moietyConservationName);
+    % CHECK factor ... if all zero then add MC thing as parameter not as
+    % variable!
+    if sum(abs(factor)) ~= 0,
+        for k2 = 1:length(factor),
+            if factor(k2) > 0,
+                % here 0 can be used (zerocheck already done)
+                formula = sprintf('%s+%g*%s',formula,abs(factor(k2)),variableNames{k2});
+            elseif factor(k2) < 0,
+                % here 0 can be used (zerocheck already done)
+                formula = sprintf('%s-%g*%s',formula,abs(factor(k2)),variableNames{k2});
+            end
+        end
+        % Add algebraic relation as variable
+        variables(variableCount).name = variable;
+        variables(variableCount).formula = formula;
+        variables(variableCount).notes = 'Removed algebraic relation';
+        variables(variableCount).type = fullModelStructure.states(statesRemove(k1)).type;
+        variables(variableCount).compartment = fullModelStructure.states(statesRemove(k1)).compartment;
+        variables(variableCount).unittype = fullModelStructure.states(statesRemove(k1)).unittype;
+        variableCount = variableCount + 1;
+        % add the constant term as a parameter
+        modelStructure.parameters(parameterCount).name = moietyConservationName;
+        modelStructure.parameters(parameterCount).value = str2num(sprintf('%g',constantTerm));
+        moietyConservationNotes = sprintf('Moiety conservation for: %s',getTextAlgebraicRelation(depVarConstant(variableCount-1),depVarFactor(variableCount-1,:)));
+        moietyConservationNotes = moietyConservationNotes(1:strfind(moietyConservationNotes,'=')-1);
+        modelStructure.parameters(parameterCount).type = 'isParameter';
+        modelStructure.parameters(parameterCount).compartment = '';
+        modelStructure.parameters(parameterCount).unittype = '';
+        modelStructure.parameters(parameterCount).notes = moietyConservationNotes;
+        parameterCount = parameterCount + 1;
+    else
+        % add the constant term as a parameter
+        modelStructure.parameters(parameterCount).name = variable;
+        modelStructure.parameters(parameterCount).value = str2num(sprintf('%g',constantTerm));
+        moietyConservationNotes = sprintf('Moiety conservation for: %s',variable);
+        modelStructure.parameters(parameterCount).type = fullModelStructure.states(statesRemove(k1)).type;
+        modelStructure.parameters(parameterCount).compartment = fullModelStructure.states(statesRemove(k1)).compartment;
+        modelStructure.parameters(parameterCount).unittype = fullModelStructure.states(statesRemove(k1)).unittype;
+        modelStructure.parameters(parameterCount).notes = moietyConservationNotes;
+        parameterCount = parameterCount + 1;        
+    end
+end
+% Now add the other variables
+for k = 1:length(fullModelStructure.variables),
+    variables(variableCount).name = fullModelStructure.variables(k).name;
+    variables(variableCount).formula = fullModelStructure.variables(k).formula;
+    variables(variableCount).type = fullModelStructure.variables(k).type;
+    variables(variableCount).compartment = fullModelStructure.variables(k).compartment;
+    variables(variableCount).unittype = fullModelStructure.variables(k).unittype;
+    variables(variableCount).notes = fullModelStructure.variables(k).notes;
+    variableCount = variableCount + 1;
+end
+% Include the variable information in the model structure
+modelStructure.variables = variables;
+% Create IQMmodel with reduced model structure
+iqmReduced = IQMmodel(modelStructure);
+
+if ~hasonlynumericICsIQM(iqm),
+    disp('Please note: The model contains non-numeric initial conditions. In the reduced model');
+    disp('these have been replaced by corresponding numeric initial conditions.');
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DISPLAY THE ALGEBRAIC RELATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [text] = getTextAlgebraicRelation(depVarConstant,depVarFactor)
+    % needed global variables
+    global ODEfctname
+    % get variable names from ODE file
+    variableNames = feval(ODEfctname,'states');
+    text = sprintf(' = %g',depVarConstant);
+    for k2 = 1:length(depVarFactor),
+        if abs(depVarFactor(k2)) > 0,    % here 0 can be used (zerocheck already done)
+            if depVarFactor(k2) > 0
+                element = sprintf('+ %g',depVarFactor(k2));
+            else 
+                element = sprintf('- %g',abs(depVarFactor(k2)));
+            end
+            text = sprintf('%s %s %s',element,variableNames{k2},text);
+        end
+    end
+return
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/analysis/IQMsteadystate.m b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/IQMsteadystate.m
new file mode 100644
index 0000000000000000000000000000000000000000..af3ecf6740dce75a1b035ba6e1fcc13ae7064d0b
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/IQMsteadystate.m	
@@ -0,0 +1,329 @@
+function [varargout] = IQMsteadystate(varargin)
+% IQMsteadystate: determines a steady-state of an IQMmodel or an ODE file 
+% description created by IQMcreateODEfile. This function should only be used 
+% for time-independent systems. Otherwise an error will
+% occur. The function is able to deal with models having a singular 
+% Jacobian, e.g., due to moity conservations.
+%
+% USAGE:
+% ======
+% [steadystate,residual,message] = IQMsteadystate(model)         
+% [steadystate,residual,message] = IQMsteadystate(model,initialCondition)         
+% [steadystate,residual,message] = IQMsteadystate(model,initialCondition,OPTIONS)
+% [steadystate,residual] = IQMsteadystate(model)         
+% [steadystate,residual] = IQMsteadystate(model,initialCondition)         
+% [steadystate,residual] = IQMsteadystate(model,initialCondition,OPTIONS)
+% [steadystate] = IQMsteadystate(model)         
+% [steadystate] = IQMsteadystate(model,initialCondition)         
+% [steadystate] = IQMsteadystate(model,initialCondition,OPTIONS)
+%                                   
+% model: IQMmodel model or name of ODE file (without .m suffix)
+% initialCondition: Array with initial conditions around which to start the
+%   search for a steady-state. If not given the initial conditions or given
+%   as an empty vector the initial values are taken from the IQMmodel.
+% OPTIONS: structure containing options
+%          OPTIONS.TolFun: Tolerance for max element in function evaluation
+%          OPTIONS.tol: Tolerance for the determination of the number of algebraic
+%               relationships in the model. If the method fails than this
+%               might be due to a wrong rank computation and in this case
+%               the tolerance should be increased. If set, the same tolerance
+%               setting is used when determining the indices of the
+%               dependent variables.
+%          OPTIONS.MaxIter: Maximum number of iterations
+%          OPTIONS.Delta: Step length for numerical differentiation to obtain 
+%               the Jacobian.
+%
+% DEFAULT VALUES:
+% ===============
+% initialCondition: the initial conditions stored in the model
+% OPTIONS.TolFun:   1e-11
+% OPTIONS.tol:      standard MATLAB tolerance: s = svd(A); tol = max(size(A))*eps(max(s));
+% OPTIONS.MaxIter:  1000
+% OPTIONS.Delta:    1e-6
+%
+% Output Arguments:
+% =================
+% steadystate: array with steadystate values
+% residual: 2-norm of the derivatives at the found steady-state. residual
+%           is optional
+% message: message about the steady state not able to find and/or message about 
+%          found algebraic relationships / moiety conservations.
+%          Message as output argument is optional. If omitted, the message
+%          will be displayed in the Matlab window.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% NEEDED GLOBAL VARIABLES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+global ODEfctname TolFun tol MaxIter Delta message
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INITIALIZATION OF MESSAGE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+message = '';
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF IQMMODEL OR FILENAME
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isIQMmodel(varargin{1}),
+    % IQMmodel
+    iqm = varargin{1};
+    % check if the model uses delays ... if yes then take care of it
+    if usedelayIQM(iqm),
+        disp('Delays are present in the model. They are going to be');
+        disp('removed automatically for steady-state computation.');
+        iqm = removedelayIQM(iqm);
+    end
+    % Create temporary ODE file
+    [ODEfctname, ODEfilefullpath] = IQMcreateTempODEfile(iqm);    
+else
+    % ODEfctname of ODE file
+    ODEfctname = varargin{1};
+    % empty iqm variable
+    iqm = [];
+    % Check if file exists
+    if exist(strcat(ODEfctname,'.m')) ~= 2,
+        error('ODE file could not be found.');
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Set default values
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+TolFun  = 1e-11;
+tol     = 0; % standard MATLAB tolerance: s = svd(A); tol = max(size(A))*eps(max(s));
+MaxIter = 1000;
+Delta   = 1e-6;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin == 1,
+    % handle non-numeric and numeric ICs
+    initialCondition = IQMcalcICvector(ODEfctname);
+    OPTIONS = []; % default options
+elseif nargin == 2,
+    initialCondition = varargin{2};
+    OPTIONS = []; % default options
+elseif nargin == 3,
+    initialCondition = varargin{2};
+    OPTIONS = varargin{3};
+else
+    error('Wrong number of input arguments');
+end
+% if empty initial condition => default values
+if isempty(initialCondition),
+    % handle non-numeric and numeric ICs
+    initialCondition = IQMcalcICvector(ODEfctname);
+end    
+% initialCondition should be a column vector!
+initialCondition = initialCondition(:); 
+% if OPTIONS = [] then use default values
+if ~isempty(OPTIONS),
+    % TolFun
+    if isfield(OPTIONS,'TolFun'),
+        if ~isempty(OPTIONS.TolFun),
+            TolFun = OPTIONS.TolFun;
+        end
+    end
+    % tol
+    if isfield(OPTIONS,'tol'),
+        if ~isempty(OPTIONS.tol),
+            tol = OPTIONS.tol;
+        end
+    end
+    % MaxIter
+    if isfield(OPTIONS,'MaxIter'),
+        if ~isempty(OPTIONS.MaxIter),
+            MaxIter = OPTIONS.MaxIter;
+        end
+    end
+    % Delta
+    if isfield(OPTIONS,'Delta'),
+        if ~isempty(OPTIONS.Delta),
+            Delta = OPTIONS.Delta;
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET THE STEADY STATE FOR THE MODEL
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+steadystate = getSteadyState(initialCondition,iqm);
+if ~isempty(steadystate),
+    residual = norm(feval(ODEfctname,0,steadystate));
+else
+    messageText = 'Steady state could not be found. Try different options and/or a different starting guess.';
+    message = sprintf('%s\n%s\n',message,messageText);
+    residual = [];
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS VARIABLE OUTPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargout == 2,
+    varargout{1} = steadystate;
+    varargout{2} = residual;
+    disp(message);
+elseif nargout == 3,
+    varargout{1} = steadystate;
+    varargout{2} = residual;
+    varargout{3} = message;
+elseif nargout < 2, 
+    varargout{1} = steadystate;
+    disp(message);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DELETE FILE IF IQMMODEL
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if strcmp('IQMmodel',class(varargin{1})),
+    IQMdeleteTempODEfile(ODEfilefullpath);
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET THE STEADY STATE OF THE MODEL
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [steadystate] = getSteadyState(initialCondition,iqm)
+% Define some global variables that are needed in other functions
+global depVar factors constantValues ODEfctname TolFun tol MaxIter Delta message
+EXITFLAG = 0;
+% Before determining the steady-state it is necessary to check if there are
+% some algebraic relationships in the model. If there are not the
+% steady-state is determined directly. If there are, the algebraic
+% relations are determined and the steady-state is calculated for a reduced
+% system.
+% check if model given as IQMmodel:
+if ~isempty(iqm),
+    % check if stoichiometric matrix gives full information
+    N = IQMstoichiometry(iqm,0,1); % no rawFlag,  but silentFlag
+    if length(initialCondition) == size(N,1),
+        % yes, full information available
+        useStoich = 1;
+    else
+        useStoich = 0;
+    end
+else
+    useStoich = 0;
+end
+% handle stoich and jac differently
+if useStoich == 0,
+    % use Jacobian!
+    % Get jacobian and determine its rankdeficiency - use default deltaX for
+    % numerical differentiation
+    J = IQMjacobian(ODEfctname,initialCondition);
+    if tol == 0,
+        d = length(J) - rank(J);        
+    else
+        d = length(J) - rank(J,tol);
+    end
+else
+    % use stoichiometry
+    if tol == 0,
+        X = rref([N,eye(size(N,1))]);
+    else
+        X = rref([N,eye(size(N,1))],tol);
+    end        
+    Nx = X(:,1:size(N,2));
+    d = length(find(sum(abs(Nx)')'==0));
+end
+if d == 0,
+    % Jacobian has full rank => no algebraic relations => "simple"
+    % computation of the steady-state
+    % The systems does not contain algebraic relations
+    OPTIONS = [];
+    OPTIONS.MaxIter = MaxIter;
+    OPTIONS.TolFun = TolFun;
+    OPTIONS.Delta = Delta;
+    [steadystate,FVAL,EXITFLAG] = fsolveIQM(@model,initialCondition,OPTIONS);
+else
+    % message
+    messageText = sprintf('The system has a rank deficiency of %d. This might be due to moiety or\nother conservations in the model, to the excessive use of zero initial\nconditions and/or integrating behavior of the system. If this does\nnot seem to be correct, please check the initial conditions and/or\nset a different value for the tolerance "tol" in the options.',d);
+    message = sprintf('%s\n%s\n',message,messageText);
+    % Jacobian is singular => assume that algebraic relations are present
+    % and solve for the steady-state by taking into account these algebraic
+    % relations, by considering the singular output directions
+    % Handle stoich and jac differently
+    if useStoich == 0,
+        message = sprintf('%s\nThe algebraic relationships are determined using the Jacobian.\nThis is numerically not very stable and you need eventually\nto change tolerance "tol" settings.\n',message);
+        % Use the singular value decomposition of the Jacobian to determine
+        % the algebraic relationships
+        [U,S,V] = svd(J);
+        U0 = U(:,end-d+1:end);
+        if tol == 0,
+            factors = rref(U0');
+        else
+            factors = rref(U0',tol);
+        end
+    else
+        message = sprintf('%s\nThe algebraic relationships are determined using the Stoichiometric matrix.\n',message);
+        % Use rref of the Stoichiometric Matrix
+       factors = X(end-d+1:end,size(N,2)+1:end);
+    end
+    constantValues = factors*initialCondition;
+    % determine the indices of the dependent variables. this is simple. 
+    % just take the index of the first non zero element in each row as 
+    % index for dependent a variable.
+    depVar = [];
+    for k = 1:size(factors,1),
+        nonZeroIndices = find(factors(k,:)~=0);
+        depVar = [depVar nonZeroIndices(1)];
+    end
+    % now do the solving for the steady-state
+    OPTIONS = [];
+    OPTIONS.MaxIter = MaxIter;
+    OPTIONS.TolFun = TolFun;
+    OPTIONS.Delta = Delta;  
+    [ssVarInDep,FVAL,EXITFLAG] = fsolveIQM(@modelIndependentVariables,getIndependentVariables(initialCondition),OPTIONS);
+    % Obtain the full state vector from the independent variables
+    steadystate = getAllVariables(ssVarInDep);
+end
+% If fsolve has not converged to a solution then return an empty vector
+if EXITFLAG ~= 1,
+    steadystate = [];
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% REMOVE THE TIME FROM THE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [xdot] = model(x)
+    global ODEfctname 
+    xdot = feval(ODEfctname,0,x);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CALL MODEL BASED ON INDEPENDENT VARIABLES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [xdotVarInDep] = modelIndependentVariables(varInDep)
+    global ODEfctname 
+    variables = getAllVariables(varInDep);
+    xdot = feval(ODEfctname,0,variables);
+    xdotVarInDep = getIndependentVariables(xdot);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET INDEPENDENT VARIABLES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [varInDep] = getIndependentVariables(variables)
+    global depVar
+    varInDep = variables(setxor([1:length(variables)],depVar));
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET ALL VARIABLES FROM INDEPENDENT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [variables] = getAllVariables(varInDep)
+    global depVar factors constantValues
+    n = size(factors,2);
+    m = length(depVar);
+    varInDepIndex = setxor(1:n,depVar);
+    A = factors(1:m,depVar);
+    B = constantValues - factors(1:m,varInDepIndex)*varInDep;
+    depVarValues = linsolve(A,B);
+    variables = zeros(n,1);
+    variables(varInDepIndex) = varInDep;
+    variables(depVar) = depVarValues;
+return      
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/analysis/IQMstoichiometry.m b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/IQMstoichiometry.m
new file mode 100644
index 0000000000000000000000000000000000000000..939fbac6c3ea8427ab65dd4a805c12e70530b11a
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/IQMstoichiometry.m	
@@ -0,0 +1,269 @@
+function [N,componentNames,reactionNames,reversibleFlag] = IQMstoichiometry(model,varargin)
+% IQMstoichiometry
+% Determines the stoichiometric matrix for the given model. In order to be
+% able to do that the differential equations for the components have to be
+% expressed in terms of reaction rates. The stoichiometric constants need 
+% to be numeric and multiplied to the reaction terms.
+%
+% Examples: d/dt(A) = -1*Re1+2*Re3-Re5+3.141*Re8
+%
+% Especially when importing models from SBML the right hand side of the
+% ODEs might show a correction term that is needed for transport between two
+% different compartments in the case that the species is defined in
+% concentration units. In this case the ODE can look as follows:
+%
+%           d/dt(B): (-1*Re1+2*Re3-Re5+3.141*Re8)/compartmentsize
+%
+% This syntax is also accepted. In this case the stoichiometric elements
+% in the parenthesis will be divided by 'compartmentsize'.
+%
+% The 'compartmentsize' is only allowed to be a parameter! It can not be a 
+% numeric value, a state, a variable, or a function!
+%
+% Except the above shown pair of parentheses, no additional parentheses are
+% allowed to appear in the ODE definitions. Otherwise, and in case that not
+% only reaction rates are present in the ODE expression, the corresponding
+% component is not taken into account for the stoichiometric matrix.
+%
+% USAGE:
+% ======
+% [N,componentNames,reactionNames,reversibleFlag] = IQMstoichiometry(model)
+%
+% model: IQMmodel to determine the stoichiometric matrix for
+%
+% DEFAULT VALUES:
+% ===============
+%
+% Output Arguments:
+% =================
+% N: stoichiometric matrix
+% componentNames: cell-array with the names of the components present in
+%   the stoichiometric matrix
+% reactionNames: cell-array with the names of the reactions present in the
+%   stoichiometric matrix
+% reversibleFlag: vector with same number of entries as reactions. An entry
+%   of 0 indicates an irreversible reaction, an entry of 1 indicates a
+%   reversible reaction. The ordering is the same as the reaction names.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF IQMmodel
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~strcmp('IQMmodel',class(model)),
+    error('Function only defined for IQMmodels.');
+end
+% get the datastructure of the model
+modelstruct = IQMstruct(model);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK EXTRA INPUT ARGUMENT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% the first extra input argument is used to force the IQMstoichiometry function 
+% not to correct the elements of the stoichiometric matrix for the
+% compartment information in cases where species are given in
+% concentrations. This is needed for model construction (BC type of
+% representation and for other things)
+% the second is used for silent use of the function
+% both flags are not further documented and should not be used by others
+% unless they fully understand their meaning
+
+rawFlag = 0;
+silentFlag = 0;
+if nargin == 2,
+    rawFlag = varargin{1};
+elseif nargin == 3,
+    rawFlag = varargin{1};
+    silentFlag = varargin{2};
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get all reaction names
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[reactionNames, dummy, reversibleFlag]  = IQMreactions(model);
+if isempty(reactionNames),
+    if silentFlag == 0,
+        error('No reactions present in the model');
+    else
+        N = [];
+        componentNames = {};
+        reactionNames = {};
+        reversibleFlag = [];
+        return
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Go trough all ODEs and check reactions ...
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% go through all ODEs and check for which components the ODEs only
+% consist of reaction terms - this returns already positive and negative
+% terms and coefficients
+componentNames = {};
+[parameterNames, parameterValues] = IQMparameters(model);
+N = [];
+for k = 1:length(modelstruct.states),
+    ODE = modelstruct.states(k).ODE;
+    % check if ODE contains only reaction terms - otherwise do not 
+    % consider the current state as component for the stoichiometric matrix
+    Nrow = getStoichiometryInformation(ODE,reactionNames,parameterNames,parameterValues,rawFlag,silentFlag);
+    if ~isempty(Nrow) && isempty(find(isnan(Nrow)==1, 1)),
+        N = [N; Nrow];
+        componentNames{size(N,1)} = modelstruct.states(k).name;
+    end
+end
+% check for zero rows in N and take them away both from N and from the
+% list of component names
+%useIndices = find(sum(abs(N')) ~= 0);
+%notUseIndices = find(sum(abs(N')) == 0);
+
+nonReactionStates = setdiff(IQMstates(model),componentNames);
+if ~isempty(nonReactionStates) && silentFlag == 0,
+    disp('For the following components no stoichiometries could be determined.');
+    disp('This is due to the syntax of the corresponding ODEs.');
+    text = '';
+    for k = 1:length(nonReactionStates),
+        text = sprintf('%s %s\n',text,nonReactionStates{k});
+    end
+    disp(text);
+end
+%componentNames = componentNames(useIndices);
+%N = N(useIndices,:);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK ODEs for reactions
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% check if given ODE expression contains only reaction terms - then return
+% the stoichiometry for this ODE. Otherwise if not only reactions are
+% present, return an empty vector.
+% in cases that the reaction rate is adjustet by the compartment volume
+% (happens especially in cases of import of SBML models containing species
+% with concentration rates and compartment volumes different from one) the
+% adjustment term and the needed parentheses should be detected and
+% neglected.
+function [Nrow] = getStoichiometryInformation(ODE,reactionNames,parameterNames,parameterValues,rawFlag,silentFlag)
+errorFlag = 0;
+% delete all white spaces from the ODE
+ODE = regexprep(ODE,'\s*','');
+% first of all check if a scaling by the compartment volume is done.
+% in this case the expected syntax is 
+% ODE = ("reactionterms")/compartmentvolume
+numberOpenParentheses = length(find(ODE == '('));
+numberClosedParentheses = length(find(ODE == ')'));
+compartmentSize = 1;
+if numberOpenParentheses ~= numberClosedParentheses,
+    % parentheses need to appear in pairs - otherwise error
+    errorFlag = 1;
+elseif numberOpenParentheses > 1,
+    % if there is more than one pair of parentheses, then error
+    errorFlag = 1;
+elseif numberOpenParentheses == 0,
+    errorFlag = 0;
+elseif ODE(1) == '(',
+    % if the first character is an open parenthesis then assume that 
+    % this is due to a adjustement to compartment sizes
+    % cut out the content of the parentheses
+    closeParenthesis = find(ODE == ')');
+    ODERHS = ODE;
+    ODE = ODERHS(2:closeParenthesis-1);
+    % check part outside parenthesis
+    rest = ODERHS(closeParenthesis+1:end);
+    % first character needs to be a '/'
+    if rest(1) ~= '/',
+        errorFlag = 1;
+    else
+        rest = rest(2:end);
+        % check if this rest corresponds to a parameter name and if yes get
+        % its value
+        index = strmatchIQM(rest,parameterNames,'exact');
+        if ~isempty(index),
+            compartmentSize = parameterValues(index);
+            errorFlag = 0;
+        else
+            if silentFlag == 0,
+                error('The stoichimetric matrix can not be computed. A compartment size seems not to be given as a parameter.');
+            else 
+                errorFlag = 1;
+            end
+        end
+    end
+else
+    % parentheses is expected as first non white space character in
+    % reaction string ... therefor an error.
+    errorFlag = 1;
+end
+% continue with the algorithm if no error occurred
+if errorFlag == 0,
+    
+    ODE = char([double(ODE) double('+')]);  % fastest strcat
+    % first explode the ODE in additive terms
+    terms = [];
+    termIndex = 1;
+    % check the sign of the first term (first character in string)
+    if ODE(1) == '-',
+        signCurrent = -1;
+        lastIndex = 2;
+    elseif ODE(1) == '+',
+        signCurrent = +1;
+        lastIndex = 2;
+    else
+        signCurrent = +1;
+        lastIndex = 1;
+    end
+    % explode in terms, check if term has the right format and if the
+    % second term features a reactionname. then construct the row of the
+    % stoichiometric matrix
+    Nrow = zeros(1,length(reactionNames));
+    startk = lastIndex;
+    for k = startk:length(ODE),
+        % check for positive term
+        if ODE(k) == '+' || ODE(k) == '-',
+            element = ODE(lastIndex:k-1);
+            % check the element if composed of term in the right format
+            multIndex = find(element == '*');
+            if length(multIndex) == 0,
+                stoichiometry = signCurrent*1;
+                reactionterm = element;
+            elseif length(multIndex) == 1,
+                absStoichiometry = str2double(element(1:multIndex-1));
+                if isempty(absStoichiometry),
+                    errorFlag = 1;
+                    break;
+                end
+                stoichiometry = signCurrent*absStoichiometry;
+                reactionterm = element(multIndex+1:end);
+            else
+                % to many multiplication signs (only one allowed)
+                errorFlag = 1;
+                break;
+            end
+            % find the index of the reaction name and add the
+            % stoichiometric information to Nrow
+            indexReaction = strmatchIQM(reactionterm,reactionNames,'exact');
+            if isempty(indexReaction),
+                errorFlag = 1;
+                break;
+            end
+            Nrow(indexReaction) = Nrow(indexReaction) + stoichiometry;
+            % increment
+            termIndex = termIndex + 1;
+            lastIndex = k+1;
+            if ODE(k) == '+',
+                signCurrent = +1;
+            else
+                signCurrent = -1;
+            end
+        end
+    end
+end
+% if an error occurred for the current ODE the Nrow is set to zero
+if errorFlag == 1,
+    Nrow = [];
+end
+% adjust stoichiometries with compartment size
+if rawFlag == 0,
+    Nrow = Nrow / compartmentSize;
+end
+return
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/analysis/behaviorlocalization/IQMlocbehavcomp.m b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/behaviorlocalization/IQMlocbehavcomp.m
new file mode 100644
index 0000000000000000000000000000000000000000..f35f09f8de7e2ad9da70458397b1dd0c7cfdd406
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/behaviorlocalization/IQMlocbehavcomp.m	
@@ -0,0 +1,381 @@
+function [varargout] = IQMlocbehavcomp(varargin)
+% IQMlocbehavcomp: Determines the importance of components in the
+% given biochemical system in the creation of an observed complex behavior,
+% such as multiple steady-states and sustained oscillations. Read below to
+% get more insight into the method.
+% 
+% Important: the analyzed model needs to be time-invariant, unstable, and 
+% non-singular. The last two are checked prior to performing the analysis
+% and a descriptive error message is returned.
+% If the model is not time-invariant some MATLAB error message will appear.
+%
+% THE METHOD
+% ==========
+% Central functions in the cell are often linked to complex dynamic 
+% behaviors, such as sustained oscillations and multistability, in a 
+% biochemical reaction network. Determination of the specific mechanisms 
+% underlying such behaviors is important, e.g., to determine sensitivity, 
+% robustness, and modelling requirements of given cell functions. 
+% 
+% The aim of the "IQMlocbehavcomp" function is to identify the 
+% components (states) in a biochemical reaction network, described by a set of 
+% ordinary differential equations, that are mainly involved in creating an
+% observed complex dynamic behavior, such as sustained oscillations or 
+% multiple steady-states. 
+% 
+% Rather than analyzing the biochemical system in a state corresponding to 
+% the complex nonlinear behavior, the system is considered at its 
+% underlying unstable steady-state. This is motivated by the fact that all 
+% complex behaviors in unforced systems can be traced to destabilization 
+% (bifurcation) of some steady-state, and hence enables the use of tools 
+% from Linear System Theory to qualitatively analyze the sources of given 
+% network behaviors.
+% 
+% A full description of this method can be found in 
+% "Linear systems approach to analysis of complex dynamic behaviours 
+% in biochemical networks", IEE Systems Biology, 1, 149-158 (2004) and
+% "Identifying feedback mechanisms behind complex cell behavior", IEEE
+% Control Systems Magazine, 24 (4), 91-102 (2004)
+%
+% USAGE
+% =====
+% [] = IQMlocbehavcomp(iqm, steadystate)  
+% [] = IQMlocbehavcomp(iqm, steadystate, OPTIONS)  
+% [importance, stateNames] = IQMlocbehavcomp(iqm, steadystate)  
+% [importance, stateNames] = IQMlocbehavcomp(iqm, steadystate, OPTIONS)  
+%
+% iqm: IQMmodel or ODE file to perform the analysis on
+% steadystate: steady-state at which to perform the analysis
+% OPTIONS: structure containing options
+%          OPTIONS.orderDataFlag: =0: non ordered data, =1: ordered data after
+%               importance (only used for plotting purpose)
+%          OPTIONS.plotTypeFlag: =0: linear y-axis, =1: logarithmic y-axis
+%          OPTIONS.minEpsilonValue, OPTIONS.maxEspilonValue: Definition of
+%                  the range of values for checking the epsilons.
+%               [-maxEspilonValue ... -minEpsilonValue ... minEpsilonValue ... maxEpsilonValue] 
+%          OPTIONS.nrPoints: number of points in the range above.
+%
+% DEFAULT VALUES:
+% ===============
+% OPTIONS.orderDataFlag: 0
+% OPTIONS.plotTypeFlag: 0
+% OPTIONS.minEpsilonValue: 0.0001
+% OPTIONS.maxEspilonValue: 1000
+% OPTIONS.nrPoints: 5000
+%
+% Output Arguments:
+% =================
+% If no output arguments are given, the result of the analysis is plotted. 
+% The importances are color-coded. Blue color is used for positive
+% importances, red color for negative importances that are smaller than
+% -1, and black color for negative importances that are between 0 and -1.
+% Since the determined epsilon perturbations are relative perturbations and
+% therefor values for epsilon < -1 (0 > importances > -1) lead to a change
+% of sign in the corresponding feedback loop, the two different colors for
+% negative importances are used to distinguish these two cases.
+%
+% importance and stateNames: to the i-th component (state) name corresponds
+%       the i-th importance value, defined by importance_i = 1/epsilon_i,
+%       where epsilon_i is the relative change in the feedback
+%       interconnection in the i-th  state (stateNames{i}) that
+%       stabilizes the considered unstable steady-state. The smaller the
+%       absolute value of the required perturbation, this means, the larger
+%       importance_i, the more important role plays state i in the
+%       creation of the observed complex behavior. In case the stabilizing
+%       value of epsilon_i has a magnitude larger than maxEpsilonValue,
+%       zero is returned for the corresponding importance.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+global minEpsilonValue maxEpsilonValue nrPoints
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF IQMMODEL OR FILENAME
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isIQMmodel(varargin{1}),
+    % IQMmodel
+    iqm = varargin{1};
+    % check delays and events
+    if usedelayIQM(iqm),
+        error('The model contains delays. These can not be handled by this function.');
+    end
+    if useeventIQM(iqm),
+        error('The model contains events. These can not be handled by this function.');
+    end    
+    % Create temporary ODE file
+    [ODEfctname, ODEfilefullpath] = IQMcreateTempODEfile(iqm);    
+else
+    % ODEfctname of ODE file
+    ODEfctname = varargin{1};
+    % Check if file exists
+    if exist(strcat(ODEfctname,'.m')) ~= 2,
+        error('ODE file could not be found.');
+    end
+end
+
+% Default values
+orderDataFlag   = 0;
+plotTypeFlag    = 0;
+minEpsilonValue = 0.0001;
+maxEpsilonValue = 1000;
+nrPoints        = 5000;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin == 2,
+    steadystate = varargin{2};
+elseif nargin == 3,
+    steadystate = varargin{2};
+    % get options for analysis method
+    OPTIONS = varargin{3};
+    % handle the options
+    % orderDataFlag
+    if isfield(OPTIONS,'orderDataFlag'),
+        if ~isempty(OPTIONS.orderDataFlag),
+            orderDataFlag = OPTIONS.orderDataFlag;
+        end
+    end
+    % plotTypeFlag
+    if isfield(OPTIONS,'plotTypeFlag'),
+        if ~isempty(OPTIONS.plotTypeFlag),
+            plotTypeFlag = OPTIONS.plotTypeFlag;
+        end
+    end
+    % minEpsilonValue
+    if isfield(OPTIONS,'minEpsilonValue'),
+        if ~isempty(OPTIONS.minEpsilonValue),
+            minEpsilonValue = OPTIONS.minEpsilonValue;
+        end
+    end
+    % maxEspilonValue
+    if isfield(OPTIONS,'maxEpsilonValue'),
+        if ~isempty(OPTIONS.maxEpsilonValue),
+            maxEpsilonValue = OPTIONS.maxEpsilonValue;
+        end
+    end
+    % nrPoints
+    if isfield(OPTIONS,'nrPoints'),
+        if ~isempty(OPTIONS.nrPoints),
+            nrPoints = OPTIONS.nrPoints;
+        end
+    end
+else
+    error('Incorrect number of input arguments.');
+end
+
+% check that the maxEpsilonValue is larger than the minEpsilonValue
+if minEpsilonValue >= maxEpsilonValue,
+    error('The max epsilon value in the options should be larger than the min epsilon value!');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK CORRECT NUMBER OF OUTPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargout ~= 0 && nargout ~= 2,
+    error('Incorrect number of output arguments');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF MODEL IS UNSTABLE AND NON SINGULAR
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% check eigenvalues for instability
+Jacobian = IQMjacobian(ODEfctname,steadystate);
+if max(real(eig(Jacobian))) < 0,
+    error(sprintf('The ODEfctname is stable - this analysis function only works with unstable models.\nIn case you are looking at a system having multiple steady-states\nyou need to specify a starting guess for the steady-state very close to the unstable steady-state.'));
+end
+% check non singularity
+Jacobian = IQMjacobian(ODEfctname,rand*ones(length(steadystate)));
+if rank(Jacobian) < length(Jacobian),
+    error(sprintf('The ODEfctname is singular. This function only works with non-singular models.\nYou might consider the use of ''IQMreducemodel''.'));
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HERE COMES THE MAIN ANALYSIS PART
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+epsilon_i = analyzeImportantStates(ODEfctname, steadystate);
+% convert epsilon_i to importance_i
+importance = 1./epsilon_i;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE VARIABLE OUTPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargout == 0,
+    plotResults(importance, ODEfctname, plotTypeFlag, orderDataFlag);
+elseif nargout == 2,
+    varargout{1} = importance;
+    varargout{2} = IQMstates(ODEfctname);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DELETE FILE IF IQMMODEL
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if strcmp('IQMmodel',class(varargin{1})),
+    IQMdeleteTempODEfile(ODEfilefullpath);
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Implementation of the method described in 
+% "Identifying mechanisms underlying complex behaviors in biochemical 
+% reaction networks", IEE Systems Biology, 1, 149-158 (2004) and
+% "Identifying feedback mechanisms behind complex cell behavior", IEEE
+% Control Systems Magazine, 24 (4), 91-102 (2004)
+%
+% for the determination of important states in biochemical networks,
+% that are the source of an observed complex behavior.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [epsilon_i] = analyzeImportantStates(ODEfctname, steadystate)
+global minEpsilonValue maxEpsilonValue nrPoints
+% determine the Jacobian
+A = IQMjacobian(ODEfctname,steadystate);
+n = length(A); I = eye(n);
+% check that the maxEpsilonValue is larger than the minEpsilonValue
+if minEpsilonValue >= maxEpsilonValue,
+    error('The max epsilon value in the options should be larger than the min epsilon value!');
+end
+% Instead of using the approach, proposed in the above mentioned articles,
+% here a simpler method is used to determine the sensitivity of the systems
+% stability to variations in the different feedback connections. This
+% method is based on perturbing directly the Jacobian of the system, at the
+% considered unstable steady-state. The feedback of component (state) number i on itself 
+% is not perturbed, only the feedback of state i on all other states,
+% corresponding to perturbations only on the interactions in the network.
+%
+% cycle through all the states and check values between minEpsilonValue and
+% maxEpsilonValue
+epsilonRange = logspace(log(minEpsilonValue)/log(10),log(maxEpsilonValue)/log(10),floor(nrPoints/2));
+epsilon_i = [];  % array to collect the epsilon_i values for the different states
+for i = 1:n,
+    % search first from zero to positive epsilon values
+    epsilon_i_temp = inf; % initialize value with maximum 
+    for j = 1:length(epsilonRange),
+        epsilon = epsilonRange(j);
+        % determine the perturbed Jacobian Ahat
+        Ahat = A; Ahat(:,i) = Ahat(:,i)*(1+epsilon); Ahat(i,i) = A(i,i);
+        % determine the max real part of the eigenvalues of the perturbed Jacobian
+        if max(real(eig(Ahat))) <= 0,
+            % since the nominal Jacobian (epsilon_i = 0) is unstable,
+            % a maximum negative realpart indicates that the system has
+            % been stabilized and the smallest positive epsilon_i value has
+            % been found. this value is now given by the "epsilon" variable
+            % break the loop and search in negative direction
+            epsilon_i_temp = epsilon;
+            break; 
+        end
+    end
+    % now search from zero to negative epsilon values
+    for j = 1:length(epsilonRange),
+        epsilon = -epsilonRange(j);
+        % check if current epsilon has magnitude larger than previously
+        % found (epsilon_i_tem). if yes then break the loop and take
+        % previously found as epsilon_i
+        if abs(epsilon) > abs(epsilon_i_temp),
+            break;
+        end
+        % otherwise continue with search        
+        % determine the perturbed Jacobian Ahat
+        Ahat = A; Ahat(:,i) = Ahat(:,i)*(1+epsilon); Ahat(i,i) = A(i,i);
+        % determine the max real part of the eigenvalues of the perturbed Jacobian
+        if max(real(eig(Ahat))) <= 0,
+            % since the nominal Jacobian (epsilon_i = 0) is unstable,
+            % a maximum negative realpart indicates that the system has
+            % been stabilized and the smallest positive epsilon_i value has
+            % been found.
+            epsilon_i_temp = epsilon;
+            break; % break the loop and search in negative direction
+        end
+    end
+    % save the determined epsilon_i value for the i-th state 
+    epsilon_i = [epsilon_i epsilon_i_temp];
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Plot the analysis results
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [] = plotResults(importance, ODEfctname, plotTypeFlag, orderDataFlag)
+% getting the names of the states in the network
+stateNames = IQMstates(ODEfctname);
+n = length(importance);
+% ordering the data after decreasing importance (if orderDataFlag = 1)
+if orderDataFlag == 1,
+    data = [abs(importance(:)), importance(:), [1:length(stateNames)]'];
+    data = sortrows(data,-1);
+    % get reordered data
+    importance = data(:,2);
+    % reorder the parameters
+    stateNamesOrdered = cell(1,length(stateNames));
+    neworder = data(:,3);
+    for k = 1:length(stateNames),
+        stateNamesOrdered{k} = stateNames{neworder(k)};
+    end
+    stateNames = stateNamesOrdered;
+else
+    neworder = [1:n];
+end
+figH = figure; clf;
+axesH = gca(figH);
+% plot importances - different colors for:
+% blue: positive stabilizing perturbations (epsilon)
+% red: negative stabilizing perturbations (epsilon > -1 => no sign change)
+% black:  negative stabilizing perturbations (epsilon < -1 => sign change)
+if plotTypeFlag == 0,
+    for k = 1:n,
+        if importance(k) >= 0,
+            bar(k,importance(k),'b'); hold on;
+        elseif importance(k) < 0 && importance(k) >= -1,
+            bar(k,-importance(k),'k'); hold on;
+        else    
+            bar(k,-importance(k),'r'); hold on;
+        end
+    end
+else
+    for k = 1:n,
+        if importance(k) >= 0,
+            handle = plot(k,importance(k),'ob'); hold on;
+            set(handle,'LineWidth',2);
+            set(handle,'MarkerFaceColor','b');            
+        elseif importance(k) < 0 && importance(k) >= -1,
+            handle = plot(k,-importance(k),'ok'); hold on;
+            set(handle,'LineWidth',2);
+            set(handle,'MarkerFaceColor','k');            
+        else    
+            handle = plot(k,-importance(k),'or'); hold on;
+            set(handle,'LineWidth',2);
+            set(handle,'MarkerFaceColor','r');            
+        end
+    end
+end    
+absImportance = abs(importance);
+yMax = 1.5*max(absImportance);
+if plotTypeFlag,
+    % min value in case of semilogy plot
+    help = sort(absImportance)';
+    help = help(find(help>0))';
+    yMin = 0.75*help(1);
+else
+    % min value to zero in case of linear plot
+    yMin = 0;
+end
+axis([0 n+1 yMin yMax]);
+set(axesH,'XTick',[1:n]);
+set(axesH,'XTickLabel',neworder);
+if plotTypeFlag == 1,
+    set(axesH,'YScale','log');
+    text([1:n]-0.4,1.4*absImportance,stateNames);
+else
+    set(axesH,'YScale','linear');
+    text([1:n]-0.4,0.02*(yMax-yMin)+absImportance,stateNames);
+end
+% plot bar at 1
+hold on
+plot([0 n+1],[1 1],'k--');
+
+% writing the axis descriptions
+xlabel('States (components) in biochemical network');
+ylabel('Importance for considered behavior (1/| \epsilon-value|)');
+return
+
+
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/analysis/behaviorlocalization/IQMlocbehavinteract.m b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/behaviorlocalization/IQMlocbehavinteract.m
new file mode 100644
index 0000000000000000000000000000000000000000..fb6f63979b7fc71c3102d2c3a21677af7f8694fa
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/behaviorlocalization/IQMlocbehavinteract.m	
@@ -0,0 +1,647 @@
+function [varargout] = IQMlocbehavinteract(varargin)
+% IQMlocbehavinteract: Determines the importance of direct interactions 
+% (e.g., reactions) between components (states) in the given biochemical
+% system in the creation of an observed complex behavior, such as multiple 
+% steady-states and sustained oscillations. Read below to get more insight 
+% into the method.
+% 
+% Important: the analyzed model needs to be time-invariant, unstable, and 
+% non-singular. The last two are checked prior to performing the analysis
+% and a descriptive error message is returned.
+% If the model is not time-invariant some MATLAB error message will appear.
+%
+% THE METHOD
+% ==========
+% Central functions in the cell are often linked to complex dynamic 
+% behaviors, such as sustained oscillations and multistability, in a 
+% biochemical reaction network. Determination of the specific mechanisms 
+% underlying such behaviors is important, e.g., to determine sensitivity, 
+% robustness, and modelling requirements of given cell functions. 
+% 
+% The aim of the "IQMlocbehavinteract" function is to identify the mechanism
+% in a biochemical reaction network, described by a set of ordinary 
+% differential equations, that are mainly involved in creating an observed 
+% complex dynamic behavior, such as sustained oscillations or multiple 
+% steady-states. 
+% 
+% Rather than analyzing the biochemical system in a state corresponding to 
+% the complex nonlinear behavior, the system is considered at its 
+% underlying unstable steady-state. This is motivated by the fact that all 
+% complex behaviors in unforced systems can be traced to destabilization 
+% (bifurcation) of some steady-state, and hence enables the use of tools 
+% from Linear System Theory to qualitatively analyze the sources of given 
+% network behaviors.
+% 
+% A full description of this method can be found in 
+% "Linear systems approach to analysis of complex dynamic behaviours 
+% in biochemical networks", IEE Systems Biology, 1, 149-158 (2004) and
+% "Identifying feedback mechanisms behind complex cell behavior", IEEE
+% Control Systems Magazine, 24 (4), 91-102 (2004)
+%
+% USAGE
+% =====
+% [] = IQMlocbehavinteract(iqm, steadystate)  
+% [] = IQMlocbehavinteract(iqm, steadystate, OPTIONS)  
+% [importance,stateNames] = IQMlocbehavinteract(iqm, steadystate)  
+% [importance,stateNames] = IQMlocbehavinteract(iqm, steadystate, OPTIONS)  
+%
+% iqm: IQMmodel or ODE file to perform the analysis on
+% steadystate: steady-state at which to perform the analysis
+% OPTIONS: structure containing options
+%          OPTIONS.plotTypeFlag: =0: linear y-axis, =1: logarithmic y-axis
+%          OPTIONS.visualizeFlag: =0: nothing, =1: setting this flag to 1 allows to monitor the
+%                   continuation of the critical locus and to see if the 
+%                   values for criticalLocusTolerance and criticalLocusNrPoints
+%                   are set acceptably.
+%          OPTIONS.omegaRange: to determine the critical frequency omega0 the function
+%                   searches in a range from omega_star/omegaRange ...
+%                   omega_star*omegaRange, where omega_star is the positive
+%                   imaginary part of the unstable pole in the linearized
+%                   system.
+%          OPTIONS.omegaRangePoints: the above range is discretized in so many steps,
+%                   allowing to find a lower and upper bound for omega0
+%          OPTIONS.bisectionThreshold: omega0 is then determined by bisection until
+%                   the bounds have a distance less than this option value
+%          OPTIONS.criticalLocusTolerance: each determined perturbation Delta_ij is
+%                   checked if it is stabilizing. This is done by
+%                   continuation. If the final value of the critical locus
+%                   is less than this option away from +1 it is a
+%                   stabilizing perturbation.
+%          OPTIONS.criticalLocusNrPoints: the number of points used for the
+%                   continuation of the critical locus (larger=>slower,
+%                   more exact, smaller => faster, eventually problems)
+% 
+% DEFAULT VALUES:
+% ===============
+% OPTIONS.plotTypeFlag: 0
+% OPTIONS.visualizeFlag: 0
+% OPTIONS.omegaRange: 10
+% OPTIONS.omegaRangePoints: 50
+% OPTIONS.bisectionThreshold: 1e-14
+% OPTIONS.criticalLocusTolerance: 1e-5
+% OPTIONS.criticalLocusNrPoints: 10
+%
+% Output Arguments:
+% =================
+% If no output arguments are given, the results of the analysis are plotted.
+% The result is color coded. Blue color corresponds to positive elements of
+% the corresponding nominal Jacobian, red color corresponds to negative elements.
+%
+% importance: each row corresponds to a direct interaction between states
+%       in the considered system. The first element in a row determines the
+%       index of the affected and the second the index of the affecting
+%       state. The third element in a row determines the inverse of the
+%       magnitude of the corresponding delta_ij value. delta_ij is the
+%       value for the relative perturbation in the direct interaction from
+%       state j to state i that stabilizes the considered steady-state.
+%       The larger this inverse is, the more important is the direct effect
+%       from state j on state i for the creation of the analyzed behavior.
+% stateNames: the name of the states corresponding to the numbering
+%       of columns and rows. 
+%
+% If no output arguments are given, the result is instead plotted.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+global omegaRange omegaRangePoints bisectionThreshold criticalLocusTolerance criticalLocusNrPoints
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF IQMMODEL OR FILENAME
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isIQMmodel(varargin{1}),
+    % IQMmodel
+    iqm = varargin{1};
+    % check delays and events
+    if usedelayIQM(iqm),
+        error('The model contains delays. These can not be handled by this function.');
+    end
+    if useeventIQM(iqm),
+        error('The model contains events. These can not be handled by this function.');
+    end       
+    % Create temporary ODE file
+    [ODEfctname, ODEfilefullpath] = IQMcreateTempODEfile(iqm);    
+else
+    % ODEfctname of ODE file
+    ODEfctname = varargin{1};
+    % Check if file exists
+    if exist(strcat(ODEfctname,'.m')) ~= 2,
+        error('ODE file could not be found.');
+    end
+end
+
+% default values
+plotTypeFlag = 0;
+visualizeFlag = 0;
+omegaRange = 10;
+omegaRangePoints = 50;
+bisectionThreshold = 1e-14;
+criticalLocusTolerance = 1e-5;
+criticalLocusNrPoints = 10;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin == 2,
+    steadystate = varargin{2};
+elseif nargin == 3,
+    steadystate = varargin{2};
+    % get options for analysis method
+    OPTIONS = varargin{3};
+    % handle the options
+    % plotTypeFlag
+    if isfield(OPTIONS,'plotTypeFlag'),
+        if ~isempty(OPTIONS.plotTypeFlag),
+            plotTypeFlag = OPTIONS.plotTypeFlag;
+        end
+    end
+    % visualizeFlag
+    if isfield(OPTIONS,'visualizeFlag'),
+        if ~isempty(OPTIONS.visualizeFlag),
+            visualizeFlag = OPTIONS.visualizeFlag;
+        end
+    end
+    % omegaRange
+    if isfield(OPTIONS,'omegaRange'),
+        if ~isempty(OPTIONS.omegaRange),
+            omegaRange = OPTIONS.omegaRange;
+        end
+    end
+    % omegaRangePoints
+    if isfield(OPTIONS,'omegaRangePoints'),
+        if ~isempty(OPTIONS.omegaRangePoints),
+            omegaRangePoints = OPTIONS.omegaRangePoints;
+        end
+    end
+    % bisectionThreshold
+    if isfield(OPTIONS,'bisectionThreshold'),
+        if ~isempty(OPTIONS.bisectionThreshold),
+            bisectionThreshold = OPTIONS.bisectionThreshold;
+        end
+    end
+    % criticalLocusTolerance
+    if isfield(OPTIONS,'criticalLocusTolerance'),
+        if ~isempty(OPTIONS.criticalLocusTolerance),
+            criticalLocusTolerance = OPTIONS.criticalLocusTolerance;
+        end
+    end
+    % criticalLocusNrPoints
+    if isfield(OPTIONS,'criticalLocusNrPoints'),
+        if ~isempty(OPTIONS.criticalLocusNrPoints),
+            criticalLocusNrPoints = OPTIONS.criticalLocusNrPoints;
+        end
+    end
+else
+    error('Incorrect number of input arguments.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK CORRECT NUMBER OF OUTPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargout ~= 0 && nargout ~= 2,
+    error('Incorrect number of output arguments');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF MODEL IS NON SINGULAR
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% check non singularity
+Jacobian = IQMjacobian(ODEfctname,rand*ones(length(steadystate)));
+if rank(Jacobian) < length(Jacobian),
+    error(sprintf('The ODEfctname is singular. This function only works with non-singular models.\nYou might consider the use of ''IQMreducemodel''.'));
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HERE COMES THE MAIN ANALYSIS PART
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+result = analyzeImportantInteractions(ODEfctname, steadystate, visualizeFlag);
+% The first column in result contains the row number
+% The second column contains the column number
+% The third contains the magnitude of the required perturbation for stabilization
+%
+% Convert the required perturbations to importance measure by inverting them
+importance = result;
+importance(:,3) = 1./importance(:,3);
+stateNames = IQMstates(ODEfctname);
+% take out importances below a certain limit
+minShowImportance = 1e-6*max(importance(:,3));
+indexTakeOutStart = find(importance(:,3)<minShowImportance);
+if ~isempty(indexTakeOutStart),
+    importance = importance(1:indexTakeOutStart(1)-1,:);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE VARIABLE OUTPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargout == 0,
+    plotResults(importance, ODEfctname, plotTypeFlag, steadystate);
+elseif nargout == 2,
+    varargout{1} = importance;
+    varargout{2} = stateNames;
+    % set acceptable format for output
+    format short g
+else 
+    error('Incorrect number of output arguments.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DELETE FILE IF IQMMODEL
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if strcmp('IQMmodel',class(varargin{1})),
+    IQMdeleteTempODEfile(ODEfilefullpath);
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Plot the results of the analysis
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [] = plotResults(importance, ODEfctname, plotTypeFlag, steadystate)
+% determine Jacobian at given steadystate (signs of elements needed for
+% choosing plot color)
+J = IQMjacobian(ODEfctname,steadystate);
+% get number of rows in importance matrix
+n = size(importance,1);
+% open new figure
+figH = figure; clf; axesH = gca(figH);
+% plot the data - blue if Jacobian element positive, red if Jacobian
+% element negative
+if plotTypeFlag == 0,
+    for k = 1:n,
+        if J(importance(k,1),importance(k,2)) >= 0,
+            bar(k,importance(k,3),'b'); hold on;
+        else
+            bar(k,importance(k,3),'r'); hold on;
+        end
+    end    
+else
+    for k = 1:n,
+        if J(importance(k,1),importance(k,2)) >= 0,
+            handle = plot(k,importance(k,3),'ob'); hold on;
+            set(handle,'LineWidth',2);
+            set(handle,'MarkerFaceColor','b');            
+        else
+            handle = plot(k,importance(k,3),'or'); hold on;
+            set(handle,'LineWidth',2);
+            set(handle,'MarkerFaceColor','r');            
+        end
+    end
+end    
+% set y-axis properties
+yMax = 1.5*max(importance(:,3));
+if plotTypeFlag,
+    % min value in case of semilogy plot
+    help = sort(importance(:,3))';
+    help = help(find(help>0))';
+    yMin = 0.75*help(1);
+else
+    % min value to zero in case of linear plot
+    yMin = 0;
+end
+axis([0 n+1 yMin yMax]);
+set(axesH,'XTick',[]);
+% construct plot text and plot it
+importanceText = {};
+for k = 1:n,
+    importanceText{k} = sprintf('%d->%d',importance(k,2),importance(k,1));
+end
+if plotTypeFlag == 1,
+    set(axesH,'YScale','log');
+    textH = text([1:n]-0.4,1.4*importance(:,3),importanceText);
+else
+    set(axesH,'YScale','linear');
+    textH = text([1:n]-0.4,0.02*(yMax-yMin)+importance(:,3),importanceText);
+end
+set(textH,'fontsize',7);    
+% write axes labels
+xlabel('Interactions ordered in decreasing importance for complex bahvior');
+ylabel('Inverse of the magnitude of stabilizing perturbations (1/| \Delta_{ij}|)');
+% return information about numbers and states in matlab workspace
+% getting the names of the states in the network
+stateNames = feval(ODEfctname,'states');
+numbersInfoText = 'The numbers and the states in the ODEfctname are related as follows:';
+for k = 1:length(stateNames),
+    numbersInfoText = sprintf('%s\n%d: %s',numbersInfoText,k,stateNames{k});
+end
+disp(numbersInfoText);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Implementation of the method described in 
+% "Identifying mechanisms underlying complex behaviors in biochemical 
+% reaction networks", IEE Systems Biology, 1, 149-158 (2004) and
+% "Identifying feedback mechanisms behind complex cell behavior", IEEE
+% Control Systems Magazine, 24 (4), 91-102 (2004)
+%
+% for the determination of important interactions between states 
+% in biochemical networks, that are the source of an observed complex 
+% behavior.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [result] = analyzeImportantInteractions(ODEfctname, steadystate, visualizeFlag)
+global omegaRange omegaRangePoints bisectionThreshold criticalLocusTolerance criticalLocusNrPoints
+% determine the Jacobian
+A = IQMjacobian(ODEfctname,steadystate);
+n = length(steadystate); I = eye(n);
+
+% what the method does - and in which order
+% 0) check that closed loop system is unstable and open loop system is stable
+% 1) determine omega0 - the frequency at which the critical eigenlocus
+%    crosses the real axis right of +1
+% 2) determine the [DELTA]_ij RGA measures for the importance of the interactions
+% 3) check if the determined delta_ij move the critical eigenlocus to +1
+% 4) return the result (delta_ijs that stabilize the system)
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check in/stability of A/Atilde
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% the closed loop system A needs to be unstable and the open loop system
+% Atilde = diag(A) need to be stable - otherwise the method is not
+% applicable 
+if max(real(eig(A))) < 0,
+    error(sprintf('The ODEfctname is stable - this analysis function only works with unstable models.\nIn case you are looking at a system having multiple steady-states\nyou need to specify a starting guess for the steady-state very close to the unstable steady-state.'));
+end
+Atilde = diag(diag(A));
+if max(real(eig(Atilde))) > 0,
+    error(sprintf('The linear open loop system is unstable. This method only works when the\ninteractionfree system is stable, and thus the instability is due to\ninteractions between components (states). You might consider the use of IQMlocbehavinteract2 instead.'));
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Determination of omega0
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% if static instability then omega0 = 0
+% else w0 is given by the frequency at which the critical eigenlocus 
+% crosses the real axis right of +1
+eigA = eig(A);
+test = sortrows([real(eigA), imag(eigA)],1);
+maxRealEigA = test(length(test),:);
+if maxRealEigA(2) == 0,
+    % static instability, since unstable eigenvalue has zero imaginary part
+    omega0 = 0;
+    eigenLoci = [];
+else
+    % dynamic instability, since unstable eigenvalue has nonzero imaginary part
+    omega_star = abs(maxRealEigA(2));
+    % now we need to determine omega0 by determining the frequency at which
+    % the critical eigenlocus crosses the real axis right of +1. this is
+    % done by optimization using omega_star as starting guess for omega_0.
+    % first determine the critical eigenlocus and a bound for optimization
+    omega_range = logspace(log10(omega_star/omegaRange), log10(omegaRange*omega_star), omegaRangePoints);
+    eigenLoci = [eig(L(A,omega_range(1)))]; % initialize with a first entry
+    for k1 = 2:length(omega_range),
+        omega = omega_range(k1);
+        eigL = eig(L(A,omega));
+        % Need to reorder eigL before adding to eigenLoci, since ordering
+        % can be different. Use least squares to determine the order
+        newEigenLoci = inf*ones(n,1);
+        minSquareValue = inf;
+        for k2 = 1:n,
+            eigLk2 = eigL(k2);  % the value to order
+            order = sortrows([[1:n]', abs(eigenLoci(:,k1-1)-eigLk2)],2);
+            newEigenLoci(order(1,1)) = eigLk2;
+        end
+        % add reordered eigenloci to vector
+        eigenLoci = [eigenLoci newEigenLoci];
+    end
+    % go through all the eigenLoci and determine the index of the critical eigenlocus
+    % and an upper and lower bound for the frequency at which it crosses
+    maxRealPart = -inf;
+    criticalEigenLocusIndex = NaN;
+    for k1 = 1:n,
+        eigenLocus = eigenLoci(k1,:);
+        % check if the maximum magnitude over the frequencies is at least > 1
+        if max(abs(eigenLocus)) > 1,
+            imagEigenLocus = imag(eigenLocus);
+            realCrossing = max(real(eigenLocus(find(imagEigenLocus(1:end-1).*imagEigenLocus(2:end) < 0))));
+            if realCrossing > maxRealPart,
+                maxRealPart = realCrossing;
+                criticalEigenLocusIndex = k1;
+            end
+        end
+    end
+    if isnan(criticalEigenLocusIndex),
+        error(sprintf('The critical eigenlocus could not be determined. Please increase the value\nof the option "omegaRange" and/or the value of the option "omegaRangePoints".'));
+    end
+    criticalEigenLocus = eigenLoci(criticalEigenLocusIndex,:);
+    index = find(real(criticalEigenLocus) == maxRealPart);
+    imagValue = imag(criticalEigenLocus(index));
+    imagValueUp = imag(criticalEigenLocus(index+1));
+    imagValueDn = imag(criticalEigenLocus(index-1));
+    if imagValue*imagValueUp < 0, 
+        omegaUp = omega_range(index+1);
+        omegaDn = omega_range(index);
+    end
+    if imagValue*imagValueDn < 0,
+        omegaUp = omega_range(index);
+        omegaDn = omega_range(index-1);
+    end
+    % use bisection between omegaUp and omegaDn to determine the value of
+    % omega0
+    omega0 = bisectOmega0(A,omegaDn,omegaUp,bisectionThreshold);
+    % plot the result of the omega0 determination
+    figH = figure; clf;
+    plotEigenLociCheck(eigenLoci,A,omega0,1);
+    % wait for user to continue 
+    disp('Press any key to continue!');
+    pause;
+    try, close(figH); catch, end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Determination of the delta_ij RGA measures
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+returnDifference = (I-L(A,omega0));
+Lambda = rga(returnDifference);
+
+warning off MATLAB:divideByZero
+DELTA = 1./Lambda;
+warning on MATLAB:divideByZero
+% set the elements that are zero in Lambda to zero in DELTA
+DELTA(find(Lambda==0))=0;
+DELTA = DELTA-diag(diag(DELTA));
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check which of the RGA elements do stabilize
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% This is done by applying the determined needed changes at omega0
+% for each of the non-zero elements in DELTA and see if the critical
+% eigenlocus is moved to +1 at this frequency - if an element is not
+% stabilizing it is set to 0
+for row = 1:n, 
+    for col = 1:n,
+        % check if element is not zero, otherwise go to next element
+        if abs(DELTA(row,col)) ~= 0,
+            delta_ij = DELTA(row,col);  
+            if ~isStabilizing(row,col,delta_ij,omega0,A,bisectionThreshold,criticalLocusTolerance,criticalLocusNrPoints,eigenLoci,visualizeFlag),
+                DELTA(row,col) = 0;
+            end
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Return the result of the analysis
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% order the elements in DELTA after their magnitude and determine row and
+% column for them - discard zero elements - this is the result
+result = sort_cut(DELTA);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Plotting check figure for omega0 determination
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [] = plotEigenLociCheck(eigenLoci,A,omega0,textFlag);
+plot(real(eigenLoci), imag(eigenLoci), 'co'); hold on;
+eigL0 = eig(L(A,omega0)); 
+eigLcrit0 = selectRightEigenLocus(eigL0);
+handle = plot(real(eigLcrit0),imag(eigLcrit0),'rx');
+set(handle,'LineWidth',2);
+handle = plot(1,0,'kx');
+set(handle,'LineWidth',2);
+V = axis; minX = V(1); maxX = V(2); minY = V(3); maxY = V(4);
+plot([minX maxX],[0 0],'k--');
+plot([0 0],[minY maxY],'k--');
+if textFlag,
+    textX = (maxX-minX)*0.05+minX;
+    textY = maxY - 0.05*(maxY-minY);
+    texttext = sprintf('Please check that the red cross appears\nwhere the critical eigenlocus crosses\nthe real axis to the right of +1.\n\nIf this is not the case then you should\nstop the function and increase the value of the "omegaRange" option.\n\nTo continue press any key!');
+    text(textX,textY,texttext,'VerticalAlignment','top');
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Select the "right" eigenlocus :)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% from a vector with eigenloci at one frequency
+% select the one which lies right from +1 as close
+% as possible on the real axis
+function [rightEL] = selectRightEigenLocus(EL)
+    % split value in real and imag part
+    EL = [real(EL) imag(EL)];
+    % take away all the values with negative real part
+    EL = EL(find(EL(:,1)>0),:);
+    % sort the values after ascending imaginary part
+    EL = [EL abs(EL(:,2))];
+    EL = sortrows(EL,3);
+    % search for the element with the smallest imaginary part (magnitude)
+    % that has a real part > 0.99  (use 0.99 instead of 1 = quick fix)
+    for k = 1:size(EL,1),
+        if EL(k,1) > 0.99, break; end
+    end
+    % assemble the result
+    rightEL = EL(k,1)+i*EL(k,2);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check if a delta_ij is stabilizing or not
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% This is done by applying the delta_ij at omega0 to L and checked
+% if the critical eigenlocus is moved to +1 at this frequency - if yes
+% 1 is returned, otherwise 0
+function [result] = isStabilizing(row,col,delta_ij,omega0,A,bisectionThreshold,criticalLocusTolerance,criticalLocusNrPoints,eigenLoci,visualizeFlag)
+    n = length(A);
+    % get nominal open loop at omega0
+    Lnom = L(A,omega0);
+    % get nominal eigenlocus at omega0
+    eigenLocus = eig(Lnom);
+    % get value of critical eigenLocus (has real part > 1 and imag part < 10*bisectionThreshold)
+    criticalLocus = eigenLocus(find((real(eigenLocus) > 1) & (abs(imag(eigenLocus)) < 10*bisectionThreshold)));
+    perturbationVector = delta_ij*[1/criticalLocusNrPoints:1/criticalLocusNrPoints:1];
+    if visualizeFlag,
+        % allows to visualize the determination if a delta_ij is
+        % stabilizing or not and to get an idea if options need to be
+        % changed
+        figH = figure(1); clf;    
+        plotEigenLociCheck(eigenLoci,A,omega0,0);
+    end  
+    for k1 = 1:length(perturbationVector),
+        % get next perturbation
+        delta = perturbationVector(k1);
+        % perturb the open loop system
+        Lpert = Lnom; 
+        Lpert(row,col) = Lpert(row,col)*(1-delta);
+        % determine eigenloci of the perturbed system
+        eigenLocus = eig(Lpert);
+        % check which eigenlocus is closest to the previous criticalLocus
+        sortedHelp = sortrows([[1:n]' abs(eigenLocus-criticalLocus)],2);
+        % get new criticalLocus
+        criticalLocus = eigenLocus(sortedHelp(1));
+        % visualize the determined critical locus
+        if visualizeFlag,
+            plot(real(criticalLocus),imag(criticalLocus),'kx');        
+        end
+    end
+    % check if the perturbed critical locus gets to +1
+    if abs(1-criticalLocus) < criticalLocusTolerance,
+        result = 1;
+    else 
+        result = 0;
+    end
+    % visualize all eigenloci for the full perturbation
+    if visualizeFlag,
+        plot(real(eigenLocus),imag(eigenLocus),'*g');    
+        disp('Press any key!');
+        pause;
+        close(figH);    
+    end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Order matrix elements after there magnitude
+% and determine row and column number, and index
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [X] = sort_cut(matrix)
+vector = matrix(:)';
+n = sqrt(length(vector));
+Y = 1:n^2;
+row = mod(Y,n); row(find(row==0))=n;
+col = ceil(Y/n);
+X = sortrows([row' col' abs(vector)'],3);
+[nx,mx] = size(X);
+INDEX = find(X(:,3)==0); INDEX = INDEX(length(INDEX))+1;
+X = X(INDEX:nx,:);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% RGA calculation
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [Lambda] = rga(matrix)
+    Lambda = matrix.*transpose(inv(matrix));
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% OPTIMIZE omega0 using bisection
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [omega0] = bisectOmega0(A,omegaDn,omegaUp,bisectionThreshold)
+    eigLup = eig(L(A,omegaUp));
+    eigLdn = eig(L(A,omegaDn));
+    count = 0;
+    while (abs(omegaUp-omegaDn)>bisectionThreshold),
+        omegaTest = (omegaDn+omegaUp)/2;
+        eigLtest = eig(L(A,omegaTest));
+        if imag(selectRightEigenLocus(eigLup))*imag(selectRightEigenLocus(eigLtest)) < 0,
+            omegaUp = omegaUp;
+            omegaDn = omegaTest;
+            eigLup = eigLup;
+            eigLdn = eigLtest;
+        end
+        if imag(selectRightEigenLocus(eigLdn))*imag(selectRightEigenLocus(eigLtest)) < 0,
+            omegaUp = omegaTest;
+            omegaDn = omegaDn;
+            eigLup = eigLtest;
+            eigLdn = eigLdn;
+        end
+        count = count + 1;
+        if count >= 100,
+            error(sprintf('Please use a larger value for the "bisectionThreshold" option.'));
+        end
+    end
+    omega0 = omegaTest;
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CALCULATE L(jomega) FROM A AND omega 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [LofOmega] = L(A,omega)
+I = eye(size(A));
+s = i*omega;
+Atilde = diag(diag(A));
+LofOmega = inv(s*I-Atilde)*(A-Atilde);
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/analysis/behaviorlocalization/IQMlocbehavinteract2.m b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/behaviorlocalization/IQMlocbehavinteract2.m
new file mode 100644
index 0000000000000000000000000000000000000000..50114651ce4f17ec3d4c866d6a4795439177204b
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/behaviorlocalization/IQMlocbehavinteract2.m	
@@ -0,0 +1,318 @@
+function [varargout] = IQMlocbehavinteract2(varargin)
+% IQMlocbehavinteract2: does in principle the same as IQMlocbehavinteract.
+% The differences are:
+%       - the value assumed for omega0 = omega_star (the imaginary part of 
+%         the unstable eigenvalue(s))                       
+%       - no check is done if the determined perturbations actually
+%         stabilize the system
+%
+% IQMlocbehavinteract2 might be used in the case where the open loop system
+% is unstable. 
+%
+% USAGE
+% =====
+% [] = IQMlocbehavinteract2(iqm, steadystate)  
+% [] = IQMlocbehavinteract2(iqm, steadystate, OPTIONS)  
+% [importance,stateNames] = IQMlocbehavinteract2(iqm, steadystate)  
+% [importance,stateNames] = IQMlocbehavinteract2(iqm, steadystate, OPTIONS)  
+%
+% iqm: IQMmodel or ODE file to perform the analysis on
+% steadystate: the steady-state at which to perform the analysis
+% OPTIONS: structure containing options
+%          OPTIONS.plotTypeFlag: =0: linear y-axis, =1: logarithmic y-axis
+% 
+% DEFAULT VALUES:
+% ===============
+% OPTIONS.plotTypeFlag: 0 (linear y-axis)
+%
+% Output Arguments:
+% =================
+% If no output argumentsd are given, the results are plotted.
+%
+% importance: each row corresponds to a direct interaction between states
+%       in the considered system. The first element in a row determines the
+%       index of the affected and the second the index of the affecting
+%       state. The third element in a row determines the inverse of the
+%       magnitude of the corresponding delta_ij value. delta_ij is the
+%       value for the relative perturbation in the corresponding
+%       interaction that will move a pole pair of the linearized system
+%       onto the imaginary axis. This might lead to stabilization of the
+%       underlying steady-state. However, it is not checked if it really is
+%       a stabilizing interaction. The function IQMlocbehavinteract does
+%       this check. The 2nd version of this function can therefor only
+%       give a hint.
+%       The larger this inverse is, the more important the direct effect
+%       from state j on state i might be for the creation of the analyzed
+%       behavior (if stabilizing). 
+% stateNames: the name of the states corresponding to the numbering
+%       of columns and rows. 
+%
+% If no output arguments are given, the result is instead plotted.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF IQMMODEL OR FILENAME
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isIQMmodel(varargin{1}),
+    % IQMmodel
+    iqm = varargin{1};
+    % check delays and events
+    if usedelayIQM(iqm),
+        error('The model contains delays. These can not be handled by this function.');
+    end
+    if useeventIQM(iqm),
+        error('The model contains events. These can not be handled by this function.');
+    end   
+    % Create temporary ODE file
+    [ODEfctname, ODEfilefullpath] = IQMcreateTempODEfile(iqm);    
+else
+    % ODEfctname of ODE file
+    ODEfctname = varargin{1};
+    % Check if file exists
+    if exist(strcat(ODEfctname,'.m')) ~= 2,
+        error('ODE file could not be found.');
+    end
+end
+
+% default values
+plotTypeFlag = 0;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin == 2,
+    steadystate = varargin{2};
+elseif nargin == 3,
+    steadystate = varargin{2};
+    % get options for analysis method
+    OPTIONS = varargin{3};
+    % handle the options
+    % plotTypeFlag
+    if isfield(OPTIONS,'plotTypeFlag'),
+        if ~isempty(OPTIONS.plotTypeFlag),
+            plotTypeFlag = OPTIONS.plotTypeFlag;
+        end
+    end    
+else
+    error('Incorrect number of input arguments.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK CORRECT NUMBER OF OUTPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargout ~= 0 && nargout ~= 2,
+    error('Incorrect number of output arguments');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF MODEL IS NON SINGULAR
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% check non singularity
+Jacobian = IQMjacobian(ODEfctname,rand*ones(length(steadystate)));
+if rank(Jacobian) < length(Jacobian),
+    error(sprintf('The ODEfctname is singular. This function only works with non-singular models.\nYou might consider the use of ''IQMreducemodel''.'));
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HERE COMES THE MAIN ANALYSIS PART
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+result = analyzeImportantInteractions(ODEfctname, steadystate);
+% The first column in result contains the row number
+% The second column contains the column number
+% The third contains the magnitude of the required perturbation for stabilization
+%
+% Convert the required perturbations to importance measure by inverting them
+importance = result;
+importance(:,3) = 1./importance(:,3);
+% take out importances below a certain limit
+minShowImportance = 1e-6*max(importance(:,3));
+indexTakeOutStart = find(importance(:,3)<minShowImportance);
+if ~isempty(indexTakeOutStart),
+    importance = importance(1:indexTakeOutStart(1)-1,:);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE VARIABLE OUTPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargout == 0,
+    plotResults(importance, ODEfctname, plotTypeFlag, steadystate);
+else
+    varargout{1} = importance;
+    varargout{2} = stateNames;
+    % set acceptable format for output
+    format short g
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DELETE FILE IF IQMMODEL
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if strcmp('IQMmodel',class(varargin{1})),
+    IQMdeleteTempODEfile(ODEfilefullpath);
+end
+return
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Plot the results of the analysis
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [] = plotResults(importance, ODEfctname, plotTypeFlag, steadystate)
+% determine Jacobian at given steadystate (signs of elements needed for
+% choosing plot color)
+J = IQMjacobian(ODEfctname,steadystate);
+% get number of rows in importance matrix
+n = size(importance,1);
+% open new figure
+figH = figure; clf; axesH = gca(figH);
+% plot the data - blue if Jacobian element positive, red if Jacobian
+% element negative
+if plotTypeFlag == 0,
+    for k = 1:n,
+        if J(importance(k,1),importance(k,2)) >= 0,
+            bar(k,importance(k,3),'b'); hold on;
+        else
+            bar(k,importance(k,3),'r'); hold on;
+        end
+    end    
+else
+    for k = 1:n,
+        if J(importance(k,1),importance(k,2)) >= 0,
+            handle = plot(k,importance(k,3),'ob'); hold on;
+            set(handle,'LineWidth',2);
+            set(handle,'MarkerFaceColor','b');            
+        else
+            handle = plot(k,importance(k,3),'or'); hold on;
+            set(handle,'LineWidth',2);
+            set(handle,'MarkerFaceColor','r');            
+        end
+    end
+end    
+% set y-axis properties
+yMax = 1.5*max(importance(:,3));
+if plotTypeFlag,
+    % min value in case of semilogy plot
+    help = sort(importance(:,3))';
+    help = help(find(help>0))';
+    yMin = 0.75*help(1);
+else
+    % min value to zero in case of linear plot
+    yMin = 0;
+end
+axis([0 n+1 yMin yMax]);
+set(axesH,'XTick',[]);
+% construct plot text and plot it
+importanceText = {};
+for k = 1:n,
+    importanceText{k} = sprintf('%d->%d',importance(k,2),importance(k,1));
+end
+if plotTypeFlag == 1,
+    set(axesH,'YScale','log');
+    textH = text([1:n]-0.4,1.4*importance(:,3),importanceText);
+else
+    set(axesH,'YScale','linear');
+    textH = text([1:n]-0.4,0.02*(yMax-yMin)+importance(:,3),importanceText);
+end
+set(textH,'fontsize',7);    
+% write axes labels
+xlabel('Interactions ordered in decreasing importance for complex bahvior');
+ylabel('Inverse of the magnitude of perturbations (1/| \Delta_{ij}|)');
+% return information about numbers and states in matlab workspace
+% getting the names of the states in the network
+stateNames = feval(ODEfctname,'states');
+numbersInfoText = 'The numbers and the states in the ODEfctname are related as follows:';
+for k = 1:length(stateNames),
+    numbersInfoText = sprintf('%s\n%d: %s',numbersInfoText,k,stateNames{k});
+end
+disp(numbersInfoText);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Implementation of the method described in 
+% "Identifying mechanisms underlying complex behaviors in biochemical 
+% reaction networks", IEE Systems Biology, 1, 149-158 (2004) and
+% "Identifying feedback mechanisms behind complex cell behavior", IEEE
+% Control Systems Magazine, 24 (4), 91-102 (2004)
+%
+% for the determination of important interactions between states 
+% in biochemical networks, that are the source of an observed complex 
+% behavior.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [result] = analyzeImportantInteractions(ODEfctname, steadystate)
+% determine the Jacobian
+A = IQMjacobian(ODEfctname,steadystate);
+n = length(steadystate); I = eye(n);
+
+% what the method does - and in which order
+% 1) determine omega0 - just use the imaginary part of the unstable eigenvalues
+% 2) determine the [DELTA]_ij RGA measures for the importance of the interactions
+% 3) check if the determined delta_ij move the critical eigenlocus to +1
+% 4) return the result (delta_ijs that stabilize the system)
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Determination of omega0
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% if static instability then omega0 = 0
+% else w0 is given by the frequency at which the critical eigenlocus 
+% crosses the real axis right of +1
+eigA = eig(A);
+test = sortrows([real(eigA), imag(eigA)],1);
+maxRealEigA = test(length(test),:);
+if maxRealEigA(2) == 0,
+    % static instability, since unstable eigenvalue has zero imaginary part
+    omega0 = 0;
+else
+    omega0 = abs(maxRealEigA(2)); 
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Determination of the delta_ij RGA measures
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+returnDifference = (I-L(A,omega0));
+Lambda = rga(returnDifference);
+warning off MATLAB:divideByZero
+DELTA = 1./Lambda;
+warning on MATLAB:divideByZero
+% set the elements that are zero in Lambda to zero in DELTA
+DELTA(find(Lambda==0))=0;
+DELTA = DELTA-diag(diag(DELTA));
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Return the result of the analysis
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% order the elements in DELTA after their magnitude and determine row and
+% column for them - discard zero elements - this is the result
+result = sort_cut(DELTA);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Order matrix elements after there magnitude
+% and determine row and column number, and index
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [X] = sort_cut(matrix)
+vector = matrix(:)';
+n = sqrt(length(vector));
+Y = 1:n^2;
+row = mod(Y,n); row(find(row==0))=n;
+col = ceil(Y/n);
+X = sortrows([row' col' abs(vector)'],3);
+[nx,mx] = size(X);
+INDEX = find(X(:,3)==0); INDEX = INDEX(length(INDEX))+1;
+X = X(INDEX:nx,:);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% RGA calculation
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [Lambda] = rga(matrix)
+    Lambda = matrix.*transpose(inv(matrix));
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CALCULATE L(jomega) FROM A AND omega 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [LofOmega] = L(A,omega)
+I = eye(size(A));
+s = i*omega;
+Atilde = diag(diag(A));
+LofOmega = inv(s*I-Atilde)*(A-Atilde);
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/IQMsensglobalfast.m b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/IQMsensglobalfast.m
new file mode 100644
index 0000000000000000000000000000000000000000..e07f26bd8bd469905bd2be299eee6f20b2c87b7f
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/IQMsensglobalfast.m	
@@ -0,0 +1,381 @@
+function [varargout] = IQMsensglobalfast(model,timevector,varargin)
+% Global sensitivity analysis method: Extended FAST method
+%
+% For more information see:
+%
+% Y. Zheng and A. Rundell (2006) Comparative study of parameter sensitivity
+% analyses of the TCR-activated Erk-MAPK signalling pathway, IEE
+% Proc.-Syst. Biol., Vol. 153, No. 4, 201-211
+%
+% Saltelli, A., Tarantola, S., and Chan, K.P.S. (1999) A quantitative
+% model-independent method for global sensitivity analysis of model
+% output, Technometrics, 41, 39–56
+%
+% USAGE:
+% ======
+% IQMsensglobalfast(model,timevector)
+% IQMsensglobalfast(model,timevector,paramNames)
+% IQMsensglobalfast(model,timevector,paramNames,OPTIONS)
+% [output] = IQMsensglobalfast(model,timevector)
+% [output] = IQMsensglobalfast(model,timevector,paramNames)
+% [output] = IQMsensglobalfast(model,timevector,paramNames,OPTIONS)
+%
+% model: IQMmodel to perform the global sensitivity analysis for
+% timevector: vector of timeinstants to consider
+% paramNames: cell-array with names of the parameters to consider
+% OPTIONS: structure with optional settings:
+%   OPTIONS.statenames: cell-array with state names which to consider as
+%       model outputs
+%   OPTIONS.variablenames: cell-array with variable names which to consider
+%       as model outputs
+%   OPTIONS.reactionnames: cell-array with reaction names which to consider
+%       as model outputs
+%   OPTIONS.Nsim: Number of simulation to carry out (approximate value)
+%   OPTIONS.range: Order of magnitude of parameter perturbations
+%   OPTIONS.firstorder: =0: use total effect, =1: use first order approx.
+%   OPTIONS.objectivefunction: ='relative': the differences between nominal
+%       and perturbed model are normalized to represent relative changes in
+%       each considered variable. ='absolute': no normalization is done.
+%       Alternatively, the user can provide the name for an own objective
+%       function to use. As template you can have a look at the two
+%       objectivefunctions in the folder:
+%       IQMlite/analysis/globalparametersensitivity/auxiliary
+%   OPTIONS.integrator: Structure with optional settings for the integrator, 
+%       either defined by odeset() for MATLAB simulation of by the integrator
+%       options setting used in IQMPsimulate.
+%
+% DEFAULT VALUES:
+% ===============
+% paramNames: Consider all parameters in the model
+% OPTIONS.statenames: Consider all states in the model
+% OPTIONS.variablenames: {} (no variables)
+% OPTIONS.reactionnames: {} (no reactions)
+% OPTIONS.Nsim: 1000
+% OPTIONS.range: 1
+% OPTIONS.firstorder: 0 (use total effect)
+% OPTIONS.objectivefunction: 'relative'
+% OPTIONS.integrator: [] (default integrator settings, defined in getDefaultIntegratorOptionsIQM.m)
+%
+% Output Arguments:
+% =================
+% If no output argument is specified, the result is plotted.
+% Otherwise, the output is a structure with the following fields:
+%
+% output.Nsim: Number of performed simulations
+% output.method: Name of the global sensitivity method
+% output.parameters: Considered parameters 
+% output.overallmeasure: Sensitivity indices for overall model output
+% output.overallparamranking: Parameter ranking regarding overall model output
+% output.singlecomponents: Names of the components, considered outputs
+% output.singlemeasure: Single sensitivity indices for all considered model outputs
+% output.singleparamranking: Parameter ranking for each considered model output
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+global Ncount 
+Ncount = 0;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE NON-NUMERIC INITIAL CONDITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% just by replacing them
+model = IQMconvertNonNum2NumIC(model);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin == 2,
+    paramNames = IQMparameters(model);
+    OPTIONS = [];
+elseif nargin == 3,
+    paramNames = varargin{1};
+    OPTIONS = [];
+elseif nargin == 4,
+    paramNames = varargin{1};
+    OPTIONS = varargin{2};
+else
+    error('Incorrect number of input arguments.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DEFAULT OPTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+statenames = IQMstates(model);
+variablenames = {};
+reactionnames = {};
+Nsim = 1000;
+range = 1;
+firstorder = 0;
+objectivefunction = 'relative';
+
+% Define default integrator options based on if IQM pro available or not
+[options_M,options_C] = getDefaultIntegratorOptionsIQM();
+if isIQMproPresent(),
+    integratoroptions = options_C;
+else
+    integratoroptions = options_M;
+    try
+        dummy = integratoroptions.method;
+    catch
+        integratoroptions.method = 'ode23s';
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try statenames = OPTIONS.statenames; catch, end
+try variablenames = OPTIONS.variablenames; catch, end
+try reactionnames = OPTIONS.reactionnames; catch, end
+try Nsim = OPTIONS.Nsim; catch, end
+try range = OPTIONS.range; catch, end
+try firstorder = OPTIONS.firstorder; catch, end
+try integratoroptions = OPTIONS.integrator; catch, end
+try objectivefunction = OPTIONS.objectivefunction; catch, end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS objecticefunction CHOICE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if strcmp(objectivefunction,'relative'),
+    objectivefunction = 'rel_sensglobaldefaultobjectiveIQM';
+elseif strcmp(objectivefunction,'absolute'),
+    objectivefunction = 'abs_sensglobaldefaultobjectiveIQM';
+else
+    % user defined objective functions
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET INDICES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+stateindices = stateindexIQM(model,statenames);
+variableindices = variableindexIQM(model,variablenames);
+reactionindices = reactionindexIQM(model,reactionnames);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% MAKE MEX MODEL - only if IQM Pro available
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isIQMproPresent(),
+    [MEXmodel, MEXmodelfullpath] = IQMmakeTempMEXmodel(model);
+else
+    MEXmodel = model;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GENERATE NOMINAL SOLUTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+paramValuesNominal = IQMparameters(model,paramNames);
+if isIQMproPresent(),
+    nomsimdata = IQMPsimulate(MEXmodel,timevector,IQMinitialconditions(model),paramNames,paramValuesNominal,integratoroptions);
+else
+    nomsimdata = IQMsimulate(MEXmodel,integratoroptions.method,timevector,[],integratoroptions);
+end
+    
+Ncount = Ncount + 1;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK FOR ZERO NOMINAL PARAMETERS and exclude them from the analysis
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+indexZero = find(paramValuesNominal == 0);
+if ~isempty(indexZero),
+    text = sprintf('%s, ',paramNames{indexZero});
+    disp(sprintf('Some parameters have nominal values of zero. They are excluded from the analysis.\nParameters: %s\n',text(1:end-2)));
+    paramValuesNominal(indexZero) = [];
+    paramNames = paramNames(setdiff(1:length(paramNames),indexZero));
+end
+
+nrparam = length(paramNames);
+
+PS=[];% reset PS
+output=[];% reset output
+%frequency and phase selection keeps # of model simulations ~ Nsim
+M = 6; % interference factor (usually 4 or 6) corresponds to higher harmonics
+%Find max frequency: there is a trade off between computation numbers
+%  and optimal ratio of max/number of phase shift evaluations
+stor_C = inf;  % initialize with very large number so always updates on first pass
+for target = 16:64  % evaluate all target levels in range, see figure 7 of ref 15 (Saltelli, Tarantola, Chan 1999)
+    y = [M;Nsim;nrparam;target];  % input vector to find max frequency
+    [W,FVAL,EXITFLAG] = fsolveIQM(@(W)FAST_max_W(W,y),nrparam*2);  % find highest frequency of interest (req from ref 15)
+    Wmax = ceil(W);  % make optimal an integer
+    if Wmax/2 ~= floor(Wmax/2), % force Wmax to be even!!
+        Wmax = Wmax + 1;
+    end
+    Ns = 2*M*Wmax+1;  % number of samples along s from -pi to pi
+    Nph = ceil(Nsim/(nrparam*Ns)); % number of random phase shift curves that keeps ~ Nsim total model evals
+    C = Ns*Nph*nrparam;  % computational costs
+    if C < stor_C  % store smallest computational cost solution
+        stor_C = C;
+        stor_W = Wmax;
+    end
+end
+Wmax = ceil(stor_W);  % make optimal value an integer
+Ns = 2*M*Wmax+1;  % number of samples along s from -pi to pi
+Nph = ceil(Nsim/(nrparam*Ns)); % number of random phase shift curves that keeps ~ Nsim total model evals
+
+%Determine maximum for complmentary frequencies
+maxw_c = floor(Wmax/(2*M));  % prevents aliasing
+wvec = ones(1,nrparam);  % construct frequency vector
+step = ceil(maxw_c/nrparam);  % want largest possible steps between freqeunces
+for i = 2:nrparam
+    wvec(i)=wvec(i-1)+step;  % exhaust frequency range between (1 and maxw_i)
+    if wvec(i)>maxw_c  % check for exceeding max allowable freq
+        wvec(i)=1;   % assign the same frequency as seldom as possible
+    end
+end
+
+%Determine parameter space for compuations
+phi = 2*pi*rand(nrparam,Nph);
+
+s = [];  % scalar variable for parameter space
+for i = 1:Ns
+    s(i) = pi/Ns*(2*i-Ns-1);  % space out sampled parameter space between -pi to pi
+end
+for k = 1:Ns % for each s sample
+    for i = 1:Nph % for each phase shift
+        for j = 1:nrparam % for each parameter
+            w = wvec; % assign freq of variations to all paramNames
+            w(j) = Wmax; % fix freq of var for parameter of interest at max freq
+            temp = 10.^(2/pi*asin(sin(w*s(k)+phi(j,i))).*range).*paramValuesNominal(:)';
+            PS(k,:,j,i)=temp;  % define parameter space for analysis
+        end
+    end
+end
+
+%Determine output for different parameter sets
+try
+    for k = 1:Ns  % for each s sample
+        for i = 1:Nph % for each phase shift
+            for j = 1:nrparam % for each parameter
+                paramValuesPerturbed = PS(k,:,j,i);  % assign parameter values from parameter space
+                %compute model output and objective function for kp
+                tic;
+                output(k,:,j,i)=feval(objectivefunction,MEXmodel,timevector,paramNames,paramValuesPerturbed,IQMinitialconditions(model),nomsimdata,stateindices,variableindices,reactionindices,integratoroptions);
+                deltaT_ = toc;
+                if k*i*j == 1,
+                    disp(sprintf('FAST: Approximate time for analysis: %d minutes',ceil(deltaT_*Ns*Nph*nrparam/60)));
+                    if ~isIQMproPresent(),
+                        disp('Analysis can be sped up considerably by installing the IQM Tools Pro.');
+                    end
+                end
+            end
+        end
+    end
+catch
+    error('Simulation failed. Please consider a reduction of the ''range'' option.');
+end
+% compute FS coefficients indices
+m = size(output,2);  % # of outputs
+A = zeros(M*Wmax,m,nrparam,Nph);  % vector for coef of FS
+B = zeros(M*Wmax,m,nrparam,Nph);  % vector for coef of FS
+for i = 1:Nph  % for each phase shift
+    for j = 1:nrparam % for each parameter
+        for f = 1:M*Wmax % for harmonic frequencies below Nyquist: ~(Ns-1)/2
+            for k = 1:Ns % for each s sample
+                A(f,:,j,i)=A(f,:,j,i)+output(k,:,j,i)*cos(f*s(k))/Ns;  %compute FS cos coef
+                B(f,:,j,i)=B(f,:,j,i)+output(k,:,j,i)*sin(f*s(k))/Ns;  %compute FS sin coef
+            end
+        end
+    end
+end
+
+%compute sensitivity indices from FS coef
+Amp = A.^2+B.^2;  % Magnitude of frequency content
+Dtot = sum(2*sum(Amp,1),4)/Nph;
+Dtot=squeeze(Dtot);
+Di = sum(2*sum(Amp(Wmax:Wmax:M*Wmax,:,:,:),1),4)/Nph;
+Di = squeeze(Di);
+D_i=sum(2*sum(Amp(1:Wmax/2,:,:,:),1),4)/Nph;
+D_i=squeeze(D_i);
+
+% take care of zeros (mostly trough states that are not affected by
+% parameters).
+indexzeros = find(Dtot==0);
+Dtot(indexzeros) = 1;
+D_i(indexzeros) = 1;
+eFAST_1 = (Di./Dtot)';
+eFAST_t = (1-D_i./Dtot)';
+
+%sort sensitivity rankings
+%rank_eFAST_1: sorted first order rankings in terms of ascending magnitude
+%rank_eFAST_1p: paramNames ranked in assending order via first order values
+[rank_eFAST_1, rank_eFAST_1p] = sort(abs(eFAST_1),1,'descend');
+%rank_eFAST_t: sorted total effect order rankings in terms of ascending magnitude
+%rank_eFAST_tp: paramNames ranked in assending order via total effect values
+[rank_eFAST_t, rank_eFAST_tp] = sort(abs(eFAST_t),1,'descend');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE OUTPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+output = [];
+output.Nsim = Ncount;
+if firstorder == 1, output.method = 'FAST First Order';
+else output.method = 'FAST Total Effect'; end
+output.parameters = paramNames(:)';
+if firstorder == 1, output.overallmeasure = eFAST_1(:,end);
+else output.overallmeasure = eFAST_t(:,end); end
+if firstorder == 1, output.overallparamranking = rank_eFAST_1p(:,end);
+else output.overallparamranking = rank_eFAST_tp(:,end); end
+output.singlecomponents = {statenames{:}, variablenames{:}, reactionnames{:}};
+if firstorder == 1, output.singlemeasure = eFAST_1(:,1:end-1);
+else output.singlemeasure = eFAST_t(:,1:end-1); end
+if firstorder == 1, output.singleparamranking = rank_eFAST_1p(:,1:end-1);
+else output.singleparamranking = rank_eFAST_tp(:,1:end-1); end
+
+% generate plotting datastructure (for IQMplot2)
+datastruct = [];
+datastruct.name = sprintf('Global Sensitivities: %s method',output.method);
+datastruct.xnames = output.parameters;
+datastruct.ynames = {'OVERALL MEASURE', output.singlecomponents{:}};    % cell-array with names of y-axis data
+datastruct.data =  [output.overallmeasure output.singlemeasure]'; %  matrix with y-axis data in rows and x-axis data in columns
+datastruct.title = sprintf('Global Sensitivities: %s method',output.method);
+datastruct.xlabel = 'Parameters';
+datastruct.xaxistitle = 'X';
+datastruct.yaxistitle = 'Y';
+% add it to the output variable
+output.plotdatastruct = datastruct;
+
+if nargout == 1,
+    varargout{1} = output;
+elseif nargout == 0,
+    % Plot the sensitivities using IQMplot2
+    IQMplot2(datastruct)
+else
+    error('Incorrect number of output arguments.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DELETE MEX MODEL
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isIQMproPresent(),
+    clear mex;
+    delete(MEXmodelfullpath);
+    clear global Ncount
+end
+clear global Ncount
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function fval = FAST_max_W(W,y)
+
+% W is highest frequency of interest
+M = y(1);  % inteference factor (usually 4 or 6) corresponds to higher harmonics
+N = y(2);  % approximate total number of model evaluations
+n_p = y(3);  % number of factors
+target = y(4);  % target value for ratio
+
+Ns = 2*M*W+1;  % number of samples along s from -pi to pi
+Nph = ceil(N/(n_p*Ns)); % number of random phase shift curves that keeps ~ N total model evals
+ratio = W/Nph;  % compute ratio
+% desired range of ration is between 16 and 64
+%For more info:  see figure 7 of ref 15 (Saltelli, Tarantola, Chan 1999)
+fval = ratio-target;  % compute difference between ratio and target
+penalty = 10;
+if ratio < 64
+    if ratio < 16
+        fval =penalty*fval;  % ratio not in desired range penalize for too small
+    end
+else
+    fval = penalty*fval; % ratio not in desired range penalize for too large
+end
+
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/IQMsensglobalprcc.m b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/IQMsensglobalprcc.m
new file mode 100644
index 0000000000000000000000000000000000000000..fd30e52f7ce70165cab19d41fa19b7a72e6c4129
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/IQMsensglobalprcc.m	
@@ -0,0 +1,289 @@
+function [varargout] = IQMsensglobalprcc(model,timevector,varargin)
+% Global sensitivity analysis method: PRCC method
+%
+% For more information see:
+%
+% Y. Zheng and A. Rundell (2006) Comparative study of parameter sensitivity
+% analyses of the TCR-activated Erk-MAPK signalling pathway, IEE
+% Proc.-Syst. Biol., Vol. 153, No. 4, 201-211
+%
+% Draper, N., and Smith, H. (1981) Applied regression analysis, Wiley,
+% New York, 2nd edn.
+%
+% USAGE:
+% ======
+% IQMsensglobalprcc(model,timevector)
+% IQMsensglobalprcc(model,timevector,paramNames)
+% IQMsensglobalprcc(model,timevector,paramNames,OPTIONS)
+% [output] = IQMsensglobalprcc(model,timevector)
+% [output] = IQMsensglobalprcc(model,timevector,paramNames)
+% [output] = IQMsensglobalprcc(model,timevector,paramNames,OPTIONS)
+%
+% model: IQMmodel to perform the global sensitivity analysis for
+% timevector: vector of timeinstants to consider
+% paramNames: cell-array with names of the parameters to consider
+% OPTIONS: structure with optional settings:
+%   OPTIONS.statenames: cell-array with state names which to consider as
+%       model outputs
+%   OPTIONS.variablenames: cell-array with variable names which to consider
+%       as model outputs
+%   OPTIONS.reactionnames: cell-array with reaction names which to consider
+%       as model outputs
+%   OPTIONS.Nsim: Number of simulation to carry out (approximate value)
+%   OPTIONS.range: Order of magnitude of parameter perturbations
+%   OPTIONS.objectivefunction: ='relative': the differences between nominal
+%       and perturbed model are normalized to represent relative changes in
+%       each considered variable. ='absolute': no normalization is done.
+%       Alternatively, the user can provide the name for an own objective
+%       function to use. As template you can have a look at the two
+%       objectivefunctions in the folder:
+%       IQMlite/analysis/globalparametersensitivity/auxiliary
+%   OPTIONS.integrator: Structure with optional settings for the integrator, 
+%       either defined by odeset() for MATLAB simulation of by the integrator
+%       options setting used in IQMPsimulate.
+%
+% DEFAULT VALUES:
+% ===============
+% paramNames: Consider all parameters in the model
+% OPTIONS.statenames: Consider all states in the model
+% OPTIONS.variablenames: {} (no variables)
+% OPTIONS.reactionnames: {} (no reactions)
+% OPTIONS.Nsim: 1000
+% OPTIONS.range: 1
+% OPTIONS.objectivefunction: 'relative'
+% OPTIONS.integrator: [] (default integrator settings, defined in getDefaultIntegratorOptionsIQM.m)
+%
+% Output Arguments:
+% =================
+% If no output argument is specified, the result is plotted.
+% Otherwise, the output is a structure with the following fields:
+%
+% output.Nsim: Number of performed simulations
+% output.method: Name of the global sensitivity method
+% output.parameters: Considered parameters 
+% output.overallmeasure: Sensitivity indices for overall model output
+% output.overallparamranking: Parameter ranking regarding overall model output
+% output.singlecomponents: Names of the components, considered outputs
+% output.singlemeasure: Single sensitivity indices for all considered model outputs
+% output.singleparamranking: Parameter ranking for each considered model output
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+global Ncount 
+Ncount = 0;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE NON-NUMERIC INITIAL CONDITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% just by replacing them
+model = IQMconvertNonNum2NumIC(model);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin == 2,
+    paramNames = IQMparameters(model);
+    OPTIONS = [];
+elseif nargin == 3,
+    paramNames = varargin{1};
+    OPTIONS = [];
+elseif nargin == 4,
+    paramNames = varargin{1};
+    OPTIONS = varargin{2};
+else
+    error('Incorrect number of input arguments.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DEFAULT OPTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+statenames = IQMstates(model);
+variablenames = {};
+reactionnames = {};
+Nsim = 1000;
+range = 1;
+objectivefunction = 'relative';
+
+% Define default integrator options based on if IQM pro available or not
+[options_M,options_C] = getDefaultIntegratorOptionsIQM();
+if isIQMproPresent(),
+    integratoroptions = options_C;
+else
+    integratoroptions = options_M;
+    try
+        dummy = integratoroptions.method;
+    catch
+        integratoroptions.method = 'ode23s';
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try statenames = OPTIONS.statenames; catch, end
+try variablenames = OPTIONS.variablenames; catch, end
+try reactionnames = OPTIONS.reactionnames; catch, end
+try Nsim = OPTIONS.Nsim; catch, end
+try range = OPTIONS.range; catch, end
+try integratoroptions = OPTIONS.integrator; catch, end
+try objectivefunction = OPTIONS.objectivefunction; catch, end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS objecticefunction CHOICE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if strcmp(objectivefunction,'relative'),
+    objectivefunction = 'rel_sensglobaldefaultobjectiveIQM';
+elseif strcmp(objectivefunction,'absolute'),
+    objectivefunction = 'abs_sensglobaldefaultobjectiveIQM';
+else
+    % user defined objective functions
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET INDICES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+stateindices = stateindexIQM(model,statenames);
+variableindices = variableindexIQM(model,variablenames);
+reactionindices = reactionindexIQM(model,reactionnames);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% MAKE MEX MODEL - only if IQM Pro available
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isIQMproPresent(),
+    [MEXmodel, MEXmodelfullpath] = IQMmakeTempMEXmodel(model);
+else
+    MEXmodel = model;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GENERATE NOMINAL SOLUTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+paramValuesNominal = IQMparameters(model,paramNames);
+if isIQMproPresent(),
+    nomsimdata = IQMPsimulate(MEXmodel,timevector,IQMinitialconditions(model),paramNames,paramValuesNominal,integratoroptions);
+else
+    nomsimdata = IQMsimulate(MEXmodel,integratoroptions.method,timevector,[],integratoroptions);
+end
+    
+Ncount = Ncount + 1;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK FOR ZERO NOMINAL PARAMETERS and exclude them from the analysis
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+indexZero = find(paramValuesNominal == 0);
+if ~isempty(indexZero),
+    text = sprintf('%s, ',paramNames{indexZero});
+    disp(sprintf('Some parameters have nominal values of zero. They are excluded from the analysis.\nParameters: %s\n',text(1:end-2)));
+    paramValuesNominal(indexZero) = [];
+    paramNames = paramNames(setdiff(1:length(paramNames),indexZero));
+end
+
+
+nrparam = length(paramNames); % number of model paramNames to perform sensitivity analysis on
+
+%Determine parameter space for compuations
+%latin hypercube sampling of parameter space
+LHS = lhsu(zeros(1,nrparam),ones(1,nrparam),Nsim); %matlab command to generate LHS sampling (using a free LHS tool)
+
+% Nsim equal intervals from 0 to 1 for each parameter
+% scale to cover full parameter space with uniform distribution in log space
+PS = 10.^((LHS-.5).*2*range).*(ones(Nsim,1)*paramValuesNominal(:)');
+
+%compute model output and evaluate objective function for each set of paramNames
+try
+    for i = 1:Nsim
+        paramValuesPerturbed = PS(i,:);  %evaluate objective function for each parameter set
+        tic;
+        output(i,:) = feval(objectivefunction,MEXmodel,timevector,paramNames,paramValuesPerturbed,IQMinitialconditions(model),nomsimdata,stateindices,variableindices,reactionindices,integratoroptions);
+        deltaT_ = toc;
+        if i == 1,
+            disp(sprintf('PRCC: Approximate time for analysis: %d minutes',ceil(deltaT_*Nsim/60)));
+            if ~isIQMproPresent(),
+                disp('Analysis can be sped up considerably by installing the IQM Tools Pro.');
+            end
+        end
+    end
+catch
+    error('Simulation failed. Please consider a reduction of the ''range'' option.');
+end
+%Perform rank transformation
+%rank output of objective function evaluations with different parameter values
+[sorted_val, rownum] = sort([PS,output]);  %sort each column in ascending order, keep track or row number in column
+[indvalue, ranking] = sort(rownum); % sort rownum to get ranking of output
+
+%compute rank transformed Pearson's correlation coeffients for each parameter set
+am = (1+Nsim)/2;  %arithmatic mean of rankings for Nsim independent runs
+n_out = size(output,2);  %size of output of objective function
+PEAR_p=zeros(nrparam,nrparam);
+PEAR_out=zeros(nrparam,n_out);
+for i = 1:nrparam
+    normp = norm(ranking(:,i)-am);  %sqrt of sum of squares for all paramNames in set
+    for j = 1:(nrparam)  % compute correlation coef for paramNames
+        numerator = sum((ranking(:,i)-am).*(ranking(:,j)-am));
+        denominator = normp*norm(ranking(:,j)-am);
+        PEAR_p(i,j)=numerator./denominator;  % PEAR correlation coefficients
+        PEAR_p(j,i)=PEAR_p(i,j); %make this a symmetric matrix
+    end
+    for j = 1:n_out  % compute correlation coef for outputs of obj func
+        numerator = sum((ranking(:,i)-am).*(ranking(:,j+nrparam)-am));
+        denominator = normp*norm(ranking(:,j+nrparam)-am);
+        PEAR_out(i,j)=numerator./denominator;  % PEAR correlation coefficients
+    end
+end
+
+%compute PRCC (-1 to 1) from rank transformed Pearson Correlation Coef
+% PRCC:  matrix with PRCC computed sensitivity indicies
+PRCC = zeros(nrparam,n_out);
+for k = 1:n_out  % for each output compute PRCC for the paramNames
+    mat = [[PEAR_p, PEAR_out(:,k)];[PEAR_out(:,k)',1]];  %append row and column of output of interest
+    imat = inv(mat);  %take inverse of matrix
+    PRCC(1:nrparam,k) = -imat(1:nrparam,nrparam+1)./sqrt(diag(imat(1:nrparam,1:nrparam)*imat(nrparam+1, nrparam+1)));
+end
+
+%sort PRCC rankings
+%rank_PRCC_p: paramNames ranked in assending order via PRCC values
+[temp rank_PRCC_p] = sort(abs(PRCC));
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE OUTPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+output = [];
+output.Nsim = Ncount;
+output.method = 'PRCC';
+output.parameters = paramNames(:)';
+output.overallmeasure = PRCC(:,end);
+output.overallparamranking = rank_PRCC_p(:,end);
+output.singlecomponents = {statenames{:}, variablenames{:}, reactionnames{:}};
+output.singlemeasure = PRCC(:,1:end-1);
+output.singleparamranking = rank_PRCC_p(:,1:end-1);
+
+% generate plotting datastructure (for IQMplot2)
+datastruct = [];
+datastruct.name = 'Global Sensitivities: PRCC method';
+datastruct.xnames = output.parameters;
+datastruct.ynames = {'OVERALL MEASURE', output.singlecomponents{:}};    % cell-array with names of y-axis data
+datastruct.data =  [output.overallmeasure output.singlemeasure]'; %  matrix with y-axis data in rows and x-axis data in columns
+datastruct.title = 'Global Sensitivities: PRCC method';
+datastruct.xlabel = 'Parameters';
+datastruct.xaxistitle = 'X';
+datastruct.yaxistitle = 'Y';
+% add it to the output variable
+output.plotdatastruct = datastruct;
+
+if nargout == 1,
+    varargout{1} = output;
+elseif nargout == 0,
+    IQMplot2(datastruct)
+else
+    error('Incorrect number of output arguments.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DELETE MEX MODEL
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isIQMproPresent(),
+    clear mex;
+    delete(MEXmodelfullpath);
+    clear global Ncount
+end
+clear global Ncount
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/IQMsensglobalsobol.m b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/IQMsensglobalsobol.m
new file mode 100644
index 0000000000000000000000000000000000000000..ae57077b42db7b5aef33cbb5ea66c184d81e5cfa
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/IQMsensglobalsobol.m	
@@ -0,0 +1,344 @@
+function [varargout] = IQMsensglobalsobol(model,timevector,varargin)
+% Global sensitivity analysis method: SOBOL's method
+%
+% For more information see:
+%
+% Y. Zheng and A. Rundell (2006) Comparative study of parameter sensitivity
+% analyses of the TCR-activated Erk-MAPK signalling pathway, IEE
+% Proc.-Syst. Biol., Vol. 153, No. 4, 201-211
+%
+% Sobol, I.M. (2001) Global sensitivity indices for nonlinear mathematical
+% models and their Monte Carlo estimates, Math. Comp. Simul., 55, 271–280
+%
+% USAGE:
+% ======
+% IQMsensglobalsobol(model,timevector)
+% IQMsensglobalsobol(model,timevector,paramNames)
+% IQMsensglobalsobol(model,timevector,paramNames,OPTIONS)
+% [output] = IQMsensglobalsobol(model,timevector)
+% [output] = IQMsensglobalsobol(model,timevector,paramNames)
+% [output] = IQMsensglobalsobol(model,timevector,paramNames,OPTIONS)
+%
+% model: IQMmodel to perform the global sensitivity analysis for
+% timevector: vector of timeinstants to consider
+% paramNames: cell-array with names of the parameters to consider
+% OPTIONS: structure with optional settings:
+%   OPTIONS.statenames: cell-array with state names which to consider as
+%       model outputs
+%   OPTIONS.variablenames: cell-array with variable names which to consider
+%       as model outputs
+%   OPTIONS.reactionnames: cell-array with reaction names which to consider
+%       as model outputs
+%   OPTIONS.Nsim: Number of simulation to carry out (approximate value)
+%   OPTIONS.range: Order of magnitude of parameter perturbations
+%   OPTIONS.firstorder: =0: use total effect, =1: use first order approx.
+%   OPTIONS.objectivefunction: ='relative': the differences between nominal
+%       and perturbed model are normalized to represent relative changes in
+%       each considered variable. ='absolute': no normalization is done.
+%       Alternatively, the user can provide the name for an own objective
+%       function to use. As template you can have a look at the two
+%       objectivefunctions in the folder:
+%       IQMlite/analysis/globalparametersensitivity/auxiliary
+%   OPTIONS.integrator: Structure with optional settings for the integrator, 
+%       either defined by odeset() for MATLAB simulation of by the integrator
+%       options setting used in IQMPsimulate.
+%
+% DEFAULT VALUES:
+% ===============
+% paramNames: Consider all parameters in the model
+% OPTIONS.statenames: Consider all states in the model
+% OPTIONS.variablenames: {} (no variables)
+% OPTIONS.reactionnames: {} (no reactions)
+% OPTIONS.Nsim: 1000
+% OPTIONS.range: 1
+% OPTIONS.firstorder: 0 (use total effect)
+% OPTIONS.objectivefunction: 'relative'
+% OPTIONS.integrator: [] (default integrator settings, defined in getDefaultIntegratorOptionsIQM.m)
+%
+% Output Arguments:
+% =================
+% If no output argument is specified, the result is plotted.
+% Otherwise, the output is a structure with the following fields:
+%
+% output.Nsim: Number of performed simulations
+% output.method: Name of the global sensitivity method
+% output.parameters: Considered parameters 
+% output.overallmeasure: Sensitivity indices for overall model output
+% output.overallparamranking: Parameter ranking regarding overall model output
+% output.singlecomponents: Names of the components, considered outputs
+% output.singlemeasure: Single sensitivity indices for all considered model outputs
+% output.singleparamranking: Parameter ranking for each considered model output
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+global Ncount 
+Ncount = 0;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE NON-NUMERIC INITIAL CONDITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% just by replacing them
+model = IQMconvertNonNum2NumIC(model);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin == 2,
+    paramNames = IQMparameters(model);
+    OPTIONS = [];
+elseif nargin == 3,
+    paramNames = varargin{1};
+    OPTIONS = [];
+elseif nargin == 4,
+    paramNames = varargin{1};
+    OPTIONS = varargin{2};
+else
+    error('Incorrect number of input arguments.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DEFAULT OPTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+statenames = IQMstates(model);
+variablenames = {};
+reactionnames = {};
+Nsim = 1000;
+range = 1;
+firstorder = 0;
+objectivefunction = 'relative';
+
+% Define default integrator options based on if IQM pro available or not
+[options_M,options_C] = getDefaultIntegratorOptionsIQM();
+if isIQMproPresent(),
+    integratoroptions = options_C;
+else
+    integratoroptions = options_M;
+    try
+        dummy = integratoroptions.method;
+    catch
+        integratoroptions.method = 'ode23s';
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try statenames = OPTIONS.statenames; catch, end
+try variablenames = OPTIONS.variablenames; catch, end
+try reactionnames = OPTIONS.reactionnames; catch, end
+try Nsim = OPTIONS.Nsim; catch, end
+try range = OPTIONS.range; catch, end
+try firstorder = OPTIONS.firstorder; catch, end
+try integratoroptions = OPTIONS.integrator; catch, end
+try objectivefunction = OPTIONS.objectivefunction; catch, end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS objecticefunction CHOICE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if strcmp(objectivefunction,'relative'),
+    objectivefunction = 'rel_sensglobaldefaultobjectiveIQM';
+elseif strcmp(objectivefunction,'absolute'),
+    objectivefunction = 'abs_sensglobaldefaultobjectiveIQM';
+else
+    % user defined objective functions
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET INDICES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+stateindices = stateindexIQM(model,statenames);
+variableindices = variableindexIQM(model,variablenames);
+reactionindices = reactionindexIQM(model,reactionnames);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% MAKE MEX MODEL - only if IQM Pro available
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isIQMproPresent(),
+    [MEXmodel, MEXmodelfullpath] = IQMmakeTempMEXmodel(model);
+else
+    MEXmodel = model;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GENERATE NOMINAL SOLUTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+paramValuesNominal = IQMparameters(model,paramNames);
+if isIQMproPresent(),
+    nomsimdata = IQMPsimulate(MEXmodel,timevector,IQMinitialconditions(model),paramNames,paramValuesNominal,integratoroptions);
+else
+    nomsimdata = IQMsimulate(MEXmodel,integratoroptions.method,timevector,[],integratoroptions);
+end
+    
+Ncount = Ncount + 1;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK FOR ZERO NOMINAL PARAMETERS and exclude them from the analysis
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+indexZero = find(paramValuesNominal == 0);
+if ~isempty(indexZero),
+    text = sprintf('%s, ',paramNames{indexZero});
+    disp(sprintf('Some parameters have nominal values of zero. They are excluded from the analysis.\nParameters: %s\n',text(1:end-2)));
+    paramValuesNominal(indexZero) = [];
+    paramNames = paramNames(setdiff(1:length(paramNames),indexZero));
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% NUMBERS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+nrparam = length(paramNames); 
+n_base = ceil(Nsim/nrparam); % base number of simulations so total number of model evals ~ Nsim
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INITIALIZATION 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+output = [];
+c_out_1 = [];
+c_out_t = [];
+
+% compute objective function outputs for base and complementary parameter sets
+NR_FAILED = 0;
+i = 1;
+
+while i<=n_base,
+    disp(sprintf('Running: %d / %d',i,n_base));
+
+    %Determine parameter space for compuations
+    %random sampling of parameter space
+    randorder1 = 2*range*(rand(1,nrparam)-0.5);
+    randorder2 = 2*range*(rand(1,nrparam)-0.5);
+    PS = paramValuesNominal(:)'.*10.^randorder1;
+    comp_PS = paramValuesNominal(:)'.*10.^randorder2;
+    try
+        tic;
+        output(i,:)=feval(objectivefunction,MEXmodel,timevector,paramNames,PS,IQMinitialconditions(model),nomsimdata,stateindices,variableindices,reactionindices,integratoroptions);
+        deltaT_ = toc;
+        if i == 1,
+            disp(sprintf('SOBOL: Approximate time for analysis: %d minutes',ceil(deltaT_*n_base*(1+nrparam*2)/60)));
+            if ~isIQMproPresent(),
+                disp('Analysis can be sped up considerably by installing the IQM Tools Pro.');
+            end
+        end
+        for j = 1:nrparam
+            %c_out_1:  use to compute 1st order sensitivity indices
+            paramValuesPerturbed = [comp_PS(1:j-1),PS(j),comp_PS(j+1:nrparam)];  %use complementary parameter set for all but pj
+            x = feval(objectivefunction,MEXmodel,timevector,paramNames,paramValuesPerturbed,IQMinitialconditions(model),nomsimdata,stateindices,variableindices,reactionindices,integratoroptions);
+            if sum(sum(isnan(x))) ~= 0,
+                error('NaN');
+            end
+            c_out_1(i,:,j)= x;
+            %c_out_t:  use to compute total effects sensitivity indices
+            paramValuesPerturbed = [PS(1:j-1),comp_PS(j),PS(j+1:nrparam)];  %use complementary parameter set for pj
+            x = feval(objectivefunction,MEXmodel,timevector,paramNames,paramValuesPerturbed,IQMinitialconditions(model),nomsimdata,stateindices,variableindices,reactionindices,integratoroptions);
+            if sum(sum(isnan(x))) ~= 0,
+                error('NaN');
+            end
+            c_out_t(i,:,j) = x;
+        end
+        i = i+1;
+    catch
+        disp('Simulation failed due to random parameter settings. Trying new point.');
+        NR_FAILED = NR_FAILED + 1;
+        if NR_FAILED > Nsim/5,
+            error('Simulation failed to often. Please consider a reduction of the ''range'' option.');
+        end 
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% compute variances
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+n_out = size(output,2);  %size of output of objective function
+f0 = zeros(1,n_out);  % integral of model output
+D=zeros(1,n_out); % total variance
+%monte carlo integrations to estimate integral functions
+for i = 1:n_base
+    f0 = f0+output(i,:)/n_base;  % estiamte integral of model output
+    D = D+output(i,:).^2/n_base; % start computation of total variance of model output
+end
+D=D-f0.^2;
+Dj=ones(nrparam,1)*D;% partial variances associated with parameter j
+Dtotj=zeros(nrparam,n_out); % total partial variance associated with parameter j
+for i = 1:n_base
+    for j = 1:nrparam
+        Dj(j,:)=Dj(j,:)-(output(i,:)-c_out_1(i,:,j)).^2/(2*n_base);  %start computation of partial variances
+        Dtotj(j,:)=Dtotj(j,:)+(output(i,:)-c_out_t(i,:,j)).^2/(2*n_base); %total variance due to pj
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% compute sensitivity indices from variances
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+components = {statenames{:}, variablenames{:}, reactionnames{:}};
+% take care of zero elements in D by deleting corresponding single components
+D(find(D==0)) = 1; % just use a one, since it is a non-sensitive output anyway. alternatively remove it:
+% if ~isempty(zeroindices),
+%     text = sprintf('%s, ',components{zeroindices});
+%     disp(sprintf('The following components are removed from consideration (not affected by param changes):\n%s',text(1:end-2)));
+%     components = components(setdiff(1:length(components),zeroindices));
+%     Dj(:,zeroindices) = [];
+%     Dtotj(:,zeroindices) = [];
+%     D(zeroindices) = [];
+% end
+Sob_1 = Dj./(ones(nrparam,1)*D);  %first order
+Sob_t = Dtotj./(ones(nrparam,1)*D);  % total effect
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% sort sensitivity rankings
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% rank_Sob_1j: sorted Sobol first order rankings in terms of ascending magnitude
+% rank_Sob_1jp: paramNames ranked in assending order via Sobol first order values
+[rank_Sob_1 rank_Sob_1p] = sort(abs(Sob_1),1,'descend');
+% rank_Sob_tj: sorted Sobol total effect rankings in terms of ascending magnitude
+% rank_Sob_tjp: paramNames ranked in assending order via Sobol total effect values
+[rank_Sob_t rank_Sob_tp] = sort(abs(Sob_t),1,'descend');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE OUTPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+output = [];
+output.Nsim = Ncount;
+if firstorder == 1, output.method = 'SOBOL First Order';
+else output.method = 'SOBOL Total Effect'; end
+output.parameters = paramNames(:)';
+if firstorder == 1, output.overallmeasure = Sob_1(:,end);
+else output.overallmeasure = Sob_t(:,end); end
+if firstorder == 1, output.overallparamranking = rank_Sob_1p(:,end);
+else output.overallparamranking = rank_Sob_tp(:,end); end
+output.singlecomponents = components;
+if firstorder == 1, output.singlemeasure = Sob_1(:,1:end-1);
+else output.singlemeasure = Sob_t(:,1:end-1); end
+if firstorder == 1, output.singleparamranking = rank_Sob_1p(:,1:end-1);
+else output.singleparamranking = rank_Sob_tp(:,1:end-1); end
+
+% generate plotting datastructure (for IQMplot2)
+datastruct = [];
+datastruct.name = sprintf('Global Sensitivities: %s method',output.method);
+datastruct.xnames = output.parameters;
+datastruct.ynames = {'OVERALL MEASURE', output.singlecomponents{:}};    % cell-array with names of y-axis data
+datastruct.data =  [output.overallmeasure output.singlemeasure]'; %  matrix with y-axis data in rows and x-axis data in columns
+datastruct.title = sprintf('Global Sensitivities: %s method',output.method);
+datastruct.xlabel = 'Parameters';
+datastruct.xaxistitle = 'X';
+datastruct.yaxistitle = 'Y';
+% add it to the output variable
+output.plotdatastruct = datastruct;
+
+if nargout == 1,
+    varargout{1} = output;
+elseif nargout == 0,
+    % Plot the sensitivities using IQMplot2
+    IQMplot2(datastruct)
+else
+    error('Incorrect number of output arguments.');
+end
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DELETE MEX MODEL
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isIQMproPresent(),
+    clear mex;
+    delete(MEXmodelfullpath);
+    clear global Ncount
+end
+clear global Ncount
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/IQMsensglobalwals.m b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/IQMsensglobalwals.m
new file mode 100644
index 0000000000000000000000000000000000000000..c4eae03d2a41ea668397cf826250ad8ea51e88d3
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/IQMsensglobalwals.m	
@@ -0,0 +1,319 @@
+function [varargout] = IQMsensglobalwals(model,timevector,varargin)
+% Global sensitivity analysis method: WALS (weighted average of local
+% sensitivities)
+%
+% For more information see:
+%
+% Y. Zheng and A. Rundell (2006) Comparative study of parameter sensitivity
+% analyses of the TCR-activated Erk-MAPK signalling pathway, IEE
+% Proc.-Syst. Biol., Vol. 153, No. 4, 201-211
+%
+% Bentele, M., Lavrik, I., Ulrich, M., Stößer, S., Heermann, D.W.,
+% Kalthoff, H., Krammer, P.H., and Eils, R. (2004) Mathematical modeling
+% reveals threshold mechanism in CD95-induced apoptosis, J. Cell
+% Biol., 166, (6), pp. 839–851
+%
+% USAGE:
+% ======
+% IQMsensglobalwals(model,timevector)
+% IQMsensglobalwals(model,timevector,paramNames)
+% IQMsensglobalwals(model,timevector,paramNames,OPTIONS)
+% [output] = IQMsensglobalwals(model,timevector)
+% [output] = IQMsensglobalwals(model,timevector,paramNames)
+% [output] = IQMsensglobalwals(model,timevector,paramNames,OPTIONS)
+%
+% model: IQMmodel to perform the global sensitivity analysis for
+% timevector: vector of timeinstants to consider
+% paramNames: cell-array with names of the parameters to consider
+% OPTIONS: structure with optional settings:
+%   OPTIONS.statenames: cell-array with state names which to consider as
+%       model outputs
+%   OPTIONS.variablenames: cell-array with variable names which to consider
+%       as model outputs
+%   OPTIONS.reactionnames: cell-array with reaction names which to consider
+%       as model outputs
+%   OPTIONS.Nsim: Number of simulation to carry out (approximate value)
+%   OPTIONS.range: Order of magnitude of parameter perturbations
+%   OPTIONS.deltaPert: relative perturbation for determining local
+%       sensitivities. If a parameters nominal value is zero a warning will 
+%       appear.
+%   OPTIONS.objectivefunction: ='relative': the differences between nominal
+%       and perturbed model are normalized to represent relative changes in
+%       each considered variable. ='absolute': no normalization is done.
+%       Alternatively, the user can provide the name for an own objective
+%       function to use. As template you can have a look at the two
+%       objectivefunctions in the folder:
+%       IQMlite/analysis/globalparametersensitivity/auxiliary
+%   OPTIONS.integrator: Structure with optional settings for the integrator, 
+%       either defined by odeset() for MATLAB simulation of by the integrator
+%       options setting used in IQMPsimulate.
+%
+% DEFAULT VALUES:
+% ===============
+% paramNames: Consider all parameters in the model
+% OPTIONS.statenames: Consider all states in the model
+% OPTIONS.variablenames: {} (no variables)
+% OPTIONS.reactionnames: {} (no reactions)
+% OPTIONS.Nsim: 1000
+% OPTIONS.range: 1
+% OPTIONS.deltaPert: 0.02 (2 percent)
+% OPTIONS.objectivefunction: 'relative'
+% OPTIONS.integrator: [] (default integrator settings, defined in getDefaultIntegratorOptionsIQM.m)
+%
+% Output Arguments:
+% =================
+% If no output argument is specified, the result is plotted.
+% Otherwise, the output is a structure with the following fields:
+%
+% output.Nsim: Number of performed simulations
+% output.method: Name of the global sensitivity method
+% output.parameters: Considered parameters 
+% output.overallmeasure: Sensitivity indices for overall model output
+% output.overallparamranking: Parameter ranking regarding overall model output
+% output.singlecomponents: Names of the components, considered outputs
+% output.singlemeasure: Single sensitivity indices for all considered model outputs
+% output.singleparamranking: Parameter ranking for each considered model output
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+global Ncount 
+Ncount = 0;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE NON-NUMERIC INITIAL CONDITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% just by replacing them
+model = IQMconvertNonNum2NumIC(model);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin == 2,
+    paramNames = IQMparameters(model);
+    OPTIONS = [];
+elseif nargin == 3,
+    paramNames = varargin{1};
+    OPTIONS = [];
+elseif nargin == 4,
+    paramNames = varargin{1};
+    OPTIONS = varargin{2};
+else
+    error('Incorrect number of input arguments.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DEFAULT OPTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+statenames = IQMstates(model);
+variablenames = {};
+reactionnames = {};
+Nsim = 1000;
+range = 1;
+deltaPert = 0.02;
+objectivefunction = 'relative';
+
+% Define default integrator options based on if IQM pro available or not
+[options_M,options_C] = getDefaultIntegratorOptionsIQM();
+if isIQMproPresent(),
+    integratoroptions = options_C;
+else
+    integratoroptions = options_M;
+    try
+        dummy = integratoroptions.method;
+    catch
+        integratoroptions.method = 'ode23s';
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try statenames = OPTIONS.statenames; catch, end
+try variablenames = OPTIONS.variablenames; catch, end
+try reactionnames = OPTIONS.reactionnames; catch, end
+try Nsim = OPTIONS.Nsim; catch, end
+try range = OPTIONS.range; catch, end
+try deltaPert = OPTIONS.deltaPert; catch, end
+try integratoroptions = OPTIONS.integrator; catch, end
+try objectivefunction = OPTIONS.objectivefunction; catch, end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS objecticefunction CHOICE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if strcmp(objectivefunction,'relative'),
+    objectivefunction = 'rel_sensglobaldefaultobjectiveIQM';
+elseif strcmp(objectivefunction,'absolute'),
+    objectivefunction = 'abs_sensglobaldefaultobjectiveIQM';
+else
+    % user defined objective functions
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET INDICES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+stateindices = stateindexIQM(model,statenames);
+variableindices = variableindexIQM(model,variablenames);
+reactionindices = reactionindexIQM(model,reactionnames);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% MAKE MEX MODEL - only if IQM Pro available
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isIQMproPresent(),
+    [MEXmodel, MEXmodelfullpath] = IQMmakeTempMEXmodel(model);
+else
+    MEXmodel = model;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GENERATE NOMINAL SOLUTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+paramValuesNominal = IQMparameters(model,paramNames);
+if isIQMproPresent(),
+    nomsimdata = IQMPsimulate(MEXmodel,timevector,IQMinitialconditions(model),paramNames,paramValuesNominal,integratoroptions);
+else
+    nomsimdata = IQMsimulate(MEXmodel,integratoroptions.method,timevector,[],integratoroptions);
+end
+    
+Ncount = Ncount + 1;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK FOR ZERO NOMINAL PARAMETERS and exclude them from the analysis
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+indexZero = find(paramValuesNominal == 0);
+if ~isempty(indexZero),
+    text = sprintf('%s, ',paramNames{indexZero});
+    disp(sprintf('Some parameters have nominal values of zero. They are excluded from the analysis.\nParameters: %s\n',text(1:end-2)));
+    paramValuesNominal(indexZero) = [];
+    paramNames = paramNames(setdiff(1:length(paramNames),indexZero));
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% NUMBERS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+nrparam = length(paramNames);
+nLocal = ceil(Nsim/nrparam); 
+nSensVariables = length(stateindices) + length(variableindices) + length(reactionindices) + 1;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INITIALIZATION 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CSSSE = zeros(nLocal,1);
+WALSmeasure = zeros(nrparam,nSensVariables);
+localSensitivities = zeros(nLocal,nrparam,nSensVariables);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% RUNNING THE SENSITIVITY ANALYSIS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+NR_FAILED = 0;
+k = 1;
+while k<=nLocal,
+    % Determine a random point in the global parameter space and perform a
+    % local sensitivity analysis around it.
+    % Use a logarithmic distribution for randomizing the global point.
+    % 1) Generate nrparam random values between -range and range
+    randorder = 2*range*(rand(1,nrparam)-0.5);
+    % 2) Generate the global point around which to perform the local
+    % analysis
+    globalparamValues = paramValuesNominal(:)'.*10.^randorder;
+    % 3) Generate nominal solution around the global point 
+    try
+        tic;
+        nomResult = feval(objectivefunction,MEXmodel,timevector,paramNames,globalparamValues,IQMinitialconditions(model),nomsimdata,stateindices,variableindices,reactionindices,integratoroptions);
+        deltaT_ = toc;
+        if k == 1,
+            disp(sprintf('WALS: Approximate time for analysis: %d minutes',ceil(deltaT_*nLocal*(1+nrparam)/60)));
+            if ~isIQMproPresent(),
+                disp('Analysis can be sped up considerably by installing the IQM Tools Pro.');
+            end
+        end
+        CSSSE(k) = nomResult(end);
+        for k2 = 1:nrparam;
+            % Do a local sensitivity analysis around the random point
+            paramValuesPerturbed = globalparamValues;
+            % Do a relative perturbation in one parameter
+            paramValuesPerturbed(k2) = paramValuesPerturbed(k2)*(1+deltaPert);
+            if paramValuesPerturbed(k2) == 0,
+                disp(sprintf('The nominal value of parameter ''%s'' is zero! The relative perturbation has no effect.',paramNames{k2}));
+            end
+            % Determine the perturbed result
+            pertResult = feval(objectivefunction,MEXmodel,timevector,paramNames,paramValuesPerturbed,IQMinitialconditions(model),nomsimdata,stateindices,variableindices,reactionindices,integratoroptions);
+            % Calculate the local sensitivity values
+            % But first check and handle zero nominal and perturbation results
+            % (happens in the case that a parameter has no effect on the
+            % considered model output)
+            indexzero = find(nomResult==0);
+            nomResultTemp = nomResult;
+            nomResultTemp(indexzero) = 1;
+            pertResultTemp = pertResult;
+            pertResultTemp(indexzero) = 1;
+            help = (pertResultTemp-nomResultTemp)./nomResultTemp/deltaPert;
+            localSensitivities(k,k2,:) = help;
+        end
+        k = k+1;
+    catch
+        disp('Simulation failed due to random parameter settings. Trying new point.');
+        NR_FAILED = NR_FAILED + 1;
+        if NR_FAILED > Nsim/5,
+            error('Simulation failed to often. Please consider a reduction of the ''range'' option.');
+        end
+    end
+end
+% Get the weight vector
+if min(CSSSE) ~= 0,
+    weight = exp(-CSSSE/(min(CSSSE)));
+else
+    % If the minimum CSSE is 0 then replace it by 1 (after all the divisor
+    % is pretty much arbitrary).
+    weight = exp(-CSSSE);
+end
+% Do the weighting of the local sensitivities using the above weights
+for k=1:nLocal
+    WALSmeasure = WALSmeasure + weight(k)*squeeze(localSensitivities(k,:,:));  
+end
+% Do the ordering of the results
+[dummy ordering] = sort(abs(WALSmeasure),1,'descend');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE OUTPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+output = [];
+output.Nsim = Ncount;
+output.method = 'WALS';
+output.parameters = paramNames(:)';
+output.overallmeasure = WALSmeasure(:,end);
+output.overallparamranking = ordering(:,end);
+output.singlecomponents = {statenames{:}, variablenames{:}, reactionnames{:}};
+output.singlemeasure = WALSmeasure(:,1:end-1);
+output.singleparamranking = ordering(:,1:end-1);
+
+% generate plotting datastructure (for IQMplot2)
+datastruct = [];
+datastruct.name = 'Global Sensitivities: WALS method';
+datastruct.xnames = output.parameters;
+datastruct.ynames = {'OVERALL MEASURE', output.singlecomponents{:}};    % cell-array with names of y-axis data
+datastruct.data =  [output.overallmeasure output.singlemeasure]'; %  matrix with y-axis data in rows and x-axis data in columns
+datastruct.title = 'Global Sensitivities: WALS method';
+datastruct.xlabel = 'Parameters';
+datastruct.xaxistitle = 'X';
+datastruct.yaxistitle = 'Y';
+% add it to the output variable
+output.plotdatastruct = datastruct;
+
+if nargout == 1,
+    varargout{1} = output;
+elseif nargout == 0,
+    % Plot the sensitivities using IQMplot2
+    IQMplot2(datastruct)
+else
+    error('Incorrect number of output arguments.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DELETE MEX MODEL
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isIQMproPresent(),
+    clear mex;
+    delete(MEXmodelfullpath);
+    clear global Ncount
+end
+clear global Ncount
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/abs_sensglobaldefaultobjectiveIQM.m b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/abs_sensglobaldefaultobjectiveIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..7699925405f943c21a78723f467bfca35704aa8a
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/abs_sensglobaldefaultobjectiveIQM.m	
@@ -0,0 +1,37 @@
+function [rawsensitivities] = abs_sensglobaldefaultobjectiveIQM(MEXmodel,timevector,paramNames,paramValues,ICs,nomsimdata,stateindices,variableindices,reactionindices,integratoroptions)
+% abs_sensglobaldefaultobjectiveIQM: Default global sensitivity analysis
+% objective function. This function determines the sqrt of the sum of
+% ABSOLUTE squared errors (SSSE), between simulations of the nominal model
+% and the perturbed model.
+%
+% The output argument contains both the SSSEs of the Single components (SSSSE)
+% (states, variables, and reactions) and a Combined version (CSSSE), which 
+% appears as last element in the output vector.
+
+global Ncount
+Ncount = Ncount + 1;
+
+% Simulate the model for given perturbations in the parameters
+if isIQMproPresent(),
+    pertsimdata = IQMPsimulate(MEXmodel,timevector,ICs,paramNames,paramValues,integratoroptions);
+else
+    modelSim = IQMparameters(MEXmodel,paramNames,paramValues);
+    pertsimdata = IQMsimulate(modelSim,integratoroptions.method,timevector,ICs,integratoroptions);
+end
+% Get the nominal and perturbed elements for comparison
+nomstatevalues = nomsimdata.statevalues(:,stateindices);
+pertstatevalues = pertsimdata.statevalues(:,stateindices);
+nomvariablevalues = nomsimdata.variablevalues(:,variableindices);
+pertvariablevalues = pertsimdata.variablevalues(:,variableindices);
+nomreactionvalues = nomsimdata.reactionvalues(:,reactionindices);
+pertreactionvalues = pertsimdata.reactionvalues(:,reactionindices);
+allnomvalues = [nomstatevalues nomvariablevalues nomreactionvalues];
+allpertvalues = [pertstatevalues pertvariablevalues pertreactionvalues];
+% get the absolute differences
+absolutevalues = allpertvalues-allnomvalues;
+% get the squared and summed differences
+SSSSE = sqrt(sum((absolutevalues).^2));
+CSSSE = sqrt(sum(sum((absolutevalues).^2))); 
+% return the data
+rawsensitivities = [SSSSE CSSSE]; 
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/rel_sensglobaldefaultobjectiveIQM.m b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/rel_sensglobaldefaultobjectiveIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..7920683f8be951b45451ed72a38877dc44d4afaa
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/rel_sensglobaldefaultobjectiveIQM.m	
@@ -0,0 +1,45 @@
+function [rawsensitivities] = rel_sensglobaldefaultobjectiveIQM(MEXmodel,timevector,paramNames,paramValues,ICs,nomsimdata,stateindices,variableindices,reactionindices,integratoroptions)
+% rel_sensglobaldefaultobjectiveIQM: Default global sensitivity analysis
+% objective function. This function determines the sqrt of the sum of
+% RELATIVE squared errors (SSSE), between simulations of the nominal model
+% and the perturbed model.
+%
+% The output argument contains both the SSSEs of the Single components (SSSSE)
+% (states, variables, and reactions) and a Combined version (CSSSE), which 
+% appears as last element in the output vector.
+
+global Ncount
+Ncount = Ncount + 1;
+
+% Simulate the model for given perturbations in the parameters
+if isIQMproPresent(),
+    pertsimdata = IQMPsimulate(MEXmodel,timevector,ICs,paramNames,paramValues,integratoroptions);
+else
+    modelSim = IQMparameters(MEXmodel,paramNames,paramValues);
+    pertsimdata = IQMsimulate(modelSim,integratoroptions.method,timevector,ICs,integratoroptions);
+end
+% Get the nominal and perturbed elements for comparison
+nomstatevalues = nomsimdata.statevalues(:,stateindices);
+pertstatevalues = pertsimdata.statevalues(:,stateindices);
+nomvariablevalues = nomsimdata.variablevalues(:,variableindices);
+pertvariablevalues = pertsimdata.variablevalues(:,variableindices);
+nomreactionvalues = nomsimdata.reactionvalues(:,reactionindices);
+pertreactionvalues = pertsimdata.reactionvalues(:,reactionindices);
+allnomvalues = [nomstatevalues nomvariablevalues nomreactionvalues];
+allpertvalues = [pertstatevalues pertvariablevalues pertreactionvalues];
+% get the relative differences
+% For this we need to handle zero nominal values. We do that by replacing
+% these zero nominal values by "1". The rational is that zero nominal
+% values happen 
+%   a) due to initial conditions (but then also the pert values are 0)
+%   b) an output is always zero (but then so are the pert values)
+%   c) well and otherwise it will become an approximation ...
+allnomvaluesNonZero = allnomvalues;
+allnomvaluesNonZero(find(allnomvalues==0)) = 1;
+relativevalues = (allpertvalues-allnomvalues)./allnomvaluesNonZero;
+% get the squared and summed differences
+SSSSE = sqrt(sum((relativevalues).^2));
+CSSSE = sqrt(sum(sum((relativevalues).^2))); 
+% return the data
+rawsensitivities = [SSSSE CSSSE]; 
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/LHS.pdf b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/LHS.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..311bc9d604809dcab477b384d614a0709dd97548
Binary files /dev/null and b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/LHS.pdf differ
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/contents.m b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/contents.m
new file mode 100644
index 0000000000000000000000000000000000000000..4d1a52f8f3878df17fc844204663f449b1f3067e
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/contents.m	
@@ -0,0 +1,30 @@
+%   Sampling utilities
+%   Contents
+%
+%   Multivariate distribution, no correlation
+%   latin_hs    : latin hypercube sampling (LHS) of multivariate normal
+%                   distribution
+%   lhsu        : LHS of multivariate uniform distribution
+%   lhs_empir   : LHS of multivariate empirical distribution
+%
+%   Multivariate distribution, with correlation
+%   lhs_iman    : LHS multivariate normal distribution, method of Iman &
+%                   Conover
+%   lhs_iman_n  : LHS multivariate normal distribution, method of Iman &
+%                   Conover, for large correlation matrix 
+%   lhs_stein   : LHS multivariate normal distribution, method of Stein
+%   ransamp     : random sampling from multivariate normal distribution
+%   lhs_empirco : LHS of multivariate empirical distribution
+%
+%   utilities:
+%   ltqnorm     : inverse of normal CDF (from Peter J. Acklam)
+%                   http://home.online.no/~pjacklam/notes/invnorm/index.html
+%   mchol       : modified Cholesky factorization for matrices that are not 
+%                 quite positive definite (from Brian Borchers)
+%   ranking     : ranking of data
+%   rank_corr   : inducing rank correlation 
+%
+%   test_sampling   : test the sampling utilities
+%   test_sampling2  : example of sampling with corr matrix that is not positive definite
+%
+%   Budiman (2004)  budiman@acss.usyd.edu.au    Revised: Nov 2004
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/latin_hs.m b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/latin_hs.m
new file mode 100644
index 0000000000000000000000000000000000000000..a078ae929801db161f9b2ba20d9024e280b6df0d
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/latin_hs.m	
@@ -0,0 +1,31 @@
+function s=latin_hs(xmean,xsd,nsample,nvar)
+% s=latin_hs(xmean,xsd,nsample,nvar)
+% LHS from normal distribution, no correlation
+% method of Stein
+% Stein, M. 1987. Large Sample Properties of Simulations Using Latin Hypercube Sampling. 
+%                 Technometrics 29:143-151
+% Input:
+%   xmean   :  mean of data (1,nvar)
+%   xsd     : std.dev of data (1,nvar)
+%   nsample : no. of samples
+%   nvar    : no. of variables
+% Output:
+%   s       : random sample (nsample,nvar)
+%
+% Uses Peter Acklam inverse normal CDF
+%
+%   Budiman (2003)
+% References:
+% Iman, R. L., and W. J. Conover. 1980. Small Sample Sensitivity Analysis Techniques for Computer Models, 
+% with an Application to Risk Assessment.Communications in Statistics: Theory and Methods A9: 1749-1874
+% McKay, M. D., W. J. Conover and R. J. Beckman. 1979.A Comparison of Three Methods for Selecting Values
+% of Input Variables in the Analysis of Output from a Computer Code. Technometrics 21: 239-245
+%
+ran=rand(nsample,nvar);
+s=zeros(nsample,nvar);
+% method of Stein
+for j=1: nvar
+   idx=randperm(nsample);
+   P=(idx'-ran(:,j))/nsample;       % probability of the cdf
+   s(:,j) = xmean(j) + ltqnorm(P).* xsd(j); % this can be replaced by any inverse distribution function
+end
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/lhs_empir.m b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/lhs_empir.m
new file mode 100644
index 0000000000000000000000000000000000000000..3b38cbb8841405c0f67a12a8a559ed1d376aab9b
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/lhs_empir.m	
@@ -0,0 +1,19 @@
+function s=lhs_empir(data,nsample)
+% s=lhs_empir(data,nsample)
+% perform lhs on multivariate empirical distribution
+%   assume no correlation
+% Input:
+%   data    : data matrix (ndata,nvar)
+%   nsample : no. of samples
+% Output:
+%   s       : random sample (nsample,nvar)
+%   Budiman (2003)
+
+[m,nvar]=size(data);
+ran=rand(nsample,nvar);
+s=zeros(nsample,nvar);
+for j=1: nvar
+   idx=randperm(nsample);
+   P=((idx'-ran(:,j))/nsample).*100;
+   s(:,j)=prctileIQM(data(:,j),P);
+end
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/lhs_empirco.m b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/lhs_empirco.m
new file mode 100644
index 0000000000000000000000000000000000000000..39d8e6b7b236d6856bf17fa4f7093679f3a0c2b5
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/lhs_empirco.m	
@@ -0,0 +1,24 @@
+function s=lhs_empirco(data,nsample)
+% s=lhs_empirco(data,nsample)
+% perform lhs on multivariate empirical distribution
+% with correlation
+% Input:
+%   data    : data matrix (ndata,nvar)
+%   nsample : no. of samples
+% Output:
+%   s       : random sample (nsample,nvar)
+%   Budiman (2003)
+
+[m,nvar]=size(data);
+corr=corrcoef(data);
+rc=rank_corr(corr,nsample); % induce correlation
+  
+for j=1:nvar
+    r=rc(:,j);
+    % draw random no.
+    u=rand(nsample,1);
+    % calc. percentile
+    p=((r-u)./nsample).*100;
+    % inverse from empirical distribution
+    s(:,j)=prctileIQM(data(:,j),p);
+end
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/lhs_iman.m b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/lhs_iman.m
new file mode 100644
index 0000000000000000000000000000000000000000..714d456162eabde2f4b76e729364e8b36c091cd0
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/lhs_iman.m	
@@ -0,0 +1,53 @@
+function z=lhs_iman(xmean,xsd,corr,nsample,ntry)
+% z=lhs_iman(xmean,xsd,corr,nsample,nloop)
+% LHS with correlation, normal distribution 
+% method of Iman & Conover
+% Iman, R. L., and W. J. Conover. 1982. A Distribution-free Approach to Inducing Rank Correlation 
+%      Among Input Variables. Communications in Statistics B 11:311-334
+%
+% Input:
+%   xmean   : mean of data (1,nvar)
+%   xsd     : std.dev of data (1,nvar)
+%   corr    : correlation matrix of the variables (nvar,nvar)
+%   nsample : no. of samples
+%   ntry    : optional, no of trial to get a close correlation matrix
+% Output:
+%   z       : random sample (nsample,nvar)
+%   Budiman (2004)
+
+nvar=length(xmean);
+
+if(nargin==4), ntry=1; end;
+
+% induce data with correlation
+P = chol(corr);
+P=P';
+
+xm=zeros(1,nvar);
+xs=ones(1,nvar);
+R=latin_hs(xm,xs,nsample,nvar);
+T = corrcoef(R);
+Q=chol(T);
+Q=Q';
+    
+S = P * inv(Q);
+RB= R*S';
+
+amin=realmax;
+for il=1:ntry
+    for j=1:nvar    
+        % rank RB
+        [r,id]=ranking(RB(:,j));
+        % sort R
+        [RS,id]=sort(R(:,j));
+        % permute RS so has the same rank as RB
+        z(:,j) = RS(r).*xsd(j)+xmean(j); 
+    end
+    ae=sum(sum(abs(corrcoef(z)-corr)));
+    if(ae<amin),
+        zb=z;
+        amin=ae;
+    end;
+end
+
+z=zb;
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/lhs_iman_n.m b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/lhs_iman_n.m
new file mode 100644
index 0000000000000000000000000000000000000000..7fb60b32ac9c7cee724412562e23802d7da98b2f
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/lhs_iman_n.m	
@@ -0,0 +1,57 @@
+function z=lhs_iman_n(xmean,xsd,corr,nsample,ntry)
+% z=lhs_iman_n(xmean,xsd,corr,nsample,ntry)
+% LHS with correlation, normal distribution 
+% Method of Iman & Conover
+% using mchol for Cholesky decomposition so that corr. matrix is positive definite  
+% 
+% Iman, R. L., and W. J. Conover. 1982. A Distribution-free Approach to Inducing Rank Correlation 
+%      Among Input Variables. Communications in Statistics B 11:311-334
+%
+% Input:
+%   xmean   : mean of data (1,nvar)
+%   xsd     : std.dev of data (1,nvar)
+%   corr    : correlation matrix of the variables (nvar,nvar)
+%   nsample : no. of samples
+%   ntry    : optional, no of trial to get a close correlation matrix
+% Output:
+%   z       : random sample (nsample,nvar)
+%   Budiman (2004)
+% using mchol from Brian Borchers
+nvar=length(xmean);
+
+if(nargin==4), ntry=1; end;
+
+% induce data with correlation
+[L,D,E]=mchol(corr);  
+%P = chol(corr+E)';
+P=L*sqrt(D);
+
+xm=zeros(1,nvar);
+xs=ones(1,nvar);
+R=latin_hs(xm,xs,nsample,nvar);
+T = corrcoef(R);
+[L,D,E]=mchol(T);  
+%Q=chol(T+E)';
+Q=L*sqrt(D);
+   
+S = P * inv(Q);
+RB= R*S';
+
+amin=realmax;
+for il=1:ntry
+    for j=1:nvar    
+        % rank RB
+        [r,id]=ranking(RB(:,j));
+        % sort R
+        [RS,id]=sort(R(:,j));
+        % permute RS so has the same rank as RB
+        z(:,j) = RS(r).*xsd(j)+xmean(j); 
+    end
+    ae=sum(sum(abs(corrcoef(z)-corr)));
+    if(ae<amin),
+        zb=z;
+        amin=ae;
+    end;
+end
+
+z=zb;
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/lhs_stein.m b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/lhs_stein.m
new file mode 100644
index 0000000000000000000000000000000000000000..300355e032aa204c6fc8bf36b8fd4e67662a705d
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/lhs_stein.m	
@@ -0,0 +1,41 @@
+function z=lhs_stein(xmean,xsd,corr,nsample,ntry)
+% z=lhs_stein(xmean,xsd,corr,nsample)
+% LHS with correlation, normal distribution
+% method of Stein (1987)
+% Stein, M. 1987. Large Sample Properties of Simulations Using Latin Hypercube Sampling. 
+%                 Technometrics 29:143-151
+% Input:
+%   xmean   : mean of data (1,nvar)
+%   xsd     : std.dev of data (1,nvar)
+%   corr    : correlation matrix of the variables (nvar,nvar)
+%   nsample : no. of samples
+%   ntry    : optional, no of trial to get a close correlation matrix
+% Output:
+%   z       : random sample (nsample,nvar)
+%   Budiman (2004)
+
+nvar=length(xmean);
+if(nargin==4), ntry=1; end;
+
+rc=rank_corr(corr,nsample); % calculate rank correlation
+
+amin=realmax;
+for il=1:ntry
+    for j=1:nvar
+        % rank correlation
+        r=rc(:,j);
+        % draw random no.
+        u=rand(nsample,1);
+        % calc. probability
+        p=(r-u)./nsample;
+        % inverse from normal distribution
+        z(:,j)=(ltqnorm(p).*xsd(j))+xmean(j);    
+    end
+    ae=sum(sum(abs(corrcoef(z)-corr)));
+    if(ae<amin),
+        zb=z;
+        amin=ae;
+    end;
+end
+
+z=zb;
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/lhsu.m b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/lhsu.m
new file mode 100644
index 0000000000000000000000000000000000000000..8f8cc856fceac9fa355f06b34cfa8fa4fa13d3b4
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/lhsu.m	
@@ -0,0 +1,19 @@
+function s=lhsu(xmin,xmax,nsample)
+% s=lhsu(xmin,xmax,nsample)
+% LHS from uniform distribution
+% Input:
+%   xmin    : min of data (1,nvar)
+%   xmax    : max of data (1,nvar)
+%   nsample : no. of samples
+% Output:
+%   s       : random sample (nsample,nvar)
+%   Budiman (2003)
+
+nvar=length(xmin);
+ran=rand(nsample,nvar);
+s=zeros(nsample,nvar);
+for j=1: nvar
+   idx=randperm(nsample);
+   P =(idx'-ran(:,j))/nsample;
+   s(:,j) = xmin(j) + P.* (xmax(j)-xmin(j));
+end
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/ltqnorm.m b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/ltqnorm.m
new file mode 100644
index 0000000000000000000000000000000000000000..fbedf414d5b9f352fa442dd8dc1506daab17721f
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/ltqnorm.m	
@@ -0,0 +1,86 @@
+function z = ltqnorm(p)
+%LTQNORM Lower tail quantile for standard normal distribution.
+%
+%   Z = LTQNORM(P) returns the lower tail quantile for the standard normal
+%   distribution function.  I.e., it returns the Z satisfying Pr{X < Z} = P,
+%   where X has a standard normal distribution.
+%
+%   LTQNORM(P) is the same as SQRT(2) * ERFINV(2*P-1), but the former returns a
+%   more accurate value when P is close to zero.
+
+%   The algorithm uses a minimax approximation by rational functions and the
+%   result has a relative error less than 1.15e-9.  A last refinement by
+%   Halley's rational method is applied to achieve full machine precision.
+
+%   Author:      Peter J. Acklam
+%   Time-stamp:  2003-04-23 08:26:51 +0200
+%   E-mail:      pjacklam@online.no
+%   URL:         http://home.online.no/~pjacklam
+
+   % Coefficients in rational approximations.
+   a = [ -3.969683028665376e+01  2.209460984245205e+02 ...
+         -2.759285104469687e+02  1.383577518672690e+02 ...
+         -3.066479806614716e+01  2.506628277459239e+00 ];
+   b = [ -5.447609879822406e+01  1.615858368580409e+02 ...
+         -1.556989798598866e+02  6.680131188771972e+01 ...
+         -1.328068155288572e+01 ];
+   c = [ -7.784894002430293e-03 -3.223964580411365e-01 ...
+         -2.400758277161838e+00 -2.549732539343734e+00 ...
+         4.374664141464968e+00  2.938163982698783e+00 ];
+   d = [  7.784695709041462e-03  3.224671290700398e-01 ...
+          2.445134137142996e+00  3.754408661907416e+00 ];
+
+   % Define break-points.
+   plow  = 0.02425;
+   phigh = 1 - plow;
+
+   % Initialize output array.
+   z = zeros(size(p));
+
+   % Rational approximation for central region:
+   k = plow <= p & p <= phigh;
+   if any(k(:))
+      q = p(k) - 0.5;
+      r = q.*q;
+      z(k) = (((((a(1)*r+a(2)).*r+a(3)).*r+a(4)).*r+a(5)).*r+a(6)).*q ./ ...
+             (((((b(1)*r+b(2)).*r+b(3)).*r+b(4)).*r+b(5)).*r+1);
+   end
+
+   % Rational approximation for lower region:
+   k = 0 < p & p < plow;
+   if any(k(:))
+      q  = sqrt(-2*log(p(k)));
+      z(k) = (((((c(1)*q+c(2)).*q+c(3)).*q+c(4)).*q+c(5)).*q+c(6)) ./ ...
+             ((((d(1)*q+d(2)).*q+d(3)).*q+d(4)).*q+1);
+   end
+
+   % Rational approximation for upper region:
+   k = phigh < p & p < 1;
+   if any(k(:))
+      q  = sqrt(-2*log(1-p(k)));
+      z(k) = -(((((c(1)*q+c(2)).*q+c(3)).*q+c(4)).*q+c(5)).*q+c(6)) ./ ...
+             ((((d(1)*q+d(2)).*q+d(3)).*q+d(4)).*q+1);
+   end
+
+   % Case when P = 0:
+   z(p == 0) = -Inf;
+
+   % Case when P = 1:
+   z(p == 1) = Inf;
+
+   % Cases when output will be NaN:
+   k = p < 0 | p > 1 | isnan(p);
+   if any(k(:))
+      z(k) = NaN;
+   end
+
+   % The relative error of the approximation has absolute value less
+   % than 1.15e-9.  One iteration of Halley's rational method (third
+   % order) gives full machine precision.
+   k = 0 < p & p < 1;
+   if any(k(:))
+      e = 0.5*erfc(-z(k)/sqrt(2)) - p(k);          % error
+      u = e * sqrt(2*pi) .* exp(z(k).^2/2);        % f(z)/df(z)
+      %z(k) = z(k) - u;                             % Newton's method
+      z(k) = z(k) - u./( 1 + z(k).*u/2 );          % Halley's method
+   end
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/mchol.m b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/mchol.m
new file mode 100644
index 0000000000000000000000000000000000000000..512368a7937d64ca2104b7ea77cdab9510247b99
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/mchol.m	
@@ -0,0 +1,126 @@
+%
+%  [L,D,E,pneg]=mchol1(G)
+%
+%  Given a symmetric matrix G, find a matrix E of "small" norm and c
+%  L, and D such that  G+E is Positive Definite, and 
+%
+%      G+E = L*D*L'
+%
+%  Also, calculate a direction pneg, such that if G is not PD, then
+%
+%      pneg'*G*pneg < 0
+%
+%  Note that if G is PD, then the routine will return pneg=[]. 
+%
+%  Reference: Gill, Murray, and Wright, "Practical Optimization", p111.
+%  Author: Brian Borchers (borchers@nmt.edu)
+%
+function [L,D,E,pneg]=mchol(G)
+%
+%  n gives the size of the matrix.
+%
+n=size(G,1);
+%
+%  gamma, zi, nu, and beta2 are quantities used by the algorithm.  
+%
+gamma=max(diag(G));
+zi=max(max(G-diag(diag(G))));
+nu=max([1,sqrt(n^2-1)]);
+beta2=max([gamma, zi/nu, 1.0E-15]);
+%
+%  Initialize diag(C) to diag(G).
+%
+C=diag(diag(G));
+%
+%  Loop through, calculating column j of L for j=1:n
+%
+
+L=zeros(n);
+D=zeros(n);
+E=zeros(n);
+
+for j=1:n,
+    bb=[1:j-1];
+    ee=[j+1:n];
+
+    %
+    %  Calculate the jth row of L.  
+    %
+    if (j > 1),
+        L(j,bb)=C(j,bb)./diag(D(bb,bb))';
+    end;
+    %
+    %  Update the jth column of C.
+    %
+    if (j >= 2),
+        if (j < n), 
+            C(ee,j)=G(ee,j)-(L(j,bb)*C(ee,bb)')';
+        end;
+    else
+        C(ee,j)=G(ee,j);
+    end;
+    %
+    % Update theta. 
+    %
+    if (j == n)
+        theta(j)=0;
+    else
+        theta(j)=max(abs(C(ee,j)));
+    end;
+    %
+    %  Update D
+    %
+    D(j,j)=max([eps,abs(C(j,j)),theta(j)^2/beta2]');
+    %
+    % Update E.
+    %
+    E(j,j)=D(j,j)-C(j,j);
+
+    
+    %
+    %  Update C again...
+    % 
+    %%%%%%%% M.Zibulevsky: begin of changes, old version is commented %%%%%%%%%%%%%
+    
+    %for i=j+1:n,
+    %    C(i,i)=C(i,i)-C(i,j)^2/D(j,j);
+    %end;
+    
+    ind=[j*(n+1)+1 : n+1 : n*n]';
+    C(ind)=C(ind)-(1/D(j,j))*C(ee,j).^2;
+
+
+end;
+
+%
+% Put 1's on the diagonal of L
+%
+%for j=1:n,
+%    L(j,j)=1;
+%end;
+
+ind=[1 : n+1 : n*n]';
+L(ind)=1;
+
+%%%%%%%%%%%%%%%%%%%%%%%% M.Zibulevsky: end of changes %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%
+%  if needed, find a descent direction.  
+%
+if ((nargout == 4) & (min(diag(C)) < 0.0))
+    [m,col]=min(diag(C));
+    rhs=zeros(n,1);
+    rhs(col)=1;
+    pneg=L'\rhs;
+else
+  pneg=[];
+end;
+
+
+return
+
+
+
+
+
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/rank_corr.m b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/rank_corr.m
new file mode 100644
index 0000000000000000000000000000000000000000..2caaba9ba0ac26a064882e1d595b1f2d5771c4d3
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/rank_corr.m	
@@ -0,0 +1,38 @@
+function rc=rank_corr(corr,nsample)
+% rc=rank_corr(corr,nsample)
+% induce rank correlation
+% method of Iman & Conover
+% Iman, R. L., and W. J. Conover. 1982. A Distribution-free Approach to
+% Inducing Rank Correlation Among Input Variables.
+% Communications in Statistics B 11:311-334.
+% Input:
+%   corr    : correlation matrix of the variables (nvar,nvar)
+%   nsample : no. of samples
+% Output:
+%   rc       : rank (nsample,nvar)
+%   Budiman (2004)
+
+nvar=length(corr);
+
+% induce data with correlation
+xm=zeros(1,nvar);
+xs=ones(1,nvar);
+R=latin_hs(xm,xs,nsample,nvar);
+T = corrcoef(R);
+P = chol(corr)';
+Q = chol(T)';
+
+% use modified cholesky for corr matrix that is not quite positive definite
+%[L,D,E]=mchol(corr);  
+%P=L*sqrt(D);
+%[L,D,E]=mchol(T);  
+%Q=L*sqrt(D);
+
+S = P * inv(Q);
+RB= R*S';
+
+for j=1:nvar    
+    % rank RB
+    [r,id]=ranking(RB(:,j));
+    rc(:,j) = r; 
+end
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/ranking.m b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/ranking.m
new file mode 100644
index 0000000000000000000000000000000000000000..beb163264fd0206f8c55a930a49597a33e62d39c
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/ranking.m	
@@ -0,0 +1,12 @@
+function [r,i]=ranking(x)   
+% [r,i]=ranking(x)   
+% Ranking of a vector  
+% input:
+%   x   : vector (nrow,1)  
+% output:
+% r : rank of the vector  (nrow,1)                                                
+% i : index vector from the sort routine  (nrow,1)                                  
+%                                                                               
+n=length(x);                                                                         
+[s,i]=sort(x);                                                             
+r(i,1)=[1:n]';
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/ransamp.m b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/ransamp.m
new file mode 100644
index 0000000000000000000000000000000000000000..60bad4dc7f11750699d5177aeb59379b24f1e92e
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/ransamp.m	
@@ -0,0 +1,19 @@
+function s=ransamp(xmean,xsd,corr,nsample)
+% s=ransamp(xmean,xsd,corr,nsample)
+% random sampling with correlation
+% Input:
+%   xmean     : mean of data (1,nvar)
+%   xsd       : std.dev of data (1,nvar)
+%   corr      : correlation matrix of the variables (nvar,nvar)
+%   nsample   : no. of samples
+% Output:
+%   s       : random sample (nsample,nvar)
+% Uses Matlab function: randn
+%   Budiman (2003)
+
+nvar=length(xmean);
+% random sampling 
+L = chol(corr);
+z = randn(nvar,nsample);
+y = L' * z ;
+s = (y'.*repmat(xsd,nsample,1))+ repmat(xmean,nsample,1);
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/test_sampling.m b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/test_sampling.m
new file mode 100644
index 0000000000000000000000000000000000000000..b9bb477334da57b9a33a3f3e1feafef5bfd33a85
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/test_sampling.m	
@@ -0,0 +1,49 @@
+% example of sampling
+clear all
+
+nsample=100;        % no of random samples to be drawn
+nvar=6;             % no of variables
+
+xmean=[10  5  4   3    20   10];    % mean
+xsd=[0.1   1  0.1   1    1   1];    % std. deviation
+%   correlation matrix
+corr=[
+    1.00  0    0     0       0     0
+    0    1.00  0     0       0     0
+    0    0     1.00  0       0     0
+    0    0     0     1.00   0.75  -0.70
+    0    0     0     0.75   1.00  -0.95
+    0    0     0    -0.70  -0.95   1.00];
+
+% first sample assume no correlation with LHS
+s=latin_hs(xmean,xsd,nsample,nvar);
+mean(s)
+std(s)
+
+pause
+% sample assume correlation with random sampling
+r=ransamp(xmean,xsd,corr,nsample);
+corrcoef(r)
+mean(r)
+std(r)
+% error in the corr. 
+ae=mean(abs(corrcoef(r)-corr))
+
+pause
+% sample assume correlation with LHS Stein
+z=lhs_stein(xmean,xsd,corr,nsample);
+corrcoef(z)
+mean(z)
+std(z)
+% error in the corr. 
+ae=mean(abs(corrcoef(z)-corr))
+
+pause
+% sample assume correlation with LHS Iman
+z=lhs_iman(xmean,xsd,corr,nsample);
+mean(z)
+std(z)
+corrcoef(z)
+% error in the corr. 
+ae=mean(abs(corrcoef(z)-corr))
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/test_sampling2.m b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/test_sampling2.m
new file mode 100644
index 0000000000000000000000000000000000000000..d43b05a05822e23b375e63536e0f4da5c0ad49cb
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/globalparametersensitivity/auxiliary/sampling/test_sampling2.m	
@@ -0,0 +1,26 @@
+% example of sampling with corr matrix that is not positive definite
+clear all
+
+nsample=100;        % no of random samples to be drawn
+nvar=8;             % no of variables
+
+xmean=[10  5  4     3   20   10  50  2];    % mean
+xsd=  [1   1  0.1   1    1    2   5  1];    % std. deviation
+%   correlation matrix
+corr=[
+1.00	0.45	-0.85	0.27	0.27	0.22	-0.38	0.37
+0.45	1.00	-0.85	-0.08	0.18	0.09	-0.21	0.20
+-0.85	-0.85	1.00	-0.10	-0.27	-0.18	0.34	-0.33
+0.27	-0.08	-0.10	1.00	0.33	0.33	-0.36	0.37
+0.27	0.18	-0.27	0.33	1.00	0.94	0.46	-0.45
+0.22	0.09	-0.18	0.33	0.94	1.00	0.54	-0.53
+-0.38	-0.21	0.34	-0.36	0.46	0.54	1.00	-1.00
+0.37	0.20	-0.33	0.37	-0.45	-0.53	-1.00	1.00];
+
+T=chol(corr);   % correlation matrix is not quite positive definite
+
+%use lhs_iman_n
+z=lhs_iman_n(xmean,xsd,corr,nsample);
+mean(z)
+std(z)
+corrcoef(z)
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/analysis/localparametersensitivity/IQMmca.m b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/localparametersensitivity/IQMmca.m
new file mode 100644
index 0000000000000000000000000000000000000000..a6b63eca2f69a696c06ab54587770301e54c80b7
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/localparametersensitivity/IQMmca.m	
@@ -0,0 +1,207 @@
+function [varargout] = IQMmca(model, varargin)
+% IQMmca: Metabolic control analysis
+% This function uses the steady state sensitivity analysis functions of the
+% IQM Tools Lite to determine flux control coefficients and concentration
+% control coefficients. Additionally it computes elasticity coefficients.
+% It is important to note that all states in the analyzed IQMmodel are
+% assumed to represent concentrations of substrates and all reactions
+% enzymatic reactions. If this is not the case for certain states and/or
+% reactions the user needs to postprocess the results by deleting the
+% corresponding columns and rows in the matrices FCC, CCC, EC. Furthermore,
+% the model should only contain irreversible reactions (consider the use of
+% IQMmakeirreversible). 
+%
+% USAGE:
+% ======
+% [] = IQMmca(model)
+% [output] = IQMmca(model)
+% [] = IQMmca(model,OPTIONS)
+% [output] = IQMmca(model,OPTIONS)
+%
+% model: IQMmodel
+% OPTIONS: structure containing options for the function:
+%           OPTIONS.pertsize: size of the perturbation that is used to
+%               determine the sensitivities. Scalar value => same
+%               perturbation for all perturbed parameters.
+%           OPTIONS.absRel: scalar value 1 or 0. =1: The perturbation
+%               chosen in the previous option is interpreted as a relative
+%               perturbation and assumed to be given in percent. =0: The
+%               perturbation in the previous option is interpreted as an
+%               absolute perturbation.
+%
+% DEFAULT VALUES:
+% ===============
+% The default perturbation is +1 percent, obtained by the following default
+% options:
+% OPTIONS.pertsize: 1 
+% OPTIONS.absRel: 1 
+%
+% Output Arguments:
+% =================
+% If no output argument is given, the determined MCA data (FCC, CCC, EC)
+% are plotted using the function IQMplot2. 
+%
+% The output argument 'output' is a MATLAB struct element with the
+% following structure:
+%
+%   output.states           cell-array with the names of the states
+%                           (substrates)
+%   output.reactions        cell-array with the name of the reaction/enzyme
+%                           names
+%   output.FCC              Matrix containing the Flux Control Coefficients
+%                           (One row per flux and one column per enzyme)
+%   output.CCC              Matrix containing the Concentration Control
+%                           Coefficients (One row per substrate and one
+%                           column per enzyme)
+%   output.EC               Matrix containing the Elasticity Coefficients
+%                           (One row per enzyme and one column per
+%                           substrate)
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE NON-NUMERIC INITIAL CONDITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% just by replacing them
+model = IQMconvertNonNum2NumIC(model);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle input arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin == 2,
+    OPTIONS = varargin{1};
+else 
+    OPTIONS = [];
+end
+% default values
+pertsize = 1;
+absRel = 1;
+% read out options
+if isfield(OPTIONS,'pertsize'),
+    if ~isempty(OPTIONS.pertsize),
+        pertsize = OPTIONS.pertsize;
+    end
+end
+if isfield(OPTIONS,'absRel'),
+    if ~isempty(OPTIONS.absRel),
+        absRel = OPTIONS.absRel;
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check that reactions are irreversible
+%%%%%%%%%%%%%%%%%%%%%%%%%
+modelx = IQMmakeirreversible(model);
+test1 = IQMreactions(model);
+test2 = IQMreactions(modelx);
+if length(test2) > length(test1),
+    error('The model contains reversible reactions. You might consider the use of IQMmakeirreversible.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%
+% Add extra multiplicative factors in front of all reactions
+% and add them as parameters in the model
+%%%%%%%%%%%%%%%%%%%%%%%%%
+% parameters: mca_factor_Reactionname
+modelstruct = IQMstruct(model);
+mcaparameters = {};
+for k = 1:length(modelstruct.reactions),
+    formula = modelstruct.reactions(k).formula;
+    mcaparameters{end+1} = sprintf('mca_factor_%s',modelstruct.reactions(k).name);
+    newformula = sprintf('%s*(%s)',mcaparameters{k},formula);
+    modelstruct.reactions(k).formula = newformula;
+    paramindex = length(modelstruct.parameters)+1;
+    modelstruct.parameters(paramindex).name = mcaparameters{k};
+    modelstruct.parameters(paramindex).value = 1;
+    modelstruct.parameters(paramindex).notes = 'Parameter used for MCA';
+end
+% convert back to IQMmodel
+mcamodel = IQMmodel(modelstruct);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%
+% Perform parameter sensitivity analysis based on mca parameters
+% This calculates Flux Control Coefficients and Concentration Control
+% Coefficients
+%%%%%%%%%%%%%%%%%%%%%%%%%
+mcasensdata = IQMsensdatastat(mcamodel,mcaparameters,pertsize,absRel);
+mcadata = IQMsensstat(mcasensdata);
+
+% Split data in Flux Control Coefficients and Concentration Control
+% Coefficients
+nameStates = IQMstates(mcamodel);
+nameReactions = IQMreactions(mcamodel);
+numberStates = length(nameStates);
+numberReactions = length(nameReactions);
+% Concentration Control Coefficients
+CCC = mcadata.Sn(1:numberStates,:);
+% Flux Control Coefficients
+FCC = mcadata.Sn(numberStates+1:end,:);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%
+% Determine the Elasticity Coefficients
+%%%%%%%%%%%%%%%%%%%%%%%%%
+EC = [];
+statesNom = mcasensdata.xssnom;
+reactionsNom = mcasensdata.rssnom;
+
+for k = 1:numberStates,
+    perturbedstate = statesNom;
+    if absRel == 0,
+        % absolute perturbation
+        deltastate = pertsize;
+    else
+        % relative perturbation
+        deltastate = statesNom(k) * pertsize/100;
+    end
+    perturbedstate(k) = perturbedstate(k) + deltastate;
+    [dummy1,dummy2,dummy3,dummy4,reactionrates] = IQMreactions(mcamodel,perturbedstate);
+    % determination of reactions sensitivities to states
+    reactionsSens = (reactionrates - reactionsNom)/deltastate;
+    % determination of normalized sensitivities (ECs)
+    ECk = inv(diag(reactionsNom))*reactionsSens*statesNom(k);
+    EC(:,k) = ECk;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%
+% Generate output data
+%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargout == 0,
+    % FCC
+    FCCplot.name = 'Flux Control Coefficients';
+    FCCplot.xnames = nameReactions;
+    FCCplot.ynames = nameReactions;
+    FCCplot.data = FCC;
+    FCCplot.title = 'Flux Control Coefficients C_e^J';
+    FCCplot.xlabel = 'Enzymes e';
+    FCCplot.xaxistitle = 'Enzymes e';
+    FCCplot.yaxistitle = 'Fluxes J';
+    % CCC
+    CCCplot.name = 'Concentration Control Coefficients';
+    CCCplot.xnames = nameReactions;
+    CCCplot.ynames = nameStates;
+    CCCplot.data = CCC;
+    CCCplot.title = 'Concentration Control Coefficients C_e^s';
+    CCCplot.xlabel = 'Enzyme e';
+    CCCplot.xaxistitle = 'Enzyme e';
+    CCCplot.yaxistitle = 'Substrate s';
+    % EC
+    ECplot.name = 'Elasticity Coefficients';
+    ECplot.xnames = nameStates;
+    ECplot.ynames = nameReactions;
+    ECplot.data = EC;
+    ECplot.title = 'Elasticity Coefficients E_s^e';
+    ECplot.xlabel = 'Substrate s';
+    ECplot.xaxistitle = 'Substrate s';
+    ECplot.yaxistitle = 'Enzyme e';
+    % do plot!
+    IQMplot2(FCCplot,CCCplot,ECplot);
+else
+    output = [];
+    output.states = nameStates;
+    output.reactions = nameReactions;
+    output.FCC = FCC;
+    output.CCC = CCC;
+    output.EC = EC;
+    varargout{1} = output;
+end
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/analysis/localparametersensitivity/IQMsensamplitude.m b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/localparametersensitivity/IQMsensamplitude.m
new file mode 100644
index 0000000000000000000000000000000000000000..0a123651168596c85a54312ee4f408876be6d3d3
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/localparametersensitivity/IQMsensamplitude.m	
@@ -0,0 +1,175 @@
+function [varargout] = IQMsensamplitude(datastructure)
+% IQMsensamplitude: Function evaluating local first order amplitude
+% sensitivities.
+%
+% USAGE:
+% ======
+% [output,plotDataS,plotDataSn] = IQMsensamplitude(datastructure)
+% [] = IQMsensamplitude(datastructure)
+%
+% datastructure: output, returned by the function IQMsensdataosc
+%
+% Output Arguments:
+% =================
+% If no output argument is given, the determined data are plotted using the
+% function IQMplot2. 
+%
+% The output argument 'output' is a MATLAB struct element with the
+% following structure:
+%
+%   output.S                matrix, with elements S_ij, defined below
+%   output.namesS           cell-array with state names for 
+%                           which the analysis has been done (for the
+%                           non-normalized sensitivities)
+%   output.parametersS      cell-array with names of parameters used in
+%                           analysis (for the non-normalized sensitivities)
+%   output.Sn               same as S, but the sensitivities are normalized
+%   output.namesSn          cell-array with state names for 
+%                           which the analysis has been done (for the
+%                           normalized sensitivities)
+%   output.parametersSn     cell-array with names of parameters used in
+%                           analysis (for the normalized sensitivities)
+%
+% The reason for having different fields for parameters and names for the
+% non-normalized and normalized sensitivities is due to the fact that zero
+% nominal parameter values lead to zero normalized sensitivities for these
+% parameters, and that zero nominal steady-state values of states lead to
+% infinite normalized sensitivities. In these cases the normalized
+% sensitivities for these parameters and states are not determined. 
+%
+% The plotDataS and plotDataSn output arguments are datastructures that 
+% can directly be used as input arguments for IQMplot2 for visualization
+% of the sensitivity analysis results. For information about how this data 
+% structure is defined please refer to the help text provided for the
+% IQMplot2 function.
+%
+% Theory:
+% =======
+% The amplitude A is defined as half the distance between the maximum 
+% (xmax) and the minimum (xmin) peak of an oscillating signal. 
+%
+% A = (xmax-xmin) / 2
+%
+% The amplitude sensitivity for the i-th component x_i wrt to the 
+% parameter p_j is defined by:
+%
+% S_ij = [ A_i(p_j+delta_p_j) - A_i(p_j) ] / delta_p_j
+%
+% The normalized sensitivity index is defined by
+%
+% Sn_ij = p_j/A_i(p_j) * S_ij
+%
+% The function A(p) is called an objective function (Varma et al. 
+% (1999) Parametric Sensitivity in Chemical Systems, Cambridge 
+% University Press, New York) and has been used in this form, e.g., by 
+% Stelling et al. (2004) Robustness properties of circadian clock 
+% architectures, PNAS, vol 101 (36), 13210-13215.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+states = datastructure.states;
+parameters = datastructure.parameters;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Output some information about the algorithm
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+disp(sprintf('Determination of amplitude sensitivities'));
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Determining amplitude sensitivities
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% determine the amplitudes of the signals of the nominal and the 
+% perturbed system and their difference - transpose the rows to obtain the 
+% components in rows and the parameter corresponding to the columns
+% nominal value
+Anom = ((max(datastructure.xnom)-min(datastructure.xnom)) / 2)';
+% initialize difference matrix
+Adif = [];
+for k = 1:length(datastructure.xpert),
+    xpertk = datastructure.xpert{k};
+    % determine the perturbed amplitudes
+    Apertk = ((max(xpertk)-min(xpertk))/2)';
+    % determine the difference
+    Adif = [Adif Apertk-Anom];
+end
+% now scale the elements in the columns with 1/deltaPert, where deltaPert
+% is the absolute perturbation to the corresponding parameter
+pertVector = [];
+for k = 1:length(datastructure.nomvalues),
+    % Determination of the absolute size of the perturbation
+    if datastructure.absRel(k) == 0,
+        % absolute perturbation
+        deltaPert = datastructure.pertSize(k);
+    else
+        % relative perturbation
+        deltaPert = datastructure.nomvalues(k) * datastructure.pertSize(k)/100;
+    end
+    pertVector = [pertVector deltaPert];
+end    
+% do the scaling
+S = Adif * inv(diag(pertVector));
+% determine the normalized sensitivity
+% in case of zero nominal values for parameters take out those parameters
+% in case of zero nominal values for states and/or reactions take out those
+% states or reactions
+% first do the scaling
+Sn = [];
+help = S*diag(datastructure.nomvalues);
+for k = 1:size(S,1),
+    Anomk = Anom(k);
+    if Anomk ~= 0,
+        Snrowk = help(k,:)/Anomk;
+    else
+        Snrowk = 0*ones(1,size(S,2));
+    end
+    Sn(k,:) = Snrowk;
+end
+% now retain only the elements in Sn that correspond to non-zero nominal 
+% values of parameters and Tnom
+parametersNonZeroIndex = find(datastructure.nomvalues~=0);
+statesNonZeroIndex = find(Anom~=0);
+Sn = Sn(statesNonZeroIndex,parametersNonZeroIndex);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Construct output variable
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+output.S = S;
+output.statesS = states;
+output.parametersS = parameters;
+output.Sn = Sn;
+output.statesSn = states(statesNonZeroIndex);
+output.parametersSn = parameters(parametersNonZeroIndex);
+
+plotdatastruct.name = 'Normalized Amplitude Sensitivities';
+plotdatastruct.xnames = output.parametersSn;
+plotdatastruct.ynames = output.statesSn;
+plotdatastruct.data = output.Sn;
+plotdatastruct.title = 'Normalized Amplitude Sensitivities';
+plotdatastruct.xlabel = 'Parameters';
+plotdatastruct.xaxistitle = 'Parameters';
+plotdatastruct.yaxistitle = 'States';
+
+plotdatastruct2.name = 'Amplitude Sensitivities';
+plotdatastruct2.xnames = output.parametersS;
+plotdatastruct2.ynames = output.statesS;
+plotdatastruct2.data = output.S;
+plotdatastruct2.title = 'Amplitude Sensitivities';
+plotdatastruct2.xlabel = 'Parameters';
+plotdatastruct2.xaxistitle = 'Parameters';
+plotdatastruct2.yaxistitle = 'States';
+
+if nargout == 1,
+    varargout{1} = output;
+elseif nargout == 2,
+    varargout{1} = output;
+    varargout{2} = plotdatastruct2;
+elseif nargout == 3,
+    varargout{1} = output;
+    varargout{2} = plotdatastruct2;
+    varargout{3} = plotdatastruct;
+elseif nargout == 0,
+    IQMplot2(plotdatastruct,plotdatastruct2);
+else
+    error('Incorrect number of output arguments.');
+end
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/analysis/localparametersensitivity/IQMsensdataosc.m b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/localparametersensitivity/IQMsensdataosc.m
new file mode 100644
index 0000000000000000000000000000000000000000..54bb3e398937b234c0919b56757f928a4aa54b0a
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/localparametersensitivity/IQMsensdataosc.m	
@@ -0,0 +1,411 @@
+function [output] = IQMsensdataosc(varargin)
+% IQMsensdataosc: Function allowing to generate data that subsequently can be 
+% used for different kinds of parametric sensitivity analyses. Used only
+% for oscillating systems! This function can only be used in the case that
+% no events are present in the model. A similar function handling models
+% with events is: 'IQMsensdataoscevents'.
+%
+% The data is obtained by simulation of the nominal and perturbed systems.
+% In each simulation of a perturbed system only a single parameter is
+% perturbed.
+%
+% The used integrator for this is 'ode23s'.
+%
+% As initial state for the simulation the initial conditions stored in the
+% model are used. As nominal parameter values the parameter values stored
+% in the model are used.
+%  
+% USAGE:
+% ======
+% [output] = IQMsensdataosc(model,timeData)
+% [output] = IQMsensdataosc(model,timeData,parameters)
+% [output] = IQMsensdataosc(model,timeData,parameters,pertSize,absRel)
+% [output] = IQMsensdataosc(model,timeData,parameters,pertSize,absRel,integratorOptions)
+% [output] = IQMsensdataosc(model,timeData,parameters,pertSize,absRel,integratorOptions,eventFunction)
+%
+% model: IQMmodel (not useable with ODE model file)
+% timeData: this argument can be a scalar, a vector of length 2, or of length 3:
+%       timeData = [timeHorizont]
+%       timeData = [timeHorizont, nrTransientHorizonts]
+%       timeData = [timeHorizont, nrTransientHorizonts, deltaT]
+%       timeHorizont: determines the time over which data is collected for
+%           later analysis.
+%       nrTransientHorizonts: before collecting data the systems is
+%           simulated over a time nrTransientHorizonts*timeHorizont. A
+%           value larger than 0 should be chosen in order to allow
+%           transients to die out.
+%       deltaT: the simulated data is returned in discrete time-steps of
+%           size deltaT
+% parameters: a cell-array with parameter names, determining the parameters
+%       that are to be considered in the analysis.
+% pertSize: either a scalar value, determining the perturbation to be
+%       applied to each of the parameters, or a vector of same length as
+%       the number of considered parameters, allowing to choose a different 
+%       perturbation for each parameter.
+% absRel: either a scalar (0 or 1), or a vector of the same length as
+%       pertSize. 0 means that the corresponding element in pertSize
+%       determines an absolute perturbatiom, 1 means it determines a
+%       relative perturbation in percent.
+% integratorOptions: standard MATLAB integrator options that can be set
+%       using the 'odeset' function.
+% eventFunction: the user can specify an event function (given by a string 
+%       with its name) that allows to collect additional data (in terms of 
+%       time-instants at which certain events occurr) for different 
+%       kinds of sensitivity analyses. Per default the event function
+%       'periodeventfunctionIQM' is used and allows to determine the 
+%       period of the oscillating system.
+%       A custom event function should be realized as an m file and be
+%       available in the MATLAB path. If you want to write a custom event
+%       function please have a look at the 'periodeventfunctionIQM'
+%       first.
+%
+% DEFAULT VALUES:
+% ===============
+%   The only required input arguments are 'model' and
+%   'timeData=[timeHorizont]'. If not specified otherwise, following
+%   default values are used: 
+%
+%   nrTransientHorizonts = 2
+%   deltaT = timeHorizont/1000
+%   parameters = all parameters in the model
+%   pertSize = 1 (percent)
+%   absRel = 1 (relative perturbation)
+%   integratorOptions = []
+%   eventFunction = 'periodeventfunctionIQM' 
+%
+% OUTPUT:
+% =======
+% The output argument 'output' is a MATLAB struct element with the
+% following structure:
+%
+%   output.model            model as obtained as input argument
+%   output.time             simulation time vector 
+%   output.tenom            time-steps for nominal system - time-steps used
+%                           to determine the period of eventual
+%                           oscillations in the system 
+%   output.tepert           cell-array, where each entry corresponds to
+%                           time-steps for a perturbed system - time-steps
+%                           used to determine the period of eventual
+%                           oscillations in the system 
+%   output.states           cell-array with statenames as elements (same
+%                           ordering as for the simulation data)
+%   output.xnom             matrix containing time instants in rows and
+%                           state values in columns
+%   output.xpert            cell-array, where each entry correponds to the 
+%                           simulation result for a single perturbed
+%                           parameter. The format of the elements is the
+%                           same as for xnom
+%   output.parameters       same as the input argument 'parameters' -
+%                           either its default or the passed values
+%   output.nomvalues        nominal values of parameters in above field
+%   output.pertSize         same as the input argument 'pertSize' -
+%                           either its default or the passed values
+%   output.absRel           same as the input argument 'absRel' -
+%                           either its default or the passed values
+%
+% The reason of using a struct element as output is that the output of 
+% IQMsensdataosc usually needs to be processed by other functions, and the
+% calling of these functions is considerably simplified by passing all
+% important data by one element only.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GLOBAL VARIABLES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+global eventValues 
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK MODEL TYPE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+iqm = varargin{1};
+if ~strcmp('IQMmodel',class(iqm)),
+    error('This function can only be used with IQMmodels, not with ODE file models!');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE NON-NUMERIC INITIAL CONDITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% just by replacing them
+iqm = IQMconvertNonNum2NumIC(iqm);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF MODEL CONTAINS EVENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(IQMevents(iqm)),
+    error('The model contains events. Please use the function ''IQMsensdataoscevents'' instead.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLING VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin == 2,
+    timeData = varargin{2};
+    parameters = IQMparameters(iqm);
+    pertSize = [];
+    absRel = [];
+    integratorOptions = [];
+    eventFunction = 'periodeventfunctionIQM';
+elseif nargin == 3,
+    timeData = varargin{2};
+    parameters = varargin{3};
+    pertSize = [];
+    absRel = [];
+    integratorOptions = [];
+    eventFunction = 'periodeventfunctionIQM';
+elseif nargin == 5,
+    timeData = varargin{2};
+    parameters = varargin{3};
+    pertSize = varargin{4};
+    absRel = varargin{5};
+    integratorOptions = [];
+    eventFunction = 'periodeventfunctionIQM';
+elseif nargin == 6,
+    timeData = varargin{2};
+    parameters = varargin{3};
+    pertSize = varargin{4};
+    absRel = varargin{5};
+    integratorOptions = varargin{6};
+    eventFunction = 'periodeventfunctionIQM';
+elseif nargin == 7,
+    timeData = varargin{2};
+    parameters = varargin{3};
+    pertSize = varargin{4};
+    absRel = varargin{5};
+    integratorOptions = varargin{6};
+    eventFunction = varargin{7};
+else
+    error('Incorrect number of input arguments.');
+end
+% check if parameters defined by a cell-array 
+% if not then convert
+if ischar(parameters),
+    parameters = {parameters};
+end
+if isempty(absRel) || isempty(pertSize),
+    pertSize = ones(1,length(parameters));
+    absRel = ones(1,length(parameters));    
+end
+% Checking and handling timeData variable
+if length(timeData) == 1,
+    timeHorizont = timeData(1); 
+    nrTransientHorizonts = 2;
+    deltaT = timeHorizont/1000;
+elseif length(timeData) == 2,
+    timeHorizont = timeData(1); 
+    nrTransientHorizonts = timeData(2);
+    deltaT = timeHorizont/1000;
+elseif length(timeData) == 3,
+    timeHorizont = timeData(1); 
+    nrTransientHorizonts = timeData(2);
+    deltaT = timeData(3);    
+else
+    error('Incorrect number of elements in ''timeData'' input argument.');
+end
+% adjust scalar elements in pertSize and absRel to number of parameters
+if length(pertSize) == 1,
+    pertSize = pertSize*ones(1,length(parameters));
+end
+if length(absRel) == 1,
+    absRel = absRel*ones(1,length(parameters));
+end
+% check length of parameters, pertSize and absRel
+if length(parameters) ~= length(pertSize) || length(parameters) ~= length(absRel),
+    error('Check the number of elements in ''parameters'', ''pertSize'', and ''absRel''\ninput arguments. They should have the same number of elements!');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% SETTING OTHER VARIABLES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Select the integrator to use
+integrator = 'ode23s';
+% get state data
+[states,stateODEs,initialCondition] = IQMstates(iqm);
+% determining the nominal values for the parasmeters
+[allParameters, allParameterValues] = IQMparameters(iqm);
+nomValues = [];
+errorText = '';
+for k1 = 1:length(parameters),
+    parameterFound = 0;
+    for k2 = 1:length(allParameters),
+        if strcmp(parameters{k1},allParameters{k2}),
+            nomValues = [nomValues, allParameterValues(k2)];
+            parameterFound = 1;
+            break;
+        end
+    end
+    if parameterFound == 0,
+        errorText = sprintf('%sParameter ''%s'', given in input arguments could not be found in the model.\n',errorText,parameters{k1});
+    end
+end
+if ~isempty(errorText),
+    errorText = sprintf('%sThe available parameters in the model are:\n',errorText);
+    for k = 1:length(allParameters),
+        errorText = sprintf('%s\n%s',errorText,allParameters{k});
+    end    
+    error(errorText);    
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INFO MESSAGE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+disp('Please make sure that the system is oscillating in a stationary state');
+disp('prior to collect data for period and amplitude determination.');
+disp('You can do this by specifying a long enough pre data collection');
+disp('horizont (nrTransientHorizonts).');
+disp(' ');
+disp('Collecting data for sensitivity analysis by simulation of the system.');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Construct time vectors for simulation
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% time vector for transients to die out
+if nrTransientHorizonts == 0,
+    time_transient = [];
+else
+    time_transient = [0:deltaT:nrTransientHorizonts*timeHorizont]; 
+end
+time_precollect = [nrTransientHorizonts*timeHorizont:deltaT:(nrTransientHorizonts+1)*timeHorizont];
+% time vector for data collection
+time = [(nrTransientHorizonts+1)*timeHorizont:deltaT:(nrTransientHorizonts+2)*timeHorizont];
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Simulate and collect data for nominal model
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+tic
+% creating nominal model ODE file
+[ODEfctname, ODEfilefullpath] = IQMcreateTempODEfile(iqm);
+% adding event function to intergrator options
+eventIntegratorOptions = odeset(integratorOptions,'Events',eventFunction);
+disp('Simulating nominal system');
+% simulate over transient time horizont
+[t,x] = feval(integrator,ODEfctname,time_transient,initialCondition,integratorOptions);
+% simulate over one time horizont to collect data for time events
+precollectInitialCondition = x(end,:);
+[tpre,xpre] = feval(integrator,ODEfctname,time_precollect,precollectInitialCondition,integratorOptions);
+% now prepare for the simulation to collect data - first get the initial condition for the simulation
+collectDataInitialCondition = xpre(end,:); 
+eventValues = min(xpre)+0.6*(max(xpre)-min(xpre));
+% simulate the nominal system
+[t2,xnom,tenom,xenom,ienom] = eval(sprintf('feval(@%s,@%s,time,collectDataInitialCondition,eventIntegratorOptions);',integrator,ODEfctname));
+if length(tenom) < 5,
+    error(sprintf('Oscillation periods could not be detected reliably.\nPlease check if the system is oscillating.\nIt might be necessary to increase the time horizont\nand/or to increase the number of transient horizonts.'));
+end
+time_elapsed = toc;
+% delete all temporary m files
+IQMdeleteTempODEfile(ODEfilefullpath);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CONVERTING EVENT DATA NOMINAL CASE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% time-events from event data is collected as column vector where the
+% time-instants of all events are listed. the data needs to be converted 
+% in order to easily determine which time instant corresponds to which
+% event
+tenomConverted = cell(1,length(collectDataInitialCondition));
+nrLongerThanTwo = 0;
+for k = 1:length(ienom),
+    indexEvent = ienom(k);
+    element = tenomConverted{indexEvent};
+    element = [element tenom(k)];
+    tenomConverted{indexEvent} = element;
+    if length(element)>2,
+        % check how many results are there with more than 2 detected
+        % time period events
+        nrLongerThanTwo = nrLongerThanTwo + 1;
+    end
+end
+tenomOutput = tenomConverted;
+if nrLongerThanTwo == 0,
+    error(sprintf('Oscillation periods could not be detected reliably.\nPlease check if the system is oscillating.\nIt might be necessary to increase the time horizont\nand/or to increase the number of transient horizonts.'));
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Simulate and collect data for perturbed model
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+disp('Simulating perturbed systems');
+time_estimated = (time_elapsed*length(parameters))/60;
+disp(sprintf('Estimated time for simulations: %5.1f minutes.\n',time_estimated));
+xpert = {};
+tepert = {};
+iepert = {};
+for k = 1:length(parameters),
+    % determine the absolute perturbation for current parameter
+    if absRel(k) == 0 || nomValues(k) == 0,
+        % absolute perturbation
+        if nomValues(k) == 0,
+            pertParamValue = nomValues(k) + pertSize(k)/100;
+        else
+            pertParamValue = nomValues(k) + pertSize(k);
+        end
+        disp(sprintf('%d) Absolute perturbation (%+g) of parameter ''%s''. Nominal: %g, perturbed: %g',k,pertSize(k),parameters{k},nomValues(k),pertParamValue));
+        if nomValues(k) == 0,
+            disp(sprintf('\tNominal value of parameter ''%s'' is zero. Using absolute perturbation instead of relative.',parameters{k}));
+            absRel(k) = 0;
+            pertSize(k) = pertSize(k)/100;
+        end
+    else
+        % relative perturbation
+        pertParamValue = nomValues(k) * (1 + pertSize(k)/100);
+        disp(sprintf('%d) Relative perturbation (%+g%%) of parameter ''%s''. Nominal: %g, perturbed: %g',k,pertSize(k),parameters{k},nomValues(k),pertParamValue));
+    end
+    % iqm is the original model - determine a perturbed model modelpert -
+    % and create an ODE file for it. rehash the path
+    iqmpert = IQMparameters(iqm,parameters{k},pertParamValue);
+    [ODEfctname, ODEfilefullpath] = IQMcreateTempODEfile(iqmpert);
+    % simulate over transient time horizont
+    [t,x] = feval(integrator,ODEfctname,time_transient,initialCondition,integratorOptions);
+    precollectInitialCondition = x(end,:);
+    [tpre,xpre] = feval(integrator,ODEfctname,time_precollect,precollectInitialCondition,integratorOptions);
+    % now prepare for the simulation to collect data - first get the initial condition for the simulation
+    collectDataInitialCondition = xpre(end,:); 
+    eventValues = min(xpre)+0.6*(max(xpre)-min(xpre));
+    % simulate the nominal system
+    [t2,xpertk,tepertk,xepertk,iepertk] = eval(sprintf('feval(@%s,@%s,time,collectDataInitialCondition,eventIntegratorOptions);',integrator,ODEfctname));
+    xpert{k} = xpertk;
+    tepert{k} = tepertk;
+    iepert{k} = iepertk;
+    % delete all temporary m files
+    IQMdeleteTempODEfile(ODEfilefullpath); 
+end
+ 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CONVERTING EVENT DATA PERTURBED CASE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% time-events from event data is collected as column vector where the
+% time-instants of all events are listed. the data needs to be converted 
+% in order to easily determine which time instant corresponds to which
+% event
+tepertOutput = {};
+for k1 = 1:length(parameters),
+    tepertConvertedElement = cell(1,length(collectDataInitialCondition));
+    iepertk = iepert{k1};
+    tepertk = tepert{k1};
+    for k2 = 1:length(iepertk),
+        indexEvent = iepertk(k2);
+        element = tepertConvertedElement{indexEvent};
+        element = [element tepertk(k2)];
+        tepertConvertedElement{indexEvent} = element;
+    end
+    tepertOutput{k1} = tepertConvertedElement;
+end
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CONSTRUCT OUTPUT STRUCTURE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+output = [];
+output.model = iqm;
+output.time = time;
+output.tenom = tenomOutput;
+output.tepert = tepertOutput;
+output.states = states;
+output.xnom = xnom;
+output.xpert = xpert;
+output.parameters = parameters;
+output.nomvalues = nomValues;
+output.pertSize = pertSize;
+output.absRel = absRel;
+return
+
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/analysis/localparametersensitivity/IQMsensdataoscevents.m b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/localparametersensitivity/IQMsensdataoscevents.m
new file mode 100644
index 0000000000000000000000000000000000000000..25959e9d8f8c4fc1713a61dbe51c1729bf24220b
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/localparametersensitivity/IQMsensdataoscevents.m	
@@ -0,0 +1,431 @@
+function [output] = IQMsensdataoscevents(varargin)
+% IQMsensdataoscevents: Function allowing to generate data that subsequently can be 
+% used for different kinds of parametric sensitivity analyses. Used only
+% for oscillating systems! This function should be used in the case that events 
+% are present in the system. It will not work if no events are present.
+%
+% The data is obtained by simulation of the nominal and perturbed systems.
+% In each simulation of a perturbed system only a single parameter is
+% perturbed.
+%
+% The used integrator for this is 'ode23s'.
+%
+% As initial state for the simulation the initial conditions stored in the
+% model are used. As nominal parameter values the parameter values stored
+% in the model are used.
+%  
+% USAGE:
+% ======
+% [output] = IQMsensdataoscevents(model,timeData)
+% [output] = IQMsensdataoscevents(model,timeData,parameters)
+% [output] = IQMsensdataoscevents(model,timeData,parameters,pertSize,absRel)
+% [output] = IQMsensdataoscevents(model,timeData,parameters,pertSize,absRel,integratorOptions)
+% [output] = IQMsensdataosc(model,timeData,parameters,pertSize,absRel,integratorOptions,eventFunction)
+%
+% model: IQMmodel (not useable with ODE model file)
+% timeData: this argument can be a scalar, a vector of length 2, or of length 3:
+%       timeData = [timeHorizont]
+%       timeData = [timeHorizont, nrTransientHorizonts]
+%       timeData = [timeHorizont, nrTransientHorizonts, deltaT]
+%       timeHorizont: determines the time over which data is collected for
+%           later analysis.
+%       nrTransientHorizonts: before collecting data the systems is
+%           simulated over a time nrTransientHorizonts*timeHorizont. A
+%           value larger than 0 should be chosen in order to allow
+%           transients to die out.
+%       deltaT: the simulated data is returned in discrete time-steps of
+%           size deltaT
+% parameters: a cell-array with parameter names, determining the parameters
+%       that are to be considered in the analysis.
+% pertSize: either a scalar value, determining the perturbation to be
+%       applied to each of the parameters, or a vector of same length as
+%       the number of considered parameters, allowing to choose a different 
+%       perturbation for each parameter.
+% absRel: either a scalar (0 or 1), or a vector of the same length as
+%       pertSize. 0 means that the corresponding element in pertSize
+%       determines an absolute perturbatiom, 1 means it determines a
+%       relative perturbation in percent.
+% integratorOptions: standard MATLAB integrator options that can be set
+%       using the 'odeset' function.
+% eventFunction: the user can specify an event function (given by a string 
+%       with its name) that allows to collect additional data (in terms of 
+%       time-instants at which certain events occurr) for different 
+%       kinds of sensitivity analyses. Per default the event function
+%       'periodeventfunctioneventsIQM' is used and allows to determine the 
+%       period of the oscillating system.
+%       A custom event function should be realized as an m file and be
+%       available in the MATLAB path. If you want to write a custom event
+%       function please have a look at the 'periodeventfunctioneventsIQM'
+%       first.
+%
+% DEFAULT VALUES:
+% ===============
+%   The only required input arguments are 'model' and
+%   'timeData=[timeHorizont]'. If not specified otherwise, following
+%   default values are used: 
+%
+%   nrTransientHorizonts = 2
+%   deltaT = timeHorizont/1000
+%   parameters = all parameters in the model
+%   pertSize = 1 (percent)
+%   absRel = 1 (relative perturbation)
+%   integratorOptions = []
+%   eventFunction = 'periodeventfunctioneventsIQM' 
+%
+% OUTPUT:
+% =======
+% The output argument 'output' is a MATLAB struct element with the
+% following structure:
+%
+%   output.model            model as obtained as input argument
+%   output.time             simulation time vector 
+%   output.tenom            time-steps for nominal system - time-steps used
+%                           to determine the period of eventual
+%                           oscillations in the system 
+%   output.tepert           cell-array, where each entry corresponds to
+%                           time-steps for a perturbed system - time-steps
+%                           used to determine the period of eventual
+%                           oscillations in the system 
+%   output.states           cell-array with statenames as elements (same
+%                           ordering as for the simulation data)
+%   output.xnom             matrix containing time instants in rows and
+%                           state values in columns
+%   output.xpert            cell-array, where each entry correponds to the 
+%                           simulation result for a single perturbed
+%                           parameter. The format of the elements is the
+%                           same as for xnom
+%   output.parameters       same as the input argument 'parameters' -
+%                           either its default or the passed values
+%   output.nomvalues        nominal values of parameters in above field
+%   output.pertSize         same as the input argument 'pertSize' -
+%                           either its default or the passed values
+%   output.absRel           same as the input argument 'absRel' -
+%                           either its default or the passed values
+%
+% The reason of using a struct element as output is that the output of 
+% IQMsensdataoscevents usually needs to be processed by other functions, and the
+% calling of these functions is considerably simplified by passing all
+% important data by one element only.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GLOBAL VARIABLES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+global eventValues EVENTfctname
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK MODEL TYPE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+iqm = varargin{1};
+if ~strcmp('IQMmodel',class(iqm)),
+    error('This function can only be used with IQMmodels, not with ODE file models!');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE NON-NUMERIC INITIAL CONDITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% just by replacing them
+iqm = IQMconvertNonNum2NumIC(iqm);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF MODEL CONTAINS EVENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(IQMevents(iqm)),
+    error('The model contains no events. Please use the function ''IQMsensdataosc'' instead.');
+end
+numberModelEvents = length(IQMevents(iqm));
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLING VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin == 2,
+    timeData = varargin{2};
+    parameters = IQMparameters(iqm);
+    pertSize = [];
+    absRel = [];
+    integratorOptions = [];
+    eventFunction = 'periodeventfunctioneventsIQM';
+elseif nargin == 3,
+    timeData = varargin{2};
+    parameters = varargin{3};
+    pertSize = [];
+    absRel = [];
+    integratorOptions = [];
+    eventFunction = 'periodeventfunctioneventsIQM';
+elseif nargin == 5,
+    timeData = varargin{2};
+    parameters = varargin{3};
+    pertSize = varargin{4};
+    absRel = varargin{5};
+    integratorOptions = [];
+    eventFunction = 'periodeventfunctioneventsIQM';
+elseif nargin == 6,
+    timeData = varargin{2};
+    parameters = varargin{3};
+    pertSize = varargin{4};
+    absRel = varargin{5};
+    integratorOptions = varargin{6};
+    eventFunction = 'periodeventfunctioneventsIQM';
+elseif nargin == 6,
+    timeData = varargin{2};
+    parameters = varargin{3};
+    pertSize = varargin{4};
+    absRel = varargin{5};
+    integratorOptions = varargin{6};
+    eventFunction = varargin{7};
+else
+    error('Incorrect number of input arguments.');
+end
+% check if parameters defined by a cell-array 
+% if not then convert
+if ischar(parameters),
+    parameters = {parameters};
+end
+if isempty(absRel) || isempty(pertSize),
+    pertSize = ones(1,length(parameters));
+    absRel = ones(1,length(parameters));    
+end
+% Checking and handling timeData variable
+if length(timeData) == 1,
+    timeHorizont = timeData(1); 
+    nrTransientHorizonts = 2;
+    deltaT = timeHorizont/1000;
+elseif length(timeData) == 2,
+    timeHorizont = timeData(1); 
+    nrTransientHorizonts = timeData(2);
+    deltaT = timeHorizont/1000;
+elseif length(timeData) == 3,
+    timeHorizont = timeData(1); 
+    nrTransientHorizonts = timeData(2);
+    deltaT = timeData(3);    
+else
+    error('Incorrect number of elements in ''timeData'' input argument.');
+end
+% adjust scalar elements in pertSize and absRel to number of parameters
+if length(pertSize) == 1,
+    pertSize = pertSize*ones(1,length(parameters));
+end
+if length(absRel) == 1,
+    absRel = absRel*ones(1,length(parameters));
+end
+% check length of parameters, pertSize and absRel
+if length(parameters) ~= length(pertSize) || length(parameters) ~= length(absRel),
+    error('Check the number of elements in ''parameters'', ''pertSize'', and ''absRel''\ninput arguments. They should have the same number of elements!');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% SETTING OTHER VARIABLES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Select the integrator to use
+integrator = 'ode23s';
+% get state data
+[states,stateODEs,initialCondition] = IQMstates(iqm);
+% determining the nominal values for the parasmeters
+[allParameters, allParameterValues] = IQMparameters(iqm);
+nomValues = [];
+errorText = '';
+for k1 = 1:length(parameters),
+    parameterFound = 0;
+    for k2 = 1:length(allParameters),
+        if strcmp(parameters{k1},allParameters{k2}),
+            nomValues = [nomValues, allParameterValues(k2)];
+            parameterFound = 1;
+            break;
+        end
+    end
+    if parameterFound == 0,
+        errorText = sprintf('%sParameter ''%s'', given in input arguments could not be found in the model.\n',errorText,parameters{k1});
+    end
+end
+if ~isempty(errorText),
+    errorText = sprintf('%sThe available parameters in the model are:\n',errorText);
+    for k = 1:length(allParameters),
+        errorText = sprintf('%s\n%s',errorText,allParameters{k});
+    end    
+    error(errorText);    
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INFO MESSAGE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+disp('Please make sure that the system is oscillating in a stationary state');
+disp('prior to collect data for period and amplitude determination.');
+disp('You can do this by specifying a long enough pre data collection');
+disp('horizont (nrTransientHorizonts).');
+disp(' ');
+disp('Collecting data for sensitivity analysis by simulation of the system.');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Construct time vectors for simulation
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% time vector for transients to die out
+if nrTransientHorizonts == 0,
+    time_transient = [];
+else
+    time_transient = [0:deltaT:nrTransientHorizonts*timeHorizont]; 
+end
+time_precollect = [nrTransientHorizonts*timeHorizont:deltaT:(nrTransientHorizonts+1)*timeHorizont];
+% time vector for data collection
+time = [(nrTransientHorizonts+1)*timeHorizont:deltaT:(nrTransientHorizonts+2)*timeHorizont];
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Simulate and collect data for nominal model
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+tic
+% creating nominal model ODE file and event functions
+[ODEfctname, ODEfilefullpath, DATAfctname, EVENTfctname, EVENTASSGNfctname] = IQMcreateTempODEfile(iqm,0,1);
+% initialize variable eventValues (not needed in the beginning but must be defined)
+eventValues = zeros(1,length(initialCondition));
+disp('Simulating nominal system');
+% simulate over transient time horizont
+[t,x]=eventsimulateIQM(ODEfctname,integrator,time_transient,initialCondition,integratorOptions,eventFunction,EVENTASSGNfctname);
+% simulate over one time horizont to collect data for time events
+precollectInitialCondition = x(end,:);
+[tpre,xpre]=eventsimulateIQM(ODEfctname,integrator,time_precollect,precollectInitialCondition,integratorOptions,eventFunction,EVENTASSGNfctname);
+% now prepare for the simulation to collect data - first get the initial condition for the simulation
+collectDataInitialCondition = xpre(end,:); 
+eventValues = min(xpre)+0.6*(max(xpre)-min(xpre));
+% simulate the nominal system
+[t2,xnom,tenom,xenom,ienom]=eventsimulateIQM(ODEfctname,integrator,time,collectDataInitialCondition,integratorOptions,eventFunction,EVENTASSGNfctname);
+% process tenom,xenom, and ienom to only keep the event data that belongs
+% to events from the event function that is important for the sensitivity
+% analysis
+eventData = [tenom xenom ienom];
+modelEventIndices = find(ismember(ienom,[1:numberModelEvents]));
+eventFunctionEvents = setdiff(1:length(ienom),modelEventIndices);
+eventData = eventData(eventFunctionEvents,:);
+if size(eventData,1) < 5,
+    error(sprintf('Oscillation periods could not be detected reliably.\nPlease check if the system is oscillating.\nIt might be necessary to increase the time horizont\nand/or to increase the number of transient horizonts.'));
+end
+tenom = eventData(:,1);
+xenom = eventData(:,2:end-1);
+ienom = eventData(:,end)-numberModelEvents;
+time_elapsed = toc;
+% delete all temporary m files
+IQMdeleteTempODEfile(ODEfilefullpath);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CONVERTING EVENT DATA NOMINAL CASE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% time-events from event data is collected as column vector where the
+% time-instants of all events are listed. the data needs to be converted 
+% in order to easily determine which time instant corresponds to which
+% event
+tenomConverted = cell(1,length(collectDataInitialCondition));
+nrLongerThanTwo = 0;
+for k = 1:length(ienom),
+    indexEvent = ienom(k);
+    element = tenomConverted{indexEvent};
+    element = [element tenom(k)];
+    tenomConverted{indexEvent} = element;
+    if length(element)>2,
+        % check how many results are there with more than 2 detected
+        % time period events
+        nrLongerThanTwo = nrLongerThanTwo + 1;
+    end
+end
+tenomOutput = tenomConverted;
+if nrLongerThanTwo == 0,
+    error(sprintf('Oscillation periods could not be detected reliably.\nPlease check if the system is oscillating.\nIt might be necessary to increase the time horizont\nand/or to increase the number of transient horizonts.'));
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Simulate and collect data for perturbed model
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+disp('Simulating perturbed systems');
+time_estimated = (time_elapsed*length(parameters))/60;
+disp(sprintf('Estimated time for simulations: %5.1f minutes.\n',time_estimated));
+xpert = {};
+tepert = {};
+iepert = {};
+for k = 1:length(parameters),
+    % determine the absolute perturbation for current parameter
+    if absRel(k) == 0 || nomValues(k) == 0,
+        % absolute perturbation
+        if nomValues(k) == 0,
+            pertParamValue = nomValues(k) + pertSize(k)/100;
+        else
+            pertParamValue = nomValues(k) + pertSize(k);
+        end
+        disp(sprintf('%d) Absolute perturbation (%+g) of parameter ''%s''. Nominal: %g, perturbed: %g',k,pertSize(k),parameters{k},nomValues(k),pertParamValue));
+        if nomValues(k) == 0,
+            disp(sprintf('\tNominal value of parameter ''%s'' is zero. Using absolute perturbation instead of relative.',parameters{k}));
+            absRel(k) = 0;
+            pertSize(k) = pertSize(k)/100;
+        end
+    else
+        % relative perturbation
+        pertParamValue = nomValues(k) * (1 + pertSize(k)/100);
+        disp(sprintf('%d) Relative perturbation (%+g%%) of parameter ''%s''. Nominal: %g, perturbed: %g',k,pertSize(k),parameters{k},nomValues(k),pertParamValue));
+    end
+    % iqm is the original model - determine a perturbed model modelpert -
+    % and create an ODE file and event functions for it
+    iqmpert = IQMparameters(iqm,parameters{k},pertParamValue);
+    [ODEfctname, ODEfilefullpath, DATAfctname, EVENTfctname, EVENTASSGNfctname] = IQMcreateTempODEfile(iqmpert,0,1);
+    % simulate over transient time horizont
+    [t,x]=eventsimulateIQM(ODEfctname,integrator,time_transient,initialCondition,integratorOptions,eventFunction,EVENTASSGNfctname);
+    precollectInitialCondition = x(end,:);
+    [tpre,xpre]=eventsimulateIQM(ODEfctname,integrator,time_precollect,precollectInitialCondition,integratorOptions,eventFunction,EVENTASSGNfctname);
+    % now prepare for the simulation to collect data - first get the initial condition for the simulation
+    collectDataInitialCondition = xpre(end,:); 
+    eventValues = min(xpre)+0.6*(max(xpre)-min(xpre));
+    % simulate the nominal system
+    [t2,xpertk,tepertk,xepertk,iepertk]=eventsimulateIQM(ODEfctname,integrator,time,collectDataInitialCondition,integratorOptions,eventFunction,EVENTASSGNfctname);
+    % process tepertk,xepertk, and iepertk to only keep the event data that belongs
+    % to events from the event function that is important for the sensitivity
+    % analysis
+    eventData = [tepertk xepertk iepertk];
+    modelEventIndices = find(ismember(iepertk,[1:numberModelEvents]));
+    eventFunctionEvents = setdiff(1:length(iepertk),modelEventIndices);
+    eventData = eventData(eventFunctionEvents,:);
+    tepertk = eventData(:,1);
+    xepertk = eventData(:,2:end-1);
+    iepertk = eventData(:,end)-numberModelEvents;
+    % select only the components specified in componentNames
+    xpert{k} = xpertk;
+    tepert{k} = tepertk;
+    iepert{k} = iepertk;
+    % delete all temporary m files
+    IQMdeleteTempODEfile(ODEfilefullpath);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CONVERTING EVENT DATA PERTURBED CASE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% time-events from event data is collected as column vector where the
+% time-instants of all events are listed. the data needs to be converted 
+% in order to easily determine which time instant corresponds to which
+% event
+tepertOutput = {};
+for k1 = 1:length(parameters),
+    tepertConvertedElement = cell(1,length(collectDataInitialCondition));
+    iepertk = iepert{k1};
+    tepertk = tepert{k1};
+    for k2 = 1:length(iepertk),
+        indexEvent = iepertk(k2);
+        element = tepertConvertedElement{indexEvent};
+        element = [element tepertk(k2)];
+        tepertConvertedElement{indexEvent} = element;
+    end
+    tepertOutput{k1} = tepertConvertedElement;
+end
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CONSTRUCT OUTPUT STRUCTURE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+output = [];
+output.model = iqm;
+output.time = time;
+output.tenom = tenomOutput;
+output.tepert = tepertOutput;
+output.states = states;
+output.xnom = xnom;
+output.xpert = xpert;
+output.parameters = parameters;
+output.nomvalues = nomValues;
+output.pertSize = pertSize;
+output.absRel = absRel;
+return
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/analysis/localparametersensitivity/IQMsensdatastat.m b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/localparametersensitivity/IQMsensdatastat.m
new file mode 100644
index 0000000000000000000000000000000000000000..8ce4ed213e1cb45249cfb0cf379319ebdf7abea0
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/localparametersensitivity/IQMsensdatastat.m	
@@ -0,0 +1,275 @@
+function [output] = IQMsensdatastat(varargin)
+% IQMsensdatastat: Function allowing to generate steady-state data that 
+% subsequently can be used for different kinds of parametric sensitivity 
+% analyses. 
+%
+% The data is obtained by determining the steady-states of the nominal 
+% and perturbed systems. In each calculation of a perturbed system only 
+% a single parameter is perturbed.
+% As initial guess for the steady-state the initial conditions stored in the
+% model are used. As nominal parameter values the parameter values stored
+% in the model are used.
+% In case the considered steady-state is unstable at least a good guess of
+% the steady-state needs to be given in the model.
+%  
+% USAGE:
+% ======
+% [output] = IQMsensdatastat(model)
+% [output] = IQMsensdatastat(model,parameters)
+% [output] = IQMsensdatastat(model,parameters,pertSize,absRel)
+% [output] = IQMsensdatastat(model,parameters,pertSize,absRel,options)
+%
+% model: IQMmodel (not useable with ODE model file)
+% parameters: a cell-array with parameter names, determining the parameters
+%       that are to be considered in the analysis.
+% pertSize: either a scalar value, determining the perturbation to be
+%       applied to each of the parameters, or a vector of same length as
+%       the number of considered parameters, allowing to choose a different 
+%       perturbation for each parameter.
+% absRel: either a scalar (0 or 1), or a vector of the same length as
+%       pertSize. 0 means that the corresponding element in pertSize
+%       determines an absolute perturbatiom, 1 means it determines a
+%       relative perturbation in percent.
+% OPTIONS: this is a data structure defining the options for the
+%       IQMsteadystate function that is used here. 
+%          OPTIONS.TolFun: Tolerance for max element in function evaluation
+%          OPTIONS.tol: Tolerance for the determination of the number of algebraic
+%               relationships in the model. If the method fails than this
+%               might be due to a wrong rank computation and in this case
+%               the tolerance should be increased. If set, the same tolerance
+%               setting is used when determining the indices of the
+%               dependent variables.
+%          OPTIONS.MaxIter: Maximum number of iterations
+%          OPTIONS.Delta: Step length for numerical differentiation to obtain 
+%               the Jacobian.
+%
+% DEFAULT VALUES:
+% ===============
+%   The only required input argument is 'model'.
+%   If not specified otherwise, following default values are used:
+%
+%   parameters = all parameters in the model
+%   pertSize = 1 (percent)
+%   absRel = 1 (relative perturbation)
+%   OPTIONS = [] (default options of the IQMsteadystate function)
+%
+% OUTPUT:
+% =======
+% The output argument 'output' is a MATLAB struct element with the
+% following structure:
+%
+%   output.model            model as obtained as input argument
+%   output.states           cell-array with names of states as elements
+%   output.xssnom           vector containing the steady-state values of
+%                           the states of the nominal system 
+%   output.xsspert          cell-array, where each entry correponds to 
+%                           a vector containing the steady-state of the
+%                           states of the perturbed systems
+%   output.reactions        cell-array with names of reactions as elements
+%   output.rssnom           vector containing the steady-state values of
+%                           the reaction rates of the nominal system 
+%   output.rsspert          cell-array, where each entry correponds to 
+%                           a vector containing the steady-state of the
+%                           reaction rates of the perturbed systems
+%   output.parameters       same as the input argument 'parameters' -
+%                           either its default or the passed values
+%   output.nomvalues        nominal values of parameters in above field
+%   output.pertSize         same as the input argument 'pertSize' -
+%                           either its default or the passed values
+%   output.absRel           same as the input argument 'absRel' -
+%                           either its default or the passed values
+%
+% The reason of using a struct element as output is that the output of 
+% IQMsensdatastat usually needs to be processed by other functions, and the
+% calling of these functions is considerably simplified by passing all
+% important data by one element only.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IQMMODEL 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+iqm = varargin{1};
+if ~strcmp('IQMmodel',class(iqm)),
+    error('This function can only be used with IQMmodels, not with ODE file models!');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE NON-NUMERIC INITIAL CONDITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% just by replacing them
+iqm = IQMconvertNonNum2NumIC(iqm);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET NAME FOR ODE FILE AND MODEL
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% path to systems temporary directory
+TEMPDIR = tempdirIQM;  
+% add path to temporary directory
+addpath(TEMPDIR);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLING VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin == 1,
+    parameters = IQMparameters(iqm);
+    pertSize = ones(1,length(parameters));
+    absRel = ones(1,length(parameters));
+    states = IQMstates(iqm);
+    OPTIONS = [];
+elseif nargin == 2,
+    parameters = varargin{2};
+    if ischar(parameters),
+        % adjusting for the case where just one parameter is given as a
+        % string
+        parameters = {parameters};
+    end
+    pertSize = ones(1,length(parameters));
+    absRel = ones(1,length(parameters));
+    states = IQMstates(iqm);
+    OPTIONS = [];
+elseif nargin == 4,
+    parameters = varargin{2};
+    pertSize = varargin{3};
+    absRel = varargin{4};
+    states = IQMstates(iqm);
+    OPTIONS = [];
+elseif nargin == 5,
+    parameters = varargin{2};
+    pertSize = varargin{3};
+    absRel = varargin{4};
+    states = IQMstates(iqm);
+    OPTIONS = varargin{5};
+else
+    error('Incorrect number of input arguments.');
+end
+% check if parameters defined by a cell-array 
+% if not then convert
+if ischar(parameters),
+    parameters = {parameters};
+end
+% adjust scalar elements in pertSize and absRel to number of parameters
+if length(pertSize) == 1,
+    pertSize = pertSize*ones(1,length(parameters));
+end
+if length(absRel) == 1,
+    absRel = absRel*ones(1,length(parameters));
+end
+% check length of parameters, pertSize and absRel
+if length(parameters) ~= length(pertSize) || length(parameters) ~= length(absRel),
+    error(sprintf('Check the number of elements in ''parameters'', ''pertSize'', and ''absRel''\ninput arguments. They should have the same number of elements!'));
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% SETTING OTHER VARIABLES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% determining the nominal values for the parameters
+[allParameters, allParameterValues] = IQMparameters(iqm);
+nomValues = [];
+errorText = '';
+for k1 = 1:length(parameters),
+    parameterFound = 0;
+    for k2 = 1:length(allParameters),
+        if strcmp(parameters{k1},allParameters{k2}),
+            nomValues = [nomValues, allParameterValues(k2)];
+            parameterFound = 1;
+            break;
+        end
+    end
+    if parameterFound == 0,
+        errorText = sprintf('%sParameter ''%s'', given in input arguments could not be found in the model.\n',errorText,parameters{k1});
+    end
+end
+if ~isempty(errorText),
+    errorText = sprintf('%sThe available parameters in the model are:\n',errorText);
+    for k = 1:length(allParameters),
+        errorText = sprintf('%s\n%s',errorText,allParameters{k});
+    end    
+    error(errorText);    
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INFO MESSAGE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+disp('Collecting data for sensitivity analysis by steady-state calculations.');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Determine steady-state for nominal model
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+tic
+disp('Steady-state computation for nominal system');
+[xnom,residual,message] = IQMsteadystate(iqm,IQMinitialconditions(iqm),OPTIONS);
+if isempty(xnom),
+    error('No steady-state could be found. Please try another starting guess.');
+end
+[dummy1,dummy2,dummy3,dummy4,rnom] = IQMreactions(iqm,xnom);
+rnom(find(abs(rnom)<eps)) = 0;
+time_elapsed = toc;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Determine steady-states for perturbed models
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+disp('Steady-state computation for perturbed systems');
+time_estimated = (time_elapsed*length(parameters))/60;
+disp(sprintf('Estimated time for calculations: %5.1f minutes.\n',time_estimated));
+xpert = {};
+rpert = {};
+nanindices = [];
+for k = 1:length(parameters),
+    % determine the absolute perturbation for current parameter
+    if absRel(k) == 0 || nomValues(k) == 0,
+        % absolute perturbation
+        if nomValues(k) == 0,
+            pertParamValue = nomValues(k) + pertSize(k)/100;
+        else
+            pertParamValue = nomValues(k) + pertSize(k);
+        end
+        disp(sprintf('%d) Absolute perturbation (%+g) of parameter ''%s''. Nominal: %g, perturbed: %g',k,pertSize(k),parameters{k},nomValues(k),pertParamValue));
+        if nomValues(k) == 0,
+            disp(sprintf('\tNominal value of parameter ''%s'' is zero. Using absolute perturbation instead of relative.',parameters{k}));
+            absRel(k) = 0;
+            pertSize(k) = pertSize(k)/100;
+        end
+    else
+        % relative perturbation
+        pertParamValue = nomValues(k) * (1 + pertSize(k)/100);
+        disp(sprintf('%d) Relative perturbation (%+g%%) of parameter ''%s''. Nominal: %g, perturbed: %g',k,pertSize(k),parameters{k},nomValues(k),pertParamValue));
+    end
+    % iqm is the original model - determine a perturbed model modelpert -
+    % and create an ODE file for it. rehash the path
+    iqmpert = IQMparameters(iqm,parameters{k},pertParamValue);
+    % get steady-state for perturbed system
+    [xpertk,residual,message] = IQMsteadystate(iqmpert,IQMinitialconditions(iqmpert),OPTIONS);
+    % handle the case when the steady-state computation does not converge
+    if isempty(xpertk),
+        disp(sprintf('\nNo convergence for parameter ''%s''. Check shown residual and eventually modify the options.\n',parameters{k}));
+        xpertk = NaN(length(IQMinitialconditions(iqmpert)),1);
+        nanindices(end+1) = k;
+    end
+    xpert{k} = real(xpertk);
+    [dummy1,dummy2,dummy3,dummy4,rpertk] = IQMreactions(iqmpert,xpert{k});
+    rpertk(find(abs(rpertk)<eps)) = 0;
+    rpert{k} = rpertk;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% REMOVE NaN Elements
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+keepindices = setdiff([1:length(parameters)],nanindices);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CONSTRUCT OUTPUT STRUCTURE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+output = [];
+output.model = iqm;
+output.states = states;
+output.xssnom = xnom;
+output.xsspert = xpert(keepindices);   
+output.reactions = IQMreactions(iqm);     
+output.rssnom = rnom;          
+output.rsspert = rpert(keepindices);         
+output.parameters = parameters(keepindices);  
+output.nomvalues = nomValues(keepindices);
+output.pertSize = pertSize(keepindices);      
+output.absRel = absRel(keepindices);          
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/analysis/localparametersensitivity/IQMsensperiod.m b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/localparametersensitivity/IQMsensperiod.m
new file mode 100644
index 0000000000000000000000000000000000000000..1b473555c7c660c48f3f98d6435e135da3072435
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/localparametersensitivity/IQMsensperiod.m	
@@ -0,0 +1,192 @@
+function [varargout] = IQMsensperiod(datastructure)
+% IQMsensperiod: Function evaluating local first order period sensitivities.
+% 
+% USAGE:
+% ======
+% [output,plotDataS,plotDataSn] = IQMsensperiod(datastructure)
+% [] = IQMsensperiod(datastructure)
+%
+% datastructure: output, returned by the function IQMsensdataosc
+%
+% Output Arguments:
+% =================
+% If no output argument is given, the determined data are plotted using the
+% function IQMplot2. 
+%
+% The output argument 'output' is a MATLAB struct element with the
+% following structure:
+%
+%   output.S                matrix, with elements S_ij, defined below
+%   output.namesS           cell-array with state names for 
+%                           which the analysis has been done (for the
+%                           non-normalized sensitivities)
+%   output.parametersS      cell-array with names of parameters used in
+%                           analysis (for the non-normalized sensitivities)
+%   output.Sn               same as S, but the sensitivities are normalized
+%   output.namesSn          cell-array with state names for 
+%                           which the analysis has been done (for the
+%                           normalized sensitivities)
+%   output.parametersSn     cell-array with names of parameters used in
+%                           analysis (for the normalized sensitivities)
+%
+% The reason for having different fields for parameters and names for the
+% non-normalized and normalized sensitivities is due to the fact that zero
+% nominal parameter values lead to zero normalized sensitivities for these
+% parameters, and that zero nominal steady-state values of states lead to
+% infinite normalized sensitivities. In these cases the normalized
+% sensitivities for these parameters and states are not determined. 
+%
+% The plotDataS and plotDataSn output arguments are datastructures that 
+% can directly be used as input arguments for IQMplot2 for visualization
+% of the sensitivity analysis results. For information about how this data 
+% structure is defined please refer to the help text provided for the
+% IQMplot2 function.
+%
+% Theory:
+% =======
+% The period sensitivity wrt to the parameter p_j is defined by:
+%
+% S_j = [ T(p_j+delta_p_j) - T(p_j) ] / delta_p_j
+%
+% where T(p) defines the period of the system for a given parameter
+% setting. The period is determined from the input arguments tenom and
+% tepert. tenom and tepert are determined by the function IQMsensdataosc. The
+% elements in these variables determine time instants at which the first
+% component in componentNames passes in the same direction through the
+% value that this component has at the end of the transient period.
+%
+% The normalized sensitivity index is defined by
+%
+% Sn_j = p_j/T(p_j) * S_j(t)
+%
+% The function T(p) is called an objective function (Varma et al. 
+% (1999) Parametric Sensitivity in Chemical Systems, Cambridge 
+% University Press, New York) and has been used in this form, e.g., by 
+% Stelling et al. (2004) Robustness properties of circadian clock 
+% architectures, PNAS, vol 101 (36), 13210-13215.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+states = datastructure.states;
+parameters = datastructure.parameters;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Output some information about the algorithm
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+disp(sprintf('Determination of period sensitivities'));
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Determining period sensitivities
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% determine the period for the nominal case (for the chosen state only)
+tenom = datastructure.tenom;
+Tnom = [];
+for k = 1:length(tenom)
+    tenomk = tenom{k};
+    Tnomk = sum(tenomk(2:end)-tenomk(1:end-1))/(length(tenomk)-1);
+    Tnom = [Tnom, Tnomk];
+end
+% determine the period for the perturbed cases (for the chosen state only)
+Tpert = [];
+tepert = datastructure.tepert;
+for k1 = 1:length(tepert),
+    tepertk1 = tepert{k1};
+    Tpertk1 = [];
+    for k2 = 1:length(tepertk1),
+        tepertk2 = tepertk1{k2};
+        if length(tepertk2) < 2,
+            Tpertk2 = 0;
+        else
+            Tpertk2 = sum(tepertk2(2:end)-tepertk2(1:end-1))/(length(tepertk2)-1);
+        end
+        Tpertk1 = [Tpertk1, Tpertk2];
+    end
+    Tpert = [Tpert; Tpertk1];
+end
+% determine the difference of the periods
+Tdif = [];
+for k = 1:size(Tpert,1),
+    Tdifk = Tpert(k,:)-Tnom;
+    Tdif = [Tdif; Tdifk];
+end
+% now scale the elements of Tdif with 1/deltaPert, where deltaPert
+% is the absolute perturbation to the corresponding parameter
+pertVector = [];
+for k = 1:length(datastructure.nomvalues),
+    % Determination of the absolute size of the perturbation
+    if datastructure.absRel(k) == 0,
+        % absolute perturbation
+        deltaPert = datastructure.pertSize(k);
+    else
+        % relative perturbation
+        deltaPert = datastructure.nomvalues(k) * datastructure.pertSize(k)/100;
+    end
+    pertVector = [pertVector deltaPert];
+end    
+% do the scaling
+S = [inv(diag(pertVector)) * Tdif]';
+% determine the normalized sensitivity
+% in case of zero nominal values for parameters take out those parameters
+% in case of zero nominal values for states and/or reactions take out those
+% states or reactions
+% first do the scaling
+Sn = [];
+help = S*diag(datastructure.nomvalues);
+for k = 1:size(S,1),
+    Tnomk = Tnom(k);
+    if Tnomk ~= 0,
+        Snrowk = help(k,:)/Tnomk;
+    else
+        Snrowk = 0*ones(1,size(S,2));
+    end
+    Sn(k,:) = Snrowk;
+end
+% now retain only the elements in Sn that correspond to non-zero nominal 
+% values of parameters and Tnom
+parametersNonZeroIndex = find(datastructure.nomvalues~=0);
+statesNonZeroIndex = find(Tnom~=0);
+Sn = Sn(statesNonZeroIndex,parametersNonZeroIndex);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Construct output variable
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+output.S = S;
+output.statesS = datastructure.states;
+output.parametersS = parameters;
+output.Sn = Sn;
+output.statesSn = datastructure.states(statesNonZeroIndex);
+output.parametersSn = parameters(parametersNonZeroIndex);
+
+plotdatastruct.name = 'Normalized Period Sensitivities';
+plotdatastruct.xnames = output.parametersSn;
+plotdatastruct.ynames = output.statesSn;
+plotdatastruct.data = output.Sn;
+plotdatastruct.title = 'Normalized Period Sensitivities';
+plotdatastruct.xlabel = 'Parameters';
+plotdatastruct.xaxistitle = 'Parameters';
+plotdatastruct.yaxistitle = 'States';
+
+plotdatastruct2.name = 'Period Sensitivities';
+plotdatastruct2.xnames = output.parametersSn;
+plotdatastruct2.ynames = output.statesSn;
+plotdatastruct2.data = output.S;
+plotdatastruct2.title = 'Period Sensitivities';
+plotdatastruct2.xlabel = 'Parameters';
+plotdatastruct2.xaxistitle = 'Parameters';
+plotdatastruct2.yaxistitle = 'States';
+
+if nargout == 1,
+    varargout{1} = output;
+elseif nargout == 2,
+    varargout{1} = output;
+    varargout{2} = plotdatastruct2;
+elseif nargout == 3,
+    varargout{1} = output;
+    varargout{2} = plotdatastruct2;
+    varargout{3} = plotdatastruct;
+elseif nargout == 0,
+    IQMplot2(plotdatastruct,plotdatastruct2);
+else
+    error('Incorrect number of output arguments.');
+end
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/analysis/localparametersensitivity/IQMsensstat.m b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/localparametersensitivity/IQMsensstat.m
new file mode 100644
index 0000000000000000000000000000000000000000..a286c6b6521d7f40ee6ad5d089dc04e7f86f87b3
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/localparametersensitivity/IQMsensstat.m	
@@ -0,0 +1,197 @@
+function [varargout] = IQMsensstat(datastructure)
+% IQMsensstat: Function evaluating local first order parameter sensitivities
+% of the steady-state values of states and reaction rates.
+%
+% USAGE:
+% ======
+% [output,plotDataS,plotDataSn] = IQMsensstat(datastructure)
+% [] = IQMsensstat(datastructure)
+%
+% datastructure: output, returned by the function IQMsensdatastat
+%
+% Output Arguments:
+% =================
+% If no output argument is given, the determined data are plotted using the
+% function IQMplot2. 
+%
+% The output argument 'output' is a MATLAB struct element with the
+% following structure:
+%
+%   output.S                matrix, with elements S_ij, defined below
+%   output.namesS           cell-array with state and reaction names for 
+%                           which the analysis has been done (for the
+%                           non-normalized sensitivities)
+%   output.parametersS      cell-array with names of parameters used in
+%                           analysis (for the non-normalized sensitivities)
+%   output.Sn               same as S, but the sensitivities are normalized
+%   output.namesSn          cell-array with state and reaction names for 
+%                           which the analysis has been done (for the
+%                           normalized sensitivities)
+%   output.parametersSn     cell-array with names of parameters used in
+%                           analysis (for the normalized sensitivities)
+%
+% The reason for having different fields for parameters and names for the
+% non-normalized and normalized sensitivities is due to the fact that zero
+% nominal parameter values lead to zero normalized sensitivities for these
+% parameters, and that zero nominal steady-state values of states or
+% reaction rates lead to infinite normalized sensitivities. In these cases
+% the normalized sensitivities for these parameters and states/reaction
+% rates are not determined.
+%
+% The plotDataS and plotDataSn output arguments are datastructures that 
+% can directly be used as input arguments for IQMplot2 for visualization
+% of the sensitivity analysis results. For information about how this data 
+% structure is defined please refer to the help text provided for the
+% IQMplot2 function.
+%
+% Theory:
+% =======
+% The steady-state sensitivity for the i-th element (state or reaction rate)
+% x_i wrt to the parameter p_j is defined by:
+%
+% S_ij = [ Xss_i(p_j+delta_p_j) - Xss_i(p_j) ] / delta_p_j
+%
+% where Xss_i is the function returning the steady-state for this element
+% (state or reaction rate) for the given parameters.
+%
+% The normalized sensitivity index is defined by
+%
+% Sn_ij = p_j/Xss_i(p_j) * S_ij
+%
+% The function Xss(p) is here used as objective function (Varma et al. 
+% (1999) Parametric Sensitivity in Chemical Systems, Cambridge 
+% University Press, New York).
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+states = datastructure.states;
+reactions = datastructure.reactions;
+parameters = datastructure.parameters;
+% combine states and reactions into elements
+elements = {};
+elementindex = 1;
+for k = 1:length(states),
+    elements{elementindex} = sprintf('%s (state)',states{k});
+    elementindex = elementindex + 1;
+end
+for k = 1:length(reactions),
+    elements{elementindex} = sprintf('%s (reaction rate)',reactions{k});
+    elementindex = elementindex + 1;
+end
+elementsdatanom = [datastructure.xssnom; datastructure.rssnom];
+elementsdatapert = {};
+for k = 1:length(parameters),
+    statespert = datastructure.xsspert{k};
+    reactionratespert = datastructure.rsspert{k};
+    elementsdatapert{k} = [statespert(:); reactionratespert(:)];
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Output some information about the algorithm
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+disp(sprintf('Determination of steady-state sensitivities'));
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Determining steady-state sensitivities
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% nominal values
+Xssnom = elementsdatanom;
+% initialize difference matrix
+Xssdif = [];
+for k = 1:length(elementsdatapert),
+    xsspertk = elementsdatapert{k};
+    % determine the difference
+    Xssdif = [Xssdif xsspertk-Xssnom];
+end
+% now scale the elements in the columns with 1/deltaPert, where deltaPert
+% is the absolute perturbation to the corresponding parameter
+pertVector = [];
+for k = 1:length(datastructure.nomvalues),
+    % Determination of the absolute size of the perturbation
+    if datastructure.absRel(k) == 0,
+        % absolute perturbation
+        deltaPert = datastructure.pertSize(k);
+    else
+        % relative perturbation
+        deltaPert = datastructure.nomvalues(k) * datastructure.pertSize(k)/100;
+    end
+    pertVector = [pertVector deltaPert];
+end    
+% determine the sensitivities
+S = Xssdif * inv(diag(pertVector));
+% determine the normalized sensitivity
+% in case of zero nominal values for parameters take out those parameters
+% in case of zero nominal values for states and/or reactions take out those
+% states or reactions
+% first do the scaling
+Sn = [];
+help = S*diag(datastructure.nomvalues);
+for k = 1:size(S,1),
+    Xssnomk = Xssnom(k);
+    if Xssnomk ~= 0,
+        Snrowk = help(k,:)/Xssnomk;
+    else
+        Snrowk = 0*ones(1,size(S,2));
+    end
+    Sn(k,:) = Snrowk;
+end
+% now all parameters with zero nominal values correspond to zero columns in
+% Sn and all elements with zero nominal steady-state values correspond to 
+% zero rows
+if size(Sn,2) > 1,
+    parametersNonZeroIndex = find(sum(abs(Sn))~=0);
+    elementsNonZeroIndex = find(sum(abs(Sn'))~=0);
+    Sn = Sn(elementsNonZeroIndex,parametersNonZeroIndex);
+else
+    parametersNonZeroIndex = find(datastructure.nomvalues~=0);
+    elementsNonZeroIndex = find(abs(Sn)~=0);
+end    
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Construct output variable
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+output.S = S;
+output.namesS = elements;
+output.parametersS = parameters;
+output.Sn = Sn;
+output.namesSn = elements(elementsNonZeroIndex);
+output.parametersSn = parameters(parametersNonZeroIndex);
+
+plotdatastruct.name = 'Normalized Steady-State Sensitivities';
+plotdatastruct.xnames = output.parametersSn;
+plotdatastruct.ynames = output.namesSn;
+plotdatastruct.data = output.Sn;
+plotdatastruct.title = 'Normalized Steady-State Sensitivities';
+plotdatastruct.xlabel = 'Parameters';
+plotdatastruct.xaxistitle = 'Parameters';
+plotdatastruct.yaxistitle = 'States and Reaction Rates';
+
+plotdatastruct2.name = 'Steady-State Sensitivities';
+plotdatastruct2.xnames = output.parametersS;
+plotdatastruct2.ynames = output.namesS;
+plotdatastruct2.data = output.S;
+plotdatastruct2.title = 'Steady-State Sensitivities';
+plotdatastruct2.xlabel = 'Parameters';
+plotdatastruct2.xaxistitle = 'Parameters';
+plotdatastruct2.yaxistitle = 'States and Reaction Rates';
+
+if nargout == 1,
+    varargout{1} = output;
+elseif nargout == 2,
+    varargout{1} = output;
+    varargout{2} = plotdatastruct2;
+elseif nargout == 3,
+    varargout{1} = output;
+    varargout{2} = plotdatastruct2;
+    varargout{3} = plotdatastruct;
+elseif nargout == 0,
+    % Check if at least any non-zero sensitivity - otherwise don't plot
+    if sum(sum(abs(S))) > eps,
+        IQMplot2(plotdatastruct,plotdatastruct2);
+    else
+        disp('All sensitivities are zero');
+    end
+else
+    error('Incorrect number of output arguments.');
+end
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/analysis/localparametersensitivity/auxiliary/periodeventfunctionIQM.m b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/localparametersensitivity/auxiliary/periodeventfunctionIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..7f68f8e6a259b4c6429278396879aa4f9a8c491b
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/localparametersensitivity/auxiliary/periodeventfunctionIQM.m	
@@ -0,0 +1,32 @@
+function [value,isterminal,direction] = periodeventfunctionIQM(t,x)
+% periodeventfunctionIQM: The purpose of this function is to collect
+% time information during simulation that allows to determine
+% the period of an oscillating system. This is realized by letting the
+% intergrator check for events that correspond to state values crossing a
+% certain threshold in positive direction.  
+% 
+% USAGE:
+% ======
+% This function is used by the function 'IQMsensdataosc'
+%
+% The function requires the presence of 1 global variable that is defined
+% in 'IQMsensdataosc':
+% 
+% eventValues: that are values of the states at which an event is triggered
+%              if the current state values pass these values in positive direction.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+% instead of having this global variable one also can hardcode certain
+% values of interest, when considering a certain problem.
+global eventValues 
+
+% Locate the time when the states determined by the out-indices  
+% pass the value defined by 'eventValues' in positive direction
+% The next three lines can be changed in order to customize the event
+% handling and to collect other data for sensitivity analysis
+value = eventValues(:)-x(:);
+isterminal = zeros(length(x),1);    % never stop the integration due to events
+direction =  ones(length(x),1);     % positive direction
+return
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/analysis/localparametersensitivity/auxiliary/periodeventfunctioneventsIQM.m b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/localparametersensitivity/auxiliary/periodeventfunctioneventsIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..47b6700e48a7194e89192ea269c3c5ff41db7e9f
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/analysis/localparametersensitivity/auxiliary/periodeventfunctioneventsIQM.m	
@@ -0,0 +1,49 @@
+function [value,isterminal,direction] = periodeventfunctioneventsIQM(t,x,varargin)
+% periodeventfunctioneventsIQM: This function has two purposes. The main
+% purpose is to collect information time information during simulation that
+% allows to determine the period of an oscillating system. This is realized
+% by letting the intergrator check for events that correspond to state
+% values crossing a certain threshold in positive direction. 
+% The second purpose is to generate events at which integrator has to be
+% stopped, the states reinitialized (according to the events that are
+% present in the model) and restarted.
+% 
+% USAGE:
+% ======
+% This function is used by the function 'IQMsensdataoscevents'
+%
+% The function requires the presence of 2 global variables that are defined
+% in 'IQMsensdataoscevents':
+% 
+% eventValues: that are values of the states at which an event is triggered
+%              if the current state values pass these values in positive direction.
+% eventHandleFunction: this is the name (string) of a function that handles
+%              the events that are present in the model
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+% instead of 'eventValues' as global variable one also can hardcode certain
+% values of interest, when considering a certain problem.
+global eventValues EVENTfctname
+
+% First implement the event handling for the events that are present in the model
+% This line should not be changed in custom event handling functions that
+% are to be used when doing sensitivity analysis
+
+% pass empty elements for the parameters and parametervalues functions
+[valueModel,isterminalModel,directionModel] = feval(EVENTfctname,t,x,varargin{:});
+
+% Now implement the events that are required to determine the period time
+% Locate the time when the states determined by the out-indices  
+% pass the values in 'eventValues' in positive direction
+% The next three lines can be changed in order to customize the event
+% handling and to collect other data for sensitivity analysis
+valuePeriod = eventValues(:)'-x(:)';
+isterminalPeriod = zeros(1,length(x));    % never stop the integration due to these events
+directionPeriod =  ones(1,length(x));     % positive direction
+
+% Combine the two event functions
+value = [valueModel valuePeriod];
+isterminal = [isterminalModel isterminalPeriod];
+direction = [directionModel directionPeriod];
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/modelreduction/IQMprepredreac.m b/IQMtools V1.2.2.2/IQMlite/tasks/modelreduction/IQMprepredreac.m
new file mode 100644
index 0000000000000000000000000000000000000000..77d0ca26015bd30208d0a73aa5eb4e0eeb5487aa
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/modelreduction/IQMprepredreac.m	
@@ -0,0 +1,201 @@
+function [output] = IQMprepredreac(model,timevectors,experiments,varargin)
+% IQMprepredreac: prepares a model for subsequent reduction of reaction rate
+% expressions. Eventual "power(x,y)" expressions are exchanged against
+% "x^y". Reaction rates are expanded by substituting in variables. Ununsed
+% elements (reactions, variables, and parameters) are deleted from the
+% model. Furthermore reference simulations are performed based on which the
+% models reactions can be reduced in following steps.
+%
+% USAGE:
+% ======
+% [output] = IQMprepredreac(model, timevectors, experiments)
+% [output] = IQMprepredreac(model, timevectors, experiments, extravariables)
+%
+% model:            IQMmodel to consider for reduction
+% timevectors:      time vectors of interest (one for each experiment)
+% experiments:      cell-array with experiment definitions 
+% extravariables:   cellarray with names of parameters that should be taken
+%                   into account as species belonging to the M vector
+%                   or parameters that are set to different values during
+%                   experiments (then they need to be kept in the reduced model)
+%
+% Output Arguments:
+% =================
+% output:   structure with necessary information
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE NON-NUMERIC INITIAL CONDITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% just by replacing them
+model = IQMconvertNonNum2NumIC(model);
+if ~hasonlynumericICsIQM(model),
+    disp('Non-numeric initial conditions will be removed in the reduced model. You can replace them after reduction if you like.');
+end
+    
+output.model = [];
+output.extravariables = [];
+output.timevectors = timevectors;
+output.reference = [];
+output.reference.experiments = experiments;
+output.reference.data = [];
+output.reference.datavalues = [];
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% check if symbolic toolbox is present
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isSymbolicpresentIQM,
+    error('The model reduction feature requires the presence of the symbolic toolbox.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% check cells
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~iscell(timevectors),
+    timevectors = {timevectors};
+end
+if ~iscell(experiments),
+    experiments = {experiments};
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% variable input arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+extravariables = {};
+if nargin > 3,
+    extravariables = varargin{1};
+end
+output.extravariables = extravariables;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% check if first argument is a model
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isIQMmodel(model),
+    error('First argument needs to be an IQMmodel.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% expand reaction expressions by substituting in all variables
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+model = substitutevarsIQM(model);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% check and replace power expressions
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[model,changeFlag] = depowerIQM(model);
+% if changeFlag == 1,
+% %    disp('Power operators are present. Support for Hill-type rate equations is only experimental at present.');
+%     model = fixExp(model);
+% end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% finally clean the model from unnecessary parameters, reactions, variables
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+output.model = cleanmodelIQM(model,1);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% simulate the experiments and save the data
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% simulate all the experiments and collect the numeric values for states
+% and reactions and additionally also the parameters (extravariables)
+states = IQMstates(output.model)';
+reactions = IQMreactions(output.model)';
+parameters = IQMparameters(output.model);
+statevalues = [];
+reactionvalues = [];
+parametervalues = [];
+for k = 1:length(experiments),
+    disp(sprintf('Simulating experiment %d/%d ...',k,length(experiments)));
+    modelexp = IQMmergemodexp(output.model,experiments{k});
+    % set maxstep options
+    options.maxstep = max(output.timevectors{k})/length(output.timevectors{k});
+    options.maxnumsteps = 10000;
+    if isIQMproPresent(),
+        simdata = IQMPsimulate(modelexp,timevectors{k},[],[],[],options);
+    else
+        simdata = IQMsimulate(modelexp,timevectors{k});
+    end
+    statevalues = [statevalues; simdata.statevalues];
+    reactionvalues = [reactionvalues; simdata.reactionvalues];
+    % get values for the extra variables that are parameters (can change
+    % during experiments)
+    parametervaluesscalar = IQMparameters(modelexp,extravariables)';
+    parametervalues = [parametervalues; parametervaluesscalar(ones(length(timevectors{k}),1),:)];
+end
+% add states extravariables and reactions together
+output.reference.data = {states{:} extravariables{:} reactions{:}};
+output.reference.datavalues = [statevalues parametervalues reactionvalues];
+return
+
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% % fixExp: for all exponential parameters, eg x^p1, fix them to the value
+% % specified in the model => x^4 if p1=4. Do this ONLY for the reaction 
+% % expressions.
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% function model = fixExp(model)
+% global parameterNames parameterValues
+% [parameterNames, parameterValues] = IQMparameters(model);
+% iqms = struct(model);
+% for k = 1:length(iqms.reactions),
+%     iqms.reactions(k).formula = fixHelper(iqms.reactions(k).formula);
+% end
+% model = IQMmodel(iqms);    
+% return
+% 
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% % fixHelper: subfunction to fixExp
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% function finalString = fixHelper(string)
+% global parameterNames parameterValues;
+% startIndex = strfind(string, '^');
+% finalString = string; index = 0;
+% if ~isempty(startIndex)
+%     finalString = string(1:startIndex(1)-1);
+%     for i = 1:length(startIndex)
+%         openParenthesis = 0;
+%         for j = startIndex(i)+1:length(string)
+%             if string(j) == '(',
+%                 openParenthesis = openParenthesis + 1;
+%             elseif string(j) == ')',
+%                 openParenthesis = openParenthesis - 1;
+%             end
+%             if openParenthesis == 0
+%                 if i == length(startIndex)
+%                     if index < i
+%                         selectedString = string([startIndex(i)+2:j-1]);
+%                         match = findsym(sym(selectedString));
+%                         [found, ia, ib] = intersect(parameterNames, match);
+%                         for k = 1:length(found)
+%                             selectedString = num2str(subs(selectedString, parameterNames(ia(k)), parameterValues(ia(k))));
+%                         end
+%                         finalString = strcat(finalString, '^(', selectedString, ')',string([j+1:end]));
+%                         break;
+%                     end
+%                 elseif j < startIndex(i+1)
+%                     if index < i
+%                         selectedString = string([startIndex(i)+2:j-1]);
+%                         match = findsym(sym(selectedString));
+%                         [found, ia, ib] = intersect(parameterNames, match);
+%                         for k = 1:length(found)
+%                             selectedString = num2str(subs(selectedString, parameterNames(ia(k)), parameterValues(ia(k))));
+%                         end
+%                         finalString = strcat(finalString, '^(', selectedString, ')', string([j+1:startIndex(i+1)-1]));
+%                         break;
+%                     end
+%                 else
+%                     index = find(startIndex > j, 1);
+%                     if isempty(index)
+%                         index = length(startIndex)+1;
+%                     end
+%                     
+%                     rep = fixHelper(string([startIndex(i)+2:j-1]));
+%                     match = regexp(rep, '(.+)[,](.+)', 'tokens');
+%                     finalString = strcat(finalString, '^(', rep, ')');
+%                     break;
+%                 end
+%             end
+%         end
+%     end
+% end
+% return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/modelreduction/IQMredallreac.m b/IQMtools V1.2.2.2/IQMlite/tasks/modelreduction/IQMredallreac.m
new file mode 100644
index 0000000000000000000000000000000000000000..6b894e91604dd29567c75b89400f36330b7be90d
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/modelreduction/IQMredallreac.m	
@@ -0,0 +1,160 @@
+function [modelred] = IQMredallreac(model,experiments,timevectors,varargin)
+% IQMredallreac: Wrapper for the IQMredreac function allowing to easily
+% go through a whole model and reduce all reactions that are possible to
+% reduce.
+% 
+% USAGE:
+% ======
+% [modelred] = IQMredallreac(model,experiments,timevectors)
+% [modelred] = IQMredallreac(model,experiments,timevectors,OPTIONS)
+% [modelred] = IQMredallreac(model,experiments,timevectors,OPTIONS,extravariables)
+%
+% model:            IQMmodel to consider for reduction
+% timevectors:      cell-array with time vectors of interest (one for each experiment)
+% experiments:      cell-array with experiment definitions 
+% extravariables:   cellarray with names of parameters that should be taken
+%                   into account as species belonging to the M vector
+%                   or parameters that are set to different values during
+%                   experiments (then they need to be kept in the reduced model)
+% OPTIONS: structure containing options for the algorithm:
+%        OPTIONS.tol: tolerance for singularity detection (smallest SV)
+%        OPTIONS.keeporigparameters: =0: do not keep original parameters
+%                                    =2: do always keep original parameters
+%                                    =1: keep original parameters only if
+%                                        it leads to fewer parameters
+%        OPTIONS.numeratorweighting: =1: weight numerator terms and denumerator terms 
+%                                    such that numerators are kept
+%                                    =0: dont do any weighting
+%
+% DEFAULT VALUES:
+% ===============
+% extravariables:               {}
+% OPTIONS.tol:                  1e-6
+% OPTIONS.keeporigparameters:   0
+% OPTIONS.numeratorweighting:   0
+%
+% Output Arguments:
+% =================
+% modelred: IQMmodel in which the defined reaction is reduced
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% check cell-arrays in input
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~iscell(experiments),
+    experiments = {experiments};
+end
+if ~iscell(timevectors),
+    timevectors = {timevectors};
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% variable input arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+OPTIONS = [];
+extravariables = {};
+if nargin >= 4,
+    OPTIONS = varargin{1};
+end
+if nargin >= 5,
+    extravariables = varargin{2};
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% prepare reduction - DOES ALSO HANDLE NON-NUMERIC ICs ... by converting
+% them to NUMERIC ICs
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+disp('Preparing data for reduction ...');
+output = IQMprepredreac(model,timevectors,experiments,extravariables);
+[reactions, formulas] = IQMreactions(output.model);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Go through all reactions
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+disp('Going through all reactions ...');
+modelred = output.model;
+for k = 1:length(reactions),
+    clc;
+    reaction = reactions{k};
+    formula = formulas{k};
+    text = sprintf('%s = %s\n',reaction,formula);
+    disp(text);
+    while 1,
+        choose = input('Reduce this reaction (1) or not (0)? ');
+        if choose == 1 || choose == 0,
+            break;
+        end
+    end
+    if choose == 1,
+        % run
+        modelsave = modelred;
+        while 1,
+            try
+                [modelred] = IQMredreac(output,reaction,OPTIONS);
+                output.model = modelred;
+            catch
+                disp(lasterr);
+            end
+            try
+                runcomparison(model,modelred,experiments,timevectors);
+            catch
+                disp(lasterr);
+                disp('Something went wrong ... you should press 0!');
+            end
+            while 1,
+                check = input('Does this look ok (1) or not (0)?');
+                if check == 1 || check == 0,
+                    break;
+                end
+            end
+            if check == 0,
+                output.model = modelsave;
+                modelred = modelsave;
+            else
+                break;
+            end
+        end
+    end
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% run comparison with original model
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [] = runcomparison(model,modelred,experiments,timevectors)
+figure(1); clf;
+for k = 1:length(experiments),
+    subplot(length(experiments),1,k);
+    % perform experiment
+    modexp = IQMmergemodexp(model,experiments{k});
+    % set maxstep options
+    options.maxstep = max(timevectors{k})/length(timevectors{k});
+    options.maxnumsteps = 10000;
+    if isIQMproPresent(),
+        expdata = IQMPsimulate(modexp,timevectors{k},[],[],[],options);
+    else
+        expdata = IQMsimulate(modexp,timevectors{k});
+    end
+    modredexp = IQMmergemodexp(modelred,experiments{k});
+    if isIQMproPresent(),
+        redexpdata = IQMPsimulate(modredexp,timevectors{k},[],[],[],options);
+    else
+        redexpdata = IQMsimulate(modredexp,timevectors{k});
+    end
+    % plot results
+    plot(expdata.time,expdata.statevalues); hold on; 
+    plot(redexpdata.time,redexpdata.statevalues,'o');
+    % legend
+    if k == 1,
+        hlhlx = legend(IQMstates(model),'Location','NorthEastOutside');
+        set(hlhlx,'Interpreter','none');
+    end
+    title(sprintf('Comparison for Experiment %d',k));
+
+    % At this point the user can add whatever comparison test between the
+    % original and reduced model that is necessary ...
+
+end
+return
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/modelreduction/IQMredreac.m b/IQMtools V1.2.2.2/IQMlite/tasks/modelreduction/IQMredreac.m
new file mode 100644
index 0000000000000000000000000000000000000000..e531934c7cd2650c2bd5a329b30b14367fc35037
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/modelreduction/IQMredreac.m	
@@ -0,0 +1,265 @@
+function [modelred] = IQMredreac(output,reaction,varargin)
+% IQMredreac: Reduction of single reaction expressions with the goal of reducing
+% complexity and number of parameters. This function requires the prior
+% execution of the IQMprepredreac.
+% 
+% USAGE:
+% ======
+% [modelred] = IQMredreac(output,reaction)
+% [modelred] = IQMredreac(output,reaction,OPTIONS)
+%
+% output: Result returned from IQMprepredreac
+% reaction: Name of the reaction that should be reduced
+% OPTIONS: structure containing options for the algorithm:
+%        OPTIONS.tol: tolerance for singularity detection (smallest SV)
+%        OPTIONS.keeporigparameters: =0: do not keep original parameters
+%                                    =2: do always keep original parameters
+%                                    =1: keep original parameters only if
+%                                        it leads to fewer parameters
+%        OPTIONS.numeratorweighting: =1: weight numerator terms and denumerator terms 
+%                                    such that numerators are kept
+%                                    =0: dont do any weighting
+%
+% DEFAULT VALUES:
+% ===============
+% OPTIONS.tol:                  1e-6
+% OPTIONS.keeporigparameters:   0
+% OPTIONS.numeratorweighting:   0
+%
+% Output Arguments:
+% =================
+% modelred: IQMmodel in which the defined reaction is reduced
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+% open needed figure that is to be updates during the whole reduction
+% procedure of the given reaction
+figH2 = figure(2); clf;
+yaxismax = 0;
+xplot = -1;
+yplot = -1;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% check if symbolic toolbox is present
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isSymbolicpresentIQM,
+    error('The model reduction feature requires the presence of the symbolic toolbox.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle variable input arguments (options)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+OPTIONS = [];
+if nargin == 3,
+    OPTIONS = varargin{1};
+end
+% default values
+tol = 1e-6;              % tolerance for singularity detection (smalles SV)
+keeporigparameters = 0;  % do not keep original parameters
+numeratorweighting = 0;  % do not weight numerators/denumerators depending on their number
+% tol
+if isfield(OPTIONS,'tol'),
+    if ~isempty(OPTIONS.tol),
+        tol = OPTIONS.tol;
+    end
+end
+% keeporigparameters
+if isfield(OPTIONS,'keeporigparameters'),
+    if ~isempty(OPTIONS.keeporigparameters),
+        keeporigparameters = OPTIONS.keeporigparameters;
+    end
+end
+% numeratorweighting
+if isfield(OPTIONS,'numeratorweighting'),
+    if ~isempty(OPTIONS.numeratorweighting),
+        numeratorweighting = OPTIONS.numeratorweighting;
+    end
+end
+
+disp(' ');
+disp('#####################################################################');
+disp(sprintf('# Reduction of reaction:  %s', reaction));
+disp('#####################################################################');
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Determine reduction information for specified reaction
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+output2 = reducereactionprepIQM(output,reaction);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Determine which terms to reduce
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% number terms in original equation
+nrorig = size(output2.reaction_trans.A,2);
+indexkeep = [1:nrorig];
+indexkeep_backup = {};
+while 1,
+    try
+        % Reduce (do this also for the case where indexkeep contains all terms)
+        output3 = reducereacIQM(output2,indexkeep,keeporigparameters);
+    catch
+        % catch errors that can occurr in cases when no reduction is possible
+        % example: reaction only defined by constant rate
+        %          ...
+        
+        disp('************************** All nominators might have been cancelled ... try nominator weighting!');
+    end
+    % Optimize parameter values
+    output4 = reduceoptimIQM(output3);
+    % check if optimization successful (do it by looking at it!)
+    orig = output3.reaction_orig.reactionvalues;
+    redopt = output4.reaction_opt.reactionvalues;
+    figH = figure(1); clf; 
+    plot(orig); hold on; plot(redopt,'r--'); 
+    
+    
+    
+    % also plot the obtained costfunction value against the ratio between the 
+    % number of parameters in the reduced and original model. Divide the
+    % cost by the mean
+    nrorigterms = length(output4.reaction_trans.c);
+    nrredterms = length(indexkeep);
+    costred_scaled = output4.reaction_opt.cost/mean(orig);
+    figure(figH2);
+    xoldplot = xplot;
+    yoldplot = yplot;
+    xplot = nrredterms/nrorigterms;
+    yplot = costred_scaled;
+    plot(xplot,yplot,'r*'); hold on;
+    if xoldplot >= 0,
+        plot(xoldplot,yoldplot,'w*'); hold on;
+        plot(xoldplot,yoldplot,'bo'); hold on;
+    end
+    yaxismax = max(yaxismax, yplot*1.1);
+    axis([0 1 0 yaxismax]);    
+    xlabel('#redterms/#origterms');
+    ylabel('optimal cost');
+    
+    
+    
+    % plot some info
+disp(' ');
+if length(indexkeep) > 1,
+    disp('Linear dependency and approximation measures');
+    disp('############################################');
+    [Us,Ss,Vs] = svd(output3.reductioninfo.Anumscaled(:,indexkeep));
+    disp(sprintf('Singular values Mscaled: %s', sprintf('%g ',diag(Ss))));
+    disp(sprintf('Elements v*(Mscaled): %s',sprintf('%g ',Vs(:,end))));
+    disp(' ');
+    [Uc,Sc,Vc] = svd(output3.reductioninfo.AnumC(:,indexkeep));
+    disp(sprintf('Singular values Mc: %s', sprintf('%g ',diag(Sc))));
+    disp(sprintf('Elements v*(Mc): %s',sprintf('%g ',Vc(:,end))));
+    disp(' ');
+end
+disp('Statistics and preliminary result ');
+disp('#################################');
+    text = sprintf('Nr parameters in original/reduced expression: %d/%d\n',length(output2.reaction_orig.parameters),length(output3.reaction_red.parameters));
+    indexdelete = setdiff([1:nrorig],indexkeep);
+    deleteText = '';
+    for k = 1:length(indexdelete),
+        deleteText = strcat(deleteText, ', ', output3.reaction_trans.A{indexdelete(k)});
+    end
+    text = sprintf('%sDeleted terms: %s\n',text,deleteText(2:end));
+    text = sprintf('%s%s_red = %s\n',text,output2.reaction,output3.reaction_red.formula);
+    disp(text);
+    % Decide what to do next
+    if length(indexkeep_backup) == 0,
+        while 1,
+            check = input('Continue (2), or end (0) (switch num weighting: 99): ');
+            if check == 2 || check == 0,
+                break;
+            elseif check == 99,
+                numeratorweighting = ~numeratorweighting;
+                disp(sprintf('numeratorweighting = %d',numeratorweighting));
+            end
+        end
+    else
+        while 1,
+            check = input('Continue (2), go back (1), end (0) (switch num weighting: 99): ');
+            if check == 2 || check == 1 || check == 0,
+                break;
+            elseif check == 99,
+                numeratorweighting = ~numeratorweighting;
+                disp(sprintf('numeratorweighting = %d',numeratorweighting));
+            end
+        end
+    end
+    if check == 1,
+        % go a step back
+        indexkeep = indexkeep_backup{end};
+        indexkeep_backup = indexkeep_backup(1:end-1);
+    elseif check == 0,
+        % end reduction
+        break;
+    else
+        % continue
+        indexkeep_backup{end+1} = indexkeep;
+        % Select what to reduce
+        Anumscaled = output2.reductioninfo.Anumscaled(:,indexkeep);
+        AnumC = output2.reductioninfo.AnumC(:,indexkeep);
+        [U,S,V] = svd(Anumscaled);
+        SAns = diag(S)';
+        VAns = V(:,end);
+        [U,S,V] = svd(AnumC);
+        SAnc = diag(S)';
+        VAnc = V(:,end);
+        V1 = abs(VAns);
+        V2 = abs(VAnc);
+        % do numeratorweighting (if on then set numerator elements to 0),
+        % avoidng the deletion of numerators
+        if numeratorweighting == 1,
+            isnomterm = output2.reductioninfo.isnomterm(indexkeep);
+            numbernom = sum(isnomterm);
+            numberden = length(isnomterm)-numbernom;
+            factor = [ones(numberden,1); 0*ones(numbernom,1)];
+            V1 = V1.*factor;
+            V2 = V2.*factor;
+        end
+        V1 = max(V1-mean(V1),0);
+        V2 = max(V2-mean(V2),0);
+        if SAns(end) < tol,
+            disp('##########################################');
+            disp('# Reduction:  Based on linear dependency #');
+            disp('##########################################');
+            V = V1+0.01*V2;
+identFlag = 1;
+        else
+            disp('####################################');
+            disp('# Reduction based on approximation #');
+            disp('####################################');
+            V = V2;
+identFlag = 0;
+        end
+
+if identFlag == 0,
+    [dummy,indexdeleteNEXT] = max(V);
+else
+% determine the k that minimizes the relative changes
+    c = output4.reaction_red.parametervalues;
+    testValues = zeros(1,length(c));
+    for k4=1:length(c),
+        ssum = 0;
+        if V(k4) ~= 0,
+            for i4=1:length(V),
+                if k4~=i4,
+                    ssum = ssum + (abs(c(k4)*V(i4)/V(k4)/c(i4)));
+                end
+            end
+            testValues(k4) = ssum;
+        else
+            testValues(k4) = inf;
+        end
+    end
+    [dummy, indexdeleteNEXT] = min(testValues);
+end
+       
+        indexkeep(indexdeleteNEXT) = [];   % delete element
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Update the model with the reduced reaction
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+modelred= redupdateIQM(output4);
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/modelreduction/auxiliary/reduceoptimIQM.m b/IQMtools V1.2.2.2/IQMlite/tasks/modelreduction/auxiliary/reduceoptimIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..637030bba6cea4523939113329a967b01dc3b98f
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/modelreduction/auxiliary/reduceoptimIQM.m	
@@ -0,0 +1,47 @@
+function [output] = reduceoptimIQM(output)
+% reduceoptimIQM: optimizes reduced parameter values
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Optimize new parameters with estimates as starting guess
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
+global opt_ref opt_formula opt_param opt_var opt_varvalues reac
+opt_ref = output.reaction_orig.reactionvalues;           % reaction value from unreduced reaction
+opt_formula = output.reaction_red.formula;               % reduced formula
+opt_param = output.reaction_red.parameters;              % parameternames in reduced formula
+opt_paramvalues = output.reaction_red.parametervalues;   % parametervalues in reduced formula
+opt_var = output.reaction_red.variables;                 % variable names
+opt_varvalues = output.reaction_red.variablevalues;      % variable values
+options.maxiter = 100;
+options.lowbounds = -1e10*ones(1,length(opt_param));
+options.highbounds = 1e10*ones(1,length(opt_param));
+options.silent = 1;
+old = inf;
+FVAL = -inf;
+while abs(old-FVAL) > 1e-4
+    old = FVAL;
+    [opt_paramvalues, FVAL] = simplexIQM(@costfunction,opt_paramvalues,options);
+end
+output.reaction_opt.parametervalues = opt_paramvalues;
+output.reaction_opt.reactionvalues = reac;
+output.reaction_opt.cost = FVAL;
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
+function [cost] = costfunction(X)
+global opt_ref opt_formula opt_param opt_var opt_varvalues reac
+% assign parameter values
+for k = 1:length(X),
+    eval(sprintf('%s = %f;',opt_param{k},X(k)));
+end
+% assign variable values
+for k = 1:length(opt_var),
+    eval(sprintf('%s = opt_varvalues(:,k);',opt_var{k}));
+end
+% evaluate reaction equation
+reac = eval(formula2vecIQM(opt_formula));
+% determine cost
+cost = sqrt(sum((reac-opt_ref).^2));
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/modelreduction/auxiliary/reducereacIQM.m b/IQMtools V1.2.2.2/IQMlite/tasks/modelreduction/auxiliary/reducereacIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..1887ee5c17c793b9b41caaa0b341147e5e9b934a
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/modelreduction/auxiliary/reducereacIQM.m	
@@ -0,0 +1,139 @@
+function [output] = reducereacIQM(output,indexkeep,varargin)
+% reducereacIQM: reduces the equation by keeping only the defined terms of
+% the A vector. Subsequently the values of the new parameters are defined.
+%
+% [output] = reducereacIQM(output,indexkeep)
+% [output] = reducereacIQM(output,indexkeep,keeporigparameters)
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% check if symbolic toolbox is present
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isSymbolicpresentIQM,
+    error('The model reduction feature requires the presence of the symbolic toolbox.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Variable input arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+keeporigparameters = 0;
+if nargin == 3,
+    keeporigparameters = varargin{1};
+end
+
+output.keeporigparameters = keeporigparameters;
+output.reaction_red = [];
+output.reaction_red.formula = [];
+output.reaction_red.formulaop = [];
+output.reaction_red.parameters = [];
+output.reaction_red.parametervalues = [];
+output.reaction_red.variables = [];
+output.reaction_red.variablevalues = [];
+output.reaction_red.reactionvalues = [];
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Build new reduced reaction expression ... use new or original parameters
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% First check if new or original parameters (output.keeporigparameters = 0
+% does not keep them =1 keeps them eventually, =2 keeps them always).
+% copy flag to extra variable to keep it on the initial value in the output
+% structure. =1: Original parameters are kept if it means that this leads to
+% fewer parameters. 
+keeporigparameters = output.keeporigparameters;
+if keeporigparameters == 1,
+    testparam = {};
+    for k = 1:length(indexkeep),
+        % determine parameters
+        testparam = getNewParameters(testparam,output.reaction_trans.c{indexkeep(k)},output.reaction_orig.parameters);
+    end
+    if length(testparam) > length(indexkeep),
+        % Keeping original parameters would lead to more parameters => skip it
+        keeporigparameters = 0;
+    end
+end
+
+expression = sym(0);
+newparam = {};
+if keeporigparameters == 0,
+    % Use new parameters (eventually more degrees of freedom and a better fit
+    newbaseparamname = ['K_' output.reaction '_'];
+    for k = 1:length(indexkeep),
+        newparam{end+1} = sprintf('%s%d',newbaseparamname,k);
+        expression = expression + sym(output.reaction_trans.A{indexkeep(k)})*sym(newparam{end});
+    end
+else
+    % Use original parameters (eventually fewer degrees of freedom and a worse fit)
+    for k = 1:length(indexkeep),
+        % determine parameters
+        newparam = getNewParameters(newparam,output.reaction_trans.c{indexkeep(k)},output.reaction_orig.parameters);
+        % build new expression
+        expression = expression + sym(output.reaction_trans.A{indexkeep(k)})*sym(output.reaction_trans.c{indexkeep(k)});
+    end
+end
+expression = [output.reaction_trans.b{1} '=' char(expression)];
+reacredRHS = solve(expression,output.reaction);
+% add info to structure
+output.reaction_red.formula = char(reacredRHS);
+output.reaction_red.parameters = newparam;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check if all numerators have been deleted (leads to an error)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if output.reaction_red.formula == '0',
+    error('All numerator terms have been deleted from the reaction expression.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Determine the parameter values (starting guesses for eventual optimization)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%    
+if keeporigparameters == 0,
+    % New parameters: Use nonlinear regression to estimate the new parameter values
+    %Ared = output.reaction_trans.Anum(:,indexkeep);
+    %bred = output.reaction_trans.bnum;
+    %output.reaction_red.parametervalues = (pinv(Ared)*bred)';
+    % Get new parameters from the old ones (as starting guess)
+    output.reaction_red.parametervalues = output.reaction_trans.cnum(indexkeep);
+else
+    % Old parameters: just use the original values
+    output.reaction_red.parametervalues = IQMparameters(output.model,output.reaction_red.parameters)';
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Determine the variables that are present and also get their numeric values
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
+output.reaction_red.variables = setdiff(explodePCIQM(findsym(sym(output.reaction_red.formula))),output.reaction_red.parameters);
+variablevalues = [];
+for k = 1:length(output.reaction_red.variables),
+    index = strmatchIQM(output.reaction_red.variables{k}, output.reaction_orig.variables, 'exact');
+    variablevalues(:,end+1) = output.reaction_orig.variablevalues(:,index);
+end
+output.reaction_red.variablevalues = variablevalues;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Determine the reaction rate for defined experiments 
+% for reduced expression
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%    
+% Define all the variables in the workspace
+for k = 1:length(output.reaction_red.variables),
+    eval(sprintf('%s = output.reaction_red.variablevalues(:,k);',output.reaction_red.variables{k}));
+end
+% Define the new parameters in the workspace
+for k = 1:length(output.reaction_red.parameters),
+    eval(sprintf('%s = output.reaction_red.parametervalues(k);',output.reaction_red.parameters{k}));
+end
+% Evaluate the reduced reaction formula
+reaceval = formula2vecIQM(output.reaction_red.formula);
+redreactionvalues = eval(reaceval);
+output.reaction_red.reactionvalues = redreactionvalues;
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Determine new parameters in expression for parameters
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [newparam] = getNewParameters(newparam, expression, possibleparam)
+addparam = explodePCIQM(findsym(sym(expression)));
+newparam = unique({newparam{:}, addparam{:}});
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/modelreduction/auxiliary/reducereactionprepIQM.m b/IQMtools V1.2.2.2/IQMlite/tasks/modelreduction/auxiliary/reducereactionprepIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..087a1f41c6269aa1acaffd44d3230388d2f9698f
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/modelreduction/auxiliary/reducereactionprepIQM.m	
@@ -0,0 +1,242 @@
+function [output] = reducereactionprepIQM(output,reaction)
+% reducereactionprepIQM: This function transforms the reaction rate in the
+% following form:
+%                       a' * c = v
+% 
+% determines the numerical values based on the simulation of the specified 
+% experiments and determines information about the reducibility of the
+% reaction expression.
+%
+% USAGE:
+% ======
+% output = reducereactionprepIQM(model,reaction)
+%
+% model:            IQMmodel to consider
+% reaction:         name of the reaction to determine M and c for
+%
+% Output Arguments:
+% =================
+% The output of this function is a matlab structure containing all
+% necessary information.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% check if symbolic toolbox is present
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isSymbolicpresentIQM,
+    error('The model reduction feature requires the presence of the symbolic toolbox.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% check if given reaction present in model
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(reactionindexIQM(output.model,reaction)),
+    error('Given reaction is not part of the model.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Define the output structure
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+output.reaction = reaction;
+output.reaction_orig = [];
+output.reaction_orig.formula = [];
+output.reaction_orig.parameters = [];
+output.reaction_orig.parametervalues = [];
+output.reaction_orig.variables = [];
+output.reaction_orig.variablevalues = [];
+output.reaction_orig.reactionvalues = [];
+output.reaction_trans = [];
+output.reaction_trans.A = [];
+output.reaction_trans.Anum = [];
+output.reaction_trans.b = [];
+output.reaction_trans.bnum = [];
+output.reaction_trans.c = [];
+output.reaction_trans.cnum = [];
+output.reductioninfo = [];
+output.reductioninfo.isnomterm = [];
+output.reductioninfo.Anumscaled = [];
+output.reductioninfo.AnumC = [];
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% get the reaction formula and add it to the output
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[reacnames,reacformulas] = IQMreactions(output.model);
+output.reaction_orig.formula = [reacformulas{reactionindexIQM(output.model,reaction)}];
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% get symbolic parameters, variables, A, b, and c
+% additionally determine a vector with indices 1 if term corresponds to
+% nominator and 0 if to denominator
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[parameters, variables, A, b, c, isnomterm] = getDataAndTransform(output);
+output.reductioninfo.isnomterm = isnomterm;
+output.reaction_orig.parameters = parameters;
+output.reaction_orig.variables = variables;
+output.reaction_trans.A = A;
+output.reaction_trans.b = b;
+output.reaction_trans.c = c;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% get numeric data for parameters, variables, A, b, and c and the reaction
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[reactionn, parametersn, variablesn, An, bn, cn] = getNumericData(output);
+output.reaction_orig.reactionvalues = reactionn;
+output.reaction_orig.parametervalues = parametersn;
+output.reaction_orig.variablevalues = variablesn;
+output.reaction_trans.Anum = An;
+output.reaction_trans.bnum = bn;
+output.reaction_trans.cnum = cn;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% determine reduction information
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[Anscaled, AnC] = getReductionInfo(output);
+output.reductioninfo.Anumscaled = Anscaled;
+output.reductioninfo.AnumC = AnC;
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Determine reduction information
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [Anscaled, AnC] = getReductionInfo(output)
+%%%%%%%%%%%%%%%%%%%%%%%
+% Scale the matrix A such that the element with the largest magnitude
+% in each column and experiment has a magnitude of 1
+%%%%%%%%%%%%%%%%%%%%%%%
+Anscaled = zeros(size(output.reaction_trans.Anum));
+for k = 1:length(output.reference.experiments),
+    Anexp = output.reaction_trans.Anum((k-1)*length(output.timevectors{k})+1:k*length(output.timevectors{k}),:);
+    Anexpscaled = Anexp*diag(1./max(abs(Anexp)));
+    Anscaled((k-1)*length(output.timevectors{k})+1:k*length(output.timevectors{k}),:) = Anexpscaled;
+end
+%%%%%%%%%%%%%%%%%%%%%%%
+% Determine the product of A and c in diagonal matrix (weighting each 
+% term in A with its corresponding coefficient
+%%%%%%%%%%%%%%%%%%%%%%%
+AnC = output.reaction_trans.Anum*diag(output.reaction_trans.cnum);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get numeric data for parameters, variables, A, b, and c
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [reactionn, parametersn, variablesn, An, bn, cn] = getNumericData(output)
+% get variable values 
+variablesn = [];
+for k = 1:length(output.reaction_orig.variables),
+    var = output.reaction_orig.variables{k};
+    % get values from reference data
+    indexdata = strmatchIQM(var,output.reference.data,'exact');
+    if ~isempty(indexdata),
+        variablesn(:,k) = output.reference.datavalues(:,indexdata);
+    end
+end
+% get reaction values
+indexdata = strmatchIQM(output.reaction,output.reference.data,'exact');
+reactionn = output.reference.datavalues(:,indexdata);
+% Get parameter values (It is assumed that these parameters are constant
+% ... and not chaged during the experiments)
+parametersn = IQMparameters(output.model,output.reaction_orig.parameters)';
+%%%%%%%%%%%%%%%%%%%%%%%
+% Determine An
+%%%%%%%%%%%%%%%%%%%%%%%
+% Define all the variables in the workspace
+for kloopx = 1:length(output.reaction_orig.variables),
+    eval(sprintf('%s = variablesn(:,kloopx);',output.reaction_orig.variables{kloopx}));
+end
+% Define the reaction in the workspace
+eval(sprintf('%s = reactionn;',output.reaction));
+% Then determine An
+An = zeros(size(variablesn,1),length(output.reaction_trans.A));
+for k = 1:length(output.reaction_trans.A),
+    Aevalk = formula2vecIQM(output.reaction_trans.A{k});
+    An(:,k) = eval(Aevalk);
+end
+%%%%%%%%%%%%%%%%%%%%%%%
+% Determine bn
+%%%%%%%%%%%%%%%%%%%%%%%
+% bn is just the negative of the reaction values
+bn = -reactionn;
+%%%%%%%%%%%%%%%%%%%%%%%
+% Determine cn
+%%%%%%%%%%%%%%%%%%%%%%%
+% Define all reaction parameters
+for kloopx = 1:length(output.reaction_orig.parameters),
+    eval(sprintf('%s = %g;',output.reaction_orig.parameters{kloopx},parametersn(kloopx)));
+end
+cn = [];
+for kloopx = 1:length(output.reaction_trans.c),
+    cn(end+1) = eval(sprintf('%s',output.reaction_trans.c{kloopx}));
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Transform the reaction expression and determine parameters, variables, A,
+% b, and c
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Instead of determining A, b, c directly we go via M * p = 0
+function [parameters, variables, A, b, c, isnomterm] = getDataAndTransform(output)
+%%%%%%%%%%%%%%%%%%%%%%%
+% Obtain M and p
+%%%%%%%%%%%%%%%%%%%%%%%
+% Convert the formula to a symbolic expression and determine numerator and denominator
+% determine numerator and denominator of reaction equation
+formulasym = sym(output.reaction_orig.formula);
+[numFsym, denFsym] = numden(formulasym);
+% Get a symbolic expression with all the variable names (not being coefficients)
+statenames = IQMstates(output.model);
+allnames = {statenames{:} output.extravariables{:}};
+variablessym = maplearrayIQM(allnames);
+% Determine the coefficients in the num and den
+[numCoeffssym,numVarssym] = coeffs(expand(numFsym), variablessym);
+[denCoeffssym,denVarssym] = coeffs(expand(denFsym), variablessym);
+Msym = [denVarssym*output.reaction -numVarssym];
+psym = [denCoeffssym numCoeffssym];
+M = {}; p = {};
+for k = 1:length(Msym),
+    M{k} = char(Msym(k));
+    p{k} = char(psym(k));
+end
+%%%%%%%%%%%%%%%%%%%%%%%
+% Obtain parameters and variables
+%%%%%%%%%%%%%%%%%%%%%%%
+parameters = explodePCIQM(findsym(psym));
+variables = setdiff(explodePCIQM(findsym(Msym)),output.reaction); % delete reaction name from list of variables
+% Clear not needed symbolic variables
+clear formulasym numFsym denFsym variablessym 
+clear numCoeffssym numVarssym denCoeffssym denVarssym
+clear Msym psym
+%%%%%%%%%%%%%%%%%%%%%%%
+% Get A, b, and c
+%%%%%%%%%%%%%%%%%%%%%%%
+% search the elements of M to determine which one corresponds to the reaction rate 
+for k = 1:length(M),
+    if strcmp(M{k},output.reaction),
+        break;
+    end
+end
+indexelement = k;
+% Determine A from M
+A = M(setdiff(1:length(M),indexelement));
+% Determine b from M (sign is important and should be negative!)
+b = {char(-sym(M{:,indexelement}))};
+% Determine c from p
+c = p(setdiff(1:length(M),indexelement));
+c_divisor = p{indexelement};
+for k = 1:length(c),
+    num = sym(c{k});
+    den = sym(c_divisor);
+    c{k} = char(num/den);
+end
+%%%%%%%%%%%%%%%%%%%%%%%
+% Get isnomterm
+%%%%%%%%%%%%%%%%%%%%%%%
+% Check output.reaction_trans.A: all elements that do not contain the 
+% reaction name correspond to a nominator term
+isnomterm = zeros(1,length(A));
+for k = 1:length(A),
+    if isempty(strfind(A{k},output.reaction)),
+        isnomterm(k) = 1;
+    end
+end
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/modelreduction/auxiliary/redupdateIQM.m b/IQMtools V1.2.2.2/IQMlite/tasks/modelreduction/auxiliary/redupdateIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..6634b1da1ef964ee4772667b8336d1d5fb6a131b
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/modelreduction/auxiliary/redupdateIQM.m	
@@ -0,0 +1,42 @@
+function [model] = redupdateIQM(output)
+% redupdateIQM: Returns an IQMmodel in which the reaction is exchanged 
+% against the reduced reaction 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+model = output.model;
+iqms = struct(model);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Exchange reaction to reduced reaction
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+index = reactionindexIQM(model,output.reaction);
+iqms.reactions(index).formula = output.reaction_red.formula;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Add/Update new parameters (if parameters already exist only their values
+% need to be changed).
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+modelparameters = IQMparameters(model);
+for k=1:length(output.reaction_opt.parametervalues),
+    % check if current parameter exists already
+    index = strmatchIQM(output.reaction_red.parameters{k},modelparameters,'exact');
+    if ~isempty(index),
+        % parameter exists already => update it
+        iqms.parameters(index).value = output.reaction_opt.parametervalues(k);
+    else
+        % parameter does not exist => add it
+        iqms.parameters(end+1).name = output.reaction_red.parameters{k};
+        iqms.parameters(end).value = output.reaction_opt.parametervalues(k);
+        iqms.parameters(end).type = '';
+        iqms.parameters(end).compartment = '';
+        iqms.parameters(end).unittype = '';
+        iqms.parameters(end).notes = '';
+    end
+end
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Clean the model and return
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+model = IQMmodel(iqms);
+model = cleanmodelIQM(model,1);
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/simulation/IQMinsilicoexp.m b/IQMtools V1.2.2.2/IQMlite/tasks/simulation/IQMinsilicoexp.m
new file mode 100644
index 0000000000000000000000000000000000000000..a9efda5197dae0bbb182670e56ffb7983a53c189
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/simulation/IQMinsilicoexp.m	
@@ -0,0 +1,206 @@
+function [varargout] = IQMinsilicoexp(model,experiment,timevector,varargin)
+% IQMinsilicoexp runs an in-silico experiment. Simulated data can be
+% returned in the IQMmeasurement format, plotted, or written in a CSV
+% or Excel measurement file (the latter only under Windows).
+%
+% USAGE:
+% ======
+% [] = IQMinsilicoexp(model,experiment,timevector [,OPTIONS])         
+% [] = IQMinsilicoexp(model,experiment,timevector,measurements [,OPTIONS])         
+% [] = IQMinsilicoexp(model,experiment,timevector,measurements,filetypeFlag [,OPTIONS])         
+% [] = IQMinsilicoexp(model,experiment,timevector,measurements,filetypeFlag,filename [,OPTIONS])         
+% [output] = IQMinsilicoexp(model,experiment,timevector [,OPTIONS])         
+% [output] = IQMinsilicoexp(model,experiment,timevector,measurements [,OPTIONS])         
+%
+% model: IQMmodel to perform the insilico experiment on
+% experiment: IQMexperiment object to apply
+% timevector: Timevector to be used for simulation
+% measurements: cell-array with the names of the components to measure
+%               (states, variables, reactions)
+% filetypeFlag: 0=plot results, 1=CSV measurement file, 2=Excel measurement
+%               file
+% filename: Name of the measurement file (or of the measurement) to generate
+% OPTIONS: structure with integrator options.
+%        OPTIONS.abstol: abs tolerance
+%        OPTIONS.reltol: rel tolerance
+%        OPTIONS.minstep: min step-size of integrator
+%        OPTIONS.maxstep: max step-size of integrator
+%        OPTIONS.maxnumsteps: maximum number of steps to be
+%          taken by the solver in its attempt to reach the next
+%          output time 
+%
+% DEFAULT VALUES:
+% ===============
+% measurements: all states are measured
+% filetypeFlag: 0 (plot the results). If output argument is specified, the 
+%               setting of the filetype flag is ignored
+% filename: combination of model and experiment name
+% OPTIONS.abstol: 1e-6
+% OPTIONS.reltol: 1e-6
+% OPTIONS.minstep: 0
+% OPTIONS.maxstep: inf
+% OPTIONS.maxnumsteps: 500
+%
+% Output Arguments:
+% =================
+% output: An IQMmeasurement object with the resulting data
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check input arguments 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isIQMmodel(model),
+    error('The first input argument needs to be an IQMmodel.');
+end
+if ~isIQMexperiment(experiment),
+    error('The first input argument needs to be an IQMexperiment.');
+end
+if length(timevector) <= 1,
+    error('The timevector is set incorrectly.');
+end
+modelstruct = struct(model);
+experimentstruct = struct(experiment);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle variable input arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+filetypeFlag = 0;
+filename = [modelstruct.name '_' experimentstruct.name];
+measurements = {};
+OPTIONS = [];
+if nargin == 4,
+    if isstruct(varargin{1}) || (isempty(varargin{1}) && isnumeric(varargin{1})),
+        OPTIONS = varargin{1};
+    else
+        measurements = varargin{1};
+    end
+elseif nargin == 5,
+    measurements = varargin{1};
+    if isstruct(varargin{2}) || (isempty(varargin{2}) && isnumeric(varargin{2})),
+        OPTIONS = varargin{2};
+    else
+        filetypeFlag = varargin{2};
+    end
+elseif nargin == 6,
+    measurements = varargin{1};
+    filetypeFlag = varargin{2};
+    if isstruct(varargin{3}) || (isempty(varargin{3}) && isnumeric(varargin{3})),
+        OPTIONS = varargin{3};
+    else
+        filename = varargin{3};
+    end    
+elseif nargin == 7.
+    measurements = varargin{1};
+    filetypeFlag = varargin{2};
+    filename = varargin{3};
+    OPTIONS = varargin{4};
+end
+
+if isempty(measurements),
+    measurements = IQMstates(model);
+end
+if ischar(measurements),
+    measurements = {measurements};
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Merge model and experiment
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+modexp = IQMmergemodexp(model,experiment);
+modelstruct = struct(modexp);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check measurements
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+meascomponenttype = [];
+meascomponentindex = [];
+modelStates = IQMstates(modexp);
+modelVariables = IQMvariables(modexp);
+modelReactions = IQMreactions(modexp);
+for k=1:length(measurements),
+    found = 0;
+    % check states
+    index = strmatchIQM(measurements{k},modelStates,'exact');
+    if ~isempty(index),
+        found = 1;
+    end
+    % check variables (if not in states)
+    if found == 0,
+        index = strmatchIQM(measurements{k},modelVariables,'exact');
+        if ~isempty(index),
+            found = 2;
+        end
+    end
+    % check reactions (if not in states and variables)
+    if found == 0,
+        index = strmatchIQM(measurements{k},modelReactions,'exact');
+        if ~isempty(index),
+            found = 3;
+        end
+    end
+    % check if it exists at all
+    if found == 0,
+        error('Measured component ''%s'' does not exist in the model.',measurements{k});
+    end
+    % save type and index
+    meascomponenttype(end+1) = found;
+    meascomponentindex(end+1) = index;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Simulate the experiment model (Non-numeric ICs handled by not providing
+% an initial condition!)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+simdata = IQMPsimulate(modexp,timevector,[],[],[],OPTIONS);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Create IQMmeasurement object
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+measstruct = struct(IQMmeasurement);
+measstruct.name = filename;
+measstruct.notes = sprintf('Insilico experiment measurements\n================================\nModel notes:\n------------\n%s\n\nExperiment notes:\n-----------------\n%s',modelstruct.notes,experimentstruct.notes);
+measstruct.time = timevector(:);
+for k=1:length(measurements),
+    type = meascomponenttype(k);
+    index = meascomponentindex(k);
+    if type == 1, % its a state
+        name = modelstruct.states(index).name;
+        notes = modelstruct.states(index).notes;
+        values = simdata.statevalues(:,index);
+    elseif type == 2, % its a variable
+        name = modelstruct.variables(index).name;
+        notes = modelstruct.variables(index).notes;
+        values = simdata.variablevalues(:,index);
+    elseif type == 3, % its a reaction
+        name = modelstruct.reactions(index).name;
+        notes = modelstruct.reactions(index).notes;
+        values = simdata.reactionvalues(:,index);
+    end        
+    maxvalues = NaN(size(values));
+    minvalues = maxvalues;
+    measstruct.data(k).name = name;
+    measstruct.data(k).notes = notes;
+    measstruct.data(k).values = values;
+    measstruct.data(k).maxvalues = maxvalues;
+    measstruct.data(k).minvalues = minvalues;
+end
+insilicomeas = IQMmeasurement(measstruct);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle the output
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargout == 0,
+    if filetypeFlag == 0,
+        % just plot the measurement
+        IQMvisualizemeasurement(insilicomeas);
+    elseif filetypeFlag == 1 || (filetypeFlag == 2 && ~ispc),
+        % export to CSV (also if XLS desired but no windows PC)
+        IQMexportCSVmeasurement(insilicomeas,filename);
+    elseif filetypeFlag == 2 && ispc,
+        % export to XLS
+        IQMexportXLSmeasurement(insilicomeas,filename);
+    end
+elseif nargout == 1,
+    varargout{1} = insilicomeas;
+end
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/simulation/IQMsimdosing.m b/IQMtools V1.2.2.2/IQMlite/tasks/simulation/IQMsimdosing.m
new file mode 100644
index 0000000000000000000000000000000000000000..9e2bc8103b3f0bc9960531909eee7e1c3238ea65
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/simulation/IQMsimdosing.m	
@@ -0,0 +1,420 @@
+function [varargout] = IQMsimdosing(moddos,dosing,varargin)
+% IQMsimdosing: Simulates the application of a dosing schedule to a model
+% that has been prepared for it and either plots or returns the simulation
+% results.
+%
+% USAGE:
+% ======
+% [output] = IQMsimdosing(moddos,dosing)         
+% [output] = IQMsimdosing(moddos,dosing,time)         
+% [output] = IQMsimdosing(moddos,dosing,time,ICs)         
+% [output] = IQMsimdosing(moddos,dosing,time,ICs,paramnames,paramvalues)         
+% [output] = IQMsimdosing(moddos,dosing,time,ICs,paramnames,paramvalues,OPTIONS)         
+%
+% moddos: IQMmodel or MEXmodel which has been prepared using the
+%   mergemoddosIQM function. Note that if you use here a model that does
+%   not fit to the dosing input, the result will most certainly be wrong.
+% dosing: IQMdosing object with which the moddos model has been prepared.
+%   This input argument defines the dosing schedule to simulate
+% time: timevector to simulate. If scalar than the value defines the end
+%   simulation time and the time vector starts at 0. 
+% ICs: vector with initial conditions
+% paramnames: parameter name or cell-array with parameter-names 
+%             Parameters which are passed to the function to be modified do have 
+%             priority over parameters that are defined in the dosing scheme
+%             (Tinf,ka, Tlag, etc.)
+% paramvalues: vector with values for the parameters (in the same order as
+%   paramnames)
+% OPTIONS:     Structure with optional settings for the integrator, 
+%              either defined by odeset() for MATLAB simulation of by the integrator
+%              options setting used in IQMPsimulate.
+%
+% DEFAULT VALUES:
+% ===============
+% time: If not defined or left empty ([]), then the timevector will be
+%   chosen to cover the full dosing schedule +50%
+%   If the only dosing event occurs at time = 0, then a default time of 20
+%   is then used.
+% ICs: [] (use initial conditions, stored in the model)
+% paramnames: {}
+% paramvalues: [] (use values stored in the model)
+% OPTIONS: [] (default integrator settings, defined in getDefaultIntegratorOptionsIQM.m)
+%
+% Output Arguments:
+% =================
+% If an output argument is given, this variable will contain a standard
+% simulation result structure containing the time and the state, variable,
+% and reactions names and values. 
+% If no output argument is given, the result is plotted using the IQMplot
+% function.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+global doseeventstruct_sim
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% SET DEFAULT VALUES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+time = [];  % indicates to calculate timevector from dosing schedule
+OPTIONS = [];
+paramnames = {};
+paramvalues = [];
+ICs = [];
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin == 2,
+elseif nargin == 3,
+    time = varargin{1};
+elseif nargin == 4,
+    time = varargin{1};
+    ICs = varargin{2};
+elseif nargin == 6,
+    time = varargin{1};
+    ICs = varargin{2};
+    paramnames = varargin{3};
+    paramvalues = varargin{4};
+elseif nargin == 7,
+    time = varargin{1};
+    ICs = varargin{2};
+    paramnames = varargin{3};
+    paramvalues = varargin{4};
+    OPTIONS = varargin{5};
+else
+    error('Incorrect number of input arguments.');
+end
+% char => cell 
+if ischar(paramnames),
+    paramnames = {paramnames};
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle default integrator options
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(OPTIONS),
+    % Define default integrator options based on if IQM pro available or not
+    [options_M,options_C] = getDefaultIntegratorOptionsIQM();
+    if isIQMproPresent(),
+        OPTIONS = options_C;
+    else
+        OPTIONS = options_M;
+    end
+end
+if ~isIQMproPresent(),
+    try
+        dummy = OPTIONS.method;
+    catch
+        OPTIONS.method = 'ode23s';
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF IQMmodel and create MEXmodel
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isIQMmodel(moddos),
+    if isIQMproPresent(),
+        [MEXmodel, MEXmodelfullpath] = IQMmakeTempMEXmodel(moddos);
+    else
+        MEXmodel = moddos;
+    end
+else
+    MEXmodel = moddos;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Create doseeventstruct
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+doseeventstruct = dosing2doseeventIQM(dosing);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle timevector definition
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(time),
+    time = round(1.5*doseeventstruct(end).time);
+    % Could handle when the dosing event is at time 0
+    % then set time to a default end time
+    if time == 0
+        time = 20;
+    end
+    timevector = [0:time/1000:time];    
+elseif length(time) == 1,
+    timevector = [0:time/1000:time];
+else
+    timevector = time;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle the case when final simulation time is smaller than the last dosing
+% times. Simply remove the corresponding entries from the doseeventstruct.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+doseeventstruct_sim = doseeventstruct;
+doseeventstruct_sim(find([doseeventstruct.time] > timevector(end))) = [];
+if isempty(doseeventstruct_sim),
+    error('Please use a final simulation time that is larger than the first dosing time.')
+end 
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Prepare the simulation
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Split the time vector into pieces from 0 to start of dosing
+% applications, during dosing applications and from last application to
+% final time.
+firstdosing = doseeventstruct_sim(1).time;
+lastdosing = doseeventstruct_sim(end).time;
+timevectorpre = timevector(find(timevector < firstdosing));
+timevectorpost = timevector(find(timevector > lastdosing));
+timevectorduring = setdiff(setdiff(timevector,timevectorpre),timevectorpost);
+% Adjust time vectors to include dosing times. This leads to the first and
+% last dosing times being included twice (need to handle this later).
+if ~isempty(timevectorpre),
+    % Add first dosing time only if pre time vector is not empty.
+    timevectorpre = [timevectorpre(:); firstdosing];
+end
+if ~isempty(timevectorpost),
+    % Add last dosing time only if post time vector is not empty.
+    timevectorpost = [lastdosing; timevectorpost(:)];
+end
+timvectorduring = sort(unique([timevectorduring(:); [doseeventstruct_sim.time]']));
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Prepare the simulation output structure
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+simout = [];
+simout.time = [];
+simout.states = {};
+simout.statevalues = [];
+simout.variables = {};
+simout.variablevalues = [];
+simout.reactions = {};
+simout.reactionvalues = [];
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Simulate the prepart (only if timevectorpre is not empty)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(timevectorpre),
+    if isIQMproPresent(),
+        presim = IQMPsimulate(MEXmodel,timevectorpre,ICs,paramnames,paramvalues,OPTIONS);
+    else
+        modelsimhere = IQMparameters(MEXmodel,paramnames,paramvalues);
+        presim = IQMsimulate(modelsimhere,OPTIONS.method,timevectorpre,ICs,OPTIONS);        
+    end    
+    
+    % add results to output structure (neglect last index, since it is also
+    % available in the during timevector). But save last state as IC for
+    % next stage simulation
+    simout.time = [simout.time; presim.time(1:end-1)];
+    simout.states = presim.states;
+    simout.statevalues = [simout.statevalues; presim.statevalues(1:end-1,:)];
+    simout.variables = presim.variables;
+    simout.variablevalues = [simout.variablevalues; presim.variablevalues(1:end-1,:)];
+    simout.reactions = presim.reactions;
+    simout.reactionvalues = [simout.reactionvalues; presim.reactionvalues(1:end-1,:)];
+    % Save info for next stage simulation
+    ICnext_values = presim.statevalues(end,:);
+else
+    % No simulation of first part => define ICs as the ones given or stored
+    % in the model
+    ICnext_values = ICs;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Simulate the part in which dosing applications occur. Here we need to
+% simulate piecewise inbetween dosing times
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for k=1:length([doseeventstruct_sim.time])-1,
+    dosetime = doseeventstruct_sim(k).time;
+    nextdosetime = doseeventstruct_sim(k+1).time;
+
+    % Determine the changes to parameters to implement dosing and timing of doses
+    paramchangevalues = [];
+    paramchangenames = {};
+    for k2 = 1:length(doseeventstruct_sim(k).input),
+        paramchangevalues = [paramchangevalues(:)' doseeventstruct_sim(k).input(k2).parametervalues(:)' dosetime];
+        paramchangenames = {paramchangenames{:} doseeventstruct_sim(k).input(k2).parameternames{:} doseeventstruct_sim(k).input(k2).timeparname};
+    end
+    % paramchangevalues and paramchangenames contains the values for dose, time, ka, Tinf, etc that are defined in the dosing scheme
+    % we need to make sure that parameters that are defined in the model or in the parameters that are passed to the IQMsimdosing
+    % function to have priority over the parameters defined in the dosing scheme.
+    % This is done by checking if paramnames has same elements as paramchangenames and then remove these double definitions from the 
+    % paramchangenames and paramchangevalues arrays.
+    double_defined_parameters = intersect(paramchangenames,paramnames);
+    for k2=1:length(double_defined_parameters),
+        % Remove the double defined ones from the paramchangenames and values (parameters passed to the simulation function have priority over definition in 
+        % dosing scheme).
+        indexremove = strmatchIQM(double_defined_parameters{k2},paramchangenames,'exact');
+        paramchangevalues(indexremove) = [];
+        paramchangenames(indexremove) = [];
+        % Report what is done
+%        fprintf('Parameter "%s" passed to IQMsimdosing function has priority over definition of same parameter in dosing scheme.',double_defined_parameters{k2});
+    end
+
+    % Combine parameter changes from dosing scheme and passed parameters to simulation function
+    paramchangevalues = [paramchangevalues(:)' paramvalues(:)'];
+    paramchangenames = {paramchangenames{:} paramnames{:}};
+    % paramchangevalues = [paramvalues(:)' doseeventstruct_sim(k).input.parametervalues dosetime*ones(1,length(doseeventstruct_sim(k).input))];
+    % paramchangenames = {paramnames{:} doseeventstruct_sim(k).input.parameternames{:} doseeventstruct_sim(k).input.timeparname};
+    
+    % Determine the timevector piece (from dosing time to next dosing time (wo application at the latter)
+    timevectorpiece = timvectorduring;
+    timevectorpiece(timevectorpiece<dosetime) = [];
+    timevectorpiece(timevectorpiece>nextdosetime) = [];
+       
+    if isIQMproPresent(),
+        sim = IQMPsimulate(MEXmodel,timevectorpiece,ICnext_values,paramchangenames,paramchangevalues,OPTIONS);
+    else
+        modelsimhere = IQMparameters(MEXmodel,paramchangenames,paramchangevalues);
+        sim = IQMsimulate(modelsimhere,OPTIONS.method,timevectorpiece,ICnext_values,OPTIONS);        
+    end 
+    
+    % add results to output structure (if timevectorpost not empty => 
+    % neglect last index, since it is also available in the next timevector
+    % piece. Do NOT neglect if timevectorpost is empty). In any case 
+    % save last state as IC for next stage simulation
+    if ~isempty(timevectorpost),
+        simout.time = [simout.time; sim.time(1:end-1)];
+        simout.statevalues = [simout.statevalues; sim.statevalues(1:end-1,:)];
+        simout.variablevalues = [simout.variablevalues; sim.variablevalues(1:end-1,:)];
+        simout.reactionvalues = [simout.reactionvalues; sim.reactionvalues(1:end-1,:)];
+    else
+        simout.time = [simout.time; sim.time(1:end)];
+        simout.statevalues = [simout.statevalues; sim.statevalues(1:end,:)];
+        simout.variablevalues = [simout.variablevalues; sim.variablevalues(1:end,:)];
+        simout.reactionvalues = [simout.reactionvalues; sim.reactionvalues(1:end,:)];
+    end
+    % add them here also (since presim might not happen ifg dosing at 0).
+    simout.states = sim.states;
+    simout.variables = sim.variables;
+    simout.reactions = sim.reactions;
+    % Save info for next stage simulation
+    ICnext_values = sim.statevalues(end,:);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Simulate the postpart (only if timevectorpost is not empty)
+% The postpart starts with the application of the LAST dosing amount
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(timevectorpost),
+    dosetime = doseeventstruct_sim(end).time;
+    % Determine the changes to parameters to implement dosing and timing of doses
+    
+    paramchangevalues = [];
+    paramchangenames = {};
+    for k2 = 1:length(doseeventstruct_sim(end).input),
+        paramchangevalues = [paramchangevalues(:)' doseeventstruct_sim(end).input(k2).parametervalues(:)' dosetime];
+        paramchangenames = {paramchangenames{:} doseeventstruct_sim(end).input(k2).parameternames{:} doseeventstruct_sim(end).input(k2).timeparname};
+    end
+    % paramchangevalues and paramchangenames contains the values for dose, time, ka, Tinf, etc that are defined in the dosing scheme
+    % we need to make sure that parameters that are defined in the model or in the parameters that are passed to the IQMsimdosing
+    % function to have priority over the parameters defined in the dosing scheme.
+    % This is done by checking if paramnames has same elements as paramchangenames and then remove these double definitions from the 
+    % paramchangenames and paramchangevalues arrays.
+    double_defined_parameters = intersect(paramchangenames,paramnames);
+    for k2=1:length(double_defined_parameters),
+        % Remove the double defined ones from the paramchangenames and values (parameters passed to the simulation function have priority over definition in 
+        % dosing scheme).
+        indexremove = strmatchIQM(double_defined_parameters{k2},paramchangenames,'exact');
+        paramchangevalues(indexremove) = [];
+        paramchangenames(indexremove) = [];
+        % Report what is done
+%        fprintf('Parameter "%s" passed to IQMsimdosing function has priority over definition of same parameter in dosing scheme.',double_defined_parameters{k2});
+    end
+    
+    paramchangevalues = [paramchangevalues(:)' paramvalues(:)'];
+    paramchangenames = {paramchangenames{:} paramnames{:}};
+
+    % Do simulation of last piece
+    if isIQMproPresent(),
+        sim = IQMPsimulate(MEXmodel,timevectorpost,ICnext_values,paramchangenames,paramchangevalues,OPTIONS);
+    else
+        modelsimhere = IQMparameters(MEXmodel,paramchangenames,paramchangevalues);
+        sim = IQMsimulate(modelsimhere,OPTIONS.method,timevectorpost,ICnext_values,OPTIONS);        
+    end    
+    
+    % Collect simulation results
+    simout.time = [simout.time; sim.time(1:end)];
+    simout.statevalues = [simout.statevalues; sim.statevalues(1:end,:)];
+    simout.variablevalues = [simout.variablevalues; sim.variablevalues(1:end,:)];
+    simout.reactionvalues = [simout.reactionvalues; sim.reactionvalues(1:end,:)];
+    % add them here also (since presim might not happen ifg dosing at 0).
+    simout.states = sim.states;
+    simout.variables = sim.variables;
+    simout.reactions = sim.reactions;    
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Finally, do remove the timepoints that are dosing time points but not
+% defined in the desired simulation time vector.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[values,removeindices] = setdiff(simout.time,timevector);
+while ~isempty(removeindices),
+    simout.time(removeindices) = [];
+    simout.statevalues(removeindices,:) = [];
+    if ~isempty(simout.variables),
+        simout.variablevalues(removeindices,:) = [];
+    end
+    if ~isempty(simout.reactions),
+        simout.reactionvalues(removeindices,:) = [];
+    end
+    [values,removeindices] = setdiff(simout.time,timevector);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Really finally, do remove double definitions of
+% time points, which can happen in the case that
+% dosing and observation time points are the same
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+lengthOLD = Inf;
+% seems that sometimes MATLABis not picking it up correctly, then 
+% we need to redo the exercise :(
+while length(simout.time) ~= lengthOLD,
+    lengthOLD = length(simout.time);
+    
+    [B,I,J] = unique(simout.time);
+    removeindices = setdiff(J,I);
+    simout.time(removeindices) = [];
+    simout.statevalues(removeindices,:) = [];
+    if ~isempty(simout.variables),
+        simout.variablevalues(removeindices,:) = [];
+    end
+    if ~isempty(simout.reactions),
+        simout.reactionvalues(removeindices,:) = [];
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle variable output arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+output = simout;
+if nargout == 1,
+    varargout{1} = output;
+elseif nargout == 0,
+    % prepare data for plotting
+    time = output.time;
+    datanames = {};
+    dataindex = 1;
+    for k = 1:length(output.states),
+        datanames{dataindex} = sprintf('%s (state)',output.states{k});
+        dataindex = dataindex + 1;
+    end
+    for k = 1:length(output.variables),
+        datanames{dataindex} = sprintf('%s (variable)',output.variables{k});
+        dataindex = dataindex + 1;
+    end
+    for k = 1:length(output.reactions),
+        datanames{dataindex} = sprintf('%s (reaction rate)',output.reactions{k});
+        dataindex = dataindex + 1;
+    end
+    datavalues = [output.statevalues, output.variablevalues, output.reactionvalues];
+    IQMplot(createdatastructIQMplotIQM(time,datavalues,datanames));
+else
+    error('Incorrect number of input arguments.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Delete MEX file if created in this function
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isIQMproPresent() && isIQMmodel(moddos),
+    clear mex
+    delete(MEXmodelfullpath);
+end
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/simulation/IQMsimulate.m b/IQMtools V1.2.2.2/IQMlite/tasks/simulation/IQMsimulate.m
new file mode 100644
index 0000000000000000000000000000000000000000..aa0eb9772d0476f4d9306cde307b154e2547de7f
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/simulation/IQMsimulate.m	
@@ -0,0 +1,154 @@
+function [varargout] = IQMsimulate(varargin)
+% IQMsimulate: This function is a wrapper function for two different types of simulation:
+%
+% 1) Simulation of IQMmodels that are automatically converted to MATLAB ODE files
+%           [output] = IQMsimulate(model)         
+%           [output] = IQMsimulate(model,time)         
+%           [output] = IQMsimulate(model,method,time)         
+%           [output] = IQMsimulate(model,method,time,ic)         
+%           [output] = IQMsimulate(model,method,time,ic,options)         
+%
+% 2) Simulation of IQMmodels with IQMdosing schemes
+%           [output] = IQMsimulate(model,dosing)         
+%           [output] = IQMsimulate(model,dosing,time)         
+%           [output] = IQMsimulate(model,dosing,time,ICs)         
+%           [output] = IQMsimulate(model,dosing,time,ICs,paramnames,paramvalues)         
+%           [output] = IQMsimulate(model,dosing,time,ICs,paramnames,paramvalues,OPTIONS)         
+%
+% Both types are distinguished by the 2nd needing an IQMdosing object as second input argument.
+% Full documentation of both types below:s
+%
+% ============================================
+% Documentation of 1st type of use:
+% (documentation for 2nd type below)
+% ============================================
+% Simulates an IQMmodel or an ODE file created by
+% IQMcreateODEfile. In case the model is given as an IQMmodel, not only the 
+% trajectories for the models states are determined, but also the time 
+% trajectories for all variables and reaction rates in the model 
+% 
+% The IQMsimulate function can deal automatically with models that contain 
+% state events. However, this is only possible in the case where a model is
+% specified as an IQMmodel, not as an ODE file model. 
+%
+% USAGE:
+% ======
+% [output] = IQMsimulate(model)         
+% [output] = IQMsimulate(model,time)         
+% [output] = IQMsimulate(model,method,time)         
+% [output] = IQMsimulate(model,method,time,ic)         
+% [output] = IQMsimulate(model,method,time,ic,options)         
+%
+% model: IQMmodel or ODE file model description
+% time: scalar value for simulation end time (default start time is 0),
+%       vector with two elements indicating start and end time, or vector
+%       with time instants for which the simulation results are to be
+%       returned.
+% method: name of a MATLAB integrator (ode45, ode23s, etc.) 
+% ic: initial conditions of the model to be simulated
+% options: standard MATLAB integrator options, set by ODESET
+%
+% DEFAULT VALUES:
+% ===============
+% time: 20 time units (=> tspan: [0 20])
+% method: 'ode23s' ('ode15s' IF algebraic rules present in the model)
+% ic: the initial conditions stored in the model
+% options: []
+%
+% Output Arguments:
+% =================
+% If no output arguments are given, the result of the simulation is plotted
+% 1) online during the simulation for monitoring purposes - the simulation 
+% can here be stopped at every instant by just clicking on the "Stop"
+% button. 2) after the simulation is finished the simulation data is plotted 
+% using the IQMplot function, allowing to browse the data.
+%
+% The output of IQMsimulate is realized as a structure:
+% output.time:              vector with time instants for the results
+% output.states:            cell-array with state names
+% output.statevalues:       matrix with state values. Each row corresponds to
+%                           one time instant.
+%
+% The following fields are only present in case the model as been given
+% as an IQMmodel:
+%
+% output.variables:         cell-array with variable names
+% output.variablevalues:    matrix with variable values. Each row corresponds to
+%                           one time instant.
+% output.reactions:         cell-array with reaction names
+% output.reactionvalues:    matrix with reaction values. Each row corresponds to
+%                           one time instant.
+%
+% ============================================
+% Documentation of 2nd type of use:
+% ============================================
+% IQMsimulatedosing: Simulates the application of a dosing schedule to an IQMmodel with relevant INPUT definitions.
+% This is a wrapper for IQMsimdosing, allowing to not merge model and dosing prior to simulation. 
+% Disadvantage: Only works on IQMmodels and thus requires recompilation with each simulation (if IQM Tools Pro present).
+%
+% USAGE:
+% ======
+% [output] = IQMsimulate(model,dosing)         
+% [output] = IQMsimulate(model,dosing,time)         
+% [output] = IQMsimulate(model,dosing,time,ICs)         
+% [output] = IQMsimulate(model,dosing,time,ICs,paramnames,paramvalues)         
+% [output] = IQMsimulate(model,dosing,time,ICs,paramnames,paramvalues,OPTIONS)         
+%
+% moddos:      IQMmodel with INPUT definitions matching the input definitions in the provided dosing scheme 
+% dosing:      IQMdosing object with dosing information to simulate the model with
+% time:        timevector to simulate. If scalar than the value defines the end
+%              simulation time and the time vector starts at 0. 
+% ICs:         vector with initial conditions
+% paramnames:  string with parameter name or cell-array with parameter-names 
+% paramvalues: vector with values for the parameters (in the same order as paramnames)
+% OPTIONS:     Structure with optional settings for the integrator, 
+%              either defined by odeset() for MATLAB simulation of by the integrator
+%              options setting used in IQMPsimulate.
+%
+% DEFAULT VALUES:
+% ===============
+% time: If not defined or left empty ([]), then the timevector will be
+%   chosen to cover the full dosing schedule +50%
+%   If the only dosing event occurs at time = 0, then a default time of 20 is then used.
+% ICs: [] (use initial conditions, stored in the model)
+% paramnames: []
+% paramvalues: [] (use values stored in the model)
+% OPTIONS: [] (default integrator settings, defined in getDefaultIntegratorOptionsIQM.m)
+%
+% Output Arguments:
+% =================
+% If an output argument is given, this variable will contain a standard
+% simulation result structure containing the time and the state, variable,
+% and reactions names and values. 
+% If no output argument is given, the result is plotted using the IQMplot
+% function.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+% Check which simulation type it is
+if nargin==1,
+    % It is type 1
+    if nargout == 1,
+        varargout{1} = simulateIQM(varargin{:});
+    else
+        simulateIQM(varargin{:});
+    end
+else
+    % Check second argument
+    if isIQMdosing(varargin{2}),
+        % It is type 2
+        if nargout == 1,
+            varargout{1} = simulatedosingIQM(varargin{:});
+        else
+            simulatedosingIQM(varargin{:});
+        end        
+    else
+        % It is type 1
+        if nargout == 1,
+            varargout{1} = simulateIQM(varargin{:});
+        else
+            simulateIQM(varargin{:});
+        end
+    end
+end
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/simulation/IQMstochsim.m b/IQMtools V1.2.2.2/IQMlite/tasks/simulation/IQMstochsim.m
new file mode 100644
index 0000000000000000000000000000000000000000..82803cc85a33c4cee87d1ea3823bdfc289b2cdb4
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/simulation/IQMstochsim.m	
@@ -0,0 +1,186 @@
+function [varargout] = IQMstochsim(model,time,V,varargin)
+% IQMstochsim: Stochastic simulation of IQMmodels that only contain mass
+% action kinetics. The simulator is based on the paper:
+% Ullah, M., Schmidt, H., Cho, K.-H., Wolkenhauer, O. (2006) Deterministic
+% Modelling and Stochastic Simulation of Pathways using MATLAB, 
+% IEE Proceedings - Systems Biology, 153(2), 53-60
+%
+% The IQMmodel needs to have a certain format, explained below.
+%
+% USAGE:
+% ======
+% [output] = IQMstochsim(model,time,V)         
+% [output] = IQMstochsim(model,time,V,units)         
+% [output] = IQMstochsim(model,time,V,units,runs)         
+% [output] = IQMstochsim(model,time,V,units,runs,Nsample)         
+%
+% model:   IQMmodel 
+%          There are certain limitations on an IQMmodel used for stochastic
+%          simulation. Please read further below.
+% time:    End time for simulation 
+% V:       Volume/NumbersFlag: If a number is given then this number is in
+%          interpreted as the volume of the reaction space (given in Liter).
+%          This is necessary in order to do stochastic simulations if the
+%          species in the model are in concentration units.
+%          If the species in the model are given in molecule numbers, the 
+%          volume is not important and this is indicated by setting V to
+%          [].
+% units:   This value is only used in the case that the species are defined
+%          in concentration units. Per default nM (units=1e-9) are assumed
+%          for all species. If the model uses uM the units argument needs
+%          to be set to 1e-6, etc. (default: 1e-9 used only if V has a
+%          numeric value) 
+% runs:    number of realizations(simulation runs) (default: 1)
+% Nsample: Each Nsample-th point will be used for output (to save memory) 
+%          (default: 100)
+%
+% Output Arguments:
+% =================
+% If no output arguments are given, the result of the simulation is
+% plotted (if runs>1 only the mean is plotted). Otherwise the output
+% argument has the following structure:
+%
+% output.time:            cell-array with time vectors for the single runs 
+% output.speciesdata:     cell-array with simulation data for the single runs
+% output.runs:            number of runs
+% output.timemean:        ensemble of all time instants in the single runs
+% output.speciesdatamean: matrix containing the means of the simulation data
+% output.species:         cell-array containing the names of the species
+%
+% FORMAT OF THE IQMmodel:
+% ======================
+% IQMmodels that can be used for stochastic simulation need to follow some
+% rules:
+% 1) All reaction kinetics need to be of mass action type and be defined in
+%    the following syntax:     'ReactionName' = 'kineticParameter' * ...
+% 2) All reactions have to be irreversible. You can use the 
+%    function IQMmakeirreversible to convert your model
+% 3) The reactions can at maximum have 2 substrates and 2 products.
+% 4) The right hand side of the ODEs needs only to consist of reaction rate
+%    terms and eventually stoichiometric coefficients. This is necessary in
+%    order to be able to determine the stoichiometric matrix.
+%    More information about the required syntax can be found in the help
+%    text of the function IQMstoichiometry
+% 5) No variables, functions, events, functionsMATLAB are allowed to be
+%    present.
+% 6) Initial conditions of species are assumed to be given in numbers of
+%    molecules
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle variable input arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+runs = 1;
+Nsample = 100;
+shownr = 0;
+units = 1e-9;
+if nargin == 3,
+elseif nargin == 4,
+    units = varargin{1};
+elseif nargin == 5,
+    units = varargin{1};
+    runs = varargin{2};
+elseif nargin == 6,
+    units = varargin{1};
+    runs = varargin{2};
+    Nsample = varargin{3};
+elseif nargin == 7,
+    units = varargin{1};
+    runs = varargin{2};
+    Nsample = varargin{3};
+    shownr  = varargin{4};
+else
+    error('Incorrect number of input arguments.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Process the model - ALSO TAKES CARE OF NON-NUMERIC ICs
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Convert model to MA structure
+MA = IQMconvert2MA(model);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Obtain necessary data for simulation
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% initial numbers of molecules (or concentration)
+n0 = MA.initialConditions;
+% stoichiometric matrix
+D = MA.N;
+% kinetic parameters
+k = MA.kineticParameters';
+% Stoich coeffs of the reactants (obtained via IQMconvert2MA)
+L = MA.L;
+
+if ~isempty(V),
+    % Models species given in concentrations ... determine stochastic rate
+    % and number of initial molecules
+    % Avogadro's number times volume
+    NAV = V*units*6.02214199e23;
+    % convert concentration to numbers
+    n0 = n0*NAV;
+    % molecularity
+    K = sum(L);
+    % 'particle' rate constant
+    kp = k./NAV.^(K-1);
+    % normalise for correct units
+    kp = kp./units.^(K-1);     
+    % stochastic rate constant
+    c = kp.*prod(factorial(L));
+else
+    % Models species given in numbers ... use the kinetic constants as
+    % stochastic rate constants.
+    c = k;
+end
+
+if shownr == 2,
+    disp('kinetic constant / stochastic rate constant');
+    [k(:) c(:)]
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Stochastic simulation
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[Ts,Ns,TT,NBAR] = stochIQM(n0,c,D,L,time,runs,Nsample,shownr);
+if nargout == 0,
+    % Display mean data
+    datanames = MA.species;
+    IQMplot(TT,NBAR,datanames);
+else
+    % return results in structure
+    output = [];
+    output.time = Ts;
+    output.speciesdata = Ns;
+    output.runs = runs;
+    output.timemean = TT;
+    output.speciesdatamean = NBAR;
+    output.species = MA.species;
+    varargout{1} = output;
+    datanames = MA.species;
+end
+return
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/simulation/auxiliary/convertFastReacModelIQM.m b/IQMtools V1.2.2.2/IQMlite/tasks/simulation/auxiliary/convertFastReacModelIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..d3a57b72fdc98ac6b55a90118539392d2dddee96
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/simulation/auxiliary/convertFastReacModelIQM.m	
@@ -0,0 +1,219 @@
+function [convmodel,K,nrODEsNorm,nrARs,fastIndex] = convertFastReacModelIQM(model)
+% convertFastReacModelIQM
+% Processes a given model which contains fast reactions and returns a
+% converted simulatable model together with the Kernel (left null space) of
+% the fast reaction stoichiometric matrix that needs to be part of the mass
+% matrix for simulation.
+%
+% The function needs to be interactive in the case that moiety
+% conservations are present in the model. ... MAYBE
+%
+% LIMITATION: "stoichiometry math" does not lead to an entry in the
+% stoichiometric matrix and thus might lead to wrong results if in
+% combination with fast reactions.
+%
+% USAGE:
+% ======
+% [convmodel,K,nrODEsNorm,nrARs,fastIndex] = convertFastReacModelIQM(model)
+%
+% model: IQMmodel to process
+%
+% Output Arguments:
+% =================
+% convmodel: converted model that can be simulated (using K as part of the
+%   mass matrix).
+% K: left null space of the fast reaction stoichiometric matrix that needs to
+%   be part of the mass matrix for simulation.
+% nrODEsNorm: number of the ODEs that are not affected by the
+%   transformation (these come first).
+% nrARs: number of the algebraic rules that have been added due to the fast
+%   reactions.
+% fastIndex: indices of the fast reactions
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF IQMmodel
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isIQMmodel(model),
+    error('Function only defined for IQMmodels.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE NON-NUMERIC INITIAL CONDITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% just by replacing them
+model = IQMconvertNonNum2NumIC(model);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF fast flag present in the model
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~usefastIQM(model),
+    error('The model does not contain any fast reactions.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF MOIETY CONSERVATIONS ARE PRESENT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%
+if hasmoietyconservationsIQM(model),
+    error(sprintf('The model contains moiety conservations. Please reduce these conservations laws\nusing the ''IQMreducemodel'' function prior to running the previous function.\n\nThe reason for not reducing the model automatically is the fact that sometimes\nit is necessary to choose a tolerance setting manually in order to obtain correct\nreduction results.'));
+end    
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DETERMINE THE STOICHIOMETRIC MATRIX (RAW settings)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[N,componentNames,reactionNames] = IQMstoichiometry(model,1,1);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET THE FAST REACTIONS AND SPLIT N INTO Nf AND Ns
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[reac_names,reac_formulas,reversibleFlag,fastFlag] = IQMreactions(model);
+fastIndex = find(fastFlag~=0);
+slowIndex = [1:length(reac_names)];
+slowIndex(fastIndex) = [];
+Nf = N(:,fastIndex);
+Ns = N; Ns(:,fastIndex) = [];
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DETERMINE THE LEFT NULL SPACE OF Nf (K)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[U,S,V] = svd(Nf);
+K = U(rank(Nf)+1:end,:);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CONSTRUCT THE NEW MODEL
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ms = struct(model);
+cms = struct(IQMmodel());
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% COPY THE UNCHANGED STUFF
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% FUNCTIONS
+cms.functions = ms.functions;
+% FUNCTIONSMATLAB
+cms.functionsMATLAB = ms.functionsMATLAB;
+% REACTIONS 
+cms.reactions = ms.reactions;
+% VARIABLES
+cms.variables = ms.variables;
+% PARAMETERS
+cms.parameters = ms.parameters;
+% EVENTS
+cms.events = ms.events;
+% NAME
+cms.name = [ms.name,'_(converted_to_handle_fast_reactions)'];
+% NOTES
+cms.notes = sprintf('PLEASE NOTE: This model has been converted due to fast reactions in the\noriginal model. Direct simulation is not possible / does lead to an\nerroneous behavior. The null space matrix K needs to be taken into account\nwhen building the ODE m-file and additionally it needs to be part of the\nmass-matrix that is used for integration.\n\n%s',ms.notes);
+% ALGEBRAIC (just copy the ones that have been in the model from the start)
+cms.algebraic = ms.algebraic;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% COPY THE ODEs NOT BEING PART OF THE STOICHIOMETRIC MATRIX
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+nonReacStates = setdiff(IQMstates(model),componentNames);
+nonReacStatesIndex = stateindexIQM(model,nonReacStates);
+cms.states = ms.states(nonReacStatesIndex);
+nrODEsNorm = length(cms.states);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% BUILD THE ALGEBRAIC RULES (0 = Nf*vf)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+vf = reac_names(fastIndex);
+% process Nf
+Nf = rref(Nf);
+% remove zero rows 
+Nf(find(sum(abs(Nf),2)==0),:) = [];
+% build ARs
+nrARs = 0;
+for k=1:size(Nf,1),
+    Nfk = Nf(k,:);
+    ARk = '';
+    for k2 = 1:length(Nfk),
+        if Nfk(k2) > 0,
+            ARk = sprintf('%s+%g*%s',ARk,Nfk(k2),vf{k2});
+        elseif Nfk(k2) < 0,
+            ARk = sprintf('%s-%g*%s',ARk,abs(Nfk(k2)),vf{k2});
+        end
+    end
+    if ~isempty(ARk),
+        % add the AR to the model structure
+        cms.algebraic(end+1).name = '';
+        cms.algebraic(end).formula = ARk;
+        cms.algebraic(end).initialCondition = [];
+        cms.algebraic(end).notes = 'Algebraic rule due to fast reactions';
+        nrARs = nrARs + 1;
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% BUILD THE REAC ODEs (Ns*vs)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Remove states if Nsk only zeros (then a state is only defined by a fast
+% reaction and it should be added as variable to the corresponding
+% algebraic rule. 
+vs = reac_names(slowIndex);
+addStatesToARs = {};
+addStatesToARsICs = [];
+for k=1:length(componentNames),
+    Nsk = Ns(k,:);
+    if sum(abs(Nsk)) ~= 0,
+        % copy the easy information
+        cms.states(end+1).name = componentNames{k};
+        index = stateindexIQM(model,componentNames{k});
+        cms.states(end).notes = ms.states(index).notes;
+        cms.states(end).initialCondition = ms.states(index).initialCondition;
+        cms.states(end).type = ms.states(index).type;
+        cms.states(end).unittype = ms.states(index).unittype;
+        cms.states(end).compartment = ms.states(index).compartment;
+        % construct the ODE
+        ODEk = '';
+        for k2 = 1:length(Nsk),
+            if Nsk(k2) > 0,
+                ODEk = sprintf('%s+%g*%s',ODEk,Nsk(k2),vs{k2});
+            elseif Nsk(k2) < 0,
+                ODEk = sprintf('%s-%g*%s',ODEk,abs(Nsk(k2)),vs{k2});
+            end
+        end
+        cms.states(end).ODE = ODEk;
+    else
+        addStatesToARs{end+1} = componentNames{k};
+        index = stateindexIQM(model,componentNames{k});
+        addStatesToARsICs(end+1) = ms.states(index).initialCondition;
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% ADD STATES TO ARs IF REMOVED AS STATES SINCE ONLY DETERMINED BY FAST REACTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for k=1:length(addStatesToARs),
+    for k2=1:length(cms.algebraic),
+        % where these names are added is unimportant. so just add them to 
+        % the ARs appearing first and having no vars assigned
+        if isempty(cms.algebraic(k2).name),
+            cms.algebraic(k2).name = addStatesToARs{k};
+            cms.algebraic(end).initialCondition = addStatesToARsICs(k);
+            % continue with next state to add
+            break;
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHANGE NULLSPACE IN THE CASE THAT Ns HAS ZERO ROWS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Comments: A.Soubret 27/10/2009
+% The function below do not works since we need to keep all the column of
+% the matrix for the mass matrix, i.e. K*dx_dt
+% Determine zero rows in Ns
+%nonzeroindices = find(sum(abs(Ns'))~=0);
+% Keep only the corresponding COLUMNS of K
+%K = K(:,nonzeroindices);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% MAKE IQMmodel
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+convmodel = IQMmodel(cms);
+
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/simulation/auxiliary/eventsimulateIQM.m b/IQMtools V1.2.2.2/IQMlite/tasks/simulation/auxiliary/eventsimulateIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..bc2919417e11109ea50fa54ed2aaad20d0467364
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/simulation/auxiliary/eventsimulateIQM.m	
@@ -0,0 +1,100 @@
+function [t,x,te,xe,ie,parameterValuesNew_ALL] = eventsimulateIQM(model,method,tspan,ic,options,eventFunction,eventAssignmentFunction)
+% eventsimulateIQM: Function realizing the simulation of systems with events
+% that cause discrete state changes. Implementation as auxiliary function
+% in order to be able to reuse the code when simulating systems with events
+% during parameter sensitivity analysis.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+parameterValuesNew = []; % for changing parameter values using events
+parameterValuesNew_ALL = []; % save new parameter values for later generation of data ...
+nominalParameters = feval(model,'parametervalues')';
+
+% initialize simulation results
+t = [];
+x = [];
+te = [];
+xe = [];
+ie = [];
+% add the eventFunction to the integrator options
+options = odeset(options,'Events',eventFunction);
+
+
+% simulate the system until end time is reached
+% in case the user provided a defined time instant vector when results are
+% to be returned, it is necessary to delete 2 event instants from the
+% vectors ...
+% in case that the event time is not a measured time instant then delete
+% the last element from the previous piece and the first element from the
+% following piece
+% in case that the event time is a member of tspan, the last two elements
+% of the previous simulation data should be deleted. 
+tspansim = tspan;
+deleteFirstElementNext = 0;
+while 1,
+    % Do the simulation until event or finished
+    parameterValuesNew = parameterValuesNew(:)';    
+    [tpiece,xpiece,tepiece,xepiece,iepiece] = eval(sprintf('feval(@%s,@%s,tspansim,ic,options,parameterValuesNew);',method,model));
+    % get the state and final piece time
+    pieceEndState = xpiece(end,:);
+    pieceEndTime = tpiece(end);
+    % check if an event has happened
+    if ~isempty(tepiece) && max(tepiece) == pieceEndTime,
+        % an event has happened ... 
+        eventTime = tepiece(end);
+        eventIndex = iepiece(end);        
+        % just delete the last element (its the event time anyway)
+        if eventTime ~= max(tspan),        
+            tpiece = tpiece(1:end-1);
+            xpiece = xpiece(1:end-1,:);
+        end
+    end
+    
+    % collect simulation data
+    t = [t; tpiece];
+    x = [x; xpiece];
+    te = [te; tepiece(:)]; 
+    ie = [ie; iepiece(:)];
+    xe = [xe; xepiece];
+    
+    if length(tspan) > 2,
+        % time vector given ...
+        % delete the time instants that DO NOT appear in
+        % the time span vector
+        index = find(~ismember(t,tspan));
+        t(index) = [];
+        x(index,:) = [];
+        
+        % if the event is at a value in the time vector give, 
+        % then must remove the first instance of this time point
+        [b m] = unique(t, 'last');
+        t = t(m);
+        x = x(m, :);
+    end
+    
+    % save parameter values for this piece
+    if isempty(parameterValuesNew),
+        parameterValuesNew_ALL = [parameterValuesNew_ALL; nominalParameters(ones(1,length(tpiece)),:)];
+    else
+        parameterValuesNew_ALL = [parameterValuesNew_ALL; parameterValuesNew(ones(1,length(tpiece)),:)];
+    end
+
+    % check if integration is finished - then break the loop and continue
+    if pieceEndTime >= max(tspansim),
+        break;
+    end
+
+    % set new initial conditions and new time vector for simulation
+    [ic,parameterValuesNew] = feval(eventAssignmentFunction,eventIndex,eventTime,pieceEndState,parameterValuesNew);
+    % set new tspansim
+    if length(tspansim) == 2,
+        % if tspansim has 2 elements:
+        tspansim = [eventTime tspansim(2)];
+    else
+        % if tspansim given as vector of time instants
+        tspansimhelp = tspansim(find(tspansim > eventTime));
+        tspansim = [eventTime tspansimhelp(:)'];
+    end
+end
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/simulation/auxiliary/simulateIQM.m b/IQMtools V1.2.2.2/IQMlite/tasks/simulation/auxiliary/simulateIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..3f5ed9cb4b559ccbb1fb0c7c09d7f1a1cef2832e
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/simulation/auxiliary/simulateIQM.m	
@@ -0,0 +1,352 @@
+function [varargout] = simulateIQM(varargin)
+% Simulates an IQMmodel or an ODE file created by
+% IQMcreateODEfile. In case the model is given as an IQMmodel, not only the 
+% trajectories for the models states are determined, but also the time 
+% trajectories for all variables and reaction rates in the model 
+% 
+% The IQMsimulate function can deal automatically with models that contain 
+% state events. However, this is only possible in the case where a model is
+% specified as an IQMmodel, not as an ODE file model. 
+%
+% USAGE:
+% ======
+% [output] = simulateIQM(model)         
+% [output] = simulateIQM(model,time)         
+% [output] = simulateIQM(model,method,time)         
+% [output] = simulateIQM(model,method,time,ic)         
+% [output] = simulateIQM(model,method,time,ic,options)         
+%
+% model: IQMmodel or ODE file model description
+% time: scalar value for simulation end time (default start time is 0),
+%       vector with two elements indicating start and end time, or vector
+%       with time instants for which the simulation results are to be
+%       returned.
+% method: name of a MATLAB integrator (ode45, ode23s, etc.) 
+% ic: initial conditions of the model to be simulated
+% options: standard MATLAB integrator options, set by ODESET
+%
+% DEFAULT VALUES:
+% ===============
+% time: 20 time units (=> tspan: [0 20])
+% method: 'ode23s' ('ode15s' IF algebraic rules present in the model)
+% ic: the initial conditions stored in the model
+% options: []
+%
+% Output Arguments:
+% =================
+% If no output arguments are given, the result of the simulation is plotted
+% 1) online during the simulation for monitoring purposes - the simulation 
+% can here be stopped at every instant by just clicking on the "Stop"
+% button. 2) after the simulation is finished the simulation data is plotted 
+% using the IQMplot function, allowing to browse the data.
+%
+% The output of IQMsimulate is realized as a structure:
+% output.time:              vector with time instants for the results
+% output.states:            cell-array with state names
+% output.statevalues:       matrix with state values. Each row corresponds to
+%                           one time instant.
+%
+% The following fields are only present in case the model as been given
+% as an IQMmodel:
+%
+% output.variables:         cell-array with variable names
+% output.variablevalues:    matrix with variable values. Each row corresponds to
+%                           one time instant.
+% output.reactions:         cell-array with reaction names
+% output.reactionvalues:    matrix with reaction values. Each row corresponds to
+%                           one time instant.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+parameterValuesNew_ALL = []; % for handling events on parameters
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INITIALIZE STUFF
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+t = [];
+x = [];
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DEAL WITH VARIABLE ARGUMENT NUMBER
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin == 1,
+    model = varargin{1};
+    method = 'ode23s';
+    tspan = [0 20];
+    ic = [];
+    options = [];
+elseif nargin == 2,
+    model = varargin{1};
+    method = 'ode23s';
+    if length(varargin{2}) == 1,
+        tspan = [0 varargin{2}];
+    else
+        tspan = varargin{2};
+    end
+    ic = [];
+    options = [];
+elseif nargin == 3,
+    model = varargin{1};
+    method = varargin{2};
+    if length(varargin{3}) == 1,
+        tspan = [0 varargin{3}];
+    else
+        tspan = varargin{3};
+    end
+    ic = [];
+    options = [];
+elseif nargin == 4,
+    model = varargin{1};
+    method = varargin{2};
+    if length(varargin{3}) == 1,
+        tspan = [0 varargin{3}];
+    else
+        tspan = varargin{3};
+    end
+    ic = varargin{4};
+    options = [];
+elseif nargin == 5,
+    model = varargin{1};
+    method = varargin{2};
+    if length(varargin{3}) == 1,
+        tspan = [0 varargin{3}];
+    else
+        tspan = varargin{3};
+    end
+    ic = varargin{4};
+    options = varargin{5};
+else
+    error('Incorrect number of input arguments');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% STUPID HANDLING OF 0 STATE MODELS (HALLELUJA SBML)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isIQMmodel(model) && nargout == 1,
+    if isfield(options,'stupidstupidsbml'),
+        if options.stupidstupidsbml == 1,
+            if isempty(IQMstates(model)),
+                varargout{1} = handle0statemodel4SBML(model,tspan);
+                return
+            end
+        end
+    end
+end
+    
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% ADD PIECEWISE TRIGGERS AS EVENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isIQMmodel(model),
+    model = addpiecewiseeventsIQM(model);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% IF DELAYS AND/OR EVENTS ARE PRESENT THEN USE A DEFAULT MAXSTEP
+% Only do that in case of an IQMmodel
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isIQMmodel(model),
+    if usedelayIQM(model) || useeventIQM(model),
+        if ~isfield(options,'MaxStep'),
+            % change only if not user provided 
+            options = odeset(options,'MaxStep',tspan(end)/1000);
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF IQMmodel AND FAST REACTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fastFlag = 0;
+fastIndex = [];
+if isIQMmodel(model),
+    if usefastIQM(model),
+        [model,K,nrODEsNorm,nrARs,fastIndex] = convertFastReacModelIQM(model);
+        % create global variable for the kernel
+        [a,b] = fileparts(tempname);
+        augmKernelName = sprintf('kernel_augm_%s',b);
+        eval(sprintf('global %s',augmKernelName));
+        fastFlag = 1;
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE ALGEBRAIC RULES IF PRESENT!
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ARnames = IQMalgebraic(model);
+ARpresent = 0;
+if ~isempty(ARnames),
+    ARpresent = 1;
+    % override integrator selection
+    method = 'ode15s';
+    % determine the mass matrix (take into account the kernel coming from
+    % the fast reactions if necessary)
+    STnames = IQMstates(model);
+    if ~fastFlag,
+        % no fast reactions
+        massM = zeros(length(ARnames)+ length(STnames));
+        massM(1:length(STnames),1:length(STnames)) = eye(length(STnames));
+    else
+        % fast reactions
+        % build the mass matrix
+        massM = zeros(nrODEsNorm+size(K,1)+length(ARnames));
+        massM(1:nrODEsNorm,1:nrODEsNorm) = eye(nrODEsNorm);
+        massM(nrODEsNorm+1:nrODEsNorm+size(K,1),nrODEsNorm+1:nrODEsNorm+size(K,2)) = K;
+        % build the matrix to multiply the ODEs with
+        augmKernelValue = zeros(nrODEsNorm+size(K,1),nrODEsNorm+size(K,2));
+        augmKernelValue(1:nrODEsNorm,1:nrODEsNorm) = eye(nrODEsNorm);
+        augmKernelValue(nrODEsNorm+1:nrODEsNorm+size(K,1),nrODEsNorm+1:nrODEsNorm+size(K,2)) = K;
+        %Remove the column corrsponding to the algebraic equations since
+        %the model does not contain them in the multiplication K*states
+        %augmKernelValue=augmKernelValue(:,1:size(augmKernelValue,2)-nrARs); 
+        eval(sprintf('%s = augmKernelValue;',augmKernelName));
+    end
+    % add the mass matrix to the options
+    options = odeset(options,'Mass',massM);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK NUMBER OF OUTPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargout ~= 0 && nargout ~= 1,
+    error('Incorrect number of output arguments');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS IQMMODEL OR ODE FILE - CHECK IF EVENTS PRESENT IN IQMmodel
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+eventFlag = 0;
+if strcmp('IQMmodel',class(model)),
+    % check for events
+    if ~isempty(IQMevents(model)) > 0,
+        eventFlag = 1;
+    end
+    if fastFlag == 0,
+        [ODEfctname, ODEfilefullpath, DATAfctname, EVENTfctname, EVENTASSGNfctname] = IQMcreateTempODEfile(model,1,eventFlag);
+    else
+        [ODEfctname, ODEfilefullpath, DATAfctname, EVENTfctname, EVENTASSGNfctname] = IQMcreateTempODEfile(model,1,eventFlag,augmKernelName);
+    end        
+else
+    % ODEfctname of ODE file
+    ODEfctname = model;
+    % Check if file exists
+    if exist(strcat(ODEfctname,'.m')) ~= 2,
+        error('ODE file could not be found.');
+    end
+end
+ 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% UPDATE INITIAL CONDITIONS (also handles non-numeric initial conditions)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% idea: if ic provided by user then use these. otherwise get the initial
+% conditions stored in the model. if non-numeric then calculate them
+if isempty(ic),
+    % Handle also non-numeric initial condition
+    ic = IQMcalcICvector(ODEfctname);
+    % gumpehe1: reverting these changes as initial conditions for the AR
+    % are required for the MATLAB ODE solvers
+    % % If algebraic rules present then we need to add the ICs of these at the end
+    % % algebraic ICs can NOT be non-numeric => always numeric
+    %     ic_algebraic = [];
+    %     allICs = feval(ODEfctname);
+    %     for k=1:length(ARnames),
+    %         ic_algebraic(end+1) = allICs{end-length(ARnames)+k};
+    %     end
+    %     ic = [ic(:)' ic_algebraic(:)'];
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% IF NO OUTPUT ARGUMENTS GIVEN THEN DISPLAY ONLINE INFORMATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargout == 0,
+    figure; drawnow;
+    options = odeset(odeset(options),'OutputFcn',@odeplot);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% SIMULATE MODEL WITH GIVEN METHOD (DIFFERENT HANDLING IN CASE OF EVENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if eventFlag == 0,
+    eval(sprintf('[t,x] = %s(@%s,tspan,ic,options);',method,ODEfctname));
+else
+    % handle the events that are present in the model
+    [t,x,dummy1,dummy2,dummy3,parameterValuesNew_ALL] = eventsimulateIQM(ODEfctname,method,tspan,ic,options,EVENTfctname,EVENTASSGNfctname);
+end
+    
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CLOSE ONLINE PLOT AGAIN IF IT WAS PRESENT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargout == 0,
+    close gcf;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DETERMINE OUTPUT VARIABLE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+output.time = t;
+output.states = IQMstates(ODEfctname)';
+output.statevalues = x(:,1:length(output.states));
+if strcmp('IQMmodel',class(model)),
+    % determine the simulation data using the 'DATAfctname'
+    [dataoutput] = feval(DATAfctname,t,x,parameterValuesNew_ALL);
+    if isfield(dataoutput,'algebraic'),
+        output.algebraic = dataoutput.algebraic;
+        output.algebraicvalues = dataoutput.algebraicvalues;
+    end
+    output.variables = dataoutput.variables;
+    output.variablevalues = dataoutput.variablevalues;
+    output.reactions = dataoutput.reactions;
+    output.reactionvalues = dataoutput.reactionvalues;
+end
+if nargout == 0,
+    % prepare data for plotting
+    time = output.time;
+    datanames = {};
+    dataindex = 1;
+    for k = 1:length(output.states),
+        datanames{dataindex} = sprintf('%s (state)',output.states{k});
+        dataindex = dataindex + 1;
+    end
+    if isfield(output,'algebraic'),
+        for k = 1:length(output.algebraic),
+            datanames{dataindex} = sprintf('%s (algebraic)',output.algebraic{k});
+            dataindex = dataindex + 1;
+        end
+    end
+    if strcmp('IQMmodel',class(model)),
+        for k = 1:length(output.variables),
+            datanames{dataindex} = sprintf('%s (variable)',output.variables{k});
+            dataindex = dataindex + 1;
+        end
+        for k = 1:length(output.reactions),
+            if ~ismember(k,fastIndex),
+                datanames{dataindex} = sprintf('%s (reaction rate)',output.reactions{k});
+            else    
+                datanames{dataindex} = sprintf('%s (reaction rate - fast)',output.reactions{k});
+            end
+            dataindex = dataindex + 1;
+        end
+        if isfield(output,'algebraic'),
+            datavalues = [output.statevalues, output.algebraicvalues, output.variablevalues, output.reactionvalues];
+        else
+            datavalues = [output.statevalues, output.variablevalues, output.reactionvalues];
+        end            
+    else
+        datavalues = [output.statevalues];
+    end
+    IQMplot(createdatastructIQMplotIQM(time,datavalues,datanames));
+elseif nargout == 1,
+    varargout{1} = output;
+else 
+    error('Incorrect number of output arguments!');
+end
+
+% Delete all temporary files (if IQMmodel)
+if isIQMmodel(model),
+    IQMdeleteTempODEfile(ODEfilefullpath);
+end
+
+% clear temp global variables
+if fastFlag == 1,
+    eval(sprintf('clear global %s',augmKernelName));
+end
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/simulation/auxiliary/simulatedosingIQM.m b/IQMtools V1.2.2.2/IQMlite/tasks/simulation/auxiliary/simulatedosingIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..3af397d1231bbd0b595252976f6d72d291998c8b
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/simulation/auxiliary/simulatedosingIQM.m	
@@ -0,0 +1,62 @@
+function [varargout] = IQMsimulatedosing(model,dosing,varargin)
+% IQMsimulatedosing: Simulates the application of a dosing schedule to an IQMmodel with relevant INPUT definitions.
+% This is a wrapper for IQMsimdosing, allowing to not merge model and dosing prior to simulation. 
+% Disadvantage: Only works on IQMmodels and thus requires recompilation with each simulation (if IQM Tools Pro present).
+%
+% USAGE:
+% ======
+% [output] = IQMsimulatedosing(model,dosing)         
+% [output] = IQMsimulatedosing(model,dosing,time)         
+% [output] = IQMsimulatedosing(model,dosing,time,ICs)         
+% [output] = IQMsimulatedosing(model,dosing,time,ICs,paramnames,paramvalues)         
+% [output] = IQMsimulatedosing(model,dosing,time,ICs,paramnames,paramvalues,OPTIONS)         
+%
+% moddos:      IQMmodel with INPUT definitions matching the input definitions in the provided dosing scheme 
+% dosing:      IQMdosing object with dosing information to simulate the model with
+% time:        timevector to simulate. If scalar than the value defines the end
+%              simulation time and the time vector starts at 0. 
+% ICs:         vector with initial conditions
+% paramnames:  string with parameter name or cell-array with parameter-names 
+% paramvalues: vector with values for the parameters (in the same order as paramnames)
+% OPTIONS:     Structure with optional settings for the integrator, 
+%              either defined by odeset() for MATLAB simulation of by the integrator
+%              options setting used in IQMPsimulate.
+%
+% DEFAULT VALUES:
+% ===============
+% time: If not defined or left empty ([]), then the timevector will be
+%   chosen to cover the full dosing schedule +50%
+%   If the only dosing event occurs at time = 0, then a default time of 20 is then used.
+% ICs: [] (use initial conditions, stored in the model)
+% paramnames: []
+% paramvalues: [] (use values stored in the model)
+% OPTIONS: [] (default integrator settings, defined in getDefaultIntegratorOptionsIQM.m)
+%
+% Output Arguments:
+% =================
+% If an output argument is given, this variable will contain a standard
+% simulation result structure containing the time and the state, variable,
+% and reactions names and values. 
+% If no output argument is given, the result is plotted using the IQMplot
+% function.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+% Check model and dosing
+if ~isIQMmodel(model),
+    error('First input argument is not an IQMmodel.');
+end
+if ~isIQMdosing(dosing),
+    error('Second input argument is not an IQMdosing object.');
+end
+
+% Combine model and dosing to prepare for IQMsimdosing
+moddos = mergemoddosIQM(model,dosing);
+
+% Call IQMsimdosing
+if nargout ~= 0,
+    varargout{1} = IQMsimdosing(moddos,dosing,varargin{:});
+else
+    IQMsimdosing(moddos,dosing,varargin{:});
+end
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tasks/simulation/auxiliary/stochIQM.m b/IQMtools V1.2.2.2/IQMlite/tasks/simulation/auxiliary/stochIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..df0ca6ee7a16de2856b2189ee4848b41f2d32ae1
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tasks/simulation/auxiliary/stochIQM.m	
@@ -0,0 +1,129 @@
+function [Ts,Ns,TT,NBAR] = stochIQM(n0,c,d,l,tf,runs,Nsample,shownr)
+% stochIQM: performs stochastic simulation of biochemical networks
+%   elementary reactions, using the Gillespie algorithm. The input and 
+%   output arguments have the following meaning:
+%   
+%   n0: Column Vector of initial populations of all the species involved 
+%   c: Row vector of stochastic rate constants of all elementary reactions
+%   d: Stoichiometry matrix with rows correspoding to species and columns
+%      corresponding to reaction channels
+%   l: Stoichiometry matrix for reactants only such that L = -D.*(D < 0); 
+%   tf: Final time of simulation    
+%   runs: Number of simulation runs to perform
+%   Nsample: output frequency
+%
+%   Ts: Cell-array of vectors of time points of reaction events
+%   Ns: Cell-array of matrices of output concentrations with a row for 
+%       each time point.
+%   TT: Vector of the ensemble of time points over all runs
+%   NBAR: Matrix with mean simulation results
+%   
+%   [Ts,Ns] = stochIQM(n0,c,d,l,tf,runs)
+%   [Ts,Ns,TT,NBAR] = stochIQM(n0,c,d,l,tf,runs)
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% preliminary operations:
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+oneszk = ones(size(c));
+i1 = l==1;                              % reactions of type: A->B, A+B->AB
+i2 = l==2;                              % reactions of type: A+A->AA
+stop = tf - eps(tf);                    % simulation stop time
+nOut = nargout;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% stochastic part:
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+TT = [];
+NBAR = [];
+if runs < 2      
+    % single run
+    [Ts,Ns] = gillespie;                       
+    TT = Ts;
+    NBAR = Ns;
+else
+    % multiple runs
+    Ts = {};
+    Ns = {};
+    for i = 1:runs, 
+        if shownr ~= 0,
+            disp(sprintf('IQMstochsim simulation run: #%d',i));
+            drawnow;
+        end
+        [Tsi,Nsi] = gillespie;                 
+        Ts{i} = Tsi;
+        Ns{i} = Nsi;
+        % calculate the mean value of the realizations
+        if i==1,
+            TT = Tsi; % use this time vector for interpolation
+            NBAR = zeros(length(n0),length(TT));
+        end
+        for k=1:length(n0),
+            NBAR(k,:) = NBAR(k,:) + interp1(Tsi,Nsi(k,:),TT,'nearest')/runs;
+        end
+    end 
+end
+% transpose the results
+TT = TT';
+NBAR = NBAR';
+if runs > 1,
+    for k=1:runs,
+        Ts{k} = Ts{k}';
+        Ns{k} = Ns{k}';
+    end
+else
+    Ts = {Ts'};
+    Ns = {Ns'};
+end
+% finished
+
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    %   gillespie algorithm (direct method):
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    function [tt,nn] = gillespie
+        t = 0;                                  % initial time
+        n = n0;                                 % initial population
+        % allocate a bit "to much" memory ... delete afterwards what is not needed
+        % (defined by trailing zeros in the time vector)
+        tt = zeros(1,2*length(TT));
+        nn = zeros(length(n0),2*length(TT));
+        k = 1;                                  % set counter
+        nsamplek = 0;                           % set sampling counter
+        while t <= stop,
+            nsamplek = nsamplek + 1;
+            if nsamplek == 1,
+                tt(k) = t;                      % record time (only Nsample-th)
+                nn(:,k) = n;                    % record population (only Nsample-th)
+                k = k + 1;                      % increment counter
+            end
+            if nsamplek >= Nsample,
+                nsamplek = 0;
+            end
+            m = n(:,oneszk);                % replicate n : size(m,2) = size(k)
+            b = double(~l);
+            b(i1) = m(i1);                  % reactions of type: A->B, A+B->AB
+            b(i2) = m(i2).*(m(i2)-1)/2;     % reactions of type: A+A->AA
+            a = c.*prod(b);                 % propensity
+            astr = sum(a);
+            if ~astr, break, end            % substrate utilised
+            tau = -1/astr*log(rand);        % time to next reaction
+            u = find(cumsum(a)>=astr*rand,1);% index of next reaction
+            n = n + d(:,u);                 % update population
+            t = t + tau;                    % update time
+        end
+        % add last result to nn and tt (only if t smaller than the max time)
+        if t < stop && tt(k-1)~=t,
+            nn(:,k) = n;
+            tt(k) = t;
+        end
+        % find trailing zero elements in tt and delete the corresponding
+        % elements from tt and nn
+        index = find(tt==0);
+        if length(index) > 1,
+            tt(index(2:end)) = [];
+            nn(:,index(2:end)) = [];
+        end
+        % add final time point (it is very certainly not present otherwise)
+        tt = [tt tf];
+        nn = [nn nn(:,end)];        
+    end
+end
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/dataset/IQMdataset2wide.m b/IQMtools V1.2.2.2/IQMlite/tools/dataset/IQMdataset2wide.m
new file mode 100644
index 0000000000000000000000000000000000000000..e6e2a0125ce4b1303eb8330a9429bae0872518a3
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/dataset/IQMdataset2wide.m	
@@ -0,0 +1,33 @@
+function [datawide] = IQMdataset2wide(data,paramnames,paramvalues)
+% This function expands a dataset from a row based format to a column based 
+% format. Records in the row based format are stored in rows, while a parameter
+% column defines the type/name of the recorded parameter. In the column  based 
+% format there is a column for each measured parameter with the column name as
+% the parameters name. 
+% The name of the columns with the parameternames and values need to be provided.
+% 
+% This function will return an empty table (error) if there are columns wit NaN values.
+%
+% [SYNTAX]
+% datawide = IQMdataset2wide(data,paramnames,paramvalues)
+%
+% [INPUT]
+% data:         MATLAB TABLE object in row format
+% paramnames:   string: name of the column in which the parameter names are recorded
+% paramvalues:  string: name of the column in which the parameter values are recorded
+%
+% [OUTPUT]
+% datawide:     dataset in wide format (one column per parameter)
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%% Check version number (>=R2013B required)
+if verLessThan('matlab','8.2.0'),
+    error('The dataset import/export functions in IQM Tools Lite require at least MATLAB R2013B.');
+end
+
+datawide = unstack(data,paramvalues,paramnames);
+
+if isempty(datawide),
+    error('Please check if the dataset to convert contains NaN values.');
+end
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/dataset/IQMexportCSVdataset.m b/IQMtools V1.2.2.2/IQMlite/tools/dataset/IQMexportCSVdataset.m
new file mode 100644
index 0000000000000000000000000000000000000000..22d94d462b7c972ad0d338937d764e251d7051f6
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/dataset/IQMexportCSVdataset.m	
@@ -0,0 +1,70 @@
+function [] = IQMexportCSVdataset(data,filename,FLAG_QUOTE)
+% This function exports a MATLAB table as standard comma separated (CSV) datafile. 
+% Nothing magic, just avoiding a lengthy "export" command and allowing similar
+% naming of functions as in previous versions.
+%
+% [SYNTAX]
+% [] = IQMexportCSVdataset(data,filename)
+% [] = IQMexportCSVdataset(data,filename,FLAG_QUOTE)
+%
+% [INPUT]
+% data:         MATLAB table object
+% filename:     Filename, possibly including relative or absolute path.
+%               Extension does not be provided ('.csv' will always be used).
+% FLAG_QUOTE:   =0 (default): do not put "quotes" around strings. =1: do it
+%               This option is ignored prior to MATLAB R2015A.
+%
+% [OUTPUT]
+% CSV file with 'filename.csv'. If the filename also includes a path to  folder
+% it will be exported there. If this folder does not yet exist, it will be created.
+ 
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%% Check version number (>=R2013B required)
+if verLessThan('matlab','8.2.0'),
+    error('The dataset import/export functions in IQM Tools Lite require at least MATLAB R2013B.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check input argument
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~ischar(filename),
+    error('Please provide a filename as second input argument.');
+end
+if ~istable(data),
+    error('The first input argument needs to be a MATLAB TABLE object.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle variable inpute arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin == 2,
+    FLAG_QUOTE = false;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Create folder if needed
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[p,f] = fileparts(filename);
+if ~isempty(p),
+    warning off
+    mkdir(p);
+    warning on
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Create filename with extension
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+filename = fullfile(p,[f '.csv']);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Export dataset
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try
+    writetable(data,filename,'Delimiter',',','FileType','text','WriteVariableNames',true,'WriteRowNames',false,'QuoteStrings',FLAG_QUOTE);
+catch
+    writetable(data,filename,'Delimiter',',','FileType','text','WriteVariableNames',true,'WriteRowNames',false);
+end    
+
+
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/dataset/IQMgetdatasetHeader.m b/IQMtools V1.2.2.2/IQMlite/tools/dataset/IQMgetdatasetHeader.m
new file mode 100644
index 0000000000000000000000000000000000000000..cbea402800cc2c6b6f75e22a8c5629c3d07aa359
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/dataset/IQMgetdatasetHeader.m	
@@ -0,0 +1,27 @@
+function [colnames] = IQMgetdatasetHeader(data)
+% This function returns the column names of the dataset in a cell-array.
+% Input dataset can be a MATLAB table or a string with the path to a
+% csv file.
+%
+% [SYNTAX]
+% colnames = IQMgetdatasetHeader(data)
+%
+% [INPUT]
+% data:         MATLAB TABLE object or string with path to a CSV dataset
+%
+% [OUTPUT]
+% colnames:     Column names of dataset in cell-array
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+% Check input
+if istable(data),
+    colnames = data.Properties.VariableNames;
+elseif ischar(data),
+    fid = fopen(data,'r');
+    line = fgetl(fid);
+    colnames = explodePCIQM(line);
+    fclose(fid);
+else
+    error('Unhandled data type.');
+end
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/dataset/IQMloadCSVdataset.m b/IQMtools V1.2.2.2/IQMlite/tools/dataset/IQMloadCSVdataset.m
new file mode 100644
index 0000000000000000000000000000000000000000..016ff07ee416ecaeb16aa3d7688f744481fcff92
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/dataset/IQMloadCSVdataset.m	
@@ -0,0 +1,225 @@
+function [varargout] = IQMloadCSVdataset(filename, varargin)
+% This function loads a standard CSV datafile with header as a TABLE object
+% into MATLAB. Nothing magic that could not be accomplished by the readtable
+% command, but allowing consistent naming as in previous versions where 
+% the DATASET object from the statistics toolbox was used. 
+%
+% Elements in numeric columns that have entries '.','NA','N/A' will be treated
+% as empty and set to NaN.
+%
+% [SYNTAX]
+% [data]    = IQMloadCSVdataset(filename)
+% [header]  = IQMloadCSVdataset(filename,FLAG_HEADER_ONLY)
+%
+% [INPUT]
+% filename:         Filename, possibly including relative or absolute path.
+%                   Extension is arbitrary.
+% FLAG_HEADER_ONLY: =0: loads dataset normally, =1: return cell-array with header names
+%
+% [OUTPUT]
+% data:      a MATLAB dataset containing the contents of the CSV datafile
+% header:    cell-array with header names
+%
+% [ASSUMPTIONS]
+% The header is expected in the first row. Special characters in header names 
+% are replaced by underscores.
+ 
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%% Check version number (>=R2013B required)
+if verLessThan('matlab','8.2.0'),
+    error('The dataset import/export functions in IQM Tools Lite require at least MATLAB R2013B.');
+end
+
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check input arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~ischar(filename),
+    error('Please provide a filename as input argument.');
+end
+if exist(filename) ~= 2,
+    error(['The file ''' filename ''' does not exist.']);
+end
+
+FLAG_HEADER_ONLY = 0;
+if nargin==2,
+    FLAG_HEADER_ONLY = varargin{1};
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Load header
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fid = fopen(filename);
+header = fgetl(fid);
+fclose(fid);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Process header
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% split into single terms (CSV)
+header = explodePCIQM(header);
+% replace all unwanted chars by underscore
+header = regexprep(header,'\W','_');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Return only header if desired
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if FLAG_HEADER_ONLY,
+    varargout{1} = header;
+    return
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Load table from CSV file
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+data = readtable(filename,'FileType','text','ReadVariableNames',true,'ReadRowNames',false,'TreatAsEmpty',{'.','NA','N/A'},'Delimiter',',');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Replace the header by the cleaned header
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+data.Properties.VariableNames = header;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle general and task specific dataset columns that should be strings but might be numeric and NaN if empty
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FLAG_HANDLE_SPECIAL_COLUMNS = 0;
+try
+    IQMcheckGeneralDataFormatHeader(data);
+    FLAG_HANDLE_SPECIAL_COLUMNS = 1;
+end
+try
+    IQMcheckTaskDatasetHeader(data);
+    FLAG_HANDLE_SPECIAL_COLUMNS = 1;
+end
+try
+    IQMcheckNLMEdatasetHeader(data);
+    FLAG_HANDLE_SPECIAL_COLUMNS = 1;
+end
+
+if FLAG_HANDLE_SPECIAL_COLUMNS,
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % If IGNORE is numeric, convert to cell with empty
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    try
+        if isnumeric(data.IGNORE),
+            data.IGNORE = cell(height(data),1);
+            data.IGNORE(1:end) = {''};
+        end
+    end
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % If IGNORE is 'NaN' set to ''
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    try
+        ix = strmatchIQM('NaN',data.IGNORE,'exact');
+        data.IGNORE(ix) = {''};
+%         ix = strmatchIQM('.',data.IGNORE,'exact');
+%         data.IGNORE(ix) = {''};
+    end
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % If USUBJID is numeric, convert to cell with strings
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    try
+        if isnumeric(data.USUBJID),
+            USUBJID = cell(height(data),1);
+            for k=1:height(data),
+                USUBJID{k} = num2str(data.USUBJID(k));
+            end
+            data.USUBJID = USUBJID;
+        end
+    end
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % If SUBJECT is numeric, convert to cell with strings
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    try
+        if isnumeric(data.SUBJECT),
+            SUBJECT = cell(height(data),1);
+            for k=1:height(data),
+                SUBJECT{k} = num2str(data.SUBJECT(k));
+            end
+            data.SUBJECT = SUBJECT;
+        end
+    end
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % If PART is numeric, convert to cell with strings
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    try
+        if isnumeric(data.PART),
+            PART = cell(height(data),1);
+            for k=1:height(data),
+                PART{k} = num2str(data.PART(k));
+            end
+            data.PART = PART;
+        end
+    end
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % If STUDY is numeric, convert to cell with strings
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    try
+        if isnumeric(data.STUDY),
+            STUDY = cell(height(data),1);
+            for k=1:height(data),
+                STUDY{k} = num2str(data.STUDY(k));
+            end
+            data.STUDY = STUDY;
+        end
+    end
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % If VALUE_TEXT is numeric, convert to cell with empty
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    try
+        if isnumeric(data.VALUE_TEXT),
+            data.VALUE_TEXT = cell(height(data),1);
+            data.VALUE_TEXT(1:end) = {''};
+        end
+    end
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % If COMMENT is numeric, convert to cell with empty
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    try
+        if isnumeric(data.COMMENT),
+            data.COMMENT = cell(height(data),1);
+            data.COMMENT(1:end) = {''};
+        end
+    end
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % If DATEDAY is of class datetime it should be converted to cellarray
+    % of strings
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    try
+        if strcmp(class(data.DATEDAY),'datetime'),
+            data.DATEDAY = cellstr(data.DATEDAY);
+        end
+    end
+
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % If VISNAME is numeric, convert to cell with empty
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    try
+        if isnumeric(data.VISNAME),
+            data.VISNAME = cell(height(data),1);
+            data.VISNAME(1:end) = {''};
+        end
+    end
+    
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle output arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargout == 1,
+    varargout{1} = data;
+else
+    error('Incorrect number of output arguments.');
+end
+
+
+
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/dataset/IQMloadNONCSVdataset.m b/IQMtools V1.2.2.2/IQMlite/tools/dataset/IQMloadNONCSVdataset.m
new file mode 100644
index 0000000000000000000000000000000000000000..97da0fd1e823c01be70c1b325c9eab034dcf2ff2
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/dataset/IQMloadNONCSVdataset.m	
@@ -0,0 +1,101 @@
+function [data] = IQMloadNONCSVdataset(filename,varargin)
+% This function loads a NON CSV datafile with header as a dataset into
+% MATLAB. Nothing magic, just avoiding a lengthy "dataset" command, and 
+% replacing non a-z,A-z,_,0-9 by underscores, so the dataset functionality
+% in MATLAB can work with it nicely.
+% Difference to loading CSV datasets is that in this function more general
+% type of files is handled. They can be tab separated, space separated,
+% etc. 
+%
+% Files that can be loaded in this way need to have numeric content (except
+% the column names in the header). Typical files that can be loaded in this 
+% way are: NONMEM and MONOLIX output tables.
+%
+% NONMEM typically has one additional "crap" line as first line and the header 
+% starting in the second line. For this the number of lines to drop can be 
+% passed to this function.
+%
+% [SYNTAX]
+% [data] = IQMloadNONCSVdataset(filename)
+% [data] = IQMloadNONCSVdataset(filename,droplines)
+%
+% [INPUT]
+% filename:     Filename, possibly including relative or absolute path.
+%               Extension is arbitrary.
+% droplines:    Number of lines before the start of the header (default: 0)
+%
+% [OUTPUT]
+% data:         MATLAB Table object
+%
+% [ASSUMPTIONS]
+% It is assumed that the dataset is rectangular and either space, tab, or
+% comma separated. A separation by semicolon, colon, etc. will not work. All 
+% data contents need to be numeric.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%% Check version number (>=R2013B required)
+if verLessThan('matlab','8.2.0'),
+    error('The dataset import/export functions in IQM Tools Lite require at least MATLAB R2013B.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle varargins
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin == 1,
+    droplines = 0;
+elseif nargin == 2,
+    droplines = varargin{1};
+else
+    error('Incorrect number of input arguments.');
+end 
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check input argument
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~ischar(filename),
+    error('Please provide a filename as input argument.');
+end
+if exist(filename) ~= 2,
+    error(['The file ''' filename ''' does not exist.']);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Load header & content
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fid = fopen(filename);
+k = 0;
+while k<droplines,
+    fgetl(fid);
+    k=k+1;
+end
+header = fgetl(fid);
+content = [];
+while ~feof(fid),
+    aline = fgetl(fid); % get one line at the time
+    [token, remain] = strtok(aline); % separate the id from the remaining columns
+    [the_id, crap] = strtok(token, '#'); % separate the id from the #1, etc.
+    new_line = [the_id remain]; % reconstitute the line without the crap
+    content = [content char(10) new_line];
+end
+fclose(fid);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Process header
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+header2 = regexprep(strtrim(header),'[\s]+',',');
+% split into single terms (CSV)
+header2 = explodePCIQM(header2);
+% replace all unwanted chars by underscore
+header2 = regexprep(header2,'\W','_');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Create table
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try
+    values = eval(['[' content ']']);
+catch
+    error('The NONCSV dataset you try to load does not fulfill the assumptions on it (rectangular, numeric only, separation by comma, space or tab).');
+end
+data = array2table(values);
+data.Properties.VariableNames = header2;
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/dataset/IQMresampleDataset.m b/IQMtools V1.2.2.2/IQMlite/tools/dataset/IQMresampleDataset.m
new file mode 100644
index 0000000000000000000000000000000000000000..045864141df3de961830a71baf6aea485ff88cab
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/dataset/IQMresampleDataset.m	
@@ -0,0 +1,140 @@
+function [datasampled] = IQMresampleDataset(data,IDname,groupName)
+% This function resamples a dataset. The structure and the number of 
+% subjects is preserved. Useful for bootstrapping. Original subjects can
+% appear several times in the resampled dataset.
+%
+% [SYNTAX]
+% [datasampled] = IQMresampleDataset(data,IDname)
+% [datasampled] = IQMresampleDataset(data,IDname,groupName)
+%
+% [INPUT]
+% data:                 Dataset (MATLAB table object) to be resampled
+% IDname:               Column name defining unique subject identifier - for example "ID"
+% groupName:            Column name defining structure to keep in the
+%                       resampled dataset (e.g. the treatment arm identifier column). 
+%                       Then resampling is done independently for each of these groups.
+%                       The values in the groupName column need to be
+%                       constant for each subject (IDname). Continuous
+%                       covariates should not be chosen - categorical
+%                       covariates are better suited. Combinations of
+%                       several covariates for grouping could be done by
+%                       defining a new categorical covariate that reflects
+%                       the modelers wishes.
+%
+% [OUTPUT]
+% The resampled dataset. 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%% Check version number (>=R2013B required)
+if verLessThan('matlab','8.2.0'),
+    error('The dataset import/export functions in IQM Tools Lite require at least MATLAB R2013B.');
+end
+
+%% Handle variable input arguments
+if nargin == 2,
+    groupName = '';
+end    
+
+%% Check input arguments
+varnames = data.Properties.VariableNames;
+
+ix = strmatchIQM(IDname,varnames,'exact');
+if isempty(ix),
+    error('Selected IDname does not exist in the dataset.');
+end
+
+if ~isempty(groupName),
+    ix = strmatchIQM(groupName,varnames,'exact');
+    if isempty(ix),
+        error('Selected groupName does not exist in the dataset.');
+    end
+end
+
+%% Determine number of groups in groupName and warn if too large
+if ~isempty(groupName),
+    groupCount = length(unique(data.(groupName)));
+    IDcount    = length(unique(data.(IDname)));
+    if groupCount > IDcount/4,
+        warning('Number of groupName elements larger than 25% of subjects.');
+    end
+end
+
+%% Resample if groupName not defined
+if isempty(groupName),
+    datasampled                 = table();
+    countID                     = 1;
+    
+    % Get all IDs
+    allID                       = unique(data.(IDname));
+    
+    % Get number of subjects
+    Nsubjects                   = length(allID);
+    
+    % Sample from the IDs
+    newID                       = allID(ceil(Nsubjects*rand(Nsubjects,1)));
+    
+    for k2=1:length(newID),
+        if isnumeric(allID),
+            datak2          = data(data.(IDname)==newID(k2),:);
+            % Update ID so it becomes unique
+            datak2.(IDname) = countID*ones(height(datak2),1);
+        else
+            datak2          = data(strcmp(data.(IDname),newID(k2)),:);
+            % Update ID so it becomes unique
+            datak2.(IDname)(1:end) = {[datak2.(IDname){1} '_' num2str(countID)]};
+        end
+        countID             = countID+1;
+        % Add to new dataset
+        datasampled         = [datasampled; datak2];
+    end
+end
+
+%% Resample if groupName is defined
+if ~isempty(groupName),
+    datasampled                 = table();
+    countID                     = 1;
+    allGROUP                    = unique(data.(groupName));
+    
+    for k=1:length(allGROUP),
+        if isnumeric(allGROUP),
+            datak                   = data(data.(groupName)==allGROUP(k),:);
+        else
+            datak                   = data(strcmp(data.(groupName),allGROUP{k}),:);
+        end
+        
+        % Get all IDs
+        allID                   = unique(datak.(IDname));
+        
+        % Get number of subjects
+        Nsubjects               = length(allID);
+        
+        % Sample from the IDs
+        newID                   = allID(ceil(Nsubjects*rand(Nsubjects,1)));
+        
+        % add new subjects to dataset
+        datasampledGROUP        = table();
+        
+        for k2=1:length(newID),
+            
+            
+            if isnumeric(allID),
+                datak2          = datak(datak.(IDname)==newID(k2),:);
+                % Update ID so it becomes unique
+                datak2.(IDname) = countID*ones(height(datak2),1);
+            else
+                datak2          = data(strcmp(data.(IDname),newID(k2)),:);
+                % Update ID so it becomes unique
+                datak2.(IDname)(1:end) = {[datak2.(IDname){1} '_' num2str(countID)]};
+            end
+            countID             = countID+1;
+            % Add to new dataset
+            datasampledGROUP    = [datasampledGROUP; datak2];
+        end
+        
+        % Add to new dataset
+        datasampled             = [datasampled; datasampledGROUP];
+    end
+end
+
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/dataset/IQMsas7bdat2csv.m b/IQMtools V1.2.2.2/IQMlite/tools/dataset/IQMsas7bdat2csv.m
new file mode 100644
index 0000000000000000000000000000000000000000..4cceba93fcbb9cf17cb5d77d9bd1f84daae085c1
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/dataset/IQMsas7bdat2csv.m	
@@ -0,0 +1,61 @@
+function [] = IQMsas7bdat2csv( filenameSAS7BDAT,pathCSVfile,version )
+% This function converts a sas7bdat file into a CSV file. It only works if
+% SAS is installed on the system and available by the command line command
+% for SAS, defined in the SETUP_PATHS_TOOLS_IQMLITE.m file.
+%
+% [SYNTAX]
+% [] = IQMsas7bdat2csv( filenameSAS7BDAT, pathCSVfile )
+%
+% [INPUT]
+% filenameSAS7BDAT:     String with path and filename of sas7bdat file
+% pathCSVfile:          Path (no filename) to where to store the CSV file. Same filename
+%                       is used as for the sas7bdat file, but with .csv at the end
+%
+% [OUTPUT]
+% exitflag:             SAS ran successfully if exitflag==0
+% 
+% CSV file is written in the specified folder.
+
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Copy the original sas file to temp folder
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+filenameversion = filenameSAS7BDAT;
+copyfile(filenameversion,fullfile(tempdirIQM,'tempsasfile.sas7bdat'),'f');
+
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Create SAS command in temp folder
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fid = fopen([tempdirIQM 'export2csv.sas'],'w');
+fprintf(fid,'libname output "%s" ;\n',tempdirIQM);
+fprintf(fid,'options fmterr=no;\n');
+fprintf(fid,'\n');
+fprintf(fid,'proc export data=output.tempsasfile\n');
+fprintf(fid,'           outfile   = "%stempsasfile.csv" replace ;\n',tempdirIQM);
+fprintf(fid,' 	        delimiter = ''%s'' ;\n',char(127));
+fprintf(fid,'run;\n');
+fclose(fid);
+
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Run SAS command
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+PATH_SAS = getSAStoolInfoIQM();
+if isempty(PATH_SAS),
+    error('Path to SAS not defined in SETUP_PATHS_TOOLS_IQMLITE.m');
+end
+
+exitflag = system(sprintf('%s %sexport2csv.sas',PATH_SAS,tempdirIQM));
+if exitflag~=0,
+    error('SAS is required for conversion from sas7bdat to CSV. It might not be available on your system.');
+end
+    
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Load file, remove commata and replace "char(127)" sign
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[~,CSVfilename] = fileparts(filenameSAS7BDAT);
+contents = fileread([tempdirIQM 'tempsasfile.csv']);
+contents = strrep(contents,',','');
+contents = strrep(contents,char(127),',');
+fid = fopen(fullfile(pathCSVfile,[CSVfilename '.csv']),'w');
+fprintf(fid,'%s',contents);
+fclose(fid);
+    
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/dataset/auxiliary/ixdataIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/dataset/auxiliary/ixdataIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..441cddd0bd6eb3a014256542dc7b066d52e2641a
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/dataset/auxiliary/ixdataIQM.m	
@@ -0,0 +1,92 @@
+function [output] = ixdataIQM(data,COLNAME,VALUES)
+% This function is a wrapper that supports easier subsetting of data.
+% data is a MATLAB dataset or table. COLNAME is the name of a numeric or 
+% cell-array column with strings. VALUES is a numeric value or a string. Or
+% a vector of numeric values or a cell-array of strings.
+%
+% In case VALUES is numeric then the indices are returned when the following
+% is true (VALUE is each value in VALUES):
+%
+%    data.(COLNAME)==VALUE
+%
+% In case of string the following is returned (VALUE is each value in VALUES):
+%
+%   strcmp(data.(COLNAME),VALUE)
+% 
+% [SYNTAX]
+% [output] = ixdataIQM(data,COLNAME,VALUES)
+%
+% [INPUT]
+% data:         MATLAB dataset or table
+% COLNAME:      Name of a numeric or cell-array column with strings 
+% VALUES:       VALUES is a numeric value or a string. Or a vector of
+%               numeric values or a cell-array of strings. 
+%
+% [OUTPUT]
+% Indices when conditions are true.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+if isempty(data),
+    output = [];
+    return
+end
+
+% Do some checks
+if ~ischar(COLNAME),
+    error('COLNAME has to be a string with the name of a column in the dataset.');
+end
+if isempty(strmatchIQM(COLNAME,data.Properties.VariableNames,'exact')),
+    error('"%s" is not a column name.',COLNAME);
+end
+
+% If VALUE is a string then make a cell array
+if ischar(VALUES),
+    VALUES = {VALUES};
+end
+
+% Run through the values and find the indices .... then stack and order
+output = [];
+for k=1:length(VALUES),
+    output = [output; get_VALUE_indices(data,COLNAME,VALUES(k))];
+end
+
+output = sort(output);
+
+return
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Auxiliaty function to get the indices
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [output] = get_VALUE_indices(data,COLNAME,VALUE)
+
+if iscell(VALUE),
+    VALUE = VALUE{1};
+end
+
+% Check if string or numeric or other
+x = data.(COLNAME)(1);
+
+if isnumeric(x),
+    if isnumeric(VALUE),
+        output = find(data.(COLNAME)==VALUE);
+    else
+        error('Trying to compare numeric column with non numeric value.');
+    end
+elseif iscell(x),
+    if ischar(x{1}),
+        if ischar(VALUE)
+            output = find(strcmp(data.(COLNAME),VALUE));
+        else
+            error('Trying to compare string column with non string value.');
+        end
+    else
+        error('Non string and non numeric column.');
+    end
+else
+    error('Unhandled type in column.');
+end
+
+output = output(:);
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/dataset/auxiliary/subsetIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/dataset/auxiliary/subsetIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..ad9e7a0a8afeb801db2852be4e27f6dd3f3cb106
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/dataset/auxiliary/subsetIQM.m	
@@ -0,0 +1,25 @@
+function [datasubset] = subsetIQM(data,COLNAME,VALUES)
+% This function allows to subset a dataset or table. Both numeric and
+% cell-array with string columns are handled.
+%
+% [SYNTAX]
+% [datasubset] = subsetIQM(data,COLNAME,VALUES)
+%
+% [INPUT]
+% data:         MATLAB dataset or table
+% COLNAME:      Name of a numeric or cell-array column with strings 
+% VALUES:       VALUES is a numeric value or a string. Or a vector of
+%               numeric values or a cell-array of strings. 
+%
+% [OUTPUT]
+% datasubset:   Subsetted dataset
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+ix = ixdataIQM(data,COLNAME,VALUES);
+
+if ~isempty(ix),
+    datasubset = data(ix,:);
+else
+    datasubset = table();
+end
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/interpolation/interp0IQM.m b/IQMtools V1.2.2.2/IQMlite/tools/interpolation/interp0IQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..e26d19a073057c69bbb9d634229f2325099ef203
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/interpolation/interp0IQM.m	
@@ -0,0 +1,27 @@
+function [yi] = interp0IQM(x,y,xi)
+% interp0IQM: zero order interpolation function (lookup table)
+% If of limits then the extreme points in y are taken as output. 
+% interp0IQM can be used together with MEX simulation files. For MEX
+% simulation functions it is IMPORTANT that the elements of the x and y
+% vectors are numeric and SEPARATED BY COMMATA! 
+% 
+% USAGE:
+% ======
+% [yi] = interp0IQM(x,y,xi)   
+%
+% x: vector of function arguments
+% y: vector of function values at the points given by x
+% xi: scalar value for which to determine y by zero order interpolation
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+yi = zeros(1,length(xi));
+for k=1:length(xi),
+    if xi(k) < x(2),
+        yi(k) = y(1);
+    elseif xi(k) >= x(end),
+        yi(k) = y(end);
+    else
+        yi(k) = y(max(find(x<=xi(k))));
+    end
+end
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/interpolation/interp1IQM.m b/IQMtools V1.2.2.2/IQMlite/tools/interpolation/interp1IQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..87193bd60977205d68193ebc7c78325c51df6bc1
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/interpolation/interp1IQM.m	
@@ -0,0 +1,27 @@
+function [yi] = interp1IQM(x,y,xi)
+% interp1IQM: linear interpolation function (lookup table)
+% Just the same as interp1 in MATLAB (except that if of limits then the extreme
+% points in y are taken as output instead of NaN). interp1IQM can be used together 
+% with MEX simulation files. For MEX simulation functions it is IMPORTANT that 
+% the elements of the x and y vectors are numeric and SEPARATED BY COMMATA!
+%
+% USAGE:
+% ======
+% [yi] = interp1IQM(x,y,xi)   
+%
+% x: vector of function arguments
+% y: vector of function values at the points given by x
+% xi: scalar value for which to determine y by linear interpolation
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+yi = zeros(1,length(xi));
+for k=1:length(xi),
+    if xi(k) < x(1),
+        yi(k) = y(1);
+    elseif xi(k) > x(end),
+        yi(k) = y(end);
+    else
+        yi(k) = interp1(x,y,xi(k));
+    end
+end
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/interpolation/interpcsIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/interpolation/interpcsIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..24ee330073c53785b11e7d75243d058f3cad2329
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/interpolation/interpcsIQM.m	
@@ -0,0 +1,671 @@
+function [yi] = interpcsIQM(x,y,xi)
+% interpcsIQM: cubic spline interpolation function (lookup table)
+% interpcsIQM can be used together with MEX simulation functions. 
+% if xi is of limits of x then the extreme points in y are taken as output.
+% For MEX simulation functions it is IMPORTANT that the elements of the 
+% x and y vectors are numeric and SEPARATED BY COMMATA!
+% 
+% USAGE:
+% ======
+% [yi] = interpcsIQM(x,y,xi)       
+%
+% x: vector of function arguments
+% y: vector of function values at the points given by x
+% xi: scalar value for which to determine y by linear interpolation
+%
+% Output Arguments:
+% =================
+% yi: the value of the dependent variable at xi.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+% input check
+if length(x) ~= length(y),
+    error('interpcsIQM: Different number of entries in x and y');
+end
+
+% number of data points
+n = length(x);
+
+% number of interpolations to compute
+ni = length(xi);
+
+% Calculate the derivatives
+d = spline_pchip_set(n, x, y);
+
+% Calculate the output
+yi = spline_pchip_val(n, x, y, d, ni, xi);
+
+% handle off limit values
+yi(find(xi<x(1))) = y(1);
+yi(find(xi>x(end))) = y(end);
+return
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% SPLINE_PCHIP_SET
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function d = spline_pchip_set ( n, x, f )
+%% SPLINE_PCHIP_SET sets derivatives for a piecewise cubic Hermite interpolant.
+%
+%  Discussion:
+%
+%    This routine computes what would normally be called a Hermite 
+%    interpolant.  However, the user is only required to supply function
+%    values, not derivative values as well.  This routine computes
+%    "suitable" derivative values, so that the resulting Hermite interpolant
+%    has desirable shape and monotonicity properties.
+%
+%    The interpolant will have an extremum at each point where
+%    monotonicity switches direction.  
+%
+%    The resulting piecewise cubic Hermite function may be evaluated
+%    by SPLINE_PCHIP_VAL.
+%
+%    This routine was originally called "PCHIM".
+%
+%  Modified:
+%
+%    14 August 2005
+%
+%  Author:
+%
+%    Fred Fritsch,
+%    Mathematics and Statistics Division,
+%    Lawrence Livermore National Laboratory.
+%
+%    MATLAB translation by John Burkardt.
+%
+%  Reference:
+%
+%    Fred Fritsch and R Carlson,
+%    Monotone Piecewise Cubic Interpolation,
+%    SIAM Journal on Numerical Analysis,
+%    Volume 17, Number 2, April 1980, pages 238-246.
+%
+%    Fred Fritsch and J Butland,
+%    A Method for Constructing Local Monotone Piecewise Cubic Interpolants,
+%    LLNL Preprint UCRL-87559, April 1982.
+%
+%  Parameters:
+%
+%    Input, integer N, the number of data points.  N must be at least 2.
+%
+%    Input, real X(N), the strictly increasing independent
+%    variable values.
+%
+%    Input, real F(N), dependent variable values to be interpolated.  This
+%    routine is designed for monotonic data, but it will work for any F-array.
+%    It will force extrema at points where monotonicity switches direction.
+%
+%    Output, real D(N), the derivative values at the
+%    data points.  If the data are monotonic, these values will determine
+%    a monotone cubic Hermite function.
+%
+
+%
+%  Check the arguments.
+%
+  if ( n < 2 )
+    ierr = -1;
+    fprintf ( 1, '\n' );
+    fprintf ( 1, 'SPLINE_PCHIP_SET - Fatal error!\n' );
+    fprintf ( 1, '  Number of data points less than 2.\n' );
+    error ( 'SPLINE_PCHIP_SET - Fatal error!' );
+  end
+
+  for i = 2 : n
+    if ( x(i) <= x(i-1) )
+      ierr = -3;
+      fprintf ( 1, '\n' );
+      fprintf ( 1, 'SPLINE_PCHIP_SET - Fatal error!\n' );
+      fprintf ( 1, '  X array not strictly increasing.\n' );
+      error ( 'SPLINE_PCHIP_SET - Fatal error!' );
+    end
+  end
+
+  ierr = 0;
+  nless1 = n - 1;
+  h1 = x(2) - x(1);
+  del1 = ( f(2) - f(1) ) / h1;
+  dsave = del1;
+%
+%  Special case N=2, use linear interpolation.
+%
+  if ( n == 2 )
+    d(1) = del1;
+    d(n) = del1;
+    return
+  end 
+%
+%  Normal case, 3 <= N.
+%
+  h2 = x(3) - x(2);
+  del2 = ( f(3) - f(2) ) / h2;
+%
+%  Set D(1) via non-centered three point formula, adjusted to be
+%  shape preserving.
+%
+  hsum = h1 + h2;
+  w1 = ( h1 + hsum ) / hsum;
+  w2 = -h1 / hsum;
+  d(1) = w1 * del1 + w2 * del2;
+
+  if ( pchst( d(1), del1 ) <= 0.0 )
+
+    d(1) = 0.0;
+%
+%  Need do this check only if monotonicity switches.
+%
+  elseif ( pchst( del1, del2 ) < 0.0 )
+
+     dmax = 3.0 * del1;
+
+     if ( abs ( dmax ) < abs ( d(1) ) )
+       d(1) = dmax;
+     end
+
+  end
+%
+%  Loop through interior points.
+%
+  for i = 2 : nless1
+
+    if ( 2 < i )
+      h1 = h2;
+      h2 = x(i+1) - x(i);
+      hsum = h1 + h2;
+      del1 = del2;
+      del2 = ( f(i+1) - f(i) ) / h2;
+    end
+%
+%  Set D(I)=0 unless data are strictly monotonic.
+%
+    d(i) = 0.0;
+
+    temp = pchst( del1, del2 );
+
+    if ( temp < 0.0 )
+
+      ierr = ierr + 1;
+      dsave = del2;
+%
+%  Count number of changes in direction of monotonicity.
+%
+    elseif ( temp == 0.0 )
+
+      if ( del2 ~= 0.0D+00 )
+        if ( pchst( dsave, del2 ) < 0.0 )
+          ierr = ierr + 1;
+        end
+        dsave = del2;
+      end
+%
+%  Use Brodlie modification of Butland formula.
+%
+    else
+
+      hsumt3 = 3.0 * hsum;
+      w1 = ( hsum + h1 ) / hsumt3;
+      w2 = ( hsum + h2 ) / hsumt3;
+      dmax = max ( abs ( del1 ), abs ( del2 ) );
+      dmin = min ( abs ( del1 ), abs ( del2 ) );
+      drat1 = del1 / dmax;
+      drat2 = del2 / dmax;
+      d(i) = dmin / ( w1 * drat1 + w2 * drat2 );
+
+    end
+
+  end
+%
+%  Set D(N) via non-centered three point formula, adjusted to be
+%  shape preserving.
+%
+  w1 = -h2 / hsum;
+  w2 = ( h2 + hsum ) / hsum;
+  d(n) = w1 * del1 + w2 * del2;
+
+  if ( pchst( d(n), del2 ) <= 0.0 )
+    d(n) = 0.0;
+  elseif ( pchst( del1, del2 ) < 0.0 )
+%
+%  Need do this check only if monotonicity switches.
+%
+    dmax = 3.0 * del2;
+
+    if ( abs ( dmax ) < abs ( d(n) ) )
+      d(n) = dmax;
+    end
+
+  end
+  
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% SPLINE_PCHIP_VAL
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
+function fe = spline_pchip_val ( n, x, f, d, ne, xe )
+
+%% SPLINE_PCHIP_VAL evaluates a piecewise cubic Hermite function.
+%
+%  Description:
+%
+%    This routine may be used by itself for Hermite interpolation, or as an
+%    evaluator for SPLINE_PCHIP_SET.
+%
+%    This routine evaluates the cubic Hermite function at the points XE.
+%
+%    Most of the coding between the call to CHFEV and the end of
+%    the IR loop could be eliminated if it were permissible to
+%    assume that XE is ordered relative to X.
+%
+%    CHFEV does not assume that X1 is less than X2.  Thus, it would
+%    be possible to write a version of SPLINE_PCHIP_VAL that assumes a strictly
+%    decreasing X array by simply running the IR loop backwards
+%    and reversing the order of appropriate tests.
+%
+%    The present code has a minor bug, which I have decided is not
+%    worth the effort that would be required to fix it.
+%    If XE contains points in [X(N-1),X(N)], followed by points less than
+%    X(N-1), followed by points greater than X(N), the extrapolation points
+%    will be counted (at least) twice in the total returned in IERR.
+%
+%    The evaluation will be most efficient if the elements of XE are
+%    increasing relative to X; that is, for all J <= K,
+%      X(I) <= XE(J)
+%    implies
+%      X(I) <= XE(K).
+%
+%    If any of the XE are outside the interval [X(1),X(N)],
+%    values are extrapolated from the nearest extreme cubic,
+%    and a warning error is returned.
+%
+%    This routine was originally named "PCHFE".
+%
+%  Modified:
+%
+%    14 August 2005
+%
+%  Author:
+%
+%    Fred Fritsch,
+%    Mathematics and Statistics Division,
+%    Lawrence Livermore National Laboratory.
+%
+%    MATLAB translation by John Burkardt.
+%
+%  Reference:
+%
+%    Fred Fritsch and R Carlson,
+%    Monotone Piecewise Cubic Interpolation,
+%    SIAM Journal on Numerical Analysis,
+%    Volume 17, Number 2, April 1980, pages 238-246.
+%
+%  Parameters:
+%
+%    Input, integer N, the number of data points.  N must be at least 2.
+%
+%    Input, real X(N), the strictly increasing independent
+%    variable values.
+%
+%    Input, real F(N), the function values.
+%
+%    Input, real D(N), the derivative values.
+%
+%    Input, integer NE, the number of evaluation points.
+%
+%    Input, real XE(NE), points at which the function is to
+%    be evaluated.
+%
+%    Output, real FE(NE), the values of the cubic Hermite
+%    function at XE.
+%
+
+%
+%  Check arguments.
+%
+  if ( n < 2 )
+    ierr = -1;
+    fprintf ( 1, '\n' );
+    fprintf ( 1, 'SPLINE_PCHIP_VAL - Fatal error!\n' );
+    fprintf ( 1, '  Number of data points less than 2.\n' );
+    error ( 'SPLINE_PCHIP_VAL - Fatal error!' );
+  end
+
+  for i = 2 : n
+    if ( x(i) <= x(i-1) )
+      ierr = -3;
+      fprintf ( 1, '\n' );
+      fprintf ( 1, 'SPLINE_PCHIP_VAL - Fatal error!\n' );
+      fprintf ( 1, '  X array not strictly increasing.\n' );
+      error ( 'SPLINE_PCHIP_VAL - Fatal error!' );
+    end
+  end
+
+  if ( ne < 1 )
+    ierr = -4;
+    fprintf ( 1, '\n' );
+    fprintf ( 1, 'SPLINE_PCHIP_VAL - Fatal error!\n' );
+    fprintf ( 1, '  Number of evaluation points less than 1.\n' );
+    fe = [];
+    return
+  end
+
+  ierr = 0;
+%
+%  Loop over intervals.
+%  The interval index is IL = IR-1.
+%  The interval is X(IL) <= X < X(IR).
+%
+  j_first = 1;
+  ir = 2;
+
+  while ( 1 )
+%
+%  Skip out of the loop if have processed all evaluation points.
+%
+    if ( ne < j_first )
+      break
+    end
+%
+%  Locate all points in the interval.
+%
+    j_save = ne + 1;
+
+    for j = j_first : ne
+      if ( x(ir) <= xe(j) )
+        j_save = j;
+        if ( ir == n )
+          j_save = ne + 1;
+        end
+        break
+      end
+    end
+%
+%  Have located first point beyond interval.
+%
+    j = j_save;
+
+    nj = j - j_first;
+%
+%  Skip evaluation if no points in interval.
+%
+    if ( nj ~= 0 )
+%
+%  Evaluate cubic at XE(J_FIRST:J-1).
+%
+      [ fe(j_first:j-1), next, ierc ] = chfev ( x(ir-1), x(ir), f(ir-1), ...
+        f(ir), d(ir-1), d(ir),  nj, xe(j_first:j-1) );
+
+      if ( ierc < 0 )
+        ierr = -5;
+        fprintf ( 1, '\n' );
+        fprintf ( 1, 'SPLINE_PCHIP_VAL - Fatal error!\n' );
+        fprintf ( 1, '  Error return from CHFEV.\n' );
+        error ( 'SPLINE_PCHIP_VAL - Fatal error!' );
+      end
+%
+%  In the current set of XE points, there are NEXT(2) to the right of X(IR).
+%
+      if ( next(2) ~= 0 )
+
+        if ( ir < n )
+          ierr = -5;
+          fprintf ( 1, '\n' );
+          fprintf ( 1, 'SPLINE_PCHIP_VAL - Fatal error!\n' );
+          fprintf ( 1, '  IR < N.\n' );
+          error ( 'SPLINE_PCHIP_VAL - Fatal error!' );
+        end
+%
+%  These are actually extrapolation points.
+%
+        ierr = ierr + next(2);
+
+      end
+%
+%  In the current set of XE points, there are NEXT(1) to the left of X(IR-1).
+%
+      if ( next(1) ~= 0 )
+%
+%  These are actually extrapolation points.
+%
+        if ( ir <= 2 )
+          ierr = ierr + next(1);
+        else
+
+          j_new = -1;
+
+          for i = j_first : j-1
+            if ( xe(i) < x(ir-1) )
+              j_new = i;
+              break
+            end
+          end
+
+          if ( j_new == -1 )
+            ierr = -5;
+            fprintf ( 1, '\n' );
+            fprintf ( 1, 'SPLINE_PCHIP_VAL - Fatal error!\n' );
+            fprintf ( 1, '  Could not bracket the data point.\n' );
+            error ( 'SPLINE_PCHIP_VAL - Fatal error!' );
+          end
+%
+%  Reset J.  This will be the new J_FIRST.
+%
+          j = j_new;
+%
+%  Now find out how far to back up in the X array.
+%
+          for i = 1 : ir-1
+            if ( xe(j) < x(i) )
+              break
+            end
+          end
+%
+%  At this point, either XE(J) < X(1) or X(i-1) <= XE(J) < X(I) .
+%
+%  Reset IR, recognizing that it will be incremented before cycling.
+%
+          ir = max ( 1, i-1 );
+
+        end
+
+      end
+
+      j_first = j;
+
+    end
+
+    ir = ir + 1;
+
+    if ( n < ir )
+      break
+    end
+
+  end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHFEV
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 
+function [ fe, next, ierr ] = chfev ( x1, x2, f1, f2, d1, d2, ne, xe )
+
+%% CHFEV evaluates a cubic polynomial given in Hermite form.
+%
+%  Discussion:
+%
+%    This routine evaluates a cubic polynomial given in Hermite form at an
+%    array of points.  While designed for use by SPLINE_PCHIP_VAL, it may
+%    be useful directly as an evaluator for a piecewise cubic
+%    Hermite function in applications, such as graphing, where
+%    the interval is known in advance.
+%
+%    The cubic polynomial is determined by function values
+%    F1, F2 and derivatives D1, D2 on the interval [X1,X2].
+%
+%  Modified:
+%
+%    14 August 2005
+%
+%  Author:
+%
+%    Fred Fritsch,
+%    Mathematics and Statistics Division,
+%    Lawrence Livermore National Laboratory.
+%
+%    MATLAB translation by John Burkardt.
+%
+%  Reference:
+%
+%    Fred Fritsch and R Carlson,
+%    Monotone Piecewise Cubic Interpolation,
+%    SIAM Journal on Numerical Analysis,
+%    Volume 17, Number 2, April 1980, pages 238-246.
+%
+%    David Kahaner, Clever Moler, Steven Nash,
+%    Numerical Methods and Software,
+%    Prentice Hall, 1988.
+%
+%  Parameters:
+%
+%    Input, real X1, X2, the endpoints of the interval of
+%    definition of the cubic.  X1 and X2 must be distinct.
+%
+%    Input, real F1, F2, the values of the function at X1 and
+%    X2, respectively.
+%
+%    Input, real D1, D2, the derivative values at X1 and
+%    X2, respectively.
+%
+%    Input, integer NE, the number of evaluation points.
+%
+%    Input, real XE(NE), the points at which the function is to
+%    be evaluated.  If any of the XE are outside the interval
+%    [X1,X2], a warning error is returned in NEXT.
+%
+%    Output, real FE(NE), the value of the cubic function
+%    at the points XE.
+%
+%    Output, integer NEXT(2), indicates the number of extrapolation points:
+%    NEXT(1) = number of evaluation points to the left of interval.
+%    NEXT(2) = number of evaluation points to the right of interval.
+%
+%    Output, integer IERR, error flag.
+%    0, no errors.
+%    -1, NE < 1.
+%    -2, X1 == X2.
+%
+  if ( ne < 1 )
+    ierr = -1;
+    fprintf ( 1, '\n' );
+    fprintf ( 1, 'CHFEV - Fatal error!\n' );
+    fprintf ( 1, '  Number of evaluation points is less than 1.\n' );
+    fprintf ( 1, '  NE = %d\n', ne );
+    error ( 'CHFEV - Fatal error!' )
+  end
+
+  h = x2 - x1;
+
+  if ( h == 0.0 )
+    ierr = -2;
+    fprintf ( 1, '\n' );
+    fprintf ( 1, 'CHFEV - Fatal error!\n' );
+    fprintf ( 1, '  The interval [X1,X2] is of zero length.\n' );
+    error ( 'CHFEV - Fatal error!' )
+  end
+%
+%  Initialize.
+%
+  ierr = 0;
+  next(1) = 0;
+  next(2) = 0;
+  xmi = min ( 0.0, h );
+  xma = max ( 0.0, h );
+%
+%  Compute cubic coefficients expanded about X1.
+%
+  delta = ( f2 - f1 ) / h;
+  del1 = ( d1 - delta ) / h;
+  del2 = ( d2 - delta ) / h;
+  c2 = -( del1 + del1 + del2 );
+  c3 = ( del1 + del2 ) / h;
+%
+%  Evaluation loop.
+%
+  for i = 1 : ne
+
+    x = xe(i) - x1;
+    fe(i) = f1 + x * ( d1 + x * ( c2 + x * c3 ) );
+%
+%  Count the extrapolation points.
+%
+    if ( x < xmi )
+      next(1) = next(1) + 1;
+    end
+
+    if ( xma < x )
+      next(2) = next(2) + 1;
+    end
+
+  end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PCHST
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 
+function value = pchst( arg1, arg2 )
+
+%% PCHST: PCHIP sign-testing routine.
+%
+%  Discussion:
+%
+%    This routine essentially computes the sign of ARG1 * ARG2.
+%
+%    The object is to do this without multiplying ARG1 * ARG2, to avoid
+%    possible over/underflow problems.
+%
+%  Modified:
+%
+%    14 August 2005
+%
+%  Author:
+%
+%    Fred Fritsch,
+%    Mathematics and Statistics Division,
+%    Lawrence Livermore National Laboratory.
+%
+%    MATLAB translation by John Burkardt.
+%
+%  Reference:
+%
+%    Fred Fritsch and R Carlson,
+%    Monotone Piecewise Cubic Interpolation,
+%    SIAM Journal on Numerical Analysis,
+%    Volume 17, Number 2, April 1980, pages 238-246.
+%
+%  Parameters:
+%
+%    Input, real ARG1, ARG2, two values to check.
+%
+%    Output, real VALUE,
+%    -1.0, if ARG1 and ARG2 are of opposite sign.
+%     0.0, if either argument is zero.
+%    +1.0, if ARG1 and ARG2 are of the same sign.
+%
+  if ( arg1 == 0.0 )
+    value = 0.0;
+  elseif ( arg1 < 0.0 )
+    if ( arg2 < 0.0 )
+      value = 1.0;
+    elseif ( arg2 == 0.0 )
+      value = 0.0;
+    elseif ( 0.0 < arg2 )
+      value = -1.0;
+    end
+  elseif ( 0.0 < arg1 )
+    if ( arg2 < 0.0 )
+      value = -1.0;
+    elseif ( arg2 == 0.0 )
+      value = 0.0;
+    elseif ( 0.0 < arg2 )
+      value = 1.0;
+    end
+  end
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/interpolation/interpcseIQM.c b/IQMtools V1.2.2.2/IQMlite/tools/interpolation/interpcseIQM.c
new file mode 100644
index 0000000000000000000000000000000000000000..457f845eff69ba4a299fef1dc81819a4c5f2cc0b
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/interpolation/interpcseIQM.c	
@@ -0,0 +1,442 @@
+/*
+ * interpcseIQM.c: Cubic spline interpolation with endpoints
+ *
+ * MEX interface: Henning Schmidt
+ * Original C-code for spline interpolation taken from:
+ *   http://www.mech.uq.edu.au/staff/jacobs/nm_lib/cmathsrc/spline.c
+ *
+ * The syntax of this MEX functions is as follows:
+ *
+ * yy = interpcseIQM(x,y,xx)
+ * yy = interpcseIQM(x,y,xx,e1,e2)
+ *
+ * x:     x-values 
+ * y:     y-values
+ * xx:    x-values at which to evaluate the spline function (allow multiple)
+ * e1,e2: endpoint derivatives (if specified, both need to be given)
+ * yy:    interpolated value
+ */
+
+/* Some includes to be sure we got everything that is needed */
+#include <mex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <string.h>
+#include <matrix.h>
+#include <math.h>
+
+/*
+ *========================================================================
+ * Initialization of the spline related functions
+ *========================================================================
+ */
+void spline (int n, int e1, int e2, double s1, double s2, double x[], double y[], double b[], double c[], double d[], int *flag);
+double seval (int n, double xx, double x[], double y[], double b[], double c[], double d[], int *last);
+
+/*
+ *========================================================================
+ * Definition of needed variables to be passed to the spline functions
+ *========================================================================
+ */
+int     n;          /* The number of data points or knots (n >= 2) */
+int     e1=0;       /* = 1 to specify the slopes at the end points, = 0 to obtain the default conditions */
+int     e2=0;       /* = 1 to specify the slopes at the end points, = 0 to obtain the default conditions */
+double  s1;         /* the slopes at the end point x[0] */
+double  s2;         /* the slopes at the end point x[n-1] */
+double* x;          /* the abscissas of the knots in strictly increasing order */
+double* y;          /* the ordinates of the knots */
+double* b=NULL;     /* arrays of spline coefficients (length n) */
+double* c=NULL;     /* arrays of spline coefficients (length n) */
+double* d=NULL;     /* arrays of spline coefficients (length n) */
+int     flag=0;     /* status flag = 0 normal return = 1 less than two data points; cannot interpolate = 2 x[] are not in ascending order */
+int     last;       /* the segment in which xx lies */
+double* xx;         /* the abscissa at which the spline is to be evaluated */
+double* yy=NULL;    /* the evaluated value at xx */
+int     nx;         /* number of xx values to interpolate the spline function at */
+int     k;          /* loop variable */
+double  b2; 
+double  c2; 
+double  d2; 
+
+/*
+ *===================================
+ * Definition of needed MEX variables
+ *===================================
+ */
+mxArray *xMX = NULL;
+mxArray *yMX = NULL;
+mxArray *xxMX = NULL;
+mxArray *s1MX = NULL;
+mxArray *s2MX = NULL;
+mxArray *yyMX = NULL;
+
+/*
+ *========================================================================
+ * MEX INTERFACE FUNCTION
+ *========================================================================
+ */
+void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
+{
+    /*************************************/
+    /* Check correct number of arguments */
+    /*************************************/
+    /* Check correct number of input arguments */
+    if (nrhs != 3 && nrhs != 5) mexErrMsgTxt("interpcseIQM: Incorrect number of input arguments.");
+    /* Check correct number of output arguments */
+    if (nlhs != 1) mexErrMsgTxt("interpcseIQM: Incorrect number of output arguments.");
+    
+    /**************************************************************************************/
+    /* Get and check input arguments and extract some first info for the spline functions */
+    /**************************************************************************************/
+    /* First input argument needs to be a double vector with length >= 2 */
+    if (!mxIsDouble(prhs[0])) mexErrMsgTxt("interpcseIQM: Check first input argument, it needs to be a vector of x-values.");
+    xMX = (mxArray *) prhs[0];
+    n = mxGetM(xMX)*mxGetN(xMX);
+    if (n<2) mexErrMsgTxt("interpcseIQM: please provide at least n points with n>=2 (add commata as element separators in the vectors!).");
+    else x = mxGetPr(xMX);    
+    
+    /* Second input argument needs to be a double vector with the same length as the first */
+    if (!mxIsDouble(prhs[1])) mexErrMsgTxt("interpcseIQM: Check second input argument, it needs to be a vector of y-values.");
+    yMX = (mxArray *) prhs[1];
+    if (n != mxGetM(yMX)*mxGetN(yMX)) mexErrMsgTxt("interpcseIQM: Second input argument (y-values) needs as many elements as first argument (x-values).");
+    y = mxGetPr(yMX);    
+    
+    /* Third input argument should be a scalar or a vector */
+    if (!mxIsDouble(prhs[2])) mexErrMsgTxt("interpcseIQM: Check third input argument, it needs to be a scalar or vector of numeric values at which to evaluate the spline.");
+    xxMX = (mxArray *) prhs[2];
+    nx = mxGetM(xxMX)*mxGetN(xxMX);
+    if (n<1) mexErrMsgTxt("interpcseIQM: please provide at least 1 points for the third input argument.");
+    xx = mxGetPr(xxMX);    
+
+    if (nrhs > 3) {
+        /* Fourth input argument needs to be a scalar double */
+        if (!mxIsDouble(prhs[3]) || !mxIsScalar(prhs[3])) mexErrMsgTxt("interpcseIQM: Check fourth input argument, it needs to be a scalar numeric value with the first derivative.");
+        s1MX = (mxArray *) prhs[3];
+        s1 = mxGetScalar(s1MX);
+        e1 = 1; /* slope given */
+    
+        /* Fifth input argument needs to be a scalar double */
+        if (!mxIsDouble(prhs[4]) || !mxIsScalar(prhs[4])) mexErrMsgTxt("interpcseIQM: Check fifth input argument, it needs to be a scalar numeric value with the last derivative.");
+        s2MX = (mxArray *) prhs[4];
+        s2 = mxGetScalar(s2MX);
+        e2 = 1; /* slope given */
+    } else {
+        e1 = 0;
+        e2 = 0;
+        s1 = 0.0;
+        s2 = 0.0;
+    }
+    
+    /**************************/
+    /* Create output argument */
+    /**************************/
+    yyMX = mxCreateDoubleMatrix(nx, 1, mxREAL);
+    yy = mxGetPr(yyMX);
+
+    /***********/
+    /* If n==2 */
+    /***********/
+    if (n==2) {        
+        if (e1 == 0 || e2 == 0) mexErrMsgTxt("interpcseIQM: n=2 requires the definition of slopes.");
+        b2 = s1;
+        c2 = -(-3.0*y[1]+3.0*y[0]+(s2+2.0*s1)*x[1]+(-s2-2.0*s1)*x[0])/(pow(x[1],2.0)-2.0*x[0]*x[1]+pow(x[0],2.0));
+        d2 = (-2.0*y[1]+2.0*y[0]+(s2+s1)*x[1]+(-s2-s1)*x[0])/(pow(x[1],3.0)-3.0*x[0]*pow(x[1],2.0)+3.0*pow(x[0],2.0)*x[1]-pow(x[0],3.0));
+        
+        /***************************************/
+        /* Call the spline evaluation function */
+        /***************************************/
+        for (k=0;k<nx;k++) {
+            yy[k] = y[0] + b2*(xx[k]-x[0]) + c2*pow(xx[k]-x[0],2.0) + d2*pow(xx[k]-x[0],3.0);
+        }
+    } else {
+    /***********/
+    /* If n!=2 */
+    /***********/        
+        /********************************/
+        /* Allocate memory for b,c,d,yy */
+        /********************************/
+        b  = (double *) mxCalloc(n, sizeof(double));
+        c  = (double *) mxCalloc(n, sizeof(double));
+        d  = (double *) mxCalloc(n, sizeof(double));
+        
+        /****************************/
+        /* Call the spline function */
+        /****************************/
+        spline(n, e1, e2, s1, s2, x, y, b, c, d, &flag);
+        
+        /***************************************/
+        /* Call the spline evaluation function */
+        /***************************************/
+        for (k=0;k<nx;k++) {
+            yy[k] = seval(n, xx[k], x, y, b, c, d, &last);
+        }
+        
+        /*************************/
+        /* Free allocated memory */
+        /*************************/
+        mxFree(b);
+        mxFree(c);
+        mxFree(d);
+    }
+
+    /*******************************/
+    /* Return the result to MATLAB */
+    /*******************************/
+    plhs[0] = yyMX;
+}
+
+/*=========================================================================
+   Cubic spline coefficients
+   -------------------------
+   Evaluate the coefficients b[i], c[i], d[i], i = 0, 1, .. n-1 for
+   a cubic interpolating spline
+
+   S(xx) = Y[i] + b[i] * w + c[i] * w**2 + d[i] * w**3
+   where w = xx - x[i]
+   and   x[i] <= xx <= x[i+1]
+
+   The n supplied data points are x[i], y[i], i = 0 ... n-1.
+
+   Input :
+   -------
+   n       : The number of data points or knots (n >= 2)
+   end1,
+   end2    : = 1 to specify the slopes at the end points
+             = 0 to obtain the default conditions
+   slope1,
+   slope2  : the slopes at the end points x[0] and x[n-1]
+             respectively
+   x[]     : the abscissas of the knots in strictly
+             increasing order
+   y[]     : the ordinates of the knots
+
+   Output :
+   --------
+   b, c, d : arrays of spline coefficients as defined above
+             (See note 2 for a definition.)
+   iflag   : status flag
+            = 0 normal return
+            = 1 less than two data points; cannot interpolate
+            = 2 x[] are not in ascending order
+
+   This C code written by ...  Peter & Nigel,
+   ----------------------      Design Software,
+                               42 Gubberley St,
+                               Kenmore, 4069,
+                               Australia.
+
+   Version ... 1.1, 30 September 1987
+   -------     2.0, 6 April 1989    (start with zero subscript)
+                                     remove ndim from parameter list
+               2.1, 28 April 1989   (check on x[])
+               2.2, 10 Oct   1989   change number order of matrix
+
+   Notes ...
+   -----
+   (1) The accompanying function seval() may be used to evaluate the
+       spline while deriv will provide the first derivative.
+   (2) Using p to denote differentiation
+       y[i] = S(X[i])
+       b[i] = Sp(X[i])
+       c[i] = Spp(X[i])/2
+       d[i] = Sppp(X[i])/6  ( Derivative from the right )
+   (3) Since the zero elements of the arrays ARE NOW used here,
+       all arrays to be passed from the main program should be
+       dimensioned at least [n].  These routines will use elements
+       [0 .. n-1].
+   (4) Adapted from the text
+       Forsythe, G.E., Malcolm, M.A. and Moler, C.B. (1977)
+       "Computer Methods for Mathematical Computations"
+       Prentice Hall
+   (5) Note that although there are only n-1 polynomial segments,
+       n elements are requird in b, c, d.  The elements b[n-1],
+       c[n-1] and d[n-1] are set to continue the last segment
+       past x[n-1].
+=========================================================================*/
+void spline (int n, int end1, int end2,
+            double slope1, double slope2,
+            double x[], double y[],
+            double b[], double c[], double d[],
+            int *iflag)
+{  /* begin procedure spline() */
+
+int    nm1, ib, i;
+double t;
+int    ascend;
+
+nm1    = n - 1;
+*iflag = 0;
+
+if (n < 2)
+  {  /* no possible interpolation */
+  *iflag = 1;
+  return;
+  }
+
+ascend = 1;
+for (i = 1; i < n; ++i) if (x[i] <= x[i-1]) ascend = 0;
+if (!ascend)
+   {
+   *iflag = 2;
+   return;
+   }
+
+if (n >= 3)
+   {    /* ---- At least quadratic ---- */
+
+   /* ---- Set up the symmetric tri-diagonal system
+           b = diagonal
+           d = offdiagonal
+           c = right-hand-side  */
+   d[0] = x[1] - x[0];
+   c[1] = (y[1] - y[0]) / d[0];
+   for (i = 1; i < nm1; ++i)
+      {
+      d[i]   = x[i+1] - x[i];
+      b[i]   = 2.0 * (d[i-1] + d[i]);
+      c[i+1] = (y[i+1] - y[i]) / d[i];
+      c[i]   = c[i+1] - c[i];
+      }
+
+   /* ---- Default End conditions
+           Third derivatives at x[0] and x[n-1] obtained
+           from divided differences  */
+   b[0]   = -d[0];
+   b[nm1] = -d[n-2];
+   c[0]   = 0.0;
+   c[nm1] = 0.0;
+   if (n != 3)
+      {
+      c[0]   = c[2] / (x[3] - x[1]) - c[1] / (x[2] - x[0]);
+      c[nm1] = c[n-2] / (x[nm1] - x[n-3]) - c[n-3] / (x[n-2] - x[n-4]);
+      c[0]   = c[0] * d[0] * d[0] / (x[3] - x[0]);
+      c[nm1] = -c[nm1] * d[n-2] * d[n-2] / (x[nm1] - x[n-4]);
+      }
+
+   /* Alternative end conditions -- known slopes */
+   if (end1 == 1)
+      {
+      b[0] = 2.0 * (x[1] - x[0]);
+      c[0] = (y[1] - y[0]) / (x[1] - x[0]) - slope1;
+      }
+   if (end2 == 1)
+      {
+      b[nm1] = 2.0 * (x[nm1] - x[n-2]);
+      c[nm1] = slope2 - (y[nm1] - y[n-2]) / (x[nm1] - x[n-2]);
+      }
+
+   /* Forward elimination */
+   for (i = 1; i < n; ++i)
+     {
+     t    = d[i-1] / b[i-1];
+     b[i] = b[i] - t * d[i-1];
+     c[i] = c[i] - t * c[i-1];
+     }
+
+   /* Back substitution */
+   c[nm1] = c[nm1] / b[nm1];
+   for (ib = 0; ib < nm1; ++ib)
+      {
+      i    = n - ib - 2;
+      c[i] = (c[i] - d[i] * c[i+1]) / b[i];
+      }
+
+   /* c[i] is now the sigma[i] of the text */
+
+   /* Compute the polynomial coefficients */
+   b[nm1] = (y[nm1] - y[n-2]) / d[n-2] + d[n-2] * (c[n-2] + 2.0 * c[nm1]);
+   for (i = 0; i < nm1; ++i)
+      {
+      b[i] = (y[i+1] - y[i]) / d[i] - d[i] * (c[i+1] + 2.0 * c[i]);
+      d[i] = (c[i+1] - c[i]) / d[i];
+      c[i] = 3.0 * c[i];
+      }
+   c[nm1] = 3.0 * c[nm1];
+   d[nm1] = d[n-2];
+
+   }  /* at least quadratic */
+
+else  /* if n >= 3 */
+   {  /* linear segment only  */
+   b[0] = (y[1] - y[0]) / (x[1] - x[0]);
+   c[0] = 0.0;
+   d[0] = 0.0;
+   b[1] = b[0];
+   c[1] = 0.0;
+   d[1] = 0.0;
+   }
+}  /* end of spline() */
+
+
+/*-------------------------------------------------------------------*/
+/*-----------------------------------------------------------------*/
+/*-----------------------------------------------------------------*/
+double seval (int n, double u,
+              double x[], double y[],
+              double b[], double c[], double d[],
+              int *last)
+/*-----------------------------------------------------------------*/
+/*Purpose ...
+  -------
+  Evaluate the cubic spline function
+
+  S(xx) = y[i] + b[i] * w + c[i] * w**2 + d[i] * w**3
+  where w = u - x[i]
+  and   x[i] <= u <= x[i+1]
+  Note that Horner's rule is used.
+  If u < x[0]   then i = 0 is used.
+  If u > x[n-1] then i = n-1 is used.
+
+  Input :
+  -------
+  n       : The number of data points or knots (n >= 2)
+  u       : the abscissa at which the spline is to be evaluated
+  Last    : the segment that was last used to evaluate U
+  x[]     : the abscissas of the knots in strictly increasing order
+  y[]     : the ordinates of the knots
+  b, c, d : arrays of spline coefficients computed by spline().
+
+  Output :
+  --------
+  seval   : the value of the spline function at u
+  Last    : the segment in which u lies
+
+  Notes ...
+  -----
+  (1) If u is not in the same interval as the previous call then a
+      binary search is performed to determine the proper interval.
+
+*/
+/*-------------------------------------------------------------------*/
+{  /* begin function seval() */
+
+int    i, j, k;
+double w;
+
+i = *last;
+if (i >= n-1) i = 0;
+if (i < 0)  i = 0;
+
+if ((x[i] > u) || (x[i+1] < u))
+  {  /* ---- perform a binary search ---- */
+  i = 0;
+  j = n;
+  do
+    {
+    k = (i + j) / 2;         /* split the domain to search */
+    if (u < x[k])  j = k;    /* move the upper bound */
+    if (u >= x[k]) i = k;    /* move the lower bound */
+    }                        /* there are no more segments to search */
+  while (j > i+1);
+  }
+*last = i;
+
+/* ---- Evaluate the spline ---- */
+w = u - x[i];
+w = y[i] + w * (b[i] + w * (c[i] + w * d[i]));
+return (w);
+}
+/*-------------------------------------------------------------------*/
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/interpolation/interpcseIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/interpolation/interpcseIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..3ce89527df824be433dcd4327815ebd6cdca3d5a
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/interpolation/interpcseIQM.m	
@@ -0,0 +1,23 @@
+% interpcseIQM: Cubic spline interpolation with endpoints
+% This is a MEX function, so this .m file only contains the documentation.
+%
+% USAGE:
+% ======
+% yy = interpcseIQM(x,y,xx)
+% yy = interpcseIQM(x,y,xx,e1,e2)
+% 
+% x:     x-values 
+% y:     y-values
+% xx:    x-values at which to evaluate the spline function (allow multiple)
+% e1,e2: endpoint derivatives (if specified, both need to be given)
+% yy:    interpolated value
+%
+% DEFAULT VALUES:
+% ===============
+% e1, e2:   =0 (no endpoint slopes defined)
+%
+% Output Arguments:
+% =================
+% yy:    scalar or vector of interpolated values.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/interpolation/interpcseIQM.mexa64 b/IQMtools V1.2.2.2/IQMlite/tools/interpolation/interpcseIQM.mexa64
new file mode 100644
index 0000000000000000000000000000000000000000..53de5972d5cc77a64ec98c393ed92fa63c1b78d1
Binary files /dev/null and b/IQMtools V1.2.2.2/IQMlite/tools/interpolation/interpcseIQM.mexa64 differ
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/interpolation/interpcseIQM.mexw32 b/IQMtools V1.2.2.2/IQMlite/tools/interpolation/interpcseIQM.mexw32
new file mode 100644
index 0000000000000000000000000000000000000000..72ad324ef6c3f73eb5dbeb4ef941ff816c0a1243
Binary files /dev/null and b/IQMtools V1.2.2.2/IQMlite/tools/interpolation/interpcseIQM.mexw32 differ
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/interpolation/interpcseIQM.mexw64 b/IQMtools V1.2.2.2/IQMlite/tools/interpolation/interpcseIQM.mexw64
new file mode 100644
index 0000000000000000000000000000000000000000..a7d08831b0bbfc22bfe6afcbb56b8bfe067ddd19
Binary files /dev/null and b/IQMtools V1.2.2.2/IQMlite/tools/interpolation/interpcseIQM.mexw64 differ
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/interpolation/interpcseSlopeIQM.c b/IQMtools V1.2.2.2/IQMlite/tools/interpolation/interpcseSlopeIQM.c
new file mode 100644
index 0000000000000000000000000000000000000000..564d4dbd0a31c0df4054d76ba89f7e8abe010ce4
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/interpolation/interpcseSlopeIQM.c	
@@ -0,0 +1,443 @@
+/*
+ * interpcseSlopeIQM.c: Cubic spline interpolation with endpoints (DERIVATIVE)
+ *
+ * MEX interface: Henning Schmidt
+ * Original C-code for spline interpolation taken from:
+ *   http://www.mech.uq.edu.au/staff/jacobs/nm_lib/cmathsrc/spline.c
+ *
+ * The syntax of this MEX functions is as follows:
+ *
+ * yy = interpcseSlopeIQM(x,y,xx)
+ * yy = interpcseSlopeIQM(x,y,xx,e1,e2)
+ *
+ * x:     x-values 
+ * y:     y-values
+ * xx:    x-values at which to evaluate the spline function (allow multiple)
+ * e1,e2: endpoint derivatives (if specified, both need to be given)
+ * yy:    DERIVATIVE OF SPLINE FUNCTION AT xx
+ */
+
+/* Some includes to be sure we got everything that is needed */
+#include <mex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <string.h>
+#include <matrix.h>
+#include <math.h>
+
+/*
+ *========================================================================
+ * Initialization of the spline related functions
+ *========================================================================
+ */
+void spline (int n, int e1, int e2, double s1, double s2, double x[], double y[], double b[], double c[], double d[], int *flag);
+double deriv (int n, double xx, double x[], double b[], double c[], double d[], int *last);
+
+/*
+ *========================================================================
+ * Definition of needed variables to be passed to the spline functions
+ *========================================================================
+ */
+int     n;          /* The number of data points or knots (n >= 2) */
+int     e1=0;       /* = 1 to specify the slopes at the end points, = 0 to obtain the default conditions */
+int     e2=0;       /* = 1 to specify the slopes at the end points, = 0 to obtain the default conditions */
+double  s1;         /* the slopes at the end point x[0] */
+double  s2;         /* the slopes at the end point x[n-1] */
+double* x;          /* the abscissas of the knots in strictly increasing order */
+double* y;          /* the ordinates of the knots */
+double* b=NULL;     /* arrays of spline coefficients (length n) */
+double* c=NULL;     /* arrays of spline coefficients (length n) */
+double* d=NULL;     /* arrays of spline coefficients (length n) */
+int     flag=0;     /* status flag = 0 normal return = 1 less than two data points; cannot interpolate = 2 x[] are not in ascending order */
+int     last;       /* the segment in which xx lies */
+double* xx;         /* the abscissa at which the spline is to be evaluated */
+double* yy=NULL;    /* the evaluated value at xx */
+int     nx;         /* number of xx values to interpolate the spline function at */
+int     k;          /* loop variable */
+double  b2; 
+double  c2; 
+double  d2; 
+
+/*
+ *===================================
+ * Definition of needed MEX variables
+ *===================================
+ */
+mxArray *xMX = NULL;
+mxArray *yMX = NULL;
+mxArray *xxMX = NULL;
+mxArray *s1MX = NULL;
+mxArray *s2MX = NULL;
+mxArray *yyMX = NULL;
+
+/*
+ *========================================================================
+ * MEX INTERFACE FUNCTION
+ *========================================================================
+ */
+void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
+{
+    /*************************************/
+    /* Check correct number of arguments */
+    /*************************************/
+    /* Check correct number of input arguments */
+    if (nrhs != 3 && nrhs != 5) mexErrMsgTxt("interpcseIQM: Incorrect number of input arguments.");
+    /* Check correct number of output arguments */
+    if (nlhs != 1) mexErrMsgTxt("interpcseIQM: Incorrect number of output arguments.");
+    
+    /**************************************************************************************/
+    /* Get and check input arguments and extract some first info for the spline functions */
+    /**************************************************************************************/
+    /* First input argument needs to be a double vector with length >= 2 */
+    if (!mxIsDouble(prhs[0])) mexErrMsgTxt("interpcseIQM: Check first input argument, it needs to be a vector of x-values.");
+    xMX = (mxArray *) prhs[0];
+    n = mxGetM(xMX)*mxGetN(xMX);
+    if (n<2) mexErrMsgTxt("interpcseIQM: please provide at least n points with n>=2 (add commata as element separators in the vectors!).");
+    else x = mxGetPr(xMX);    
+    
+    /* Second input argument needs to be a double vector with the same length as the first */
+    if (!mxIsDouble(prhs[1])) mexErrMsgTxt("interpcseIQM: Check second input argument, it needs to be a vector of y-values.");
+    yMX = (mxArray *) prhs[1];
+    if (n != mxGetM(yMX)*mxGetN(yMX)) mexErrMsgTxt("interpcseIQM: Second input argument (y-values) needs as many elements as first argument (x-values).");
+    y = mxGetPr(yMX);    
+    
+    /* Third input argument should be a scalar or a vector */
+    if (!mxIsDouble(prhs[2])) mexErrMsgTxt("interpcseIQM: Check third input argument, it needs to be a scalar or vector of numeric values at which to evaluate the spline.");
+    xxMX = (mxArray *) prhs[2];
+    nx = mxGetM(xxMX)*mxGetN(xxMX);
+    if (n<1) mexErrMsgTxt("interpcseIQM: please provide at least 1 points for the third input argument.");
+    xx = mxGetPr(xxMX);    
+
+    if (nrhs > 3) {
+        /* Fourth input argument needs to be a scalar double */
+        if (!mxIsDouble(prhs[3]) || !mxIsScalar(prhs[3])) mexErrMsgTxt("interpcseIQM: Check fourth input argument, it needs to be a scalar numeric value with the first derivative.");
+        s1MX = (mxArray *) prhs[3];
+        s1 = mxGetScalar(s1MX);
+        e1 = 1; /* slope given */
+    
+        /* Fifth input argument needs to be a scalar double */
+        if (!mxIsDouble(prhs[4]) || !mxIsScalar(prhs[4])) mexErrMsgTxt("interpcseIQM: Check fifth input argument, it needs to be a scalar numeric value with the last derivative.");
+        s2MX = (mxArray *) prhs[4];
+        s2 = mxGetScalar(s2MX);
+        e2 = 1; /* slope given */
+    } else {
+        e1 = 0;
+        e2 = 0;
+        s1 = 0.0;
+        s2 = 0.0;
+    }
+    
+    /**************************/
+    /* Create output argument */
+    /**************************/
+    yyMX = mxCreateDoubleMatrix(nx, 1, mxREAL);
+    yy = mxGetPr(yyMX);
+
+    /***********/
+    /* If n==2 */
+    /***********/
+    if (n==2) {        
+        if (e1 == 0 || e2 == 0) mexErrMsgTxt("interpcseIQM: n=2 requires the definition of endpoint-slopes.");
+        b2 = s1;
+        c2 = -(-3.0*y[1]+3.0*y[0]+(s2+2.0*s1)*x[1]+(-s2-2.0*s1)*x[0])/(pow(x[1],2.0)-2.0*x[0]*x[1]+pow(x[0],2.0));
+        d2 = (-2.0*y[1]+2.0*y[0]+(s2+s1)*x[1]+(-s2-s1)*x[0])/(pow(x[1],3.0)-3.0*x[0]*pow(x[1],2.0)+3.0*pow(x[0],2.0)*x[1]-pow(x[0],3.0));
+        
+        /***************************************/
+        /* Call the spline evaluation function */
+        /***************************************/
+        for (k=0;k<nx;k++) {
+            yy[k] = b2 + 2.0*c2*(xx[k]-x[0]) + 3.0*d2*pow(xx[k]-x[0],2.0);
+        }
+    } else {
+    /***********/
+    /* If n!=2 */
+    /***********/        
+        /********************************/
+        /* Allocate memory for b,c,d,yy */
+        /********************************/
+        b  = (double *) mxCalloc(n, sizeof(double));
+        c  = (double *) mxCalloc(n, sizeof(double));
+        d  = (double *) mxCalloc(n, sizeof(double));
+        
+        /****************************/
+        /* Call the spline function */
+        /****************************/
+        spline(n, e1, e2, s1, s2, x, y, b, c, d, &flag);
+        
+        /***************************************/
+        /* Call the spline evaluation function */
+        /***************************************/
+        for (k=0;k<nx;k++) {
+            yy[k] = deriv(n, xx[k], x, b, c, d, &last);
+        }
+        
+        /*************************/
+        /* Free allocated memory */
+        /*************************/
+        mxFree(b);
+        mxFree(c);
+        mxFree(d);
+    }
+
+    /*******************************/
+    /* Return the result to MATLAB */
+    /*******************************/
+    plhs[0] = yyMX;
+}
+
+/*=========================================================================
+   Cubic spline coefficients
+   -------------------------
+   Evaluate the coefficients b[i], c[i], d[i], i = 0, 1, .. n-1 for
+   a cubic interpolating spline
+
+   S(xx) = Y[i] + b[i] * w + c[i] * w**2 + d[i] * w**3
+   where w = xx - x[i]
+   and   x[i] <= xx <= x[i+1]
+
+   The n supplied data points are x[i], y[i], i = 0 ... n-1.
+
+   Input :
+   -------
+   n       : The number of data points or knots (n >= 2)
+   end1,
+   end2    : = 1 to specify the slopes at the end points
+             = 0 to obtain the default conditions
+   slope1,
+   slope2  : the slopes at the end points x[0] and x[n-1]
+             respectively
+   x[]     : the abscissas of the knots in strictly
+             increasing order
+   y[]     : the ordinates of the knots
+
+   Output :
+   --------
+   b, c, d : arrays of spline coefficients as defined above
+             (See note 2 for a definition.)
+   iflag   : status flag
+            = 0 normal return
+            = 1 less than two data points; cannot interpolate
+            = 2 x[] are not in ascending order
+
+   This C code written by ...  Peter & Nigel,
+   ----------------------      Design Software,
+                               42 Gubberley St,
+                               Kenmore, 4069,
+                               Australia.
+
+   Version ... 1.1, 30 September 1987
+   -------     2.0, 6 April 1989    (start with zero subscript)
+                                     remove ndim from parameter list
+               2.1, 28 April 1989   (check on x[])
+               2.2, 10 Oct   1989   change number order of matrix
+
+   Notes ...
+   -----
+   (1) The accompanying function seval() may be used to evaluate the
+       spline while deriv will provide the first derivative.
+   (2) Using p to denote differentiation
+       y[i] = S(X[i])
+       b[i] = Sp(X[i])
+       c[i] = Spp(X[i])/2
+       d[i] = Sppp(X[i])/6  ( Derivative from the right )
+   (3) Since the zero elements of the arrays ARE NOW used here,
+       all arrays to be passed from the main program should be
+       dimensioned at least [n].  These routines will use elements
+       [0 .. n-1].
+   (4) Adapted from the text
+       Forsythe, G.E., Malcolm, M.A. and Moler, C.B. (1977)
+       "Computer Methods for Mathematical Computations"
+       Prentice Hall
+   (5) Note that although there are only n-1 polynomial segments,
+       n elements are requird in b, c, d.  The elements b[n-1],
+       c[n-1] and d[n-1] are set to continue the last segment
+       past x[n-1].
+=========================================================================*/
+void spline (int n, int end1, int end2,
+            double slope1, double slope2,
+            double x[], double y[],
+            double b[], double c[], double d[],
+            int *iflag)
+{  /* begin procedure spline() */
+
+int    nm1, ib, i;
+double t;
+int    ascend;
+
+nm1    = n - 1;
+*iflag = 0;
+
+if (n < 2)
+  {  /* no possible interpolation */
+  *iflag = 1;
+  return;
+  }
+
+ascend = 1;
+for (i = 1; i < n; ++i) if (x[i] <= x[i-1]) ascend = 0;
+if (!ascend)
+   {
+   *iflag = 2;
+   return;
+   }
+
+if (n >= 3)
+   {    /* ---- At least quadratic ---- */
+
+   /* ---- Set up the symmetric tri-diagonal system
+           b = diagonal
+           d = offdiagonal
+           c = right-hand-side  */
+   d[0] = x[1] - x[0];
+   c[1] = (y[1] - y[0]) / d[0];
+   for (i = 1; i < nm1; ++i)
+      {
+      d[i]   = x[i+1] - x[i];
+      b[i]   = 2.0 * (d[i-1] + d[i]);
+      c[i+1] = (y[i+1] - y[i]) / d[i];
+      c[i]   = c[i+1] - c[i];
+      }
+
+   /* ---- Default End conditions
+           Third derivatives at x[0] and x[n-1] obtained
+           from divided differences  */
+   b[0]   = -d[0];
+   b[nm1] = -d[n-2];
+   c[0]   = 0.0;
+   c[nm1] = 0.0;
+   if (n != 3)
+      {
+      c[0]   = c[2] / (x[3] - x[1]) - c[1] / (x[2] - x[0]);
+      c[nm1] = c[n-2] / (x[nm1] - x[n-3]) - c[n-3] / (x[n-2] - x[n-4]);
+      c[0]   = c[0] * d[0] * d[0] / (x[3] - x[0]);
+      c[nm1] = -c[nm1] * d[n-2] * d[n-2] / (x[nm1] - x[n-4]);
+      }
+
+   /* Alternative end conditions -- known slopes */
+   if (end1 == 1)
+      {
+      b[0] = 2.0 * (x[1] - x[0]);
+      c[0] = (y[1] - y[0]) / (x[1] - x[0]) - slope1;
+      }
+   if (end2 == 1)
+      {
+      b[nm1] = 2.0 * (x[nm1] - x[n-2]);
+      c[nm1] = slope2 - (y[nm1] - y[n-2]) / (x[nm1] - x[n-2]);
+      }
+
+   /* Forward elimination */
+   for (i = 1; i < n; ++i)
+     {
+     t    = d[i-1] / b[i-1];
+     b[i] = b[i] - t * d[i-1];
+     c[i] = c[i] - t * c[i-1];
+     }
+
+   /* Back substitution */
+   c[nm1] = c[nm1] / b[nm1];
+   for (ib = 0; ib < nm1; ++ib)
+      {
+      i    = n - ib - 2;
+      c[i] = (c[i] - d[i] * c[i+1]) / b[i];
+      }
+
+   /* c[i] is now the sigma[i] of the text */
+
+   /* Compute the polynomial coefficients */
+   b[nm1] = (y[nm1] - y[n-2]) / d[n-2] + d[n-2] * (c[n-2] + 2.0 * c[nm1]);
+   for (i = 0; i < nm1; ++i)
+      {
+      b[i] = (y[i+1] - y[i]) / d[i] - d[i] * (c[i+1] + 2.0 * c[i]);
+      d[i] = (c[i+1] - c[i]) / d[i];
+      c[i] = 3.0 * c[i];
+      }
+   c[nm1] = 3.0 * c[nm1];
+   d[nm1] = d[n-2];
+
+   }  /* at least quadratic */
+
+else  /* if n >= 3 */
+   {  /* linear segment only  */
+   b[0] = (y[1] - y[0]) / (x[1] - x[0]);
+   c[0] = 0.0;
+   d[0] = 0.0;
+   b[1] = b[0];
+   c[1] = 0.0;
+   d[1] = 0.0;
+   }
+}  /* end of spline() */
+
+
+/*-------------------------------------------------------------------*/
+/*-----------------------------------------------------------------*/
+/*-----------------------------------------------------------------*/
+double deriv (int n, double u,
+              double x[],
+              double b[], double c[], double d[],
+              int *last)
+/*-----------------------------------------------------------------*/
+/* Purpose ...
+   -------
+   Evaluate the derivative of the cubic spline function
+
+   S(x) = B[i] + 2.0 * C[i] * w + 3.0 * D[i] * w**2
+   where w = u - X[i]
+   and   X[i] <= u <= X[i+1]
+   Note that Horner's rule is used.
+   If U < X[0] then i = 0 is used.
+   If U > X[n-1] then i = n-1 is used.
+
+   Input :
+   -------
+   n       : The number of data points or knots (n >= 2)
+   u       : the abscissa at which the derivative is to be evaluated
+   last    : the segment that was last used
+   x       : the abscissas of the knots in strictly increasing order
+   b, c, d : arrays of spline coefficients computed by spline()
+
+   Output :
+   --------
+   deriv : the value of the derivative of the spline
+           function at u
+   last  : the segment in which u lies
+
+   Notes ...
+   -----
+   (1) If u is not in the same interval as the previous call then a
+       binary search is performed to determine the proper interval.
+
+*/
+/*-------------------------------------------------------------------*/
+{  /* begin function deriv() */
+
+int    i, j, k;
+double w;
+
+i = *last;
+if (i >= n-1) i = 0;
+if (i < 0) i = 0;
+
+if ((x[i] > u) || (x[i+1] < u))
+  {  /* ---- perform a binary search ---- */
+  i = 0;
+  j = n;
+  do
+    {
+    k = (i + j) / 2;          /* split the domain to search */
+    if (u < x[k])  j = k;     /* move the upper bound */
+    if (u >= x[k]) i = k;     /* move the lower bound */
+    }                         /* there are no more segments to search */
+  while (j > i+1);
+  }
+*last = i;
+
+/* ---- Evaluate the derivative ---- */
+w = u - x[i];
+w = b[i] + w * (2.0 * c[i] + w * 3.0 * d[i]);
+return (w);
+
+} /* end of deriv() */
+/*-------------------------------------------------------------------*/
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/interpolation/interpcseSlopeIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/interpolation/interpcseSlopeIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..73f15b9d3fe0d8822309efdd4ea3fa4c7cc5e14a
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/interpolation/interpcseSlopeIQM.m	
@@ -0,0 +1,23 @@
+% interpcseSlopeIQM: Cubic spline interpolation with endpoints, returning
+% the derivative at the considered point.
+% This is a MEX function, so this .m file only contains the documentation.
+%
+% USAGE:
+% ======
+% yy = interpcseSlopeIQM(x,y,xx)
+% yy = interpcseSlopeIQM(x,y,xx,e1,e2)
+% 
+% x:     x-values 
+% y:     y-values
+% xx:    x-values at which to evaluate the derivative of the spline function (allow multiple)
+% e1,e2: endpoint derivatives (if specified, both need to be given)
+%
+% DEFAULT VALUES:
+% ===============
+% e1, e2:   =0 (no endpoint slopes defined)
+%
+% Output Arguments:
+% =================
+% yy:    derivative of spline at interpolation point
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/interpolation/interpcseSlopeIQM.mexa64 b/IQMtools V1.2.2.2/IQMlite/tools/interpolation/interpcseSlopeIQM.mexa64
new file mode 100644
index 0000000000000000000000000000000000000000..febd477f4ea371403e86d24ead9265ca9a43a805
Binary files /dev/null and b/IQMtools V1.2.2.2/IQMlite/tools/interpolation/interpcseSlopeIQM.mexa64 differ
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/interpolation/interpcseSlopeIQM.mexw32 b/IQMtools V1.2.2.2/IQMlite/tools/interpolation/interpcseSlopeIQM.mexw32
new file mode 100644
index 0000000000000000000000000000000000000000..ed44deeee33656587078adc2cd4b629f635f6d38
Binary files /dev/null and b/IQMtools V1.2.2.2/IQMlite/tools/interpolation/interpcseSlopeIQM.mexw32 differ
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/interpolation/interpcseSlopeIQM.mexw64 b/IQMtools V1.2.2.2/IQMlite/tools/interpolation/interpcseSlopeIQM.mexw64
new file mode 100644
index 0000000000000000000000000000000000000000..4e9706e5ec27ac711ddfd20a1cc6e7a682f24ecc
Binary files /dev/null and b/IQMtools V1.2.2.2/IQMlite/tools/interpolation/interpcseSlopeIQM.mexw64 differ
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/interpolation/interpcsexIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/interpolation/interpcsexIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..fa92e38d51db09f6f43c6ff4ce2d41735f992a86
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/interpolation/interpcsexIQM.m	
@@ -0,0 +1,40 @@
+function [yy] = interpcsexIQM(x,y,xx,varargin)
+% interpcsexIQM: Cubic spline interpolation with endpoints
+% This is an interface function only to interpcseIQM. Only in the C-code
+% simulation of models there is a difference. interpcseIQM does only
+% evaluate the spline coefficients once in the first call. Subsequent calls
+% only evaluate the spline function. This leads to a considerable speed-up.
+% On the other hand, interpcsexIQM in the C-code simulation does evaluate
+% the spline coefficients each time it is called. => time dependent splines
+% can be implemented. However, for MATLAB simulation there is no
+% difference.
+%
+% USAGE:
+% ======
+% yy = interpcsexIQM(x,y,xx)
+% yy = interpcsexIQM(x,y,xx,e1,e2)
+% 
+% x:     x-values 
+% y:     y-values
+% xx:    x-values at which to evaluate the spline function (allow multiple)
+% e1,e2: endpoint derivatives (if specified, both need to be given)
+% yy:    interpolated value
+%
+% DEFAULT VALUES:
+% ===============
+% e1, e2:   =0 (no endpoint slopes defined)
+%
+% Output Arguments:
+% =================
+% yy:    scalar or vector of interpolated values.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+if nargin < 3 || nargin > 5,
+    error('interpcsexIQM: incorrect number of input arguments.');
+elseif nargin == 3,
+    yy = interpcseIQM(x,y,xx);
+elseif nargin == 5,
+    yy = interpcseIQM(x,y,xx,varargin{1},varargin{2});
+end    
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/interpolation/interpcsexSlopeIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/interpolation/interpcsexSlopeIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..99de226306cee389a0778e59b7ab577c8437b74d
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/interpolation/interpcsexSlopeIQM.m	
@@ -0,0 +1,39 @@
+function [yy] = interpcsexSlopeIQM(x,y,xx,varargin)
+% interpcsexSlopeIQM: Cubic spline interpolation with endpoints (DERIVATIVE)
+% This is an interface function only to interpcseSlopeIQM. Only in the C-code
+% simulation of models there is a difference. interpcseSlopeIQM does only
+% evaluate the spline coefficients once in the first call. Subsequent calls
+% only evaluate the spline function. This leads to a considerable speed-up.
+% On the other hand, interpcsexSlopeIQM in the C-code simulation does evaluate
+% the spline coefficients each time it is called. => time dependent splines
+% can be implemented. However, for MATLAB simulation there is no
+% difference.
+%
+% USAGE:
+% ======
+% yy = interpcsexSlopeIQM(x,y,xx)
+% yy = interpcsexSlopeIQM(x,y,xx,e1,e2)
+% 
+% x:     x-values 
+% y:     y-values
+% xx:    x-values at which to evaluate the derivative of the spline function (allow multiple)
+% e1,e2: endpoint derivatives (if specified, both need to be given)
+%
+% DEFAULT VALUES:
+% ===============
+% e1, e2:   =0 (no endpoint slopes defined)
+%
+% Output Arguments:
+% =================
+% yy:    spline derivative at the interpolated point (xx)
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+if nargin < 3 || nargin > 5,
+    error('interpcsexSlopeIQM: incorrect number of input arguments.');
+elseif nargin == 3,
+    yy = interpcseSlopeIQM(x,y,xx);
+elseif nargin == 5,
+    yy = interpcseSlopeIQM(x,y,xx,varargin{1},varargin{2});
+end    
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/IQMeditBCGUI/IQMeditBC.fig b/IQMtools V1.2.2.2/IQMlite/tools/model/IQMeditBCGUI/IQMeditBC.fig
new file mode 100644
index 0000000000000000000000000000000000000000..48fc139528aeb7bb236d6d69c682173a305c201a
Binary files /dev/null and b/IQMtools V1.2.2.2/IQMlite/tools/model/IQMeditBCGUI/IQMeditBC.fig differ
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/IQMeditBCGUI/IQMeditBC.m b/IQMtools V1.2.2.2/IQMlite/tools/model/IQMeditBCGUI/IQMeditBC.m
new file mode 100644
index 0000000000000000000000000000000000000000..f2576bf3c07dbe5431be9076fc895623c0f7cbec
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/IQMeditBCGUI/IQMeditBC.m	
@@ -0,0 +1,756 @@
+function varargout = IQMeditBC(varargin)
+% IQMeditBC: GUI for editing IQMmodels in a more biochemically oriented format
+%
+% USAGE:
+% ======
+% [model] = IQMeditBC()
+% [model] = IQMeditBC(modelin)
+%
+% modelin: input IQMmodel for editing
+%
+% Output Arguments:
+% =================
+% model: edited IQMmodel as output
+%
+%
+% Explanation of differences between an ODE based model and a model in 
+% biochemical representation =========================================
+% ===========================
+% - All states in the biochemical representation correspond to species.
+% - In the "STATE INFORMATION"-part of the model description initial
+% conditions and optional information is entered. Additionally ODEs for
+% states can be defined just as in IQMedit (except that the additional
+% information and the comment then is added after the initial condition and
+% not after the ODE).
+% - In the "REACTIONS"-part of the model reaction equations are defined,
+% instead of reaction rates. Please refer to the help text in the IQMeditBC
+% GUI for more information about the syntax.
+% - All reaction rates are expected to have amount/time units. As long as
+% no compartments are present in the model or that all compartment sizes
+% are equal to 1, amount/time and concentration/time will give the same
+% result.
+%
+% Explanation of the OPTIONAL INFORMATION 
+% =======================================
+% States, parameters, and variables can be provided with additional
+% information that is optional. This information is required for the export
+% to SBML and for the conversion of an ODE based description of an IQMmodel
+% to a biochemical representation of an IQMmodel and vice versa.
+%
+% For species the additional information has the following syntax:
+%     {'isSpecie':speciescompartment:speciesunittype}
+% the speciescompartment is a string with the name of the compartment the
+% species is located in. this compartment name has to be the name of a
+% variable, or a parameter that is defined as a compartment (see
+% below). The speciesunittype is either 'amount' or 'concentration'. 
+%
+% For compartments the additional information has the following syntax:
+%     {'isCompartment':nameoutsidecompartment}
+% where nameoutsidecompartment is a string with the name of the outside
+% compartment. if there is no outside compartment the name should be
+% represented by an empty string. example - correct: {'isCompartment':}. 
+% example - wrong: {'isCompartment'} (missing ':').
+%
+% For constant values (parameters) the additional information has the following syntax:
+%     {'isParameter'}
+%
+% As long as no compartments are present in the model and the model is not
+% supposed to be exported to SBML the optional infomation is not required
+% to be present.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+% Begin initialization code - DO NOT EDIT
+gui_Singleton = 1;
+gui_State = struct('gui_Name',       mfilename, ...
+                   'gui_Singleton',  gui_Singleton, ...
+                   'gui_OpeningFcn', @IQMeditBC_OpeningFcn, ...
+                   'gui_OutputFcn',  @IQMeditBC_OutputFcn, ...
+                   'gui_LayoutFcn',  [], ...
+                   'gui_Callback',   []);
+if nargin && ischar(varargin{1})
+   gui_State.gui_Callback = str2func(varargin{1});
+end
+if nargout
+    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
+else
+    gui_mainfcn(gui_State, varargin{:});
+end
+% End initialization code - DO NOT EDIT
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GUI STANDARD FUNCTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% OPENING FUNCTION (AFTER CREATION)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function IQMeditBC_OpeningFcn(hObject, eventdata, handles, varargin)
+
+% Process input argument
+nvarargin = nargin-3;
+textModel = 0;
+if nvarargin == 0,
+    % start with empty IQMmodel
+    iqm = IQMmodel();
+else
+    if strcmp('IQMmodel',class(varargin{1})),
+        iqm = varargin{1};
+    else 
+        error('Input argument of unknown type');
+        delete(hObject);
+    end
+end
+try
+    handles.editText = convertModelToTextBCIQM(iqm);  
+catch
+    if nvarargin ~= 0,
+        handles.editText.name = sprintf('Error converting the IQMmodel to the biochemical representation!\n%s',lasterr);
+    else 
+        handles.editText.name = '';
+    end
+    handles.editText. notes = '';
+    handles.editText.states = '';
+    handles.editText.parameters = '';
+    handles.editText.variables = '';
+    handles.editText.reactions = '';
+    handles.editText.events = '';
+    handles.editText.functions = '';
+    handles.editText.functionsMATLAB = '';
+end
+handles.output = iqm;               
+% Create data used by the different callbacks
+handles.helpText = getHelpText();
+handles.activeView = 'complete';
+handles.IQMplotHandle = [];
+% Initialize the IQMeditBC window with initial content
+set(handles.editor,'String',setPartsToCompleteTextBCIQM(handles.editText));
+set(handles.helptext,'String',handles.helpText.complete);
+set(handles.headline,'String','Complete Model View');
+set(handles.time,'String','20');
+% Update handles structure
+guidata(hObject, handles);
+uiwait;
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% OUTPUT TO COMMAND LINE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function varargout = IQMeditBC_OutputFcn(hObject, eventdata, handles)
+% varargout  cell array for returning output args (see VARARGOUT);
+varargout{1} = handles.output;
+% close the GUI
+delete(hObject);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CLOSE CALLBACK
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function IQMeditBC_CloseRequestFcn(hObject, eventdata, handles)
+% warn that last changes will get lost 
+% and let the user choose
+selection = questdlg(sprintf('Close IQMeditBC?\nChanges made in the last window will get lost!\nIf you want to keep changes press the ''Exit''\nbutton instead.'),...
+                     'Close Request Function',...
+                     'Yes','No','Yes');
+switch selection,
+    case 'Yes',
+        uiresume;
+    case 'No'
+        return
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GUI SPECIALIZED FUNCTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% SIMULATE CALLBACK
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function simulate_Callback(hObject, eventdata, handles)
+    global lastSimulationValue
+    errorSimulation = 0;
+    % Update all views
+    handles = updateAllViews(handles);
+    % convert the text description into an IQMmodel
+    [iqm, errorFlag] = convertTextToModel(handles);
+    if ~errorFlag,
+        % get the simulation time
+        timeString = get(handles.time,'String');
+        time = str2double(timeString);
+        % Simulate IQMmodel for given time
+        % catch all possible errors
+        try
+            tspan = [0:time/1000:time];
+            % handles also non-numeric ics
+            outputSimulation = IQMsimulate(iqm,'ode23s',tspan,IQMcalcICvector(iqm));
+        catch
+            % Process the simulation error
+            processError(lasterr,'Error during simulation');
+            errorSimulation = 1;
+        end
+        if ~errorSimulation,
+            % Try to close previous IQMplot figure
+            try
+                close handles.IQMplotHandle;
+            catch
+            end
+            % prepare data for plotting
+            time = outputSimulation.time;
+            datanames = {};
+            dataindex = 1;
+            for k = 1:length(outputSimulation.states),
+                datanames{dataindex} = char([double(outputSimulation.states{k}) double(' (state)')]); % fastest strcat
+                dataindex = dataindex + 1;
+            end
+            for k = 1:length(outputSimulation.variables),
+                datanames{dataindex} = char([double(outputSimulation.variables{k}) double(' (variable)')]); % fastest strcat 
+                dataindex = dataindex + 1;
+            end
+            for k = 1:length(outputSimulation.reactions),
+                datanames{dataindex} = char([double(outputSimulation.reactions{k}) double(' (reaction)')]); % fastest strcat  
+                dataindex = dataindex + 1;
+            end
+            datavalues = [outputSimulation.statevalues, outputSimulation.variablevalues, outputSimulation.reactionvalues];
+            handles.IQMplotHandle = IQMplot(createdatastructIQMplotIQM(time,datavalues,datanames));
+            % make button for updating initial conditions visible
+            set(handles.updateICsimulate,'Visible','on');
+            lastSimulationValue = outputSimulation.statevalues(end,:);
+        end
+    end
+    % Update handles structure
+    guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% UPDATE INITIAL CONDITIONS WITH LAST VALUE OF SIMULATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function updateICsimulate_Callback(hObject, eventdata, handles)
+    global lastSimulationValue
+    % Update all views
+    handles = updateAllViews(handles);
+    % convert the text description into an IQMmodel
+    [iqm, errorFlag] = convertTextToModel(handles);
+    if ~errorFlag,
+        % set new initial conditions (handle also non-numeric initial
+        % conditions)
+        iqm = IQMoverwriteICs(iqm,lastSimulationValue);
+        % convert model to text again 
+        handles.editText = convertModelToTextBCIQM(iqm); 
+        % rewrite the data in the current view (only needed if the view
+        % shows state or complete information)
+        if strcmp(handles.activeView,'states'),
+            % Update editor content with state information
+            set(handles.editor,'String',handles.editText.states);
+        elseif strcmp(handles.activeView,'complete'),
+            % Update editor content with complete information
+            completeEditText = setPartsToCompleteTextBCIQM(handles.editText);
+            set(handles.editor,'String',completeEditText);
+        end
+    end
+    % Update handles structure
+    guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% STEADY-STATE CALLBACK
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function steadystate_Callback(hObject, eventdata, handles)
+    global steadyStateValues
+    errorSteadyState = 0;
+    % Update all views
+    handles = updateAllViews(handles);
+    % convert the text description into an IQMmodel
+    [iqm, errorFlag] = convertTextToModel(handles);
+    if ~errorFlag,
+        % get the steady-state
+        try
+            [steadystate,residual,message] = IQMsteadystate(iqm);
+        catch
+            % Process the steadystate error
+            processError(lasterr,'Error during steady-state computation');
+            errorSteadyState = 1;
+        end
+        if ~errorSteadyState,
+            % construct result text and display it in the editor window
+            resultText = sprintf('%s',message);
+            if ~isempty(steadystate),
+                resultText = sprintf('%s\nThe steady-state is given by:\n',message);
+                IQMstructure = IQMstruct(iqm);
+                for k = 1:length(IQMstructure.states),
+                    stateName = IQMstructure.states(k).name;
+                    resultText = sprintf('%s\n%s = %g',resultText,stateName,steadystate(k));
+                end
+                % make button for updating initial conditions visible
+                set(handles.updateIC,'Visible','on');
+                steadyStateValues = steadystate;
+            else
+                resultText = sprintf('%s\nIn order to start at a different steady-state you can change to initial conditions for the states. Changing the options of the steady-state solver is only possible from the command line version of IQMsteadystate',resultText);
+            end
+            set(handles.editor,'String',resultText);
+            % Update help text with complete help
+            set(handles.helptext,'String',handles.helpText.steadystate);
+            % Update headline text
+            set(handles.headline,'String','Steady State of Model');
+            % Set new active view
+            handles.activeView = 'steadystate';
+        end
+    end
+    % Update handles structure
+    guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% UPDATE INITIAL CONDITIONS WITH STEADY STATE INFORMATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function updateIC_Callback(hObject, eventdata, handles)
+    global steadyStateValues
+    % Update all views
+    handles = updateAllViews(handles);
+    % convert the text description into an IQMmodel
+    [iqm, errorFlag] = convertTextToModel(handles);
+    if ~errorFlag,
+        % set new initial conditions (handle also non-numeric initial
+        % conditions)
+        iqm = IQMoverwriteICs(iqm,steadyStateValues);
+        % convert model to text again 
+        handles.editText = convertModelToTextBCIQM(iqm);  
+    end
+    % Update handles structure
+    guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EXPORT TEXTBC CALLBACK
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function exportTextBC_Callback(hObject, eventdata, handles)
+    % Update all views
+    handles = updateAllViews(handles);
+    % get filename for the TXTBC file
+    [filename, pathname] = uiputfile('*.txtbc', 'Save IQMmodel as .txtbc file');
+    % check if a filename returned
+    if filename ~= 0,
+        % cut of the extension from the filename
+        [path,filename,ext] = fileparts(filename);
+        % remove whitespaces from filename
+        filename = strrep(filename,' ','');
+        % add the extension
+        filepathname = strcat(pathname,'/',filename,'.txtbc');
+        % save the TextFile
+        completeEditText = setPartsToCompleteTextBCIQM(handles.editText);
+        fid = fopen(filepathname,'w');
+        fwrite(fid,completeEditText);
+        status = fclose(fid);
+    end
+    % Update handles structure
+    guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EXPORT TEXT CALLBACK
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function exportText_Callback(hObject, eventdata, handles)
+    % Update all views
+    handles = updateAllViews(handles);
+    % get filename for the TXT file
+    [filename, pathname] = uiputfile('*.txt', 'Save IQMmodel as .txt file');
+    % check if a filename returned
+    if filename ~= 0,
+        % cut of the extension from the filename
+        [path,filename,ext] = fileparts(filename);
+        % remove whitespaces from filename
+        filename = strrep(filename,' ','');
+        % add the extension
+        filepathname = strcat(pathname,'/',filename,'.txt');
+        % convert the text description into an IQMmodel
+        [iqm, errorFlag] = convertTextToModel(handles);
+        if ~errorFlag,
+            % convert the model into a TEXT description
+            [modelTextStructure] = convertModelToTextIQM(iqm);
+            [completeText] = setPartsToCompleteTextIQM(modelTextStructure);
+            % save the text
+            fid = fopen(filepathname,'w');
+            fwrite(fid,completeText);
+            status = fclose(fid);
+        end
+    end
+    % Update handles structure
+    guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EXIT IQMEDITBC CALLBACK
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function exit_Callback(hObject, eventdata, handles)
+    % Update all views
+    handles = updateAllViews(handles);
+    % convert the text description into an IQMmodel
+    [iqm, errorFlag] = convertTextToModel(handles);
+    if ~errorFlag,
+        % set edited IQMmodel as output
+        handles.output = iqm;
+    end
+    % Update handles structure
+    guidata(hObject, handles);
+    uiresume;
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GUI EDITOR BUTTONS FUNCTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EDIT COMPLETE MODEL DESCRIPTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function complete_Callback(hObject, eventdata, handles)
+    % Update all views
+    handles = updateAllViews(handles);
+    % Update editor content with complete information
+    completeEditText = setPartsToCompleteTextBCIQM(handles.editText);
+    set(handles.editor,'String',completeEditText);
+    % Update help text with complete help
+    set(handles.helptext,'String',handles.helpText.complete);    
+    % Update headline text
+    set(handles.headline,'String','Complete Model View');
+    % Set new active view
+    handles.activeView = 'complete';
+    % Update handles structure
+    guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EDIT NAME MODEL DESCRIPTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function name_Callback(hObject, eventdata, handles)
+    % Update all views
+    handles = updateAllViews(handles);
+    % Update editor content with name information
+    set(handles.editor,'String',handles.editText.name);
+    % Update help text with name help
+    set(handles.helptext,'String',handles.helpText.name);    
+    % Update headline text
+    set(handles.headline,'String','Model Name View');
+    % Set new active view
+    handles.activeView = 'name';
+    % Update handles structure
+    guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EDIT NOTES MODEL DESCRIPTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function notes_Callback(hObject, eventdata, handles)
+    % Update all views
+    handles = updateAllViews(handles);
+    % Update editor content with notes information
+    set(handles.editor,'String',handles.editText.notes);
+    % Update help text with notes help
+    set(handles.helptext,'String',handles.helpText.notes);    
+    % Update headline text
+    set(handles.headline,'String','Model Notes View');
+    % Set new active view
+    handles.activeView = 'notes';
+    % Update handles structure
+    guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% VIEW HTML NOTES CALLBACK
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function htmlnotes_Callback(hObject, eventdata, handles)
+    % Update all views
+    handles = updateAllViews(handles);
+    % Update editor content with notes information
+    set(handles.editor,'String',handles.editText.notes);
+    % Update help text with notes help
+    set(handles.helptext,'String',handles.helpText.notes);    
+    % Update headline text
+    set(handles.headline,'String','Model Notes View');
+    % Set new active view
+    handles.activeView = 'notes';
+    % get the text in the notes
+    notesText = handles.editText.notes;
+    % write this text to a temporary html file
+    filefullpath = strcat(tempnameIQM,'.html');
+    fid = fopen(filefullpath,'w');
+    fprintf(fid,notesText);
+    status = fclose(fid);
+    % open and display the file
+    open(filefullpath);
+    % Update handles structure
+    guidata(hObject, handles);    
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EDIT STATES MODEL DESCRIPTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function states_Callback(hObject, eventdata, handles)
+    % Update all views
+    handles = updateAllViews(handles);
+    % Update editor content with states information
+    set(handles.editor,'String',handles.editText.states);
+    % Update help text with states help
+    set(handles.helptext,'String',handles.helpText.states);    
+    % Update headline text
+    set(handles.headline,'String','Model States View');
+    % Set new active view
+    handles.activeView = 'states';
+    % Update handles structure
+    guidata(hObject, handles);
+return
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EDIT PARAMETERS MODEL DESCRIPTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function parameters_Callback(hObject, eventdata, handles)
+    % Update all views
+    handles = updateAllViews(handles);
+    % Update editor content with parameters information
+    set(handles.editor,'String',handles.editText.parameters);
+    % Update help text with parameters help
+    set(handles.helptext,'String',handles.helpText.parameters);    
+    % Update headline text
+    set(handles.headline,'String','Model Parameters View');
+    % Set new active view
+    handles.activeView = 'parameters';
+    % Update handles structure
+    guidata(hObject, handles);
+return
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EDIT VARIABLES MODEL DESCRIPTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function variables_Callback(hObject, eventdata, handles)
+    % Update all views
+    handles = updateAllViews(handles);
+    % Update editor content with variables information
+    set(handles.editor,'String',handles.editText.variables);
+    % Update help text with variables help
+    set(handles.helptext,'String',handles.helpText.variables);    
+    % Update headline text
+    set(handles.headline,'String','Model Variables View');
+    % Set new active view
+    handles.activeView = 'variables';
+    % Update handles structure
+    guidata(hObject, handles);
+return
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EDIT REACTIONS MODEL DESCRIPTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function reactions_Callback(hObject, eventdata, handles)
+    % Update all views
+    handles = updateAllViews(handles);
+    % Update editor content with reactions information
+    set(handles.editor,'String',handles.editText.reactions);
+    % Update help text with reactions help
+    set(handles.helptext,'String',handles.helpText.reactions);    
+    % Update headline text
+    set(handles.headline,'String','Model Reactions View');
+    % Set new active view
+    handles.activeView = 'reactions';
+    % Update handles structure
+    guidata(hObject, handles);
+return
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EDIT FUNCTIONS MODEL DESCRIPTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function functions_Callback(hObject, eventdata, handles)
+    % Update all views
+    handles = updateAllViews(handles);
+    % Update editor content with functions information
+    set(handles.editor,'String',handles.editText.functions);
+    % Update help text with functions help
+    set(handles.helptext,'String',handles.helpText.functions);    
+    % Update headline text
+    set(handles.headline,'String','Model Functions View');
+    % Set new active view
+    handles.activeView = 'functions';
+    % Update handles structure
+    guidata(hObject, handles);
+return
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EDIT EVENTS MODEL DESCRIPTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function events_Callback(hObject, eventdata, handles)
+    % Update all views
+    handles = updateAllViews(handles);
+    % Update editor content with events information
+    set(handles.editor,'String',handles.editText.events);
+    % Update help text with events help
+    set(handles.helptext,'String',handles.helpText.events);    
+    % Update headline text
+    set(handles.headline,'String','Model Events View');
+    % Set new active view
+    handles.activeView = 'events';
+    % Update handles structure
+    guidata(hObject, handles);
+return
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EDIT MATLAB FUNCTIONS MODEL DESCRIPTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function functionsMATLAB_Callback(hObject, eventdata, handles)
+    % Update all views
+    handles = updateAllViews(handles);
+    % Update editor content with functions information
+    set(handles.editor,'String',handles.editText.functionsMATLAB);
+    % Update help text with functions help
+    set(handles.helptext,'String',handles.helpText.functionsMATLAB);    
+    % Update headline text
+    set(handles.headline,'String','Model MATLAB Functions View');
+    % Set new active view
+    handles.activeView = 'functionsMATLAB';
+    % Update handles structure
+    guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% OTHER FUNCTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% UPDATE ALL VIEWS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Update the views data variables and restructure matrix text to string text
+function [handles] = updateAllViews(handles)
+% set the update IC buttons to invisible 
+    set(handles.updateIC,'Visible','off');
+    set(handles.updateICsimulate,'Visible','off');    
+    % do the rest
+    if ~strcmp(handles.activeView,'steadystate') && ~strcmp(handles.activeView,'exportsbml'),
+        % Do this only if active view has been some model text
+        if ~strcmp(handles.activeView,'complete'),
+            % Get editor content in variable corresponding to the active view
+            evalString = sprintf('matrixText = get(handles.editor,''String'');',handles.activeView);
+            eval(evalString);
+            % Restructure the content from matrix to string
+            stringText = convertMatrixToStringText(matrixText);
+            % Update view content with string text
+            evalString = sprintf('handles.editText.%s = stringText;',handles.activeView);
+            eval(evalString);
+        elseif strcmp(handles.activeView,'complete'),
+            % Get the text in the complete view
+            matrixText = get(handles.editor,'String');
+            % Restructure the content from matrix to string
+            completeEditText = convertMatrixToStringText(matrixText);
+            % Cut text in pieces and update the different views
+            handles.editText = getPartsFromCompleteTextBCIQM(completeEditText);
+        end
+    end
+return
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CONVERT MATRIX TEXT TO STRING
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [stringText] = convertMatrixToStringText(matrixText)
+    % convert text to numbers
+    doubleText = double(matrixText);
+    % exchange all "LF" and "CR" against "32"
+    doubleText(find(doubleText==10)) = 32;
+    doubleText(find(doubleText==13)) = 32;
+    % add new line character to each line, then transpose the matrix
+    doubleText = [doubleText 10*ones(size(doubleText,1),1)]';
+    % vectorize the matrix and transpose again
+    vectorDoubleText = doubleText(:)';
+    % get the text
+    stringText = char(vectorDoubleText);
+return
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CONVERT TEXT DESCRIPTION TO IQMMODEL
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [iqm, errorFlag] = convertTextToModel(handles)
+    % convert the text description to an IQMmodel
+    errorFlag = 0;
+    completeEditText = setPartsToCompleteTextBCIQM(handles.editText);
+    [IQMstructure,errorMsg] = convertTextBCToModelIQM(completeEditText);
+    if ~isempty(errorMsg),
+        errordlg(errorMsg,'Error','On');
+        errorFlag = 1;
+        iqm = [];
+    else
+        %%%%%%%%%%%%%%%%%% Construct model and return
+        iqm = IQMmodel(IQMstructure);
+    end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DEFINE HELP TEXTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [helpText] = getHelpText()
+    % Define the help texts for the different sections
+    helpText.complete = sprintf('The editor shows a view of the complete model. You can edit the model using this view or the other views (Name, Notes, States, etc.). More information about the syntax of the model description can be found in the help text for the different views.\n\nIMPORTANT: Do not change the limiters (e.g., "********** MODEL PARAMETERS") between the different parts of the model. The order of the different parts IS important and should not be changed.');
+    helpText.name = 'Here you can enter the name of the model. All spaces and line breaks are being ignored but displayed. Allowed characters are characters you would expect a MATLAB function to consist of (a-z,A-Z,0-9,-,_)';
+    helpText.notes = 'Here you can enter notes about the model. Any characters are allowed';
+    helpText.states = sprintf('In this view you enter the initial conditions for the species in the model. Initial conditions are in principle optional. If no initial condition is given for a species, it is set to zero by default. Definitions of initial conditions start always in a new line but can go over several lines. The syntax is "statename(0) = initial value {optional information} %% optional comment". Spaces and line breaks are ignored. Furthermore, you can add ODEs using the same syntax as in IQMedit ("d/dt(statename) = ODE expression"). Note that in IQMeditBC the additional information and the comment are added after the initial conditions. To learn more about the optional information, please type "help IQMeditBC".\nThe optional comment is not allowed to contain any square brackets or the strings "d/dt(" and "(0)".\n\nAlgebraic Rules: They are defined between the ODEs and the initialconditions. Their syntax is as follows: "0 = mathematical expression : variable %% optional comment". The “variable” is the one which is determined by the AR.');
+    helpText.parameters = 'In this view you can enter the models parameters. A new parameter definition starts always in a new line. The syntax is "parametername = numerical value {optional information} %% optional comment". Spaces and line breaks are ignored. The "parametername" needs to consist of characters that are allowed for MATLAB variables. Parameter names are not allowed to have the same name as states, variables, reactions, or functions.\nThe optional information is placed in square brackets. To learn more about the optional information, please type "help IQMeditBC". The optional comment is not allowed to contain the character "=".';
+    helpText.variables = 'In this view you can enter the models variables. A new variable definition starts always in a new line, but can go over several lines. The syntax is "variablename = expression {optional information} %% optional comment". Spaces and line breaks are ignored. The "variablename" needs to consist of characters that are allowed for MATLAB variables. The expression can contain states, variables that have been declared before, and parameters. Variable names are not allowed to have the same name as states, parameters, reactions, or functions.\nThe optional information is placed in square brackets. To learn more about the optional information, please type "help IQMeditBC".\nThe optional comment is not allowed to contain the character "=".';
+    helpText.reactions = sprintf('In this view you can enter the models reaction equations. A new reaction equation definition starts always in a new line but can go over several lines. The syntax for reversible reactions is:\n  substrate terms <=> product terms : reactionname {fast} %% optional comment"\n      vf = forward reaction rate formula\n      vr = reverse reaction rate formula\nand the syntax for irreversible reactions is:\n  substrate terms => product terms : reactionname %% optional comment."\n      vf = forward reaction rate formula\nThe substrate and product terms are defined by "stoichiometry1*species1 + stoichiometry2*species2+...". Spaces and line breaks are ignored. The "reactionname" and the species names need to consist of characters that are allowed for MATLAB variables. In the reaction comments the characters "=", "=>", "<=>", ":", "vf=", and "vr=" are NOT ALLOWED!\nThe identifier "{fast}" indicates that a reaction happens infinitely fast and should only be present in this case.');
+    helpText.functions = 'In this view you can enter functions that are used in the mathematical expressions of the model. A new function definition starts always in a new line, but can go over several lines. The syntax is "functionname(argumentname1, argumentname2, ...) = expression %% optional comment". Spaces and line breaks are ignored. The "functionname" and the names of the arguments needs to consist of characters that are allowed for MATLAB variables. Function names are not allowed to have the same name as states, parameters, variables, or reactions. The optional comment is not allowed to contain the character "=".';        
+    helpText.events = 'In this view you can enter events that are used to set state variables of the model to certain values when a certain condition is fulfilled. The syntax for an event is: "eventname=trigger,variable1,value1,...,variablen,valuen %% optional comment". The values can be numerical but also be represented by a formula that is allowed to contain states, parameters, etc. The trigger expression is an arbitrary boolean expression which goes from false to true in the case that an event should be fired. The event is only fired when the trigger function goes from false to true. The optional comment is not allowed to contain the character "=".';
+    helpText.functionsMATLAB = 'In this view you can enter functions in the standard MATLAB syntax. This feature is used, e.g., to implement the SBML piecewise operator, but it can also be used to implement events such as changing a certain parameter at a certain time, etc. States, however, can not be changed. Calls for the defined functions have then to be placed correctly in the other parts of the model.';
+    helpText.steadystate = 'This view shows the result of the steady-state computation. The steady-state computation uses the initial conditions of the models states as starting guess. If the steady-state computation fails you can try to change the initial conditions of the model. The steady-state computation also gives information over possible linear dependencies between the ODEs, resulting in algebraic relations between certain states, of the model.';
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS ERRORS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Errors occurr due to errors in the created m file (undefined 
+% identifiers mainly). Here we interprete the error message and inform
+% the user. If error reason can't be found then just print the initial
+% error message
+function [] = processError(lasterr, title)
+    errorString = lasterr;
+    % parse the error string
+    if ~isempty(strfind(errorString,'Error:')),
+        % cut off error substring
+        errorString = errorString(8:end);
+        if ~isempty(strfind(errorString,'File:')),
+            errorString = errorString(7:end);
+            temp = strfind(errorString,'Line:');
+            if ~isempty(temp),
+                % extract the filename
+                filename = strtrim(errorString(1:temp(1)-1));
+                % extract line number
+                temp2 = strfind(errorString,'Column:');
+                linenumber = str2num(strtrim(errorString(temp(1)+6:temp2(1)-1)));
+                % open the ODE file and extract the line "linenumber"
+                fid = fopen(filename, 'r');
+                for k = 1:linenumber,
+                    linecontent = fgetl(fid);
+                end
+                fclose(fid);
+                % replace all characters < 32 by 32
+                temp = double(linecontent);
+                temp(find(temp<32)) = 32;
+                linecontent = char(temp);
+                errordlg(sprintf('%s\n\n%s',title,linecontent),'Error','on');
+            else
+                errordlg(sprintf('%s\n\n%s',title,errorString),'Error','on');
+            end
+        else
+            errordlg(sprintf('%s\n\n%s',title,lasterr),'Error','on');
+        end
+    else
+        errordlg(sprintf('%s\n\n%s',title,lasterr),'Error','on');
+    end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DELETE WHITESPACES IN STRINGS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Useful for taking away whitespaces in kineticLaw formulas, as
+% seen in some example models
+function [outputString] = removeWhiteSpace(inputString)
+outputString = strrep(inputString,' ','');
+% return
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/IQMeditGUI/IQMedit.fig b/IQMtools V1.2.2.2/IQMlite/tools/model/IQMeditGUI/IQMedit.fig
new file mode 100644
index 0000000000000000000000000000000000000000..3ee362619c3a03a58c6866da1ed2b072ff09d732
Binary files /dev/null and b/IQMtools V1.2.2.2/IQMlite/tools/model/IQMeditGUI/IQMedit.fig differ
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/IQMeditGUI/IQMedit.m b/IQMtools V1.2.2.2/IQMlite/tools/model/IQMeditGUI/IQMedit.m
new file mode 100644
index 0000000000000000000000000000000000000000..256537c2dd930ff876e8ea1c6217b6782b39bdb3
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/IQMeditGUI/IQMedit.m	
@@ -0,0 +1,742 @@
+function varargout = IQMedit(varargin)
+% IQMedit: GUI for editing IQMmodels
+%
+% USAGE:
+% ======
+% [model] = IQMedit()
+% [model] = IQMedit(modelin)
+%
+% modelin: input IQMmodel for editing
+%
+% Output Arguments:
+% =================
+% model: edited IQMmodel as output
+%
+% Requirements for an ODE representation to be converted to a biochemical
+% representation of an IQMmodel =========================================
+% =============================
+% - All states in the biochemical representation correspond to species,
+% this means in the ODE representation no states are allowed whose ODEs are
+% not defined in terms of reaction rates.
+% - Reversible reactions need to be identified as such by setting the
+% "[reversible]" identifier. The reaction rate expression is then required
+% to have the format:    ReactionName = ForwardRate - ReverseRate
+% - In case that compartments are present in the model, the optional
+% information for the states (see below) is not anymore optional.
+% Furthermore, then the reaction rates are assumed to represent amount
+% rates (as is done in SBML).
+% 
+% As long as no compartments are present in the model (or that all
+% compartment sizes are equal to 1) the optional information might be
+% neglected.
+%
+% Explanation of the OPTIONAL INFORMATION
+% =======================================
+% States, parameters, and variables can be provided with additional
+% information that is optional. This information is required for the export
+% to SBML and for the conversion of an ODE based description of an IQMmodel
+% to an biochemical representation of an IQMmodel.
+%
+% States, parameters, and variables can have different biochemical interpretations:
+% They can represent species, compartment sizes, and/or parameters. Each of
+% these three can be defined by ODEs, static relationships, or constant
+% values.
+%
+% For species the additional information has the following syntax:
+%     {'isSpecie':speciescompartment:speciesunittype}
+% the speciescompartment is a string with the name of the compartment the
+% species is located in. this compartment name has to be the name of a
+% state, a variable, or a parameter that is defined as a compartment (see
+% below). the speciesunittype is either 'amount' or 'concentration'
+%
+% For compartments the additional information has the following syntax:
+%     {'isCompartment':nameoutsidecompartment}
+% where nameoutsidecompartment is a string with the name of the outside
+% compartment. if there is no outside compartment the name should be
+% represented by an empty string. example - correct: {'isCompartment':}. 
+% example - wrong: {'isCompartment'} (missing ':').
+%
+% For constant values (parameters) the additional information has the following syntax:
+%     {'isParameter'}
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+% Begin initialization code - DO NOT EDIT
+gui_Singleton = 1;
+gui_State = struct('gui_Name',       mfilename, ...
+                   'gui_Singleton',  gui_Singleton, ...
+                   'gui_OpeningFcn', @IQMedit_OpeningFcn, ...
+                   'gui_OutputFcn',  @IQMedit_OutputFcn, ...
+                   'gui_LayoutFcn',  [], ...
+                   'gui_Callback',   []);
+if nargin && ischar(varargin{1})
+   gui_State.gui_Callback = str2func(varargin{1});
+end
+if nargout
+    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
+else
+    gui_mainfcn(gui_State, varargin{:});
+end
+% End initialization code - DO NOT EDIT
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GUI STANDARD FUNCTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% OPENING FUNCTION (AFTER CREATION)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function IQMedit_OpeningFcn(hObject, eventdata, handles, varargin)
+
+% Process input argument
+nvarargin = nargin-3;
+textModel = 0;
+if nvarargin == 0,
+    % start with empty IQMmodel
+    iqm = IQMmodel();
+else
+    if strcmp('IQMmodel',class(varargin{1})),
+        iqm = varargin{1};
+    else 
+        error('Input argument of unknown type');
+        delete(hObject);
+    end
+end
+handles.editText = convertModelToTextIQM(iqm);
+handles.output = iqm;               
+
+% Create data used by the different callbacks
+handles.helpText = getHelpText();
+handles.activeView = 'complete';
+handles.IQMplotHandle = [];
+% Initialize the IQMedit window with initial content
+set(handles.editor,'String',setPartsToCompleteTextIQM(handles.editText));
+set(handles.helptext,'String',handles.helpText.complete);
+set(handles.headline,'String','Complete Model View');
+set(handles.time,'String','20');
+% Update handles structure
+guidata(hObject, handles);
+uiwait;
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% OUTPUT TO COMMAND LINE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function varargout = IQMedit_OutputFcn(hObject, eventdata, handles)
+% varargout  cell array for returning output args (see VARARGOUT);
+varargout{1} = handles.output;
+% close the GUI
+delete(hObject);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CLOSE CALLBACK
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function IQMedit_CloseRequestFcn(hObject, eventdata, handles)
+% warn that last changes will get lost 
+% and let the user choose
+selection = questdlg(sprintf('Close IQMedit?\nLast changes might get lost. If you want to\nkeep all changes press the ''Exit'' button instead.'),...
+                     'Close Request Function',...
+                     'Yes','No','Yes');
+switch selection,
+    case 'Yes',
+        uiresume;
+    case 'No'
+        return
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GUI SPECIALIZED FUNCTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% SIMULATE CALLBACK
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function simulate_Callback(hObject, eventdata, handles)
+    global lastSimulationValue
+    errorSimulation = 0;
+    % Update all views
+    handles = updateAllViews(handles);
+    % convert the text description into an IQMmodel
+    [iqm, errorFlag] = convertTextToModel(handles);
+    if ~errorFlag,
+        % get the simulation time
+        timeString = get(handles.time,'String');
+        time = str2double(timeString);
+        % Simulate IQMmodel for given time
+        % catch all possible errors
+        try
+            tspan = [0:time/1000:time];
+            % handles also non-numeric ics
+            outputSimulation = IQMsimulate(iqm,'ode23s',tspan,IQMcalcICvector(iqm));
+        catch
+            % Process the simulation error
+            processError(lasterr,'Error during simulation');
+            errorSimulation = 1;
+        end
+        if ~errorSimulation,
+            % Try to close previous IQMplot figure
+            try
+                close handles.IQMplotHandle;
+            catch
+            end
+            % prepare data for plotting
+            time = outputSimulation.time;
+            datanames = {};
+            dataindex = 1;
+            for k = 1:length(outputSimulation.states),
+                datanames{dataindex} = char([double(outputSimulation.states{k}) double(' (state)')]); % fastest strcat
+                dataindex = dataindex + 1;
+            end
+            for k = 1:length(outputSimulation.variables),
+                datanames{dataindex} = char([double(outputSimulation.variables{k}) double(' (variable)')]); % fastest strcat 
+                dataindex = dataindex + 1;
+            end
+            for k = 1:length(outputSimulation.reactions),
+                datanames{dataindex} = char([double(outputSimulation.reactions{k}) double(' (reaction)')]); % fastest strcat  
+                dataindex = dataindex + 1;
+            end
+            datavalues = [outputSimulation.statevalues, outputSimulation.variablevalues, outputSimulation.reactionvalues];
+            handles.IQMplotHandle = IQMplot(createdatastructIQMplotIQM(time,datavalues,datanames));
+            % make button for updating initial conditions visible
+            set(handles.updateICsimulate,'Visible','on');
+            lastSimulationValue = outputSimulation.statevalues(end,:);
+        end
+    end
+    % Update handles structure
+    guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% UPDATE INITIAL CONDITIONS WITH LAST VALUE OF SIMULATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function updateICsimulate_Callback(hObject, eventdata, handles)
+    global lastSimulationValue
+    % Update all views
+    handles = updateAllViews(handles);
+    % convert the text description into an IQMmodel
+    [iqm, errorFlag] = convertTextToModel(handles);
+    if ~errorFlag,
+        % set new initial conditions (handle also non-numeric initial
+        % conditions)
+        iqm = IQMoverwriteICs(iqm,lastSimulationValue);
+        % convert model to text again 
+        handles.editText = convertModelToTextIQM(iqm); 
+        % rewrite the data in the current view (only needed if the view
+        % shows state or complete information)
+        if strcmp(handles.activeView,'states'),
+            % Update editor content with state information
+            set(handles.editor,'String',handles.editText.states);
+        elseif strcmp(handles.activeView,'complete'),
+            % Update editor content with complete information
+            completeEditText = setPartsToCompleteTextIQM(handles.editText);
+            set(handles.editor,'String',completeEditText);
+        end
+    end
+    % Update handles structure
+    guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% STEADY-STATE CALLBACK
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function steadystate_Callback(hObject, eventdata, handles)
+    global steadyStateValues
+    errorSteadyState = 0;
+    % Update all views
+    handles = updateAllViews(handles);
+    % convert the text description into an IQMmodel
+    [iqm, errorFlag] = convertTextToModel(handles);
+    if ~errorFlag,
+        % get the steady-state
+        try
+            [steadystate,residual,message] = IQMsteadystate(iqm);
+        catch
+            % Process the steadystate error
+            processError(lasterr,'Error during steady-state computation');
+            errorSteadyState = 1;
+        end
+        if ~errorSteadyState,
+            % construct result text and display it in the editor window
+            resultText = sprintf('%s',message);
+            if ~isempty(steadystate),
+                resultText = sprintf('%s\nThe steady-state is given by:\n',message);
+                IQMstructure = IQMstruct(iqm);
+                for k = 1:length(IQMstructure.states),
+                    stateName = IQMstructure.states(k).name;
+                    resultText = sprintf('%s\n%s = %g',resultText,stateName,steadystate(k));
+                end
+                % make button for updating initial conditions visible
+                set(handles.updateIC,'Visible','on');
+                steadyStateValues = steadystate;
+            else
+                resultText = sprintf('%s\nIn order to start at a different steady-state you can change to initial conditions for the states. Changing the options of the steady-state solver is only possible from the command line version of IQMsteadystate',resultText);
+            end
+            set(handles.editor,'String',resultText);
+            % Update help text with complete help
+            set(handles.helptext,'String',handles.helpText.steadystate);
+            % Update headline text
+            set(handles.headline,'String','Steady State of Model');
+            % Set new active view
+            handles.activeView = 'steadystate';
+        end
+    end
+    % Update handles structure
+    guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% UPDATE INITIAL CONDITIONS WITH STEADY STATE INFORMATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function updateIC_Callback(hObject, eventdata, handles)
+    global steadyStateValues
+    % Update all views
+    handles = updateAllViews(handles);
+    % convert the text description into an IQMmodel
+    [iqm, errorFlag] = convertTextToModel(handles);
+    if ~errorFlag,
+        % set new initial conditions (handle also non-numeric initial
+        % conditions)
+        iqm = IQMoverwriteICs(iqm,steadyStateValues);
+        % convert model to text again 
+        handles.editText = convertModelToTextIQM(iqm);  
+    end
+    % Update handles structure
+    guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EXPORT TEXT CALLBACK
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function exportText_Callback(hObject, eventdata, handles)
+    % Update all views
+    handles = updateAllViews(handles);
+    % get filename for the TXT file
+    [filename, pathname] = uiputfile('*.txt', 'Save IQMmodel as .txt file');
+    % check if a filename returned
+    if filename ~= 0,
+        % cut of the extension from the filename
+        [path,filename,ext] = fileparts(filename);
+        % remove whitespaces from filename
+        filename = strrep(filename,' ','');
+        % add the extension
+        filepathname = strcat(pathname,'/',filename,'.txt');
+        % save the TextFile
+        completeEditText = setPartsToCompleteTextIQM(handles.editText);
+        fid = fopen(filepathname,'w');
+        fwrite(fid,completeEditText);
+        status = fclose(fid);
+    end
+    % Update handles structure
+    guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EXPORT TEXTBC CALLBACK
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function exportTextBC_Callback(hObject, eventdata, handles)
+    % Update all views
+    handles = updateAllViews(handles);
+    % get filename for the TXTBC file
+    [filename, pathname] = uiputfile('*.txtbc', 'Save IQMmodel as .txtbc file');
+    % check if a filename returned
+    if filename ~= 0,
+        % cut of the extension from the filename
+        [path,filename,ext] = fileparts(filename);
+        % remove whitespaces from filename
+        filename = strrep(filename,' ','');
+        % add the extension
+        filepathname = strcat(pathname,'/',filename,'.txtbc');
+        % convert the text description into an IQMmodel
+        [iqm, errorFlag] = convertTextToModel(handles);
+        if ~errorFlag,
+            % convert the model into a TEXTBC description
+            [modelTextBCStructure] = convertModelToTextBCIQM(iqm);
+            [completeTextBC] = setPartsToCompleteTextBCIQM(modelTextBCStructure);
+            % save the text
+            fid = fopen(filepathname,'w');
+            fwrite(fid,completeTextBC);
+            status = fclose(fid);
+        end
+    end
+    % Update handles structure
+    guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EXIT IQMEDIT CALLBACK
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function exit_Callback(hObject, eventdata, handles)
+    % Update all views
+    handles = updateAllViews(handles);
+    % convert the text description into an IQMmodel
+    [iqm, errorFlag] = convertTextToModel(handles);
+    if ~errorFlag,
+        % set edited IQMmodel as output
+        handles.output = iqm;
+    end
+    % Update handles structure
+    guidata(hObject, handles);
+    uiresume;
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GUI EDITOR BUTTONS FUNCTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EDIT COMPLETE MODEL DESCRIPTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function complete_Callback(hObject, eventdata, handles)
+    % Update all views
+    handles = updateAllViews(handles);
+    % Update editor content with complete information
+    completeEditText = setPartsToCompleteTextIQM(handles.editText);
+    set(handles.editor,'String',completeEditText);
+    % Update help text with complete help
+    set(handles.helptext,'String',handles.helpText.complete);    
+    % Update headline text
+    set(handles.headline,'String','Complete Model View');
+    % Set new active view
+    handles.activeView = 'complete';
+    % Update handles structure
+    guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EDIT NAME MODEL DESCRIPTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function name_Callback(hObject, eventdata, handles)
+    % Update all views
+    handles = updateAllViews(handles);
+    % Update editor content with name information
+    set(handles.editor,'String',handles.editText.name);
+    % Update help text with name help
+    set(handles.helptext,'String',handles.helpText.name);    
+    % Update headline text
+    set(handles.headline,'String','Model Name View');
+    % Set new active view
+    handles.activeView = 'name';
+    % Update handles structure
+    guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EDIT NOTES MODEL DESCRIPTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function notes_Callback(hObject, eventdata, handles)
+    % Update all views
+    handles = updateAllViews(handles);
+    % Update editor content with notes information
+    set(handles.editor,'String',handles.editText.notes);
+    % Update help text with notes help
+    set(handles.helptext,'String',handles.helpText.notes);    
+    % Update headline text
+    set(handles.headline,'String','Model Notes View');
+    % Set new active view
+    handles.activeView = 'notes';
+    % Update handles structure
+    guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% VIEW HTML NOTES CALLBACK
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function htmlnotes_Callback(hObject, eventdata, handles)
+    % Update all views
+    handles = updateAllViews(handles);
+    % Update editor content with notes information
+    set(handles.editor,'String',handles.editText.notes);
+    % Update help text with notes help
+    set(handles.helptext,'String',handles.helpText.notes);    
+    % Update headline text
+    set(handles.headline,'String','Model Notes View');
+    % Set new active view
+    handles.activeView = 'notes';
+    % get the text in the notes
+    notesText = handles.editText.notes;
+    % write this text to a temporary html file
+    filefullpath = strcat(tempnameIQM,'.html');
+    fid = fopen(filefullpath,'w');
+    fprintf(fid,notesText);
+    status = fclose(fid);
+    % open and display the file
+    open(filefullpath);
+    % Update handles structure
+    guidata(hObject, handles);    
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EDIT STATES MODEL DESCRIPTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function states_Callback(hObject, eventdata, handles)
+    % Update all views
+    handles = updateAllViews(handles);
+    % Update editor content with states information
+    set(handles.editor,'String',handles.editText.states);
+    % Update help text with states help
+    set(handles.helptext,'String',handles.helpText.states);    
+    % Update headline text
+    set(handles.headline,'String','Model States View');
+    % Set new active view
+    handles.activeView = 'states';
+    % Update handles structure
+    guidata(hObject, handles);
+return
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EDIT PARAMETERS MODEL DESCRIPTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function parameters_Callback(hObject, eventdata, handles)
+    % Update all views
+    handles = updateAllViews(handles);
+    % Update editor content with parameters information
+    set(handles.editor,'String',handles.editText.parameters);
+    % Update help text with parameters help
+    set(handles.helptext,'String',handles.helpText.parameters);    
+    % Update headline text
+    set(handles.headline,'String','Model Parameters View');
+    % Set new active view
+    handles.activeView = 'parameters';
+    % Update handles structure
+    guidata(hObject, handles);
+return
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EDIT VARIABLES MODEL DESCRIPTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function variables_Callback(hObject, eventdata, handles)
+    % Update all views
+    handles = updateAllViews(handles);
+    % Update editor content with variables information
+    set(handles.editor,'String',handles.editText.variables);
+    % Update help text with variables help
+    set(handles.helptext,'String',handles.helpText.variables);    
+    % Update headline text
+    set(handles.headline,'String','Model Variables View');
+    % Set new active view
+    handles.activeView = 'variables';
+    % Update handles structure
+    guidata(hObject, handles);
+return
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EDIT REACTIONS MODEL DESCRIPTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function reactions_Callback(hObject, eventdata, handles)
+    % Update all views
+    handles = updateAllViews(handles);
+    % Update editor content with reactions information
+    set(handles.editor,'String',handles.editText.reactions);
+    % Update help text with reactions help
+    set(handles.helptext,'String',handles.helpText.reactions);    
+    % Update headline text
+    set(handles.headline,'String','Model Reactions View');
+    % Set new active view
+    handles.activeView = 'reactions';
+    % Update handles structure
+    guidata(hObject, handles);
+return
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EDIT FUNCTIONS MODEL DESCRIPTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function functions_Callback(hObject, eventdata, handles)
+    % Update all views
+    handles = updateAllViews(handles);
+    % Update editor content with functions information
+    set(handles.editor,'String',handles.editText.functions);
+    % Update help text with functions help
+    set(handles.helptext,'String',handles.helpText.functions);    
+    % Update headline text
+    set(handles.headline,'String','Model Functions View');
+    % Set new active view
+    handles.activeView = 'functions';
+    % Update handles structure
+    guidata(hObject, handles);
+return
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EDIT EVENTS MODEL DESCRIPTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function events_Callback(hObject, eventdata, handles)
+    % Update all views
+    handles = updateAllViews(handles);
+    % Update editor content with events information
+    set(handles.editor,'String',handles.editText.events);
+    % Update help text with events help
+    set(handles.helptext,'String',handles.helpText.events);    
+    % Update headline text
+    set(handles.headline,'String','Model Events View');
+    % Set new active view
+    handles.activeView = 'events';
+    % Update handles structure
+    guidata(hObject, handles);
+return
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EDIT MATLAB FUNCTIONS MODEL DESCRIPTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function functionsMATLAB_Callback(hObject, eventdata, handles)
+    % Update all views
+    handles = updateAllViews(handles);
+    % Update editor content with functions information
+    set(handles.editor,'String',handles.editText.functionsMATLAB);
+    % Update help text with functions help
+    set(handles.helptext,'String',handles.helpText.functionsMATLAB);    
+    % Update headline text
+    set(handles.headline,'String','Model MATLAB Functions View');
+    % Set new active view
+    handles.activeView = 'functionsMATLAB';
+    % Update handles structure
+    guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% OTHER FUNCTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% UPDATE ALL VIEWS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Update the views data variables and restructure matrix text to string text
+function [handles] = updateAllViews(handles)
+    % set the update IC buttons to invisible 
+    set(handles.updateIC,'Visible','off');
+    set(handles.updateICsimulate,'Visible','off');    
+    % do the rest
+    if ~strcmp(handles.activeView,'steadystate') && ~strcmp(handles.activeView,'exportsbml'),
+        % Do this only if active view has been some model text
+        if ~strcmp(handles.activeView,'complete'),
+            % Get editor content in variable corresponding to the active view
+            evalString = sprintf('matrixText = get(handles.editor,''String'');',handles.activeView);
+            eval(evalString);
+            % Restructure the content from matrix to string
+            stringText = convertMatrixToStringText(matrixText);
+            % Update view content with string text
+            evalString = sprintf('handles.editText.%s = stringText;',handles.activeView);
+            eval(evalString);
+        elseif strcmp(handles.activeView,'complete'),
+            % Get the text in the complete view
+            matrixText = get(handles.editor,'String');
+            % Restructure the content from matrix to string
+            completeEditText = convertMatrixToStringText(matrixText);
+            % Cut text in pieces and update the different views
+            handles.editText = getPartsFromCompleteTextIQM(completeEditText);
+        end
+    end
+return
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CONVERT MATRIX TEXT TO STRING
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [stringText] = convertMatrixToStringText(matrixText)   
+    % convert text to numbers
+    doubleText = double(matrixText);
+    % exchange all "LF" and "CR" against "32"
+    doubleText(find(doubleText==10)) = 32;
+    doubleText(find(doubleText==13)) = 32;
+    % add new line character to each line, then transpose the matrix
+    doubleText = [doubleText 10*ones(size(doubleText,1),1)]';
+    % vectorize the matrix and transpose again
+    vectorDoubleText = doubleText(:)';
+    % get the text
+    stringText = char(vectorDoubleText);
+return
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CONVERT TEXT DESCRIPTION TO IQMMODEL
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [iqm, errorFlag] = convertTextToModel(handles)
+    % convert the text description to an IQMmodel
+    errorFlag = 0;
+    completeEditText = setPartsToCompleteTextIQM(handles.editText);
+    [IQMstructure,errorMsg] = convertTextToModelIQM(completeEditText);
+    if ~isempty(errorMsg),
+        errordlg(errorMsg,'Error','On');
+        errorFlag = 1;
+        iqm = [];
+    else
+        %%%%%%%%%%%%%%%%%% Construct model and return
+        iqm = IQMmodel(IQMstructure);
+    end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DEFINE HELP TEXTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [helpText] = getHelpText()
+    % Define the help texts for the different sections
+    helpText.complete = sprintf('The editor shows a view of the complete model. You can edit the model using this view or the other views (Name, Notes, States, etc.). More information about the syntax of the model description can be found in the help text for the different views.\n\nIMPORTANT: Do not change the limiters (e.g., "********** MODEL PARAMETERS") between the different parts of the model. The order of the different parts IS important and should not be changed.');
+    helpText.name = 'Here you can enter the name of the model. All spaces and line breaks are being ignored but displayed. Allowed characters are characters you would expect a MATLAB function to consist of (a-z,A-Z,0-9,-,_)';
+    helpText.notes = 'Here you can enter notes about the model. Any characters are allowed';
+    helpText.states = sprintf('In this view you enter the models ODEs and initial conditions for the states. A new ODE starts always in a new line, but can go over several lines. The syntax is: "d/dt(statename) = ODE expression {optional information} %% optional comment". Spaces and line breaks are ignored. The "statename" needs to consist of characters that are allowed for MATLAB variables. The expression can contain variables, reactions, states, and parameters. The optional information is placed in square brackets. To learn more about the optional information, please type "help IQMedit".\nInitial conditions are optional. If no initial condition is given for a state, it is zero by default. Definitions of initial conditions start always in a new line but can go over several lines. The syntax is "statename(0) = initial value". Spaces and line breaks are ignored. The order of the initial conditions does not need to match the order of the ODEs.\nIMPORTANT: Define first the ODEs, then the initial conditions. The optional comment is not allowed to contain any square brackets or the strings "d/dt(" and "(0)"\n\nAlgebraic Rules: They are defined between the ODEs and the initialconditions. Their syntax is as follows: "0 = mathematical expression : variable %% optional comment". The “variable” is the one which is determined by the AR.');
+    helpText.parameters = 'In this view you can enter the models parameters. A new parameter definition starts always in a new line. The syntax is "parametername = numerical value {optional information} %% optional comment". Spaces and line breaks are ignored. The "parametername" needs to consist of characters that are allowed for MATLAB variables. Parameter names are not allowed to have the same name as states, variables, reactions, or functions.\nThe optional information is placed in square brackets. To learn more about the optional information, please type "help IQMedit". The optional comment is not allowed to contain the character "=".';
+    helpText.variables = 'In this view you can enter the models variables. A new variable definition starts always in a new line, but can go over several lines. The syntax is "variablename = expression {optional information} %% optional comment". Spaces and line breaks are ignored. The "variablename" needs to consist of characters that are allowed for MATLAB variables. The expression can contain states, variables that have been declared before, and parameters. Variable names are not allowed to have the same name as states, parameters, reactions, or functions.\nThe optional information is placed in square brackets. To learn more about the optional information, please type "help IQMedit".\nThe optional comment is not allowed to contain the character "=".';
+    helpText.reactions = sprintf('In this view you can enter the models reactions. A new reaction definition starts always in a new line, but can go over several lines. The syntax is "reactionname = expression {reversible} %% optional comment". Spaces and line breaks are ignored. The "reactionname" needs to consist of characters that are allowed for MATLAB variables. The expression can contain states, variables, and parameters. Reaction names are not allowed to have the same name as states, parameters, variables, or functions. The identifier "{reversible}" should be present when a reaction is reversible only. The identifier "{fast}" indicates that a reaction happens infinitely fast. The comment is separated from the rest by "%%". In the reaction comments the character "=" is NOT ALLOWED!\nYou can specify the ODEs for species in terms of reactions or by directly using kinetic formulas in the ODEs. In the latter case reactions do not need to be specified. A combination of both approaches is possible but not very consistent, and should therefore be avoided.');
+    helpText.functions = 'In this view you can enter functions that are used in the mathematical expressions of the model. A new function definition starts always in a new line, but can go over several lines. The syntax is "functionname(argumentname1, argumentname2, ...) = expression %% optional comment". Spaces and line breaks are ignored. The "functionname" and the names of the arguments needs to consist of characters that are allowed for MATLAB variables. Function names are not allowed to have the same name as states, parameters, variables, or reactions. The optional comment is not allowed to contain the character "=".';        
+    helpText.events = 'In this view you can enter events that are used to set state variables of the model to certain values when a certain condition is fulfilled. The syntax for an event is: "eventname=trigger,variable1,value1,...,variablen,valuen %% optional comment". The values can be numerical but also be represented by a formula that is allowed to contain states, parameters, etc. The trigger expression is an arbitrary boolean expression which goes from false to true in the case that an event should be fired. The event is only fired when the trigger function goes from false to true. The optional comment is not allowed to contain the character "=".';
+    helpText.functionsMATLAB = 'In this view you can enter functions in the standard MATLAB syntax. This feature is used, e.g., to implement the SBML piecewise operator, but it can also be used to implement events such as changing a certain parameter at a certain time, etc. States, however, can not be changed. Calls for the defined functions have then to be placed correctly in the other parts of the model.';
+    helpText.steadystate = 'This view shows the result of the steady-state computation. The steady-state computation uses the initial conditions of the models states as starting guess. If the steady-state computation fails you can try to change the initial conditions of the model. The steady-state computation also gives information over possible linear dependencies between the ODEs, resulting in algebraic relations between certain states, of the model.';
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS ERRORS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Errors occurr due to errors in the created m file (undefined 
+% identifiers mainly). Here we interprete the error message and inform
+% the user. If error reason can't be found then just print the initial
+% error message
+function [] = processError(lasterr, title)
+    errorString = lasterr;
+    % parse the error string
+    if ~isempty(strfind(errorString,'Error:')),
+        % cut off error substring
+        errorString = errorString(8:end);
+        if ~isempty(strfind(errorString,'File:')),
+            errorString = errorString(7:end);
+            temp = strfind(errorString,'Line:');
+            if ~isempty(temp),
+                % extract the filename
+                filename = strtrim(errorString(1:temp(1)-1));
+                % extract line number
+                temp2 = strfind(errorString,'Column:');
+                linenumber = str2num(strtrim(errorString(temp(1)+6:temp2(1)-1)));
+                % open the ODE file and extract the line "linenumber"
+                fid = fopen(filename, 'r');
+                for k = 1:linenumber,
+                    linecontent = fgetl(fid);
+                end
+                fclose(fid);
+                % replace all characters < 32 by 32
+                temp = double(linecontent);
+                temp(find(temp<32)) = 32;
+                linecontent = char(temp);
+                errordlg(sprintf('%s\n\n%s',title,linecontent),'Error','on');
+            else
+                errordlg(sprintf('%s\n\n%s',title,errorString),'Error','on');
+            end
+        else
+            errordlg(sprintf('%s\n\n%s',title,lasterr),'Error','on');
+        end
+    else
+        errordlg(sprintf('%s\n\n%s',title,lasterr),'Error','on');
+    end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DELETE WHITESPACES IN STRINGS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Useful for taking away whitespaces in kineticLaw formulas, as
+% seen in some example models
+function [outputString] = removeWhiteSpace(inputString)
+outputString = strrep(inputString,' ','');
+% return
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/functions/andIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/model/functions/andIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..e28e9dbea30962d4514ad92f5ea6defeb164ee07
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/functions/andIQM.m	
@@ -0,0 +1,32 @@
+function [result] = andIQM(varargin)
+% andIQM: This function is used instead of the MATLAB "and" function, 
+% allowing more than two input arguments, each of type "logical". Its use 
+% is mainly thought for evaluation of decision arguments in SBML piecewise 
+% statements.
+% 
+% USAGE:
+% ======
+% [result] = andIQM(arg1,arg2,...,argn)   
+%
+% arg1...argn: input arguments of type boolean.
+%
+% Output Arguments:
+% =================
+% result: arg1 && arg2 && ... && argn
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK TYPE OF INPUT ARGUMENTS AND DO IT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+result = true;
+for k = 1:nargin,
+    if ~strcmp('logical', class(varargin{k})),
+        error('At least one input argument to the "andIQM" function is not of type "logical".');
+    end
+    result = result && varargin{k};
+end
+return
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/functions/delayIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/model/functions/delayIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..0a0b5597894f41f90ef39d1c3383f0e1a77a4e1e
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/functions/delayIQM.m	
@@ -0,0 +1,42 @@
+function [output] = delayIQM(input,tau,time,queuename)
+% delayIQM: realizes a time delay of "tau" time units
+%
+% input:     the input that is to be delayed
+% tau:       the delay
+% time:      the time of the input
+% queuename: unique name for the variable storing the queue data
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+% get the queuedata for the current delay
+eval(sprintf('global %s',queuename));
+eval(sprintf('queue = %s;',queuename));
+
+if isempty(queue),
+% initialize the queue if first call
+    queue(1,1) = -1e10;
+    queue(1,2) = input;
+    queue(2,1) = time+tau;  % add delay to time in order to store the output time
+    queue(2,2) = input;
+else
+% add new time point to the queue
+    % if last time+tau < max stored time ... delete all time points larger
+    % than time + tau (can happen during event handling)
+    queue(find(queue(:,1)>=time+tau),:) = [];
+    % add the new point
+    queue(end+1,1) = time+tau;   % add delay to time in order to store the output time
+    queue(end,2) = input;
+end
+
+% % make unique time values (not necessary due to line 23 above???)
+% [dummy,indexunique] = unique(queue(:,1),'first');
+% queue = queue(indexunique,:);
+
+% interpolate to find the correct value for the current time. 
+% (linear interpolation)
+output = interp1IQM(queue(:,1),queue(:,2),time);
+
+% store the queue under the right name again
+eval(sprintf('%s = queue;',queuename));
+
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/functions/indexmaxIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/model/functions/indexmaxIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..7a785118df0fe4bfe47d3a6252faf9302a668652
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/functions/indexmaxIQM.m	
@@ -0,0 +1,22 @@
+function [result] = indexmaxIQM(varargin)
+% matchmaxIQM: This function searches for the maximum input argument and returns the
+% index of the max.
+% 
+% USAGE:
+% ======
+% [result] = indexmaxIQM(arg1,arg2,...,argn)
+%
+% arg1...argn: scalar input arguments of type double.
+%
+% Output Arguments:
+% =================
+% result: index of the largest element of X
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DO IT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[v,result] = max([varargin{:}]);
+return
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/functions/maxIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/model/functions/maxIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..e91e5e1bb37ee34b3ad1929ed4cdf2f3e7e630fe
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/functions/maxIQM.m	
@@ -0,0 +1,22 @@
+function [result] = maxIQM(varargin)
+% maxIQM: This function is used instead of the MATLAB "max" function, 
+% allowing more than two scalar input arguments, each of type "double".
+% 
+% USAGE:
+% ======
+% [result] = maxIQM(arg1,arg2,...,argn)   
+%
+% arg1...argn: scalar input arguments of type double.
+%
+% Output Arguments:
+% =================
+% result: max(arg1,arg2,arg3, ....)
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DO IT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+result = max([varargin{:}]);
+return
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/functions/minIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/model/functions/minIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..9e13456ff5c870e18d30f1d1f99ff59ea3e21d8e
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/functions/minIQM.m	
@@ -0,0 +1,22 @@
+function [result] = minIQM(varargin)
+% minIQM: This function is used instead of the MATLAB "min" function, 
+% allowing more than two scalar input arguments, each of type "double".
+% 
+% USAGE:
+% ======
+% [result] = minIQM(arg1,arg2,...,argn)   
+%
+% arg1...argn: scalar input arguments of type double.
+%
+% Output Arguments:
+% =================
+% result: min(arg1,arg2,arg3, ....)
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DO IT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+result = min([varargin{:}]);
+return
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/functions/multiplyIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/model/functions/multiplyIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..72a30fba709931f460b142a7ada9684d93af24ff
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/functions/multiplyIQM.m	
@@ -0,0 +1,15 @@
+function [result] = multiplyIQM(varargin)
+% multiplyIQM: Implementing the multiply MathML function
+% 
+% USAGE:
+% ======
+% [result] = multiplyIQM(arg1,arg2,...,argn)   
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+result = 1;
+for k = 1:nargin,
+    result = result * varargin{k};
+end
+return
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/functions/orIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/model/functions/orIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..df6164ebfe39d5c09d400e21a94b55821a8000e8
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/functions/orIQM.m	
@@ -0,0 +1,31 @@
+function [result] = orIQM(varargin)
+% orIQM: This function is used instead of the MATLAB "or" function, 
+% allowing more than two input arguments, each of type "logical". Its use 
+% is mainly thought for evaluation of decision arguments in SBML piecewise 
+% statements.
+% 
+% USAGE:
+% ======
+% [result] = orIQM(arg1,arg2,...,argn)   
+%
+% arg1...argn: input arguments of type boolean.
+%
+% Output Arguments:
+% =================
+% result: arg1 || arg2 || ... || argn
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK TYPE OF INPUT ARGUMENTS AND DO IT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+result = false;
+for k = 1:nargin,
+    if ~strcmp('logical', class(varargin{k})),
+        error('At least one input argument to the "orIQM" function is not of type "logical".');
+    end
+    result = result || varargin{k};
+end
+return
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/functions/piecewiseIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/model/functions/piecewiseIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..6189195d88cb00157029720a1034d4274e505770
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/functions/piecewiseIQM.m	
@@ -0,0 +1,43 @@
+function [result] = piecewiseIQM(varargin)
+% piecewiseIQM: This function implements support for the SBML / MATHML
+% piecewise operator.
+% 
+% USAGE:
+% ======
+% [result] = piecewiseIQM(resultiftrue1,decision1,resultiftrue2,decision2,...,resultiftruen,decisionn)   
+% [result] = piecewiseIQM(resultiftrue1,decision1,resultiftrue2,decision2,...,resultiftruen,decisionn,defaultresult)    
+%
+% decision1,...,decisionn: logical argument, e.g. returned from a comparison
+% result1,...,resultn: returnvalue in case the corresponding decision is
+%   evaluated to be true
+% defaultresult: if none of the decisions are true this defaultresult is returned.
+%
+% Output Arguments:
+% =================
+% result: the result corresponding to the decision that is true. if no
+%   decision is true and no defaultresult i given an error will occurr.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DETERMINE THE OUTPUT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+result = [];
+% check if odd or even number of input arguments
+oddnumber = mod(nargin,2);
+for k = 1:2:nargin-oddnumber,
+    if varargin{k+1},
+        result = varargin{k};
+        break;
+    end
+end
+if isempty(result),
+    if oddnumber,
+        result = varargin{nargin};
+    else
+        error('A piecewise statement is wrongly defined - missing (but needed) default value.');
+    end
+end
+return
+   
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/functions/piecewiseSmoothIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/model/functions/piecewiseSmoothIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..288bb4989ffa4d96220cca3247d65dc8d60b6df9
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/functions/piecewiseSmoothIQM.m	
@@ -0,0 +1,30 @@
+function y = piecewiseSmoothIQM(t,y0,y1,alpha)
+% piecewiseSmoothIQM: This function implements a smoothing function between
+% two values y0 and y1. alpha is the steepness factor. 
+% For alpha>>1, 
+%               y=y0 for t<0 and 
+%               y=y1 for t>0. 
+% For low values of alpha, the function provide a
+% smooth interpolation between y0 and y1 in function of t
+% 
+% 
+% USAGE:
+% ======
+% y = piecewiseSmoothIQM(t,y0,y1,alpha)
+%
+% t: regression variable (i.e. y=y(t))
+% y0: output value for y when t-> -Inf
+% y1: output value for y when t-> +Inf
+% alpha: steepness factor
+%
+% Output Arguments:
+% =================
+% result: the result corresponding to the decision that is true. if no
+%   decision is true and no defaultresult i given an error will occurr.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+y=(y0+y1.*exp(alpha.*t))./(1+exp(alpha.*t));
+
+
+   
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/functions/piecewiseT0IQM.m b/IQMtools V1.2.2.2/IQMlite/tools/model/functions/piecewiseT0IQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..5e5935d991593d2ebb4bcf38f67fd53ff6101f7d
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/functions/piecewiseT0IQM.m	
@@ -0,0 +1,47 @@
+function [result] = piecewiseT0IQM(varargin)
+% piecewiseT0IQM: This function is identical to the piecewiseIQM function.
+% The only difference is that during model export to a simulation model the
+% trigger conditions for the piecewise expressions are not added to the
+% simulation model as events. Thus the main reason for having this function
+% here is to allow for a switching based on the initial conditions, rather
+% than for a switching during simulation.
+% 
+% USAGE:
+% ======
+% [result] = piecewiseT0IQM(resultiftrue1,decision1,resultiftrue2,decision2,...,resultiftruen,decisionn)   
+% [result] = piecewiseT0IQM(resultiftrue1,decision1,resultiftrue2,decision2,...,resultiftruen,decisionn,defaultresult)    
+%
+% decision1,...,decisionn: logical argument, e.g. returned from a comparison
+% result1,...,resultn: returnvalue in case the corresponding decision is
+%   evaluated to be true
+% defaultresult: if none of the decisions are true this defaultresult is returned.
+%
+% Output Arguments:
+% =================
+% result: the result corresponding to the decision that is true. if no
+%   decision is true and no defaultresult i given an error will occurr.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DETERMINE THE OUTPUT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+result = [];
+% check if odd or even number of input arguments
+oddnumber = mod(nargin,2);
+for k = 1:2:nargin-oddnumber,
+    if varargin{k+1},
+        result = varargin{k};
+        break;
+    end
+end
+if isempty(result),
+    if oddnumber,
+        result = varargin{nargin};
+    else
+        error('A piecewise statement is wrongly defined - missing (but needed) default value.');
+    end
+end
+return
+   
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/functions/xorIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/model/functions/xorIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..d3a4c497d4570ace53ba9e39db5f126a01afc2d8
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/functions/xorIQM.m	
@@ -0,0 +1,38 @@
+function [result] = xorIQM(varargin)
+% xorIQM: This function is used instead of the MATLAB "or" function, 
+% allowing more than two input arguments, each of type "logical". Its use 
+% is mainly thought for evaluation of decision arguments in SBML piecewise 
+% statements.
+% 
+% USAGE:
+% ======
+% [result] = xorIQM(arg1,arg2,...,argn)   
+%
+% arg1...argn: input arguments of type boolean.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK TYPE OF INPUT ARGUMENTS AND DO IT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+result = false;
+foundFalse = 0;
+foundTrue = 0;
+for k = 1:nargin,
+    if ~strcmp('logical', class(varargin{k})),
+        error('At least one input argument to the "xorIQM" function is not of type "logical".');
+    end
+    result = xor(result, varargin{k});
+%     if varargin{k},
+%         foundTrue = 1;
+%     else
+%         foundFalse = 1;
+%     end
+end
+% if foundTrue == 1 && foundFalse == 1,
+%     result = true;
+% else
+%     result = false;
+% end 
+return
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/allkineticlaws.m b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/allkineticlaws.m
new file mode 100644
index 0000000000000000000000000000000000000000..fba31c81f29dac299e25756dbe0d710db82371a6
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/allkineticlaws.m	
@@ -0,0 +1,119 @@
+allLawsNames = {    
+    'kin_allosteric_inihib_empirical_rev'
+    'kin_allosteric_inihib_mwc_irr'
+    'kin_catalytic_activation_irr'
+    'kin_catalytic_activation_rev'
+    'kin_comp_inihib_irr'
+    'kin_comp_inihib_rev'
+    'kin_constantflux'
+    'kin_degradation'
+    'kin_hill_1_modifier_rev'
+    'kin_hill_2_modifiers_rev'
+    'kin_hill_cooperativity_irr'
+    'kin_hill_rev'
+    'kin_hyperbolic_modifier_irr'
+    'kin_hyperbolic_modifier_rev'
+    'kin_iso_uni_uni_rev'
+    'kin_mass_action_irr'
+    'kin_mass_action_rev'
+    'kin_michaelis_menten_irr'
+    'kin_michaelis_menten_rev'
+    'kin_mixed_activation_irr'
+    'kin_mixed_activation_rev'
+    'kin_mixed_inihib_irr'
+    'kin_mixed_inihib_rev'
+    'kin_noncomp_inihib_irr'
+    'kin_noncomp_inihib_rev'
+    'kin_ordered_bi_bi_rev'
+    'kin_ordered_bi_uni_rev'
+    'kin_ordered_uni_bi_rev'
+    'kin_ping_pong_bi_bi_rev'
+    'kin_specific_activation_irr'
+    'kin_specific_activation_rev'
+    'kin_substrate_activation_irr'
+    'kin_substrate_inihib_irr'
+    'kin_substrate_inihib_rev'
+    'kin_uncomp_inihib_irr'
+    'kin_uncomp_inihib_rev'
+    'kin_uni_uni_rev'
+};
+
+allLawsArguments = {
+{'Vf','substrate','Kms','Vr','product','Kmp','inhibitor','Ki','n'}
+{'V','substrate','Ks','n','L','inhibitor','Ki'}
+{'V','substrate','activator','Kms','Ka'}
+{'Vf','substrate','Kms','Vr','product','Kmp','activator','Ka'}
+{'V','substrate','Km','inhibitor','Ki'}
+{'Vf','substrate','Kms','Vr','product','Kmp','inhibitor','Ki'}
+{'v'}
+{'kdeg','substrate'}
+{'Vf','substrate','Shalve','product','Keq','Phalve','h','modifier','Mhalve','alpha'}
+{'Vf','substrate','Shalve','product','Keq','Phalve','h','modifierA','MAhalve','modifierB','MBhalve','alphaA','alphaB','alphaAB'}
+{'V','substrate','h','Shalve'}
+{'Vf','substrate','Shalve','product','Keq','Phalve','h'}
+{'V','substrate','b','modifier','a','Kd','Km'}
+{'Vf','substrate','Kms','Vr','product','Kmp','b','modifier','a','Kd'}
+{'Vf','substrate','product','Keq','Kii','Kms','Kmp'}
+{'k','substrate'}
+{'k1','substrate','k2','product'}
+{'V','substrate','Km'}
+{'Vf','substrate','Kms','Vr','product','Kmp'}
+{'V','substrate','activator','Kms','Kas','Kac'}
+{'Vf','substrate','Kms','Vr','product','Kmp','activator','Kas','Kac'}
+{'V','substrate','Km','inhibitor','Kis','Kic'}
+{'Vf','substrate','Kms','Vr','product','Kmp','inhibitor','Kis','Kic'}
+{'V','substrate','Km','inhibitor','Ki'}
+{'Vf','substrate','Kms','Vr','product','Kmp','inhibitor','Ki'}
+{'Vf','substratea','substrateb','productp','productq','Keq','Kip','Kma','Kmb','Kia','Vr','Kmq','Kmp','Kib'}
+{'Vf','substratea','substrateb','product','Keq','Kma','Kmb','Vr','Kmp','Kia'}
+{'Vf','substrate','productp','productq','Keq','Kms','Kip','Vr','Kmq','Kmp'}
+{'Vf','substratea','substrateb','productp','productq','Keq','Kiq','Kma','Kmb','Vr','Kmq','Kia','Kmp'}
+{'V','substrate','activator','Kms','Ka'}
+{'Vf','substrate','Kms','Vr','product','Kmp','activator','Ka'}
+{'V','substrate','Ksa','Ksc'}
+{'V','substrate','Km','Ki'}
+{'Vf','substrate','Kms','Vr','product','Kmp','Ki'}
+{'V','substrate','Km','inhibitor','Ki'}
+{'Vf','substrate','Kms','Vr','product','Kmp','inhibitor','Ki'}
+{'Vf','substrate','product','Keq','Kms','Kmp'}
+};
+
+allLawsFormulas = {
+'((Vf*substrate/Kms - Vr*product/Kmp) / (1 + substrate/Kms + product/Kmp + (inhibitor/Ki)^n))'
+'(V*substrate*(Ks+substrate)^(n-1) / ( L*(Ks*(1+inhibitor/Ki))^n + (Ks+substrate)^n ))'
+'(V*substrate*activator / ( (Kms + substrate)*(Ka+activator) )'
+'(( Vf*substrate/Kms - Vr*product/Kmp )*activator / ( (1+substrate/Kms+product/Kmp)*(Ka+activator) ))'
+'(V*substrate / ( Km*(1+inhibitor/Ki) + substrate ))'
+'((Vf*substrate/Kms - Vr*product/Kmp) / ( 1+substrate/Kms+product/Kmp+inhibitor/Ki ))'
+'(v)'
+'(kdeg*substrate)'
+'(Vf*substrate/Shalve*(1-product/(substrate*Keq))*(substrate/Shalve+product/Phalve)^(h-1) / ( (1+(modifier/Mhalve)^h)/(1+alpha*(modifier/Mhalve)^h)+(substrate/Shalve + product/Phalve)^h ))'
+'(Vf*substrate/Shalve*(1-product/(substrate*Keq))*(substrate/Shalve+product/Phalve)^(h-1) / ( (1+(modifierA/MAhalve)^h + 1+(modifierB/MBhalve)^h) / ( 1+alphaA*(modifierA/MAhalve)^h+alphaB*(modifierB/MBhalve)^h+alphaA*alphaB*alphaAB*(modifierA/MAhalve)^h*(modifierB/MBhalve)^h ) + (substrate/Shalve + product/Phalve)^h ))'
+'(V*substrate^h / ( Shalve^h + substrate^h ))'
+'(Vf*substrate/Shalve*(1-product/(substrate*Keq))*(substrate/Shalve+product/Phalve)^(h-1) / ( 1+(substrate/Shalve + product/Phalve)^h ))'
+'(V*substrate*(1+b*modifier/(a*Kd)) / ( Km*(1+modifier/Kd) + substrate*(1+modifier/(a*Kd)) ))'
+'((Vf*substrate/Kms - Vr*product/Kmp)*(1+b*modifier/(a*Kd)) / ( 1+modifier/Kd+(substrate/Kms+product/Kmp)*(1+modifier/(a*Kd)) ))'
+'(Vf*(substrate-product/Keq) / ( substrate*(1+product/Kii) + Kms*(1+product/Kmp) ))'
+'(k*substrate)'
+'(k1*substrate-k2*product)'
+'(V*substrate / ( Km + substrate ))'
+'((Vf*substrate/Kms+Vr*product/Kmp) / ( 1+substrate/Kms+product/Kmp ) )'
+'(V*substrate*activator / ( Kms*(Kas+activator) + substrate*(Kac+activator) ))'
+'((Vf*substrate/Kms - Vr*product/Kmp)*activator / ( Kas+activator+(substrate/Kms+product/Kmp)*(Kac+activator) ))'
+'(V*substrate / ( (Km*(1+inhibitor/Kis) + substrate*(1+inhibitor/Kic) ))'
+'((Vf*substrate/Kms - Vr*product/Kmp) / ( 1+inhibitor/Kis+(substrate/Kms+product/Kmp)*(1+inhibitor/Kic) ))'
+'(V*substrate / ( (Km+substrate)*(1+inhibitor/Ki) ))'
+'((Vf*substrate/Kms-Vr*product/Kmp) / ( (1+substrate/Kms+product/Kmp)*(1+inhibitor/Ki) ))'
+'(Vf*(substratea*substrateb-productp*productq/Keq) / (substratea*substrateb*(1+productp/Kip) + Kma*substrateb + Kmb*(substratea+Kia)+Vf/(Vr*Keq)*(Kmq*productp*(1+substratea/Kia) + productq*(Kmp*(1+Kia*substrateb/(Kma*Kmb))+productp*(1+substrateb/Kib))) ))'
+'(Vf*(substratea*substrateb-product/Keq) / ( substratea*substrateb+Kma*substrateb+Kmb*substratea+Vf/(Vr*Keq)*(Kmp+product*(1+substratea/Kia)) ))'
+'(Vf*(substrate-productp*productq/Keq) / ( Kms+substrate*(1+productp/Kip)+Vf/(Vr*Keq)*(Kmq*productp+Kmp*productq+productp*productq) );)'
+'(Vf*( substratea*substrateb-productp*productq/Keq ) / (substratea*substrateb*(1+productq/Kiq)+Kma*substrateb+Kmb*substratea+Vf/(Vr*Keq)*(Kmq*productp*(1+substratea/Kia)+productq*(Kmp+productp))))'
+'(V*substrate*activator/( Kms*Ka+(Kms+substrate)*activator )'
+'(( Vf*substrate/Kms-Vr*product/Kmp )*activator / ( Ka+(1+substrate/Kms+product/Kmp)*activator ))'
+'(V*(substrate/Ksa)^2 / ( 1+substrate/Ksc+substrate/Ksa+(substrate/Ksa)^2 ))'
+'(V*substrate / ( Km + substrate + Km*(substrate/Ki)^2 ))'
+'((Vf*substrate/Kms-Vr*product/Kmp) / ( 1+substrate/Kms+product/Kmp+(substrate/Ki)^2 ))'
+'(V*substrate / ( Km + substrate*(1+inhibitor/Ki) ))'
+'(( Vf*substrate/Kms-Vr*product/Kmp ) / ( 1+(substrate/Kms+product/Kmp)*(1+inhibitor/Ki) ))'
+'(Vf*( substrate-product/Keq ) / ( substrate+Kms*(1+product/Kmp) ))'
+};
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/getkinformulaIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/getkinformulaIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..4b272014e62908ed3f3cbaaed0cab48d09cc7108
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/getkinformulaIQM.m	
@@ -0,0 +1,50 @@
+function [R] = getkinformulaIQM(R)
+% getkinformulaIQM: auxiliary function to convert rate law functions to
+% formulas.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+Rorig = R;
+R = ['#' R '#'];
+% Load names of all kinetic laws
+allkineticlaws
+
+% Check if kinetic rate expression present
+found = 0;
+for k=1:length(allLawsNames),
+    if ~isempty(regexp(R,['\W' allLawsNames{k} '\W'])),
+        % it is present
+        % get the arguments of the reaction
+        ratelawname = allLawsNames{k};
+        indexstart = strfind(R,ratelawname);
+        arguments = R(indexstart+length(ratelawname):end);
+        parentheses = 0;
+        for k2=1:length(arguments),
+            if arguments(k2) == '(',
+                parentheses = parentheses+1;
+            end
+            if arguments(k2) == ')',
+                parentheses = parentheses-1;
+                if parentheses == 0,
+                    break;
+                end
+            end
+        end
+        arguments = arguments(2:k2-1);
+        arguments = explodePCIQM(arguments);
+        preLaw = R(1:indexstart-1);
+        postLaw = R(k2+indexstart+length(ratelawname):end);
+        R = [preLaw(2:end) allLawsFormulas{k} postLaw(1:end-1)];
+        % finally exchange the argument names
+        changearguments = allLawsArguments{k};
+        R = regexprep(R,'(\W)',' $1 ');
+        for k2=1:length(arguments),
+            R = regexprep(R,['\W' changearguments{k2} '\W'], arguments{k2});
+        end
+        R = regexprep(R,' ','');
+        found = 1;
+    end
+end
+if found == 0,
+    R = Rorig;
+end
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_allosteric_inihib_empirical_rev.m b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_allosteric_inihib_empirical_rev.m
new file mode 100644
index 0000000000000000000000000000000000000000..59474ed73600a3c6b0ae230a93bbfac57e8b4945
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_allosteric_inihib_empirical_rev.m	
@@ -0,0 +1,21 @@
+function [R] = kin_allosteric_inihib_empirical_rev(Vf,substrate,Kms,Vr,product,Kmp,inhibitor,Ki,n)
+% kin_allosteric_inihib_empirical_rev: Allosteric inhibition (reversible) kinetics
+% 
+% Application restrictions: 
+% =========================
+%   - Only reversible
+%   - exactly 1 substrate
+%   - exactly 1 product
+%
+% USAGE:
+% ======
+% R = kin_allosteric_inihib_empirical_rev(Vf,substrate,Kms,Vr,product,Kmp,inhibitor,Ki,n)
+%
+% Output Arguments:
+% =================
+% R = (Vf*substrate/Kms - Vr*product/Kmp) / (1 + substrate/Kms + product/Kmp + (inhibitor/Ki)^n)
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+R = (Vf*substrate/Kms - Vr*product/Kmp) / (1 + substrate/Kms + product/Kmp + (inhibitor/Ki)^n);
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_allosteric_inihib_mwc_irr.m b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_allosteric_inihib_mwc_irr.m
new file mode 100644
index 0000000000000000000000000000000000000000..5bb628db94e6bb4084337247fa7648aeed2deb44
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_allosteric_inihib_mwc_irr.m	
@@ -0,0 +1,20 @@
+function [R] = kin_allosteric_inihib_mwc_irr(V,substrate,Ks,n,L,inhibitor,Ki)
+% kin_allosteric_inihib_mwc_irr: Allosteric inhibition (irreversible) kinetics
+%
+% Application restrictions: 
+% =========================
+%   - Only irreversible
+%   - exactly 1 substrate
+%
+% USAGE:
+% ======
+% R = kin_allosteric_inihib_mwc_irr(V,substrate,Ks,n,L,inhibitor,Ki)
+%
+% Output Arguments:
+% =================
+% R = V*substrate*(Ks+substrate)^(n-1) / ( L*(Ks*(1+inhibitor/Ki))^n + (Ks+substrate)^n )
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+R = V*substrate*(Ks+substrate)^(n-1) / ( L*(Ks*(1+inhibitor/Ki))^n + (Ks+substrate)^n );
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_catalytic_activation_irr.m b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_catalytic_activation_irr.m
new file mode 100644
index 0000000000000000000000000000000000000000..f1ef280639f9f6f27c59049d46cc609050477fde
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_catalytic_activation_irr.m	
@@ -0,0 +1,20 @@
+function [R] = kin_catalytic_activation_irr(V,substrate,activator,Kms,Ka)
+% kin_catalytic_activation_irr: Catalytic activation (irreversible) kinetics
+%
+% Application restrictions: 
+% =========================
+%   - Only irreversible
+%   - exactly 1 substrate
+%
+% USAGE:
+% ======
+% R = kin_catalytic_activation_irr(V,substrate,activator,Kms,Ka)
+%
+% Output Arguments:
+% =================
+% R = V*substrate*activator / ( (Kms + substrate)*(Ka+activator) )
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+R = V*substrate*activator / ( (Kms + substrate)*(Ka+activator) )
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_catalytic_activation_rev.m b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_catalytic_activation_rev.m
new file mode 100644
index 0000000000000000000000000000000000000000..8613dc1a54cb3ec6cb6019152921a1353d37d694
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_catalytic_activation_rev.m	
@@ -0,0 +1,21 @@
+function [R] = kin_catalytic_activation_rev(Vf,substrate,Kms,Vr,product,Kmp,activator,Ka)
+% kin_catalytic_activation_rev: Catalytic activation (reversible) kinetics
+%
+% Application restrictions: 
+% =========================
+%   - Only reversible
+%   - exactly 1 substrate
+%   - exactly 1 product
+%
+% USAGE:
+% ======
+% R = kin_catalytic_activation_rev(Vf,substrate,Kms,Vr,product,Kmp,activator,Ka)
+%
+% Output Arguments:
+% =================
+% R = ( Vf*substrate/Kms - Vr*product/Kmp )*activator / ( (1+substrate/Kms+product/Kmp)*(Ka+activator) )
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+R = ( Vf*substrate/Kms - Vr*product/Kmp )*activator / ( (1+substrate/Kms+product/Kmp)*(Ka+activator) );
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_comp_inihib_irr.m b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_comp_inihib_irr.m
new file mode 100644
index 0000000000000000000000000000000000000000..34526bfcd0c74d1dd050354e67313d6c25bb8889
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_comp_inihib_irr.m	
@@ -0,0 +1,20 @@
+function [R] = kin_comp_inihib_irr(V,substrate,Km,inhibitor,Ki)
+% kin_comp_inihib_irr: Competitive inhibition (irreversible) kinetics
+%
+% Application restrictions: 
+% =========================
+%   - Only irreversible
+%   - exactly 1 substrate
+%
+% USAGE:
+% ======
+% R = kin_comp_inihib_irr(V,substrate,Km,inhibitor,Ki)
+%
+% Output Arguments:
+% =================
+% R = V*substrate / ( Km*(1+inhibitor/Ki) + substrate )
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+R = V*substrate / ( Km*(1+inhibitor/Ki) + substrate );
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_comp_inihib_rev.m b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_comp_inihib_rev.m
new file mode 100644
index 0000000000000000000000000000000000000000..f5ace96d598ad61772488b35ff364ccd3f494e6c
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_comp_inihib_rev.m	
@@ -0,0 +1,21 @@
+function [R] = kin_comp_inihib_rev(Vf,substrate,Kms,Vr,product,Kmp,inhibitor,Ki)
+% kin_comp_inihib_rev: Competitive inhibition (reversible) kinetics
+%
+% Application restrictions: 
+% =========================
+%   - Only reversible
+%   - exactly 1 substrate
+%   - exactly 1 product
+%
+% USAGE:
+% ======
+% R = kin_comp_inihib_rev(Vf,substrate,Kms,Vr,product,Kmp,inhibitor,Ki)
+%
+% Output Arguments:
+% =================
+% R = (Vf*substrate/Kms - Vr*product/Kmp) / ( 1+substrate/Kms+product/Kmp+inhibitor/Ki )
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+R = (Vf*substrate/Kms - Vr*product/Kmp) / ( 1+substrate/Kms+product/Kmp+inhibitor/Ki );
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_constantflux.m b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_constantflux.m
new file mode 100644
index 0000000000000000000000000000000000000000..a8d9acb7a76900840a8b44aece33f3d7a5bf0f4a
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_constantflux.m	
@@ -0,0 +1,19 @@
+function [R] = kin_constantflux(v)
+% kin_constantflux: Competitive inhibition (reversible) kinetics
+%
+% Application restrictions: 
+% =========================
+%   - Be careful that concentrations do not become negative!
+%
+% USAGE:
+% ======
+% R = kin_constantflux(v)
+%
+% Output Arguments:
+% =================
+% R = v
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+R = v;
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_degradation.m b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_degradation.m
new file mode 100644
index 0000000000000000000000000000000000000000..791731b5e5516784f4ccc499206010f3499aeebd
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_degradation.m	
@@ -0,0 +1,20 @@
+function [R] = kin_degradation(kdeg,substrate)
+% kin_degradation: Linear degradation kinetics
+%
+% Application restrictions: 
+% =========================
+%   - Only irreversible
+%   - exactly 1 substrate
+%
+% USAGE:
+% ======
+% R = kin_degradation(kdeg,substrate)
+%
+% Output Arguments:
+% =================
+% R = kdeg*substrate
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+R = kdeg*substrate;
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_hill_1_modifier_rev.m b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_hill_1_modifier_rev.m
new file mode 100644
index 0000000000000000000000000000000000000000..87f68d23febfa3ae3a7adee1eb0eaedb6f30e584
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_hill_1_modifier_rev.m	
@@ -0,0 +1,20 @@
+function [R] = kin_hill_1_modifier_rev(Vf,substrate,Shalve,product,Keq,Phalve,h,modifier,Mhalve,alpha)
+% kin_hill_1_modifier_rev: Reversible Hill type kinetics with one modifier
+%
+% Application restrictions: 
+% =========================
+%   - Only reversible
+%   - exactly 1 substrate
+%   - exactly 1 product
+%
+% USAGE:
+% ======
+% R = kin_hill_1_modifier_rev(Vf,substrate,Shalve,product,Keq,Phalve,h,modifier,Mhalve,alpha)
+%
+% Output Arguments:
+% =================
+% R = Vf*substrate/Shalve*(1-product/(substrate*Keq))*(substrate/Shalve+product/Phalve)^(h-1) / ( (1+(modifier/Mhalve)^h)/(1+alpha*(modifier/Mhalve)^h)+(substrate/Shalve + product/Phalve)^h ) 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+R = Vf*substrate/Shalve*(1-product/(substrate*Keq))*(substrate/Shalve+product/Phalve)^(h-1) / ( (1+(modifier/Mhalve)^h)/(1+alpha*(modifier/Mhalve)^h)+(substrate/Shalve + product/Phalve)^h );
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_hill_2_modifiers_rev.m b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_hill_2_modifiers_rev.m
new file mode 100644
index 0000000000000000000000000000000000000000..0d8c3f681a1fce2fb34bcba0e2c58bd8c4955cd5
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_hill_2_modifiers_rev.m	
@@ -0,0 +1,20 @@
+function [R] = kin_hill_2_modifiers_rev(Vf,substrate,Shalve,product,Keq,Phalve,h,modifierA,MAhalve,modifierB,MBhalve,alphaA,alphaB,alphaAB)
+% kin_hill_2_modifiers_rev: Reversible Hill type kinetics with one modifier
+%
+% Application restrictions: 
+% =========================
+%   - Only reversible
+%   - exactly 1 substrate
+%   - exactly 1 product
+%
+% USAGE:
+% ======
+% R = kin_hill_2_modifiers_rev(Vf,substrate,Shalve,product,Keq,Phalve,h,modifierA,MAhalve,modifierB,MBhalve,alphaA,alphaB,alphaAB)
+%
+% Output Arguments:
+% =================
+% R = Vf*substrate/Shalve*(1-product/(substrate*Keq))*(substrate/Shalve+product/Phalve)^(h-1) / ( (1+(modifierA/MAhalve)^h + 1+(modifierB/MBhalve)^h) / ( 1+alphaA*(modifierA/MAhalve)^h+alphaB*(modifierB/MBhalve)^h+alphaA*alphaB*alphaAB*(modifierA/MAhalve)^h*(modifierB/MBhalve)^h ) + (substrate/Shalve + product/Phalve)^h ) 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+R = Vf*substrate/Shalve*(1-product/(substrate*Keq))*(substrate/Shalve+product/Phalve)^(h-1) / ( (1+(modifierA/MAhalve)^h + 1+(modifierB/MBhalve)^h) / ( 1+alphaA*(modifierA/MAhalve)^h+alphaB*(modifierB/MBhalve)^h+alphaA*alphaB*alphaAB*(modifierA/MAhalve)^h*(modifierB/MBhalve)^h ) + (substrate/Shalve + product/Phalve)^h );
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_hill_cooperativity_irr.m b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_hill_cooperativity_irr.m
new file mode 100644
index 0000000000000000000000000000000000000000..4c18d9193621f313d6d3188e3a6110a7338058e8
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_hill_cooperativity_irr.m	
@@ -0,0 +1,20 @@
+function [R] = kin_hill_cooperativity_irr(V,substrate,h,Shalve)
+% kin_hill_cooperativity_irr: Hill type (irreversible) kinetics
+%
+% Application restrictions: 
+% =========================
+%   - Only irreversible
+%   - exactly 1 substrate
+%
+% USAGE:
+% ======
+% R = kin_hill_cooperativity_irr(V,substrate,h,Shalve)
+%
+% Output Arguments:
+% =================
+% R = V*substrate^h / ( Shalve^h + substrate^h )
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+R = V*substrate^h / ( Shalve^h + substrate^h );
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_hill_rev.m b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_hill_rev.m
new file mode 100644
index 0000000000000000000000000000000000000000..c9684388468cbe9f9025ed72096d03353016ec56
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_hill_rev.m	
@@ -0,0 +1,21 @@
+function [R] = kin_hill_rev(Vf,substrate,Shalve,product,Keq,Phalve,h)
+% kin_hill_rev: Hill type (reversible) kinetics
+%
+% Application restrictions: 
+% =========================
+%   - Only reversible
+%   - exactly 1 substrate
+%   - exactly 1 product
+%
+% USAGE:
+% ======
+% R = kin_hill_rev(Vf,substrate,Shalve,product,Keq,Phalve,h)
+%
+% Output Arguments:
+% =================
+% R = Vf*substrate/Shalve*(1-product/(substrate*Keq))*(substrate/Shalve+product/Phalve)^(h-1) / ( 1+(substrate/Shalve + product/Phalve)^h ) 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>> 
+
+R = Vf*substrate/Shalve*(1-product/(substrate*Keq))*(substrate/Shalve+product/Phalve)^(h-1) / ( 1+(substrate/Shalve + product/Phalve)^h );
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_hyperbolic_modifier_irr.m b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_hyperbolic_modifier_irr.m
new file mode 100644
index 0000000000000000000000000000000000000000..11cebbb4c80c9f6623cff52e42e35dbe49c6afce
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_hyperbolic_modifier_irr.m	
@@ -0,0 +1,20 @@
+function [R] = kin_hyperbolic_modifier_irr(V,substrate,b,modifier,a,Kd,Km)
+% kin_hyperbolic_modifier_irr: Hyperbolic modifier (irreversible) kinetics
+%
+% Application restrictions: 
+% =========================
+%   - Only irreversible
+%   - exactly 1 substrate
+%
+% USAGE:
+% ======
+% R = kin_hyperbolic_modifier_irr(V,substrate,b,modifier,a,Kd,Km)
+%
+% Output Arguments:
+% =================
+% R = V*substrate*(1+b*modifier/(a*Kd)) / ( Km*(1+modifier/Kd) + substrate*(1+modifier/(a*Kd)) )
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+R = V*substrate*(1+b*modifier/(a*Kd)) / ( Km*(1+modifier/Kd) + substrate*(1+modifier/(a*Kd)) );
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_hyperbolic_modifier_rev.m b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_hyperbolic_modifier_rev.m
new file mode 100644
index 0000000000000000000000000000000000000000..ac7fbac17a2fbac4053fe1f3955263f07df0305e
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_hyperbolic_modifier_rev.m	
@@ -0,0 +1,21 @@
+function [R] = kin_hyperbolic_modifier_rev(Vf,substrate,Kms,Vr,product,Kmp,b,modifier,a,Kd)
+% kin_hyperbolic_modifier_rev: Hyperbolic modifier (reversible) kinetics
+%
+% Application restrictions: 
+% =========================
+%   - Only reversible
+%   - exactly 1 substrate
+%   - exactly 1 product
+%
+% USAGE:
+% ======
+% R = kin_hyperbolic_modifier_rev(Vf,substrate,Kms,Vr,product,Kmp,b,modifier,a,Kd)
+%
+% Output Arguments:
+% =================
+% R = (Vf*substrate/Kms - Vr*product/Kmp)*(1+b*modifier/(a*Kd)) / ( 1+modifier/Kd+(substrate/Kms+product/Kmp)*(1+modifier/(a*Kd) )
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+R = (Vf*substrate/Kms - Vr*product/Kmp)*(1+b*modifier/(a*Kd)) / ( 1+modifier/Kd+(substrate/Kms+product/Kmp)*(1+modifier/(a*Kd)) );
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_iso_uni_uni_rev.m b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_iso_uni_uni_rev.m
new file mode 100644
index 0000000000000000000000000000000000000000..8302264bcea816d13bb28b099a4fe4555a3d8aba
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_iso_uni_uni_rev.m	
@@ -0,0 +1,21 @@
+function [R] = kin_iso_uni_uni_rev(Vf,substrate,product,Keq,Kii,Kms,Kmp)
+% kin_iso_uni_uni_rev: enzyme isomerization product inhibition
+%
+% Application restrictions: 
+% =========================
+%   - Only reversible
+%   - exactly 1 substrate
+%   - exactly 1 product
+%
+% USAGE:
+% ======
+% R = kin_iso_uni_uni_rev(Vf,substrate,product,Keq,Kii,Kms,Kmp)
+%
+% Output Arguments:
+% =================
+% R = Vf*(substrate-product/Keq) / ( substrate*(1+product/Kii) + Kms*(1+product/Kmp) )
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+R = Vf*(substrate-product/Keq) / ( substrate*(1+product/Kii) + Kms*(1+product/Kmp) );
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_mass_action_irr.m b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_mass_action_irr.m
new file mode 100644
index 0000000000000000000000000000000000000000..4d08526d2449fbdad3d9731fcb533da004a1d41c
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_mass_action_irr.m	
@@ -0,0 +1,21 @@
+function [R] = kin_mass_action_irr(k,substrate)
+% kin_mass_action_irr: Mass action (irreversible) kinetics
+%
+% Application restrictions: 
+% =========================
+%   - Only irreversible
+%   - exactly 1 substrate (several substrates can be realized by
+%   substrate=substrate1*substrate2*...
+%
+% USAGE:
+% ======
+% R = kin_mass_action_irr(k,substrate)
+%
+% Output Arguments:
+% =================
+% R = k*substrate
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+R = k*substrate;
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_mass_action_rev.m b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_mass_action_rev.m
new file mode 100644
index 0000000000000000000000000000000000000000..26121e45917bff1a3a7c1c938f6f4fb6abab5d39
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_mass_action_rev.m	
@@ -0,0 +1,23 @@
+function [R] = kin_mass_action_rev(k1,substrate,k2,product)
+% kin_mass_action_rev: Mass action (reversible) kinetics
+%
+% Application restrictions: 
+% =========================
+%   - Only reversible
+%   - exactly 1 substrate (several substrates can be realized by
+%   substrate=substrate1*substrate2*...
+%   - exactly 1 product (several products can be realized by
+%   product=product1*product2*...
+%
+% USAGE:
+% ======
+% R = kin_mass_action_rev(k1,substrate,k2,product)
+%
+% Output Arguments:
+% =================
+% R = k1*substrate-k2*product
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+R = k1*substrate-k2*product;
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_michaelis_menten_irr.m b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_michaelis_menten_irr.m
new file mode 100644
index 0000000000000000000000000000000000000000..ef3b7fee5f49c3725e9836d5151deab18021f849
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_michaelis_menten_irr.m	
@@ -0,0 +1,20 @@
+function [R] = kin_michaelis_menten_irr(V,substrate,Km)
+% kin_michaelis_menten_irr: Michaelis Menten (irreversible) kinetics
+%
+% Application restrictions: 
+% =========================
+%   - Only irreversible
+%   - exactly 1 substrate
+%
+% USAGE:
+% ======
+% R = kin_michaelis_menten_irr(V,substrate,Km)
+%
+% Output Arguments:
+% =================
+% R = V*substrate / ( Km + substrate )
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+R = V*substrate / ( Km + substrate );
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_michaelis_menten_rev.m b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_michaelis_menten_rev.m
new file mode 100644
index 0000000000000000000000000000000000000000..1334112f831e1829fb3106fb961f98d063108f7b
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_michaelis_menten_rev.m	
@@ -0,0 +1,21 @@
+function [R] = kin_michaelis_menten_rev(Vf,substrate,Kms,Vr,product,Kmp)
+% kin_michaelis_menten_rev: Michaelis Menten (reversible) kinetics
+%
+% Application restrictions: 
+% =========================
+%   - Only reversible
+%   - exactly 1 substrate
+%   - exactly 1 product
+%
+% USAGE:
+% ======
+% R = kin_michaelis_menten_rev(Vf,substrate,Kms,Vr,product,Kmp)
+%
+% Output Arguments:
+% =================
+% R = (Vf*substrate/Kms+Vr*product/Kmp) / ( 1+substrate/Kms+product/Kmp ) 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+R = (Vf*substrate/Kms+Vr*product/Kmp) / ( 1+substrate/Kms+product/Kmp ) ;
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_mixed_activation_irr.m b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_mixed_activation_irr.m
new file mode 100644
index 0000000000000000000000000000000000000000..e7f1d6120e4d352d815b3fe9b667a58033662683
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_mixed_activation_irr.m	
@@ -0,0 +1,20 @@
+function [R] = kin_mixed_activation_irr(V,substrate,activator,Kms,Kas,Kac)
+% kin_mixed_activation_irr: Mixed activation irreversible
+%
+% Application restrictions: 
+% =========================
+%   - Only irreversible
+%   - exactly 1 substrate
+%
+% USAGE:
+% ======
+% R = kin_mixed_activation_irr(V,substrate,activator,Kms,Kas,Kac)
+%
+% Output Arguments:
+% =================
+% R = V*substrate*activator / ( Kms*(Kas+activator) + substrate*(Kac+activator) )
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+R = V*substrate*activator / ( Kms*(Kas+activator) + substrate*(Kac+activator) );
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_mixed_activation_rev.m b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_mixed_activation_rev.m
new file mode 100644
index 0000000000000000000000000000000000000000..34489ece6be7153fc7289062e8f17f1bca9a1cf6
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_mixed_activation_rev.m	
@@ -0,0 +1,21 @@
+function [R] = kin_mixed_activation_rev(Vf,substrate,Kms,Vr,product,Kmp,activator,Kas,Kac)
+% kin_mixed_activation_rev: Mixed activation reversible
+%
+% Application restrictions: 
+% =========================
+%   - Only reversible
+%   - exactly 1 substrate
+%   - exactly 1 product
+%
+% USAGE:
+% ======
+% R = kin_mixed_activation_rev(Vf,substrate,Kms,Vr,product,Kmp,activator,Kas,Kac)
+%
+% Output Arguments:
+% =================
+% R = (Vf*substrate/Kms - Vr*product/Kmp)*activator / ( Kas+activator+(substrate/Kms+product/Kmp)*(Kac+activator) )
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+R = (Vf*substrate/Kms - Vr*product/Kmp)*activator / ( Kas+activator+(substrate/Kms+product/Kmp)*(Kac+activator) );
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_mixed_inihib_irr.m b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_mixed_inihib_irr.m
new file mode 100644
index 0000000000000000000000000000000000000000..20d0e8cef6819d62d21cd6cc42a9a0be59b3a1be
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_mixed_inihib_irr.m	
@@ -0,0 +1,20 @@
+function [R] = kin_mixed_inihib_irr(V,substrate,Km,inhibitor,Kis,Kic)
+% kin_mixed_inihib_irr: Mixed inhibition (irreversible) kinetics
+%
+% Application restrictions: 
+% =========================
+%   - Only irreversible
+%   - exactly 1 substrate
+%
+% USAGE:
+% ======
+% R = kin_mixed_inihib_irr(V,substrate,Km,inhibitor,Kis,Kic)
+%
+% Output Arguments:
+% =================
+% R = V*substrate / ( (Km*(1+inhibitor/Kis) + substrate*(1+inhibitor/Kic) )
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+R = V*substrate / ( Km*(1+inhibitor/Kis) + substrate*(1+inhibitor/Kic) );
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_mixed_inihib_rev.m b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_mixed_inihib_rev.m
new file mode 100644
index 0000000000000000000000000000000000000000..1e63c9234ea5df2c30414df9003386d760c186b4
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_mixed_inihib_rev.m	
@@ -0,0 +1,21 @@
+function [R] = kin_mixed_inihib_rev(Vf,substrate,Kms,Vr,product,Kmp,inhibitor,Kis,Kic)
+% kin_mixed_inihib_rev: Mixed inhibition (reversible) kinetics
+%
+% Application restrictions: 
+% =========================
+%   - Only reversible
+%   - exactly 1 substrate
+%   - exactly 1 product
+%
+% USAGE:
+% ======
+% R = kin_mixed_inihib_rev(Vf,substrate,Kms,Vr,product,Kmp,inhibitor,Kis,Kic)
+%
+% Output Arguments:
+% =================
+% R = (Vf*substrate/Kms - Vr*product/Kmp) / ( 1+inhibitor/Kis+(substrate/Kms+product/Kmp)*(1+inhibitor/Kic) )
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+R = (Vf*substrate/Kms - Vr*product/Kmp) / ( 1+inhibitor/Kis+(substrate/Kms+product/Kmp)*(1+inhibitor/Kic) );
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_noncomp_inihib_irr.m b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_noncomp_inihib_irr.m
new file mode 100644
index 0000000000000000000000000000000000000000..79e79141f0e702a6d3897f44a8a27d2401ee3883
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_noncomp_inihib_irr.m	
@@ -0,0 +1,20 @@
+function [R] = kin_noncomp_inihib_irr(V,substrate,Km,inhibitor,Ki)
+% kin_noncomp_inihib_irr: Noncompetitive inhibition (irreversible) kinetics
+%
+% Application restrictions: 
+% =========================
+%   - Only irreversible
+%   - exactly 1 substrate
+%
+% USAGE:
+% ======
+% R = kin_noncomp_inihib_irr(V,substrate,Km,inhibitor,Ki)
+%
+% Output Arguments:
+% =================
+% R = V*substrate / ( (Km+substrate)*(1+inhibitor/Ki) )
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+R = V*substrate / ( (Km+substrate)*(1+inhibitor/Ki) );
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_noncomp_inihib_rev.m b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_noncomp_inihib_rev.m
new file mode 100644
index 0000000000000000000000000000000000000000..6660e52b02bfdded13c9b23de41a471ca9ca9a5e
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_noncomp_inihib_rev.m	
@@ -0,0 +1,21 @@
+function [R] = kin_noncomp_inihib_rev(Vf,substrate,Kms,Vr,product,Kmp,inhibitor,Ki)
+% kin_noncomp_inihib_rev: Noncompetitive inhibition (reversible) kinetics
+%
+% Application restrictions: 
+% =========================
+%   - Only reversible
+%   - exactly 1 substrate
+%   - exactly 1 product
+%
+% USAGE:
+% ======
+% R = kin_noncomp_inihib_rev(Vf,substrate,Kms,Vr,product,Kmp,inhibitor,Ki)
+%
+% Output Arguments:
+% =================
+% R = (Vf*substrate/Kms-Vr*product/Kmp) / ( (1+substrate/Kms+product/Kmp)*(1+inhibitor/Ki) )
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+R = (Vf*substrate/Kms-Vr*product/Kmp) / ( (1+substrate/Kms+product/Kmp)*(1+inhibitor/Ki) );
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_ordered_bi_bi_rev.m b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_ordered_bi_bi_rev.m
new file mode 100644
index 0000000000000000000000000000000000000000..e4f936fb459d43e73ebe836f60964e78eb01c86f
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_ordered_bi_bi_rev.m	
@@ -0,0 +1,21 @@
+function [R] = kin_ordered_bi_bi_rev(Vf,substratea,substrateb,productp,productq,Keq,Kip,Kma,Kmb,Kia,Vr,Kmq,Kmp,Kib)
+% kin_ordered_bi_bi_rev: ordered bi-bi reversible
+%
+% Application restrictions: 
+% =========================
+%   - Only reversible
+%   - exactly 2 substrates
+%   - exactly 2 products
+%
+% USAGE:
+% ======
+% R = kin_ordered_bi_bi_rev(Vf,substratea,substrateb,productp,productq,Keq,Kip,Kma,Kmb,Kia,Vr,Kmq,Kmp,Kib)
+%
+% Output Arguments:
+% =================
+% R = Vf*(substratea*substrateb-productp*productq/Keq) / (substratea*substrateb*(1+productp/Kip) + Kma*substrateb + Kmb*(substratea+Kia)+Vf/(Vr*Keq)*(Kmq*productp*(1+substratea/Kia) + productq*(Kmp*(1+Kia*substrateb/(Kma*Kmb))+productp*(1+substrateb/Kib))) )
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+R = Vf*(substratea*substrateb-productp*productq/Keq) / (substratea*substrateb*(1+productp/Kip) + Kma*substrateb + Kmb*(substratea+Kia)+Vf/(Vr*Keq)*(Kmq*productp*(1+substratea/Kia) + productq*(Kmp*(1+Kia*substrateb/(Kma*Kmb))+productp*(1+substrateb/Kib))) );
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_ordered_bi_uni_rev.m b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_ordered_bi_uni_rev.m
new file mode 100644
index 0000000000000000000000000000000000000000..04a4aa4616e6b16c6bd6585c44b30132d502a286
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_ordered_bi_uni_rev.m	
@@ -0,0 +1,21 @@
+function [R] = kin_ordered_bi_uni_rev(Vf,substratea,substrateb,product,Keq,Kma,Kmb,Vr,Kmp,Kia)
+% kin_ordered_bi_uni_rev: ordered bi-uni reversible
+%
+% Application restrictions: 
+% =========================
+%   - Only reversible
+%   - exactly 2 substrates
+%   - exactly 1 product
+%
+% USAGE:
+% ======
+% R = kin_ordered_bi_uni_rev(Vf,substratea,substrateb,product,Keq,Kma,Kmb,Vr,Kmp,Kia)
+%
+% Output Arguments:
+% =================
+% R = Vf*(substratea*substrateb-product/Keq) / ( substratea*substrateb+Kma*substrateb+Kmb*substratea+Vf/(Vr*Keq)*(Kmp+product*(1+substratea/Kia)) ) 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+R = Vf*(substratea*substrateb-product/Keq) / ( substratea*substrateb+Kma*substrateb+Kmb*substratea+Vf/(Vr*Keq)*(Kmp+product*(1+substratea/Kia)) );
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_ordered_uni_bi_rev.m b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_ordered_uni_bi_rev.m
new file mode 100644
index 0000000000000000000000000000000000000000..a2b521c95aaaea5b694c108802d8396a819647c7
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_ordered_uni_bi_rev.m	
@@ -0,0 +1,21 @@
+function [R] = kin_ordered_uni_bi_rev(Vf,substrate,productp,productq,Keq,Kms,Kip,Vr,Kmq,Kmp)
+% kin_ordered_uni_bi_rev: ordered uni-bi reversible
+%
+% Application restrictions: 
+% =========================
+%   - Only reversible
+%   - exactly 1 substrate
+%   - exactly 2 products
+%
+% USAGE:
+% ======
+% R = kin_ordered_uni_bi_rev(Vf,substrate,productp,productq,Keq,Kms,Kip,Vr,Kmq,Kmp)
+%
+% Output Arguments:
+% =================
+% R = Vf*(substrate-productp*productq/Keq) / ( Kms+substrate*(1+productp/Kip)+Vf/(Vr*Keq)*(Kmq*productp+Kmp*productq+productp*productq) ) 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+R = Vf*(substrate-productp*productq/Keq) / ( Kms+substrate*(1+productp/Kip)+Vf/(Vr*Keq)*(Kmq*productp+Kmp*productq+productp*productq) ); 
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_ping_pong_bi_bi_rev.m b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_ping_pong_bi_bi_rev.m
new file mode 100644
index 0000000000000000000000000000000000000000..18ca676d796643396ebb403723d6a4a3b5166046
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_ping_pong_bi_bi_rev.m	
@@ -0,0 +1,21 @@
+function [R] = kin_ping_pong_bi_bi_rev(Vf,substratea,substrateb,productp,productq,Keq,Kiq,Kma,Kmb,Vr,Kmq,Kia,Kmp)
+% kin_ping_pong_bi_bi_rev: Ping pong bi bi kinetics (reversible) 
+%
+% Application restrictions: 
+% =========================
+%   - Only reversible
+%   - exactly 2 substrates
+%   - exactly 2 products
+%
+% USAGE:
+% ======
+% R = kin_ping_pong_bi_bi_rev(Vf,substratea,substrateb,productp,productq,Keq,Kiq,Kma,Kmb,Vr,Kmq,Kia,Kmp)
+%
+% Output Arguments:
+% =================
+% R = Vf*( substratea*substrateb-productp*productq/Keq ) / (substratea*substrateb*(1+productq/Kiq)+Kma*substrateb+Kmb*substratea+Vf/(Vr*Keq)*(Kmq*productp*(1+substratea/Kia)+productq*(Kmp+productp)))
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+R = Vf*( substratea*substrateb-productp*productq/Keq ) / (substratea*substrateb*(1+productq/Kiq)+Kma*substrateb+Kmb*substratea+Vf/(Vr*Keq)*(Kmq*productp*(1+substratea/Kia)+productq*(Kmp+productp)));
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_specific_activation_irr.m b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_specific_activation_irr.m
new file mode 100644
index 0000000000000000000000000000000000000000..76614e397ef1c367a48e191a62bf5c6a8cb60379
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_specific_activation_irr.m	
@@ -0,0 +1,20 @@
+function [R] = kin_specific_activation_irr(V,substrate,activator,Kms,Ka)
+% kin_specific_activation_irr: Specific activation (irreversible) kinetics
+%
+% Application restrictions: 
+% =========================
+%   - Only irreversible
+%   - exactly 1 substrate
+%
+% USAGE:
+% ======
+% R = kin_specific_activation_irr(V,substrate,activator,Kms,Ka)
+%
+% Output Arguments:
+% =================
+% R = V*substrate*activator/( Kms*Ka+(Kms+substrate)*activator )
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+R = V*substrate*activator/( Kms*Ka+(Kms+substrate)*activator );
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_specific_activation_rev.m b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_specific_activation_rev.m
new file mode 100644
index 0000000000000000000000000000000000000000..5a09a725e2b73337a6dbc22cd1f6702cdb262c5e
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_specific_activation_rev.m	
@@ -0,0 +1,21 @@
+function [R] = kin_specific_activation_rev(Vf,substrate,Kms,Vr,product,Kmp,activator,Ka)
+% kin_specific_activation_rev: Specific activation (reversible) kinetics
+%
+% Application restrictions: 
+% =========================
+%   - Only reversible
+%   - exactly 1 substrate
+%   - exactly 1 product
+%
+% USAGE:
+% ======
+% R = kin_specific_activation_rev(Vf,substrate,Kms,Vr,product,Kmp,activator,Ka)
+%
+% Output Arguments:
+% =================
+% R = ( Vf*substrate/Kms-Vr*product/Kmp )*activator / ( Ka+(1+substrate/Kms+product/Kmp)*activator )  
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+R = ( Vf*substrate/Kms-Vr*product/Kmp )*activator / ( Ka+(1+substrate/Kms+product/Kmp)*activator );
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_substrate_activation_irr.m b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_substrate_activation_irr.m
new file mode 100644
index 0000000000000000000000000000000000000000..8476e2d1463998735550e14be5b9e382cc6dd29f
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_substrate_activation_irr.m	
@@ -0,0 +1,20 @@
+function [R] = kin_substrate_activation_irr(V,substrate,Ksa,Ksc)
+% kin_substrate_activation_irr: Substrate activation (irreversible) kinetics
+%
+% Application restrictions: 
+% =========================
+%   - Only irreversible
+%   - exactly 1 substrate
+%
+% USAGE:
+% ======
+% R = kin_substrate_activation_irr(V,substrate,Ksa,Ksc)
+%
+% Output Arguments:
+% =================
+% R = V*(substrate/Ksa)^2 / ( 1+substrate/Ksc+substrate/Ksa+(substrate/Ksa)^2 ) 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+R = V*(substrate/Ksa)^2 / ( 1+substrate/Ksc+substrate/Ksa+(substrate/Ksa)^2 );
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_substrate_inihib_irr.m b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_substrate_inihib_irr.m
new file mode 100644
index 0000000000000000000000000000000000000000..efbb9e24a3480deed4781f5c07e9ae188bd0a0a8
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_substrate_inihib_irr.m	
@@ -0,0 +1,20 @@
+function [R] = kin_substrate_inihib_irr(V,substrate,Km,Ki)
+% kin_substrate_inihib_irr: Substrate inhibition (irreversible) kinetics
+%
+% Application restrictions: 
+% =========================
+%   - Only irreversible
+%   - exactly 1 substrate
+%
+% USAGE:
+% ======
+% R = kin_substrate_inihib_irr(V,substrate,Km,Ki)
+%
+% Output Arguments:
+% =================
+% R = V*substrate / ( Km + substrate + Km*(substrate/Ki)^2 )
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+R = V*substrate / ( Km + substrate + Km*(substrate/Ki)^2 );
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_substrate_inihib_rev.m b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_substrate_inihib_rev.m
new file mode 100644
index 0000000000000000000000000000000000000000..e7806dc0c8ee0d91db64c9f1648430c87b76b0f5
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_substrate_inihib_rev.m	
@@ -0,0 +1,21 @@
+function [R] = kin_substrate_inihib_rev(Vf,substrate,Kms,Vr,product,Kmp,Ki)
+% kin_substrate_inihib_rev: Substrate inhibition (reversible) kinetics
+%
+% Application restrictions: 
+% =========================
+%   - Only reversible
+%   - exactly 1 substrate
+%   - exactly 1 product
+%
+% USAGE:
+% ======
+% R = kin_substrate_inihib_rev(Vf,substrate,Kms,Vr,product,Kmp,Ki)
+%
+% Output Arguments:
+% =================
+% R = (Vf*substrate/Kms-Vr*product/Kmp) / ( 1+substrate/Kms+product/Kmp+(substrate/Ki)^2 ) 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+R = (Vf*substrate/Kms-Vr*product/Kmp) / ( 1+substrate/Kms+product/Kmp+(substrate/Ki)^2 );
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_uncomp_inihib_irr.m b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_uncomp_inihib_irr.m
new file mode 100644
index 0000000000000000000000000000000000000000..50cd55b2e8a228ca9a904f60a2230354c4d965eb
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_uncomp_inihib_irr.m	
@@ -0,0 +1,20 @@
+function [R] = kin_uncomp_inihib_irr(V,substrate,Km,inhibitor,Ki)
+% kin_uncomp_inihib_irr: Uncompetitive inhibition (irreversible) kinetics
+%
+% Application restrictions: 
+% =========================
+%   - Only irreversible
+%   - exactly 1 substrate
+%
+% USAGE:
+% ======
+% R = kin_uncomp_inihib_irr(V,substrate,Km,inhibitor,Ki)
+%
+% Output Arguments:
+% =================
+% R = V*substrate / ( Km + substrate*(1+inhibitor/Ki) )
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+R = V*substrate / ( Km + substrate*(1+inhibitor/Ki) );
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_uncomp_inihib_rev.m b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_uncomp_inihib_rev.m
new file mode 100644
index 0000000000000000000000000000000000000000..01c04b62122d7bb8554062d6c3c5d1d36f127f07
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_uncomp_inihib_rev.m	
@@ -0,0 +1,21 @@
+function [R] = kin_uncomp_inihib_rev(Vf,substrate,Kms,Vr,product,Kmp,inhibitor,Ki)
+% kin_uncomp_inihib_rev: Uncompetitive inhibition (reversible) kinetics
+%
+% Application restrictions: 
+% =========================
+%   - Only reversible
+%   - exactly 1 substrate
+%   - exactly 1 product
+%
+% USAGE:
+% ======
+% R = kin_uncomp_inihib_rev(Vf,substrate,Kms,Vr,product,Kmp,inhibitor,Ki)
+%
+% Output Arguments:
+% =================
+% R = ( Vf*substrate/Kms-Vr*product/Kmp ) / ( 1+(substrate/Kms+product/Kmp)*(1+inhibitor/Ki) ) 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+R = ( Vf*substrate/Kms-Vr*product/Kmp ) / ( 1+(substrate/Kms+product/Kmp)*(1+inhibitor/Ki) );
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_uni_uni_rev.m b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_uni_uni_rev.m
new file mode 100644
index 0000000000000000000000000000000000000000..5a9e688f72982550890cc7891afd343a27fbff7f
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/model/kineticlaws/kin_uni_uni_rev.m	
@@ -0,0 +1,21 @@
+function [R] = kin_uni_uni_rev(Vf,substrate,product,Keq,Kms,Kmp)
+% kin_uni_uni_rev: uni uni reversible kinetics
+%
+% Application restrictions: 
+% =========================
+%   - Only reversible
+%   - exactly 1 substrate
+%   - exactly 1 product
+%
+% USAGE:
+% ======
+% R = kin_uni_uni_rev(Vf,substrate,product,Keq,Kms,Kmp)
+%
+% Output Arguments:
+% =================
+% R = Vf*( substrate-product/Keq ) / ( substrate+Kms*(1+product/Kmp) )
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+R = Vf*( substrate-product/Keq ) / ( substrate+Kms*(1+product/Kmp) );
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/optimization/SSmIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/optimization/SSmIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..3b5fb3d78762be6537e416437d466e9cf9d3f2e1
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/optimization/SSmIQM.m	
@@ -0,0 +1,338 @@
+function [X,FVAL,result] = SSmIQM(varargin)
+% SSmIQM: Interface function to a Global optimization algorithm for 
+% MINLP's based on Scatter Search. 
+%
+% Note that the optimization method itself is not included in 
+% the toolbox but that it can be downloaded from
+% http://www.iim.csic.es/~gingproc/software.html
+%
+%   SSm attempts to solve problems of the form:
+%       min F(x)  subject to:  ceq(x) = 0 (equality constraints)
+%        x                     c_L <= c(x) <= c_U (inequality constraints)
+%                              x_L <= x <= x_U (bounds on the decision variables)            
+%
+% If you use SSm and publish the results, please cite the following papers:
+%
+% Egea, J.A., M. Rodriguez-Fernandez, J. R. Banga and R. Martí (2007) Scatter 
+% Search for chemical and bioprocess optimization. Journal of Global Optimization 
+% 37(3):481-503.
+%
+% Rodriguez-Fernandez, M., J. A. Egea and J. R. Banga (2006) Novel Metaheuristic for Parameter 
+% Estimation in Nonlinear Dynamic Biological Systems. BMC Bioinformatics 7:483.
+%
+% This interface function addresses the SSm package:
+%   Function   : SSm beta 3.3.1
+%   Written by : Process Engineering Group IIM-CSIC (jegea@iim.csic.es)
+%   Created on : 15/06/2005
+%   Last Update: 12/03/2008
+%   Email      : gingproc@iim.csic.es
+%   (c) CSIC, Spanish Council for Scientific Research
+%
+% USAGE:
+% ======
+% [info] = SSmIQM()
+% [X,FVAL,result] = SSmIQM(FUN,X,OPTIONS)
+%
+% FUN: Function to optimize
+% X: Starting Guess (Not strictly required but kept for the sake of
+%    compatible optimization function calls)
+% OPTIONS: structure containing options for the algorithm:
+%        OPTIONS.vtr: cost function value to reach
+%        OPTIONS.highbounds: vector containing upper bounds for parameters
+%           Instead of a vector highbounds can also be a scalar > 1. In the
+%           latter case the highbounds are determined by multiplying this
+%           scalar to the initial parameter guess X. This latter case works
+%           only for positive X(i) ... if negative present then the user
+%           needs to specify a whole highbounds vector. 
+%        OPTIONS.lowbounds: vector containing lower bounds for parameters.
+%           Instead of a vector lowbounds can also be a scalar < 1. In the
+%           latter case the lowbounds are determined by multiplying this
+%           scalar to the initial parameter guess X. This latter case works
+%           only for positive X(i) ... if negative present then the user
+%           needs to specify a whole lowbounds vector. 
+% User options
+%        OPTIONS.maxfunevals: Maximum number of function evaluations
+%        OPTIONS.maxtime: Maximum time (in minutes) for optimization
+%        OPTIONS.silent: =0: output of info, =1: no output
+%        OPTIONS.plot. Plots convergence curves: 
+%               0-Deactivated,
+%               1-Plot curves on line,
+%               2-Plot final results
+%        OPTIONS.weight: Weight that multiplies the penalty term added
+%           to the objective function in constrained problems
+%        OPTIONS.tolc: Maximum absolute violation of the constraints.
+%        OPTIONS.log_var: Indexes of the variables which will be used
+%           to generate diverse solutions in different orders of magnitude
+% Global options
+%        OPTIONS.dim_refset: Number of elements in Refset
+%        OPTIONS.ndiverse: Number of solutions generated by the
+%           diversificator 
+%        OPTIONS.initiate: Type of Refset initialization
+%               0: Take bounds, middle point and fill by euclidean distance
+%               1: Evaluate all the diverse solutions,take the dim_refset/2 best
+%                  solutions and fill by euclidean distance
+%        OPTIONS.combination: Type of combination of Refset elements
+%               1: hyper-rectangles
+%               2: linear combinations
+%        OPTIONS.regenerate: Type of Refset regeneration 
+%               1: Regeneration by distance diversity
+%               2: Regeneration by direction diversity
+%               3: Randomly alternates 1 and 2
+%        OPTIONS.delete: Maximum number of Refset elements
+%           deleted when regenerating Refset
+%               'standard': Maximum deleted elements=dim_refset/2 
+%                           (half of the elements)
+%               'aggressive': Delete dim_refset-1 (all of them except the 
+%                           best solution found)
+%        OPTIONS.intens: Iteration interval between intensifications
+%        OPTIONS.tolfun: Function tolerance for joining the Refset
+%        OPTIONS.diverse_criteria: Criterion for diversification in the Refset
+%               1: euclidean distance
+%               2: tolerances
+%        OPTIONS.tolx: Variable tolerance for joining the Refset when 
+%           the euclidean distance is deactivated        
+% Local options
+%        OPTIONS.local.solver: Choose local solver:
+%               0: local search off, 'constrnew','fminsearch','nomad','solnp',
+%               'n2fb','dn2fb','dhc','fsqp','ipopt', 'misqp','lsqnonlin'
+%        OPTIONS.local.n1: Number of function evaluations before applying
+%           local search for the 1st time
+%        OPTIONS.local.n2: Minimum number of function evaluations in the 
+%           global phase between 2 local calls
+%        OPTIONS.local.finish: Local solver (see above) to be used in the
+%           final refinement.
+%        OPTIONS.local.bestx: (=1): This option ignores all the local search
+%           filters and perform a local search only when the best function
+%           value has been improved. This is useful for those problems in
+%           which local searches are not providing satisfactory solutions
+%           but still it can help a bit more than pure global search.
+%           (=0): option deactivated.
+%
+% Output Arguments:
+% =================
+% info:     calling the function w/o input argument returns information about
+%           the options and a flag indicating if the algorithm can handle
+%           constraints or not
+% X:        Found solution
+% FVAL:     Value of the function FUN at X
+% result:   Structure containing results
+%
+%       result.fbest                   = Best objective function value
+%                                         found after the optimization
+%       result.xbest                   = Vector providing the best
+%                                         function value
+%       result.cpu_time                = Time in seconds consumed in the
+%                                         optimization
+%       result.f                       = Vector containing the best
+%                                         objective function value after each
+%                                         iteration
+%       result.x                       = Matrix containing the best vector
+%                                         after each iteration
+%       result.time                    = Vector containing the cpu time
+%                                         consumed after each iteration
+%       result.neval                   = Vector containing the number of
+%                                         function evaluations after each
+%                                         iteration
+%       result.numeval                 = Number of function evaluations
+%       result.local_solutions         = Local solutions found by the
+%                                         local solver (in rows)
+%       result.local_solutions_values  = Function values of the local
+%                                         solutions
+%       result.end_crit                = Criterion to finish the
+%                                         optimization
+%                                         1: Maximal number of function
+%                                         evaluations achieved
+%                                         2: Maximum allowed CPU Time
+%                                         achieved
+%                                         3: Value to reach achieved
+%
+% DEFAULT VALUES:
+% ===============
+% OPTIONS.lowbounds:        0.1  => lowbounds = 0.1*X 
+% OPTIONS.highbounds:       10  => highbounds = 10*X 
+% OPTIONS.maxfunevals:      400*ndim
+% OPTIONS.maxtime:          120 (minutes)        
+% OPTIONS.silent:           0          
+% OPTIONS.plot              0
+% OPTIONS.weight:           1e6
+% OPTIONS.tolc:             1e-5
+% OPTIONS.log_var:          [1:ndim] (all variables)
+%
+% OPTIONS.dim_refset:       'auto'
+% OPTIONS.ndiverse:         10*ndim
+% OPTIONS.initiate:         1
+% OPTIONS.combination:      1
+% OPTIONS.regenerate:       3
+% OPTIONS.delete:           'standard'
+% OPTIONS.intens:           10
+% OPTIONS.tolfun:           1e-4
+% OPTIONS.diverse_criteria: 1
+% OPTIONS.tolx:             1e-3      
+%
+% OPTIONS.local.solver:     'dn2fb'
+% OPTIONS.local.n1:         100*ndim
+% OPTIONS.local.n2:         200*ndim
+% OPTIONS.local.finish:     'dn2fb'
+% OPTIONS.local.bestx:      0
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF SSm IS PRESENT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(which('ssm_kernel')),
+    error(sprintf('SSm is not installed on your system! SSmIQM is only the interface function.\nYou can download SSm from: http://www.iim.csic.es/~gingproc/software.html.\nAfter installation you can use the SSmIQM interface function included in the IQM Tools Lite.'));
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% ASSIGNING DEFAULT OUTPUT VALUES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+X = [];
+FVAL = [];
+result = [];
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin == 0,
+    X.name = 'SSmIQM';
+    X.constrained = 1;
+    X.description = 'Scatter Search based optimization (global)';
+    X.defaultOptions.names = {'maxfunevals', 'maxtime'};
+    X.defaultOptions.values = {'20000','500'};
+    X.defaultOptions.description = {'Maximum number of function evaluations', 'Maximum time in minutes'};
+    return
+elseif nargin == 2,
+    FUN = varargin{1};
+    X = varargin{2};
+    OPTIONS = [];
+elseif nargin == 3,
+    FUN = varargin{1};
+    X = varargin{2};
+    OPTIONS = varargin{3};
+else
+    error('Incorrect number of input arguments.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Set default values
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ndim = length(X);
+lowbounds = 0.1*X;
+highbounds = 10*X;
+
+%%%%%%%%%%%%%%
+% SSm options
+%%%%%%%%%%%%%%
+opts = [];
+% user options
+opts.maxeval = 400*ndim;    % Maximum number of function evaluations 
+opts.maxtime = 120*60;      % Maximum CPU time in seconds
+opts.iterprint = 1;         % Print each iteration on screen
+opts.plot      = 0;         % Plots convergence curves: 0-Deactivated,
+                            % 1-Plot curves on line, 2-Plot final results
+opts.weight    = 1e6;       % Weight that multiplies the penalty term added
+                            % to the objective function in constrained
+                            % problems
+opts.tolc      = 1e-5;                            
+opts.log_var   = [];        % Indexes of the variables which will be used
+                            % to generate diverse solutions in different
+                            % orders of magnitude global options
+% global options
+opts.dim_refset = 'auto';
+opts.ndiverse = 10*ndim;
+opts.initiate = 1;
+opts.combination = 1;
+opts.regenerate = 3;
+opts.delete = 'standard';
+opts.intens = 10;
+opts.tolf = 1e-4;           % Function tolerance for joining the Refset
+opts.diverse_criteria = 1;  % Criterion for diversification in the Refset
+                            %    1: euclidean distance
+                            %    2: tolerances
+opts.tolx = 1e-3;           % Variable tolerance for joining the Refset when 
+                            % the euclidean distance is deactivated        
+% local options
+opts.local.solver = 'dn2fb';      % Choose local solver:
+                                  % 0: local search off, 'constrnew',
+                                  % 'fminsearch','nomad','solnp',
+                                  % 'n2fb','dn2fb','dhc','fsqp','ipopt',
+                                  % 'misqp','lsqnonlin'
+opts.local.n1 = 100*ndim;   % Number of function evaluations before applying
+                            % local search for the 1st time
+opts.local.n2 = 200*ndim;   % Minimum number of function evaluations in the 
+                            % global phase between 2 local calls         
+opts.local.finish = 'dn2fb'; % Local solver for final refinement                            
+opts.local.bestx = 0; 
+                           
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% options - Structure containing optional settings
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% user options
+try opts.maxeval            = OPTIONS.maxfunevals; catch, end; 
+try opts.maxtime            = 60*OPTIONS.maxtime; catch, end; % SSm expects seconds
+try opts.iterprint          = ~OPTIONS.silent; catch, end;
+try opts.plot           	= OPTIONS.plot; catch, end;
+try opts.weight             = OPTIONS.weight; catch, end;
+try opts.log_var            = OPTIONS.log_var; catch, end;
+% global options
+try opts.dim_refset         = OPTIONS.dim_refset; catch, end; 
+try opts.ndiverse           = OPTIONS.ndiverse; catch, end; 
+try opts.initiate           = OPTIONS.initiate; catch, end; 
+try opts.combination        = OPTIONS.combination; catch, end; 
+try opts.regenerate         = OPTIONS.regenerate; catch, end; 
+try opts.delete             = OPTIONS.delete; catch, end; 
+try opts.intens             = OPTIONS.intens; catch, end; 
+try opts.tolf               = OPTIONS.tolfun; catch, end; 
+try opts.diverse_criteria   = OPTIONS.diverse_criteria; catch, end;
+try opts.tolx               = OPTIONS.tolx; catch, end;
+% local options
+try opts.local.solver       = OPTIONS.local.solver ; catch, end;
+try opts.local.n1           = OPTIONS.local.n1; catch, end;
+try opts.local.n2           = OPTIONS.local.n2; catch, end;
+try opts.local.finish       = OPTIONS.local.finish; catch, end;
+try opts.local.bestx        = OPTIONS.local.bestx; catch, end;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% problem - Structure containing problem settings
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[lowbounds, highbounds] = handleLowHighBoundsIQM(OPTIONS,X,lowbounds,highbounds);
+if ~ischar(FUN),
+    FUN = func2str(FUN);    % convert function handle to string
+end
+problem = [];
+problem.f = FUN;            % Name of the file containing the objective function
+problem.x_L = lowbounds;    % Lower bounds of decision variables
+problem.x_U = highbounds;   % Upper bounds of decision variables
+problem.x_0 = X;            % Initial point(s) (optional)
+try problem.vtr = OPTIONS.vtr; catch, end; % value to reach
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% call SSm 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+disp('If you use SSm and publish the results, please cite the following papers:');
+disp(' ');
+disp('Egea, J.A., M. Rodriguez-Fernandez, J. R. Banga and R. Martí (2007) Scatter');
+disp('Search for chemical and bioprocess optimization. Journal of Global Optimization');
+disp('37(3):481-503.');
+disp(' ');
+disp('Rodriguez-Fernandez, M., J. A. Egea and J. R. Banga (2006) Novel Metaheuristic');
+disp('for Parameter Estimation in Nonlinear Dynamic Biological Systems.');
+disp('BMC Bioinformatics 7:483.');
+useFAST = 0;
+if isfield(OPTIONS,'fast'),
+    if OPTIONS.fast == 1,
+        useFAST = 1;
+    end
+end
+if useFAST,
+    result = fssm_kernel(problem,opts);
+else
+    result = ssm_kernel(problem,opts);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% handle output
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+X = result.xbest;
+FVAL = result.fbest;
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/optimization/auxiliary/handleLowHighBoundsIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/optimization/auxiliary/handleLowHighBoundsIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..28682e2b4c99de03fe9db512905eb8137bc2868c
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/optimization/auxiliary/handleLowHighBoundsIQM.m	
@@ -0,0 +1,68 @@
+function [lowbounds,highbounds] = handleLowHighBoundsIQM(OPTIONS,X,lowbounds,highbounds)
+% handleLowHighBoundsIQM: Handles low and high bounds definitions in the options
+% for all optimizers.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+ndim = length(X);
+
+% lowbounds
+if isfield(OPTIONS,'lowbounds'),
+    if ~isempty(OPTIONS.lowbounds),
+        if length(OPTIONS.lowbounds) == ndim,
+            lowbounds = OPTIONS.lowbounds;
+        else
+            if length(OPTIONS.lowbounds) == 1,
+                if ~isempty(find(X<0, 1)),
+                    error('Please specify a vector for the lower bounds using OPTIONS.lowbounds.');
+                end
+                lowbounds = X*OPTIONS.lowbounds;
+            else
+                error('The OPTIONS.lowbounds setting is not correct.');
+            end
+        end
+    else
+        lowbounds = -Inf(1,ndim);
+    end
+else
+    if ~isempty(find(X<0, 1)),
+        error('Please specify a vector for the lower bounds using OPTIONS.lowbounds.');
+    end
+end
+% highbounds
+if isfield(OPTIONS,'highbounds'),
+    if ~isempty(OPTIONS.highbounds),
+        if length(OPTIONS.highbounds) == ndim,
+            highbounds = OPTIONS.highbounds;
+        else
+            if length(OPTIONS.highbounds) == 1,
+               if ~isempty(find(X<0, 1)),
+                    error('Please specify a vector for the higher bounds using OPTIONS.highbounds.');
+               end
+                highbounds = X*OPTIONS.highbounds;
+            else
+                error('The OPTIONS.highbounds setting is not correct.');
+            end
+        end
+    else
+        highbounds = Inf(1,ndim);
+    end
+else
+    if ~isempty(find(X<0, 1)),
+        error('Please specify a vector for the higher bounds using OPTIONS.highbounds.');
+    end
+end
+lowbounds = lowbounds(:)';
+highbounds = highbounds(:)';
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK BOUND VIOLATION FOR INITIAL GUESS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+indexXhi = find(X(:) > highbounds(:), 1);
+if ~isempty(indexXhi),
+    error('Initial guess does violate high parameter bounds.');
+end
+indexXlo = find(X(:) < lowbounds(:), 1);
+if ~isempty(indexXlo),
+    error('Initial guess does violate low parameter bounds.');
+end
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/optimization/auxiliary/isres/isrsort.c b/IQMtools V1.2.2.2/IQMlite/tools/optimization/auxiliary/isres/isrsort.c
new file mode 100644
index 0000000000000000000000000000000000000000..b5d5972166414cba9047e004a22a3ec1bc464889
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/optimization/auxiliary/isres/isrsort.c	
@@ -0,0 +1,69 @@
+/*
+ * Optimized SRSORT Stochastic Ranking Procedure (Stochastic Bubble Sort)
+ * based on the code by Thomas Philip Runarsson (e-mail: tpr@verk.hi.is).
+ *
+*/
+
+#include "mex.h"
+#define MAX(A,B) ((A) > (B) ? (A):(B))
+
+void mexFunction(int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[])
+{
+  int n ;
+  double *P, *f, *phi ;  
+  int i, j ;
+  double pf, *I, Is, *G ;
+
+  /* check input arguments */
+  if (nrhs != 3)
+    mexErrMsgTxt("usage: I = isrsort(f,phi,pf) ;") ;
+
+  /* get pointers to input */
+  n = mxGetM(prhs[0]) ;
+  f = mxGetPr(prhs[0]) ;
+  phi = mxGetPr(prhs[1]) ;
+  P = mxGetPr(prhs[2]) ;
+  pf = P[0] ;
+
+  /* initialize index */
+  plhs[0] = mxCreateDoubleMatrix(n,1,mxREAL) ;
+  I = mxGetPr(plhs[0]) ;
+  for (i=1;i<=n;i++)
+    I[i-1] =(double)i ;
+
+  /* allocate random vector */
+  if ((G = (double *) mxCalloc(n-1,sizeof(double))) == NULL)
+    mexErrMsgTxt("fault: memory allocation error in mxCalloc") ;
+
+  /* Set evil seed (initial seed) */
+  srand((unsigned)time(NULL));
+  
+  /* perform stochastic bubble sort */
+  for (i=0;i<n;i++) {
+    Is = 0 ;
+    
+    /* Faster randomize */
+    for (i=0;i<n-1;i++)
+        G[i] = rand()/((double)RAND_MAX);
+
+    for (j=0;j<(n-1);j++) {
+      if (((phi[(int)I[j]-1]==phi[(int)I[j+1]-1]) && (phi[(int)I[j]-1]==0)) || (G[j]<pf) ) {
+        if (f[(int)I[j]-1]>f[(int)I[j+1]-1]) {
+          Is = I[j] ;
+          I[j] = I[j+1] ;
+          I[j+1] = Is ;
+        }
+      }
+      else {
+        if (phi[(int)I[j]-1]>phi[(int)I[j+1]-1]) { 
+          Is = I[j] ;
+          I[j] = I[j+1] ;
+          I[j+1] = Is ;
+        }
+      }
+    }
+    if (Is == 0)
+      break ;
+  }
+  mxFree(G) ;
+}
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/optimization/auxiliary/isres/isrsort.mexa64 b/IQMtools V1.2.2.2/IQMlite/tools/optimization/auxiliary/isres/isrsort.mexa64
new file mode 100644
index 0000000000000000000000000000000000000000..52c3994aba603e92fa29789c2586f9996fc8a2c1
Binary files /dev/null and b/IQMtools V1.2.2.2/IQMlite/tools/optimization/auxiliary/isres/isrsort.mexa64 differ
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/optimization/auxiliary/isres/isrsort.mexw32 b/IQMtools V1.2.2.2/IQMlite/tools/optimization/auxiliary/isres/isrsort.mexw32
new file mode 100644
index 0000000000000000000000000000000000000000..56917248f3051efd291c8d8683ce51a6df09fa7c
Binary files /dev/null and b/IQMtools V1.2.2.2/IQMlite/tools/optimization/auxiliary/isres/isrsort.mexw32 differ
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/optimization/auxiliary/isres/isrsort.mexw64 b/IQMtools V1.2.2.2/IQMlite/tools/optimization/auxiliary/isres/isrsort.mexw64
new file mode 100644
index 0000000000000000000000000000000000000000..217e40d1de002af72edd20c07447b1ac1c61db06
Binary files /dev/null and b/IQMtools V1.2.2.2/IQMlite/tools/optimization/auxiliary/isres/isrsort.mexw64 differ
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/optimization/auxiliary/pswarm/InitPatternSearch.m b/IQMtools V1.2.2.2/IQMlite/tools/optimization/auxiliary/pswarm/InitPatternSearch.m
new file mode 100644
index 0000000000000000000000000000000000000000..0133833b16959682a6ced7c03cd56810761da605
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/optimization/auxiliary/pswarm/InitPatternSearch.m	
@@ -0,0 +1,30 @@
+function [Problem]=InitPatternSearch(Problem)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Subrotine InitPatternSearch
+%
+%  This subroutine initializes the search directions for the poll step
+%
+%  User provided directions can be included in the
+%                        Problem.Poll.SearchDirections.UserSpecified matrix
+%
+%  Provides the coordinate directions
+%
+%  Input:
+%    Problem - The problem structure
+%
+%  Output:
+%    Problem - The problem structure updated
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% aivaz@dps.uminho.pt 01/12/2006
+
+% Coordinate Search for Variables
+Problem.Poll.SearchDirections.Base=[eye(Problem.Variables) ...
+                                   -eye(Problem.Variables)];
+
+% A set of directions specified by user
+Problem.Poll.SearchDirections.UserSpecified =[];
+
+return;
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/optimization/auxiliary/pswarm/PenaltyEval.m b/IQMtools V1.2.2.2/IQMlite/tools/optimization/auxiliary/pswarm/PenaltyEval.m
new file mode 100644
index 0000000000000000000000000000000000000000..5ad95f9c7cc79edcfda28d3ab17f59a714521adc
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/optimization/auxiliary/pswarm/PenaltyEval.m	
@@ -0,0 +1,40 @@
+function [Problem,ObjValue] = PenaltyEval(Problem, x)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Subrotine PenaltyEval
+%  This subrotine is called to evaluate the objective function
+%
+%  Input:
+%    Problem - The problem structure
+%    x - Real part of point to evaluate
+%    varargin - Extra parameters for objective function
+%
+%  Output:
+%    Problem - The problem structure updated
+%    ObjValue - Objective function value. Returns +Inf for unfeasible
+%       points
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%aivaz@dps.uminho.pt 06/12/2006
+
+% adapted for IQM Tools Lite by Henning Schmidt 
+
+% Bound feasibility is enforced by the projection onto the bound feasible
+% domain
+% LB <= x' && x'<=UB
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Continue with original function
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try
+    ObjValue=feval(Problem.ObjFunction, x);
+    % update counter
+    Problem.Stats.ObjFunCounter=Problem.Stats.ObjFunCounter+1;
+catch
+    error('pswarm:ObjectiveError', ...
+        ['Cannot continue because user supplied objective function' ...
+        ' failed with the following error:\n%s'], lasterr)
+end
+
+return;
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/optimization/auxiliary/pswarm/PollStep.m b/IQMtools V1.2.2.2/IQMlite/tools/optimization/auxiliary/pswarm/PollStep.m
new file mode 100644
index 0000000000000000000000000000000000000000..e9a1a319743ecc2c19516dcd2a98f5e4d2be7dbb
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/optimization/auxiliary/pswarm/PollStep.m	
@@ -0,0 +1,67 @@
+function [Problem,Population]=PollStep(Problem,Population)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  subroutine PollStep
+%
+%  Performe a poll step for the pattern search on the leader particle of
+%  the particle swarm.
+%
+%  Input:
+%    Problem - Problem structure
+%    Population - The population
+%
+%  Output:
+%    Poblem - Problem structure updated
+%    Population - Population updated
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% aivaz@dps.uminho.pt 30/03/2007
+
+%
+% Proceed with a poll step on the leader
+%
+
+% Columnwise search directions.
+D= [Problem.Poll.SearchDirections.Base, ...
+    Problem.Poll.SearchDirections.UserSpecified];
+
+% Columnwise Leader
+Leader=Population.y(Population.Leader,:)';
+
+% for all directions
+for i=1:size(D,2)
+    % Compute trial point
+    Trial=Projection(Leader+Population.Delta*D(:,i),Problem.LB,Problem.UB);
+    % Compute objective function
+    [Problem,ObjTrial]= PenaltyEval(Problem, Trial');
+    
+    % Check for progress
+    if Population.fy(Population.Leader)>ObjTrial
+        % a successful poll step. Update counter.
+        Problem.Stats.SuccPollSteps=Problem.Stats.SuccPollSteps+1;
+        % update leader
+        Population.y(Population.Leader,:)=Trial;
+        Population.fy(Population.Leader)=ObjTrial;
+        
+        % Success obtained along the previous successful direction?
+        if ~isempty(Problem.Poll.LastSuccess) && ...
+                isequal(Problem.Poll.LastSuccess(:),D(:,i))
+            % Yes. Increase Delta
+            Population.Delta=Population.Delta*Problem.IncreaseDelta;
+        else
+            % No. Update previous direction
+            Problem.Poll.LastSuccess=D(:,i);
+        end
+        
+        % Return. Successful poll step
+        return;
+    end
+end
+
+% No success in poll step. Decrease Delta.
+if Population.Delta>Problem.Tolerance
+    Population.Delta=Population.Delta*Problem.DecreaseDelta;
+end
+
+return;
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/optimization/auxiliary/pswarm/Projection.m b/IQMtools V1.2.2.2/IQMlite/tools/optimization/auxiliary/pswarm/Projection.m
new file mode 100644
index 0000000000000000000000000000000000000000..73428c677a2c1c0830d6626067c7e792f2a89a2d
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/optimization/auxiliary/pswarm/Projection.m	
@@ -0,0 +1,27 @@
+function X=Projection(X, L, U)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+%  subrotine Projection
+%
+%  Input:
+%    X - Point to be projected
+%    L - Domain lower bound
+%    U - Domain upper bound
+%
+%  Output:
+%    X - Projected point
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% aivaz@dps.uminho.pt 06/12/2006
+
+%Do you really need comments?
+for i=1:length(X)
+    if X(i)<L(i)
+        X(i)=L(i);
+    end
+    if X(i)>U(i)
+        X(i)=U(i);
+    end
+end
+
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/optimization/auxiliary/pswarm/lgpl.txt b/IQMtools V1.2.2.2/IQMlite/tools/optimization/auxiliary/pswarm/lgpl.txt
new file mode 100644
index 0000000000000000000000000000000000000000..5ab7695ab8cabe0c5c8a814bb0ab1e8066578fbb
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/optimization/auxiliary/pswarm/lgpl.txt	
@@ -0,0 +1,504 @@
+		  GNU LESSER GENERAL PUBLIC LICENSE
+		       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+		  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/optimization/auxiliary/pswarm/unifrndIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/optimization/auxiliary/pswarm/unifrndIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..920834f4de23921c46fcdc2fff2f4ce2b6cd4077
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/optimization/auxiliary/pswarm/unifrndIQM.m	
@@ -0,0 +1,66 @@
+function [output] = unifrndIQM(lower,upper,varargin)
+% unifrndIQM: creates an array of uniformly distributed random variables for
+%   which the lower and upper bounds can be specified.
+%
+% USAGE:
+% ======
+% [output] = unifrndIQM(lower,upper)         
+% [output] = unifrndIQM(lower,upper,dim)         
+% [output] = unifrndIQM(lower,upper,dim1,dim2)         
+% 
+% lower: lower bound(s). Either a scalar or a vector (same size as 'upper' or scalar allowed).
+% upper: upper bound(s). Either a scalar or a vector (same size as 'lower' or scalar allowed).
+% dim: in case lower and upper are scalars this defined the dimensions of
+%      the random matrix
+% dim1,dim2:  in case lower and upper are scalars this defined the dimensions of
+%      the random matrix
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK INPUTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if size(lower,2) ~= size(upper,2) || size(lower,1) ~= size(upper,1),
+    if (size(lower,1) == 1 || size(lower,2) == 1) && (size(upper,1) == 1 || size(upper,2) == 1),
+        if isscalar(lower),
+            lower = lower*ones(size(upper));
+        elseif isscalar(upper),
+            upper = upper*ones(size(lower));
+        else
+            error('Wrong dimensions of ''lower'' and ''upper''.');
+        end
+    else
+        error('Wrong dimensions of ''lower'' and ''upper''.');
+    end
+end
+     
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin < 2 || nargin > 4,
+    error('Incorrect number of input arguments'); 
+end
+if nargin > 2 && length(lower) > 1,
+    error('If dimensions are specified, the ''lower'' and ''upper'' arguments need to be scalars.');
+end
+if nargin == 3,
+    dim1 = varargin{1};
+    dim2 = dim1;
+elseif nargin == 4,
+    dim1 = varargin{1};
+    dim2 = varargin{2};
+else
+    dim1 = size(upper,1);
+    dim2 = size(upper,2);
+end
+
+output = lower/2+upper/2 + (lower/2-upper/2) .* (2*rand(dim1,dim2)-1);
+
+% Handle trouble with higher low bounds than upper
+if ~isscalar(lower) || ~isscalar(upper)
+    output(lower > upper) = NaN;
+elseif lower > upper
+    output(:) = NaN;
+end
+return
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/optimization/fSSmIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/optimization/fSSmIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..be1c9f68b4b71ac131a5f4ebd58ecfb65bab76e3
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/optimization/fSSmIQM.m	
@@ -0,0 +1,341 @@
+function [X,FVAL,result] = fSSmIQM(varargin)
+% fSSmIQM: Interface function to a Global optimization algorithm for 
+% MINLP's based on Scatter Search ("fast" version). 
+%
+% Note that the optimization method itself is not included in 
+% the toolbox but that it can be downloaded from
+% http://www.iim.csic.es/~gingproc/software.html
+%
+%   fSSm attempts to solve problems of the form:
+%       min F(x)  subject to:  ceq(x) = 0 (equality constraints)
+%        x                     c_L <= c(x) <= c_U (inequality constraints)
+%                              x_L <= x <= x_U (bounds on the decision variables)            
+%
+% If you use fSSm and publish the results, please cite the following papers:
+%
+% Egea, J.A., M. Rodriguez-Fernandez, J. R. Banga and R. Martí (2007) Scatter 
+% Search for chemical and bioprocess optimization. Journal of Global Optimization 
+% 37(3):481-503.
+%
+% Rodriguez-Fernandez, M., J. A. Egea and J. R. Banga (2006) Novel Metaheuristic for Parameter 
+% Estimation in Nonlinear Dynamic Biological Systems. BMC Bioinformatics 7:483.
+%
+% This interface function addresses the (f)SSm package:
+%   Function   : SSm beta 3.3.1
+%   Written by : Process Engineering Group IIM-CSIC (jegea@iim.csic.es)
+%   Created on : 15/06/2005
+%   Last Update: 12/03/2008
+%   Email      : gingproc@iim.csic.es
+%   (c) CSIC, Spanish Council for Scientific Research
+%
+% USAGE:
+% ======
+% [info] = fSSmIQM()
+% [X,FVAL,result] = fSSmIQM(FUN,X,OPTIONS)
+%
+% FUN: Function to optimize
+% X: Starting Guess (Not strictly required but kept for the sake of
+%    compatible optimization function calls)
+% OPTIONS: structure containing options for the algorithm:
+%        OPTIONS.vtr: cost function value to reach
+%        OPTIONS.highbounds: vector containing upper bounds for parameters
+%           Instead of a vector highbounds can also be a scalar > 1. In the
+%           latter case the highbounds are determined by multiplying this
+%           scalar to the initial parameter guess X. This latter case works
+%           only for positive X(i) ... if negative present then the user
+%           needs to specify a whole highbounds vector. 
+%        OPTIONS.lowbounds: vector containing lower bounds for parameters.
+%           Instead of a vector lowbounds can also be a scalar < 1. In the
+%           latter case the lowbounds are determined by multiplying this
+%           scalar to the initial parameter guess X. This latter case works
+%           only for positive X(i) ... if negative present then the user
+%           needs to specify a whole lowbounds vector. 
+% User options
+%        OPTIONS.maxfunevals: Maximum number of function evaluations
+%        OPTIONS.maxtime: Maximum time (in minutes) for optimization
+%        OPTIONS.silent: =0: output of info, =1: no output
+%        OPTIONS.plot. Plots convergence curves: 
+%               0-Deactivated,
+%               1-Plot curves on line,
+%               2-Plot final results
+%        OPTIONS.weight: Weight that multiplies the penalty term added
+%           to the objective function in constrained problems
+%        OPTIONS.tolc: Maximum absolute violation of the constraints.
+%        OPTIONS.log_var: Indexes of the variables which will be used
+%           to generate diverse solutions in different orders of magnitude
+% Global options
+%        OPTIONS.dim_refset: Number of elements in Refset
+%        OPTIONS.ndiverse: Number of solutions generated by the
+%           diversificator 
+%        OPTIONS.initiate: Type of Refset initialization
+%               0: Take bounds, middle point and fill by euclidean distance
+%               1: Evaluate all the diverse solutions,take the dim_refset/2 best
+%                  solutions and fill by euclidean distance
+%        OPTIONS.combination: Type of combination of Refset elements
+%               1: hyper-rectangles
+%               2: linear combinations
+%        OPTIONS.regenerate: Type of Refset regeneration 
+%               1: Regeneration by distance diversity
+%               2: Regeneration by direction diversity
+%               3: Randomly alternates 1 and 2
+%        OPTIONS.delete: Maximum number of Refset elements
+%           deleted when regenerating Refset
+%               'standard': Maximum deleted elements=dim_refset/2 
+%                           (half of the elements)
+%               'aggressive': Delete dim_refset-1 (all of them except the 
+%                           best solution found)
+%        OPTIONS.intens: Iteration interval between intensifications
+%        OPTIONS.tolfun: Function tolerance for joining the Refset
+%        OPTIONS.diverse_criteria: Criterion for diversification in the Refset
+%               1: euclidean distance
+%               2: tolerances
+%        OPTIONS.tolx: Variable tolerance for joining the Refset when 
+%           the euclidean distance is deactivated        
+% Local options
+%        OPTIONS.local.solver: Choose local solver:
+%               0: local search off, 'constrnew','fminsearch','nomad','solnp',
+%               'n2fb','dn2fb','dhc','fsqp','ipopt', 'misqp','lsqnonlin'
+%        OPTIONS.local.n1: Number of function evaluations before applying
+%           local search for the 1st time
+%        OPTIONS.local.n2: Minimum number of function evaluations in the 
+%           global phase between 2 local calls
+%        OPTIONS.local.finish: Local solver to be used in the final
+%           refinement.
+%        OPTIONS.local.bestx: (=1): This option ignores all the local search
+%           filters and perform a local search only when the best function
+%           value has been improved. This is useful for those problems in
+%           which local searches are not providing satisfactory solutions
+%           but still it can help a bit more than pure global search.
+%           (=0): option deactivated.
+%
+% Output Arguments:
+% =================
+% info:     calling the function w/o input argument returns information about
+%           the options and a flag indicating if the algorithm can handle
+%           constraints or not
+% X:        Found solution
+% FVAL:     Value of the function FUN at X
+% result:   Structure containing results
+%
+%       result.fbest                   = Best objective function value
+%                                         found after the optimization
+%       result.xbest                   = Vector providing the best
+%                                         function value
+%       result.cpu_time                = Time in seconds consumed in the
+%                                         optimization
+%       result.f                       = Vector containing the best
+%                                         objective function value after each
+%                                         iteration
+%       result.x                       = Matrix containing the best vector
+%                                         after each iteration
+%       result.time                    = Vector containing the cpu time
+%                                         consumed after each iteration
+%       result.neval                   = Vector containing the number of
+%                                         function evaluations after each
+%                                         iteration
+%       result.numeval                 = Number of function evaluations
+%       result.local_solutions         = Local solutions found by the
+%                                         local solver (in rows)
+%       result.local_solutions_values  = Function values of the local
+%                                         solutions
+%       result.end_crit                = Criterion to finish the
+%                                         optimization
+%                                         1: Maximal number of function
+%                                         evaluations achieved
+%                                         2: Maximum allowed CPU Time
+%                                         achieved
+%                                         3: Value to reach achieved
+%
+% DEFAULT VALUES:
+% ===============
+% OPTIONS.lowbounds:        0.1  => lowbounds = 0.1*X 
+% OPTIONS.highbounds:       10  => highbounds = 10*X 
+% OPTIONS.maxfunevals:      400*ndim
+% OPTIONS.maxtime:          120 (minutes)        
+% OPTIONS.silent:           0          
+% OPTIONS.plot              0
+% OPTIONS.weight:           1e6
+% OPTIONS.tolc:             1e-5
+% OPTIONS.log_var:          [1:ndim] (all variables)
+%
+% OPTIONS.dim_refset:       'auto'
+% OPTIONS.ndiverse:         10*ndim
+% OPTIONS.initiate:         1
+% OPTIONS.combination:      1
+% OPTIONS.regenerate:       3
+% OPTIONS.delete:           'standard'
+% OPTIONS.intens:           10
+% OPTIONS.tolfun:           1e-4
+% OPTIONS.diverse_criteria: 1
+% OPTIONS.tolx:             1e-3      
+%
+% OPTIONS.local.solver:     'dn2fb'
+% OPTIONS.local.n1:         100*ndim
+% OPTIONS.local.n2:         200*ndim
+% OPTIONS.local.finish:     'dn2fb'
+% OPTIONS.local.bestx:      0
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF SSm IS PRESENT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(which('ssm_kernel')),
+    error(sprintf('SSm is not installed on your system! SSmIQM is only the interface function.\nYou can download SSm from: http://www.iim.csic.es/~gingproc/software.html.\nAfter installation you can use the SSmIQM interface function included in the IQM Tools Lite.'));
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% ASSIGNING DEFAULT OUTPUT VALUES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+X = [];
+FVAL = [];
+result = [];
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin == 0,
+    X.name = 'fSSmIQM';
+    X.constrained = 1;
+    X.description = '(fast) Scatter Search based optimization (global)';
+    X.defaultOptions.names = {'maxfunevals', 'maxtime'};
+    X.defaultOptions.values = {'20000','500'};
+    X.defaultOptions.description = {'Maximum number of function evaluations', 'Maximum time in minutes'};
+    return
+elseif nargin == 2,
+    FUN = varargin{1};
+    X = varargin{2};
+    OPTIONS = [];
+elseif nargin == 3,
+    FUN = varargin{1};
+    X = varargin{2};
+    OPTIONS = varargin{3};
+else
+    error('Incorrect number of input arguments.');
+end
+% always use the fast version 
+OPTIONS.fast = 1;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Set default values
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ndim = length(X);
+lowbounds = 0.1*X;
+highbounds = 10*X;
+
+%%%%%%%%%%%%%%
+% SSm options
+%%%%%%%%%%%%%%
+opts = [];
+% user options
+opts.maxeval = 400*ndim;    % Maximum number of function evaluations 
+opts.maxtime = 120*60;      % Maximum CPU time in seconds
+opts.iterprint = 1;         % Print each iteration on screen
+opts.plot      = 0;         % Plots convergence curves: 0-Deactivated,
+                            % 1-Plot curves on line, 2-Plot final results
+opts.weight    = 1e6;       % Weight that multiplies the penalty term added
+                            % to the objective function in constrained
+                            % problems
+opts.tolc      = 1e-5;                            
+opts.log_var   = [];        % Indexes of the variables which will be used
+                            % to generate diverse solutions in different
+                            % orders of magnitude global options
+% global options
+opts.dim_refset = 'auto';
+opts.ndiverse = 10*ndim;
+opts.initiate = 1;
+opts.combination = 1;
+opts.regenerate = 3;
+opts.delete = 'standard';
+opts.intens = 10;
+opts.tolf = 1e-4;           % Function tolerance for joining the Refset
+opts.diverse_criteria = 1;  % Criterion for diversification in the Refset
+                            %    1: euclidean distance
+                            %    2: tolerances
+opts.tolx = 1e-3;           % Variable tolerance for joining the Refset when 
+                            % the euclidean distance is deactivated        
+% local options
+opts.local.solver = 'dn2fb';      % Choose local solver:
+                                  % 0: local search off, 'constrnew',
+                                  % 'fminsearch','nomad','solnp',
+                                  % 'n2fb','dn2fb','dhc','fsqp','ipopt',
+                                  % 'misqp','lsqnonlin'
+opts.local.n1 = 100*ndim;   % Number of function evaluations before applying
+                            % local search for the 1st time
+opts.local.n2 = 200*ndim;   % Minimum number of function evaluations in the 
+                            % global phase between 2 local calls         
+opts.local.finish = 'dn2fb'; % Local solver for final refinement                            
+opts.local.bestx = 0; 
+                            
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% options - Structure containing optional settings
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% user options
+try opts.maxeval            = OPTIONS.maxfunevals; catch, end; 
+try opts.maxtime            = 60*OPTIONS.maxtime; catch, end; % SSm expects seconds
+try opts.iterprint          = ~OPTIONS.silent; catch, end;
+try opts.plot           	= OPTIONS.plot; catch, end;
+try opts.weight             = OPTIONS.weight; catch, end;
+try opts.tolc               = OPTIONS.tolc; catch, end;
+try opts.log_var            = OPTIONS.log_var; catch, end;
+% global options
+try opts.dim_refset         = OPTIONS.dim_refset; catch, end; 
+try opts.ndiverse           = OPTIONS.ndiverse; catch, end; 
+try opts.initiate           = OPTIONS.initiate; catch, end; 
+try opts.combination        = OPTIONS.combination; catch, end; 
+try opts.regenerate         = OPTIONS.regenerate; catch, end; 
+try opts.delete             = OPTIONS.delete; catch, end; 
+try opts.intens             = OPTIONS.intens; catch, end; 
+try opts.tolf               = OPTIONS.tolfun; catch, end; 
+try opts.diverse_criteria   = OPTIONS.diverse_criteria; catch, end;
+try opts.tolx               = OPTIONS.tolx; catch, end;
+% local options
+try opts.local.solver       = OPTIONS.local.solver ; catch, end;
+try opts.local.n1           = OPTIONS.local.n1; catch, end;
+try opts.local.n2           = OPTIONS.local.n2; catch, end;
+try opts.local.finish       = OPTIONS.local.finish; catch, end;
+try opts.local.bestx        = OPTIONS.local.bestx; catch, end;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% problem - Structure containing problem settings
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[lowbounds, highbounds] = handleLowHighBoundsIQM(OPTIONS,X,lowbounds,highbounds);
+if ~ischar(FUN),
+    FUN = func2str(FUN);    % convert function handle to string
+end
+problem = [];
+problem.f = FUN;            % Name of the file containing the objective function
+problem.x_L = lowbounds;    % Lower bounds of decision variables
+problem.x_U = highbounds;   % Upper bounds of decision variables
+problem.x_0 = X;            % Initial point(s) (optional)
+try problem.vtr = OPTIONS.vtr; catch, end; % value to reach
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% call SSm 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%disp('If you use SSm and publish the results, please cite the following papers:');
+%disp(' ');
+%disp('Egea, J.A., M. Rodriguez-Fernandez, J. R. Banga and R. Martí (2007) Scatter');
+%disp('Search for chemical and bioprocess optimization. Journal of Global Optimization');
+%disp('37(3):481-503.');
+%disp(' ');
+%disp('Rodriguez-Fernandez, M., J. A. Egea and J. R. Banga (2006) Novel Metaheuristic');
+%disp('for Parameter Estimation in Nonlinear Dynamic Biological Systems.');
+%disp('BMC Bioinformatics 7:483.');
+useFAST = 0;
+if isfield(OPTIONS,'fast'),
+    if OPTIONS.fast == 1,
+        useFAST = 1;
+    end
+end
+if useFAST,
+    result = fssm_kernel(problem,opts);
+else
+    result = ssm_kernel(problem,opts);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% handle output
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+X = result.xbest;
+FVAL = result.fbest;
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/optimization/isresIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/optimization/isresIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..3d2c1e9ba059c668bbe1517c78abbfd5788c78c8
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/optimization/isresIQM.m	
@@ -0,0 +1,413 @@
+function [X,FVAL,EXITFLAG] = isresIQM(varargin)
+% isresIQM: Stochastic Ranking for Constrained Evolutionary Minimization.
+%
+% The algorithm is described in:
+% Thomas Philip Runarsson and Xin Yao, Search Biases in Constrained 
+% Evolutionary Optimization. IEEE Transactions on Systems, Man and 
+% Cybernetics -- Part C: Applications and Reviews. Vol. 35, No. 2, 
+% pp 233-243, May 2005.
+%
+% The code of this function is based on the original code written by
+% Thomas Philip Runarsson (e-mail: tpr@verk.hi.is)
+%
+% If global variable stopOptimization is set to 1, the optimization is
+% stopped. This allows for stopping parameter estimation functions on user
+% request. 
+% 
+% USAGE:
+% ======
+% [info] = isresIQM()
+% [X,FVAL,EXITFLAG] = isresIQM(FUN,X)
+% [X,FVAL,EXITFLAG] = isresIQM(FUN,X,OPTIONS)
+%
+% FUN: Function to optimize
+%      The cost function is required to have the following calling syntax:
+%         [output] = FUN(X)
+%      The 'output' can be a scalar defining the 'cost', or the 'output'
+%      can be a cell array with two elements: {'cost', 'constraints'}.
+%      The 'cost' output argument has a scalar value indicating the 'cost'
+%      of a given set of parameter values X.
+%      The algorithm is able to handle inequality constraints, where
+%      feasible parameter sets are defined by negative values of the
+%      corresponding constraint functions. The 'constraints' output
+%      argument is a vector, where each entry corresponds to one
+%      constraint. If the value of an element is positive the corresponding
+%      contraint is active. Simple min/max bounds on parameters need not be
+%      specified using constraint functions but are taken care of by the
+%      isresIQM algorithm. 
+%
+% X: Starting Guess for parameter vector
+%
+% OPTIONS: structure containing options for the algorithm:
+%        OPTIONS.lowbounds: vector containing upper bounds for parameters
+%           Instead of a vector highbounds can also be a scalar > 1. In the
+%           latter case the highbounds are determined by multiplying this
+%           scalar to the initial parameter guess X. This latter case works
+%           only for positive X(i) ... if negative present then the user
+%           needs to specify a whole lowbounds vector. 
+%        OPTIONS.higbounds: vector containing lower bounds for parameters.
+%           Instead of a vector lowbounds can also be a scalar < 1. In the
+%           latter case the lowbounds are determined by multiplying this
+%           scalar to the initial parameter guess X. This latter case works
+%           only for positive X(i) ... if negative present then the user
+%           needs to specify a whole highbounds vector. 
+%        OPTIONS.linlog: string, either 'linear' or 'log'. 'linear' means
+%               that the parameters are optimized based on their real
+%               values, while 'log' means that the parameters are optimized
+%               based on their exponent to the base 10. Choose 'linear' for
+%               tight min max bounds, and choose 'log' for very wide
+%               bounds. The parameter bounds are always given as "real
+%               values" and not as exponents!
+%        OPTIONS.lambda: scalar, integer, population size (number of offspring) (100 to 400)
+%        OPTIONS.maxgen: maximum number of generations
+%        OPTIONS.maxtime: Maximum time (in minutes) for optimization
+%        OPTIONS.mu: parent number (mu/lambda usually 1/7)
+%        OPTIONS.pf: pressure on fitness in [0 0.5] try around 0.45
+%        OPTIONS.varphi: expected rate of convergence (usually 1)
+%        OPTIONS.outputFunction: string with output function name. If
+%               not given or if empty then no output function will be used.
+%               This output function can be used to display data, or to 
+%               save optimization information to a file. The function needs
+%               to be in the MATLAB path. Its calling syntax is:
+%
+%                   'outputFunction'(g,BestParameters,BestMin,Min,Mean,Std,NrFeas,Time)
+%
+%                   g: current generation number
+%                   BestParameters: the currently best set of parameters
+%                   BestMin: the currently minimal cost function value    
+%                   Min: min costfunction value in current generation (only feasible parameter sets count) 
+%                   Mean: mean costfunction value in current generation (only feasible parameter sets count)  
+%                   Std: standard deviation of cost function in current generation  (only feasible parameter sets count) 
+%                   NrFeas: number of feasible parameter sets in current generation   
+%                   Time: elapsed time
+%        OPTIONS.silent: =0: output of info, =1: no output
+%
+% DEFAULT VALUES:
+% ===============
+% OPTIONS.lowbounds:    0.1  => lowbounds = 0.1*X 
+% OPTIONS.highbounds:   10   => highbounds = 10*X 
+% OPTIONS.linlog:       'linear'
+% OPTIONS.lambda:       200
+% OPTIONS.maxgen:       ndim*200
+% OPTIONS.maxtime:      inf
+% OPTIONS.mu:           lambda*1/7
+% OPTIONS.pf:           0.45
+% OPTIONS.varphi:       1
+% OPTIONS.outputFunction: '' (no output function)
+% OPTIONS.silent:         0 (no output of info)
+%
+% Output Arguments:
+% =================
+% info: calling the function w/o input argument returns information about
+%       the options and a flag indicating if the algorithm can handle
+%       constraints or not
+% X: Best feasible individual           ([] if EXITFLAG = 0)
+% FVAL: Value of the function FUN at X  ([] if EXITFLAG = 0)
+% EXITFLAG: =1 if solution is feasible, =0 if solution is infeasible
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+global stopOptimization
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check if isrsort.c is compiled to MEX function
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if exist('isrsort') ~= 3,
+    % Is not compiled yet, do it
+    currentpath = pwd;
+    cd(fileparts(which('isrsort.c')));
+    mex isrsort.c;
+    cd(currentpath);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin == 0,
+    X = [];
+    X.name = 'isresIQM';
+    X.constrained = 1;
+    X.description = 'Stochastic Ranking for Constrained Evolutionary Minimization (global)';  
+    X.defaultOptions.names = {'maxgen', 'maxtime'};
+    X.defaultOptions.values = {'1000','500'};
+    X.defaultOptions.description = {'Maximum number of generations', 'Maximum time in minutes'};
+    FVAL = [];
+    EXITFLAG = [];
+    return
+elseif nargin == 2,
+    FUN = varargin{1};
+    X = varargin{2};
+    OPTIONS = [];
+elseif nargin == 3,
+    FUN = varargin{1};
+    X = varargin{2};
+    OPTIONS = varargin{3};
+else
+    error('Incorrect number of input arguments.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Set default values
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ndim = length(X);
+% Default parameter bounds
+lowbounds = 0.1*X;
+highbounds = 10*X;
+% Other
+lambda = 200;
+maxgen = ndim*200;
+mu = ceil(lambda * 1/7);
+pf = 0.45;
+varphi = 1;
+maxtime = inf;
+linlog = 0;  % 0='linear', 1='log'
+silent = 0;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle OPTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% silent
+if isfield(OPTIONS,'silent'),
+    if ~isempty(OPTIONS.silent),
+        silent = OPTIONS.silent;
+    end
+end
+% linlog
+if isfield(OPTIONS,'linlog'),
+    if strcmp(OPTIONS.linlog,'linear'),
+        linlog = 0;
+    elseif strcmp(OPTIONS.linlog,'log'),
+        linlog = 1;
+    else
+        error('Wrong setting for OPTIONS.linlog.');
+    end
+end
+% lamba
+if isfield(OPTIONS,'lambda'),
+    if ~isempty(OPTIONS.lambda),
+        lambda = OPTIONS.lambda;
+    end
+    if ~isfield(OPTIONS,'mu'),
+        % set also mu in case mu not defined by options
+        mu = ceil(lambda*1/7);
+    end
+end
+% maxgen
+if isfield(OPTIONS,'maxgen'),
+    if ~isempty(OPTIONS.maxgen),
+        maxgen = OPTIONS.maxgen;
+    end
+end
+% maxtime
+if isfield(OPTIONS,'maxtime'),
+    if ~isempty(OPTIONS.maxtime),
+        maxtime = OPTIONS.maxtime;
+    end
+end
+% mu
+if isfield(OPTIONS,'mu'),
+    if ~isempty(OPTIONS.mu),
+        mu = OPTIONS.mu;
+    end
+end
+% pf
+if isfield(OPTIONS,'pf'),
+    if ~isempty(OPTIONS.pf),
+        pf = OPTIONS.pf;
+    end
+end
+% varphi
+if isfield(OPTIONS,'varphi'),
+    if ~isempty(OPTIONS.varphi),
+        varphi = OPTIONS.varphi;
+    end
+end
+% outputFunction
+outputFunction = '';
+if isfield(OPTIONS,'outputFunction'),
+    if ~isempty(OPTIONS.outputFunction),
+        outputFunction = OPTIONS.outputFunction;
+    end
+end
+% low and highbounds:
+[lowbounds, highbounds] = handleLowHighBoundsIQM(OPTIONS,X,lowbounds,highbounds);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle linlog
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if linlog == 1, % 'log'
+    lowbounds = log10(lowbounds);
+    highbounds = log10(highbounds);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Initialize population
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+parameterPopulation = ones(lambda,1)*lowbounds+rand(lambda,ndim).*(ones(lambda,1)*(highbounds-lowbounds));
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Selection index vector
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+sI = (1:ceil(mu))'*ones(1,ceil(lambda/mu)); sI = sI(1:lambda);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Initial algorithm parameter settings
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+eta = ones(lambda,1)*(highbounds-lowbounds)/sqrt(ndim);
+gamma = 0.85;
+alpha = 0.2;
+chi = (1/(2*ndim)+1/(2*sqrt(ndim)));
+varphi = sqrt((2/chi)*log((1/alpha)*(exp(varphi^2*chi/2)-(1-alpha))));
+tau  = varphi/(sqrt(2*sqrt(ndim)));
+tau_ = varphi/(sqrt(2*ndim));
+ub = ones(lambda,1)*highbounds;
+lb = ones(lambda,1)*lowbounds;
+eta_u = eta(1,:);
+nretry = 10;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Other
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+f = zeros(lambda,1); 
+phi = zeros(lambda,ndim);
+BestMin = inf;
+BestMean = inf;
+BestStd = inf;
+BestParameters = [];
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Loop over 'maxgen' generations
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+tic;
+if ~silent,
+    disp(sprintf('    #g        BestMin          Min(g)        Mean(g)         Std(g)     NrFeas     Time'));
+end
+for g=1:maxgen,
+    % fitness evaluation
+    for loop=1:lambda,
+        if linlog == 0, % linear
+            funoutput = feval(FUN,parameterPopulation(loop,:));
+        else % log
+            funoutput = feval(FUN,10.^parameterPopulation(loop,:));
+        end
+        if iscell(funoutput),
+            f(loop) = funoutput{1};
+            phivec = funoutput{2};
+        else
+            f(loop) = funoutput;
+            phivec = [];
+        end
+        if ~isempty(phivec),
+            phi(loop,:) = phivec(:)';
+        end
+    end
+    
+    FeasiblePhi = find((sum((phi>0),2)<=0));
+    NonFeasibleNaN = find(isnan(f));
+    NonFeasibleInf = find(isnan(f));
+    Feasible = setdiff(FeasiblePhi, union(NonFeasibleNaN,NonFeasibleInf));
+    
+    % Performance / statistics
+    if ~isempty(Feasible),
+        [MinGeneration,MinInd] = min(f(Feasible));
+        MinInd = Feasible(MinInd);
+        MeanGeneration = mean(f(Feasible));
+        StdGeneration = std(f(Feasible));
+        if MinGeneration < BestMin,
+            BestParameters = parameterPopulation(MinInd,:);
+            BestMin = MinGeneration;
+            BestMean = MeanGeneration;
+            BestStd = StdGeneration;
+        end    
+    else
+        MinGeneration = NaN; MeanGeneration = NaN;
+    end
+    NrFeas = length(Feasible);
+
+    % Compute penalty function "quadratic loss function" (or any other)
+    phi(find(phi<=0)) = 0;
+    phi = sum(phi.^2,2);
+
+    % Selection using stochastic ranking 
+    I = isrsort(f,phi,pf);
+    parameterPopulation = parameterPopulation(I(sI),:); 
+    eta = eta(I(sI),:);
+
+    % Update eta (traditional technique using exponential smoothing)
+    eta_ = eta;
+    eta(mu:end,:) = eta(mu:end,:).*exp(tau_*randn(lambda-mu+1,1)*ones(1,ndim)+tau*randn(lambda-mu+1,ndim));
+
+    % Upper bound on eta (used?)
+    for i=1:ndim,
+        I = find(eta(:,i)>eta_u(i));
+        eta(I,i) = eta_u(i)*ones(size(I));
+    end
+
+    % make a copy of the individuals for repeat ...
+    x_ = parameterPopulation;
+
+    % differential variation
+    parameterPopulation(1:mu-1,:) = parameterPopulation(1:mu-1,:) + gamma*(ones(mu-1,1)*parameterPopulation(1,:) - parameterPopulation(2:mu,:));
+
+    % Mutation
+    parameterPopulation(mu:end,:) = parameterPopulation(mu:end,:) + eta(mu:end,:).*randn(lambda-mu+1,ndim);
+
+    % If variables are out of bounds retry "nretry" times
+    I = find((parameterPopulation>ub) | (parameterPopulation<lb));
+    retry = 1 ;
+    while ~isempty(I)
+        parameterPopulation(I) = x_(I) + eta(I).*randn(length(I),1);
+        I = find((parameterPopulation>ub) | (parameterPopulation<lb));
+        if (retry>nretry), 
+            break; 
+        end
+        retry = retry + 1;
+    end
+    % ignore failures
+    if ~isempty(I),
+        parameterPopulation(I) = x_(I);
+    end
+
+    % exponential smoothing
+    eta(mu:end,:) = eta_(mu:end,:) + alpha*(eta(mu:end,:) - eta_(mu:end,:));
+
+    % output
+    if ~silent,
+        disp(sprintf(' %5.0f   %12.6f   %12.6g   %12.6g   %12.6g       %5.0f     %1.2e sec', g, BestMin, MinGeneration, MeanGeneration, StdGeneration, NrFeas, toc));
+    end
+    % call output function if defined
+    if ~isempty(outputFunction),
+        if linlog == 0, % linear
+            feval(outputFunction, g, BestParameters, BestMin, MinGeneration, MeanGeneration, StdGeneration, NrFeas, toc);
+        else % log
+            feval(outputFunction, g, 10.^BestParameters, BestMin, MinGeneration, MeanGeneration, StdGeneration, NrFeas, toc);
+        end
+    end
+    
+    if toc/60 > maxtime,
+        % Break the loop when more than 'OPTIONS.maxtime' minutes elapsed
+        break;
+    end
+    if stopOptimization == 1,
+        disp('User Interrupt.');
+        break;
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check results and define output
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(BestParameters),
+    % only infeasible parameter sets
+    EXITFLAG = 0;
+    X = [];
+    FVAL = [];
+else
+    EXITFLAG = 1;
+    if linlog == 0, % linear
+        X = BestParameters;
+    else % log
+        X = 10.^BestParameters;
+    end
+    FVAL = BestMin;
+end
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/optimization/pswarmIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/optimization/pswarmIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..7f43912790674165fa85cffd1ff92ffd79c8e278
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/optimization/pswarmIQM.m	
@@ -0,0 +1,520 @@
+function [X,FVAL,RunData] = pswarmIQM(varargin)
+% pswarmIQM: Particle swarm pattern search algorithm for global optimization.
+%
+% Algorithm developed by A. Ismael F. Vaz and L. N. Vicente.
+% aivaz@dps.uminho.pt 04/04/2007
+% More information: http://www.norg.uminho.pt/aivaz/pswarm/
+%
+% In case of a publication that was prepared using pswarm, users
+% are asked to cite the following publication:
+% A. I. F. Vaz and L. N. Vicente, A particle swarm pattern search method
+% for bound constrained global optimization,
+% Journal of Global Optimization, 39 (2007) 197-219.
+%
+% The PSwarm algorithm takes advantage of the particle swarm algorithm in
+% looking for a global optimum in the search phase of the pattern search
+% algorithm. The pattern search enforces convergence for a local optimum.
+%
+% If the global variable stopOptimization is set to 1, the optimization is
+% stopped. This allows for stopping parameter estimation functions on user
+% request. 
+% 
+% USAGE:
+% ======
+% [info] = pswarmIQM()
+% [X,FVAL,RunData] = pswarmIQM(FUN,X)
+% [X,FVAL,RunData] = pswarmIQM(FUN,X,OPTIONS)
+%
+% FUN:      Function to optimize
+% X:        Starting Guess
+% OPTIONS:  Structure containing options for the algorithm. 
+%       OPTIONS.lowbounds: vector with lower bounds for variables 
+%       OPTIONS.highbounds: vector with lower bounds for variables
+%       OPTIONS.logFlag: Flag indicating if the parameter space should be
+%               searched linearly (0) or logarithmically (1).
+%       OPTIONS.Cognitial: cognitial parameter in the velocity equation
+%       OPTIONS.InerciaFinalWeight: The value of the inercia parameter in the velocity
+%             at last iteration.
+%       OPTIONS.InerciaInitialWeight: The value of the inercia parameter in the
+%             velocity equation at first iteration.
+%       OPTIONS.maxfunevals: Maximum number of objective function evaluations. Since the
+%             algorithm is population based this maximum number of
+%             objective function evaluation may be sligtly exceeded.
+%       OPTIONS.maxiter: Maximum number of iterations allowed.
+%       OPTIONS.popsize: Population size.
+%       OPTIONS.Social: Social parameter in the velocity equation.
+%       OPTIONS.MaxVelocityFactor: Velocity will be projected in the set
+%             (UB-LB)*MaxVelocityFactor.
+%       OPTIONS.CPTolerance: Stopping criteria tolerance.
+%       OPTIONS.InitialDelta: Initial pattern search grid step.
+%       OPTIONS.DeltaIncreseFactor: Delta will be increased by this factor (on
+%             successful poll steps).
+%       OPTIONS.DeltaDecreaseFactor: Delta willbe decreased by this factor (on
+%             unsuccessful poll steps).
+%       OPTIONS.InitialDeltaFactor: The inicial Delta will be the min(UB-LB) times this
+%             factor.
+%       OPTIONS.silent: 0=show iterations, 1=do not show iterations.
+%
+% DEFAULT VALUES:
+% ===============
+%       OPTIONS.lowbounds:              1e-3*X
+%       OPTIONS.highbounds:             1e3*X
+%       OPTIONS.Cognitial:              0.5000
+%       OPTIONS.InerciaFinalWeight:     0.4000
+%       OPTIONS.InerciaInitialWeight:   0.9000
+%       OPTIONS.maxfunevals:            5000*length(X);
+%       OPTIONS.maxiter:                1000*length(X);
+%       OPTIONS.popsize:                20*length(X);
+%       OPTIONS.Social:                 0.5000
+%       OPTIONS.MaxVelocityFactor:      0.5000
+%       OPTIONS.CPTolerance:            1.0000e-005
+%       OPTIONS.InitialDelta:           2
+%       OPTIONS.DeltaIncreaseFactor:    2
+%       OPTIONS.DeltaDecreaseFactor:    0.5000
+%       OPTIONS.InitialDeltaFactor:     5
+%       OPTIONS.silent:                 0
+%
+% Output Arguments:
+% =================
+% info: calling the function w/o input argument returns information about
+%       the options and a flag indicating if the algorithm can handle
+%       constraints or not
+% X:        Found solution (The best particle obtained for the population (Leader))
+% FVAL:     Value of the function FUN at X 
+% RunData:  Some statistics obout the algorithm run
+%
+% Copyright Information:
+% ======================
+% Copyright (C) 2007 A. Ismael F. Vaz and L. N. Vicente.
+% aivaz@dps.uminho.pt 04/04/2007
+% http://www.norg.uminho.pt/aivaz
+% http://www.mat.uc.pt/~lnv
+%
+% Algorithm adapted and included in the IQM TOOLS LITE by Henning Schmidt, 
+% with permission of the authors.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GLOBAL VARIABLES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+global stopOptimization
+if isempty(stopOptimization),
+    stopOptimization = 0;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin == 0,
+    X = [];
+    X.name = 'pswarmIQM';
+    X.constrained = 1;
+    X.description = 'Particle swarm pattern search algorithm (global)';       
+    X.defaultOptions.names = {'maxfunevals', 'maxiter'};
+    X.defaultOptions.values = {'100000','40000'};
+    X.defaultOptions.description = {'Maximum number of function evaluations', 'Maximum number of iterations'};
+    FVAL = [];
+    RunData = [];
+    return
+elseif nargin == 2,
+    FUN = varargin{1};
+    X = varargin{2};
+    OPTIONS = [];
+elseif nargin == 3,
+    FUN = varargin{1};
+    X = varargin{2};
+    OPTIONS = varargin{3};
+else
+    error('Incorrect number of input arguments.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE OPTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DefaultOpt.lowbounds = 1e-3*X;
+DefaultOpt.highbounds = 1e3*X;
+DefaultOpt.Cognitial = 0.5000;
+DefaultOpt.InerciaFinalWeight = 0.4000;
+DefaultOpt.InerciaInitialWeight = 0.9000;
+DefaultOpt.maxfunevals = 5000*length(X);
+DefaultOpt.maxiter = 1000*length(X);
+DefaultOpt.popsize = 20*length(X);
+DefaultOpt.Social = 0.5000;
+DefaultOpt.MaxVelocityFactor = 0.5000;
+DefaultOpt.CPTolerance = 1.0000e-005;
+DefaultOpt.InitialDelta = 2;
+DefaultOpt.DeltaIncreaseFactor = 2;
+DefaultOpt.DeltaDecreaseFactor = 0.5000;
+DefaultOpt.InitialDeltaFactor = 5;
+DefaultOpt.silent = 0;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CREATE INITIAL POPULATION STRUCTURE (just one entry)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+InitialPopulation(1).x = X;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CREATE PROBLEM STRUCTURE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+Problem = [];
+Problem.ObjFunction = FUN;
+Problem.LB = GetOption('lowbounds',OPTIONS,DefaultOpt);
+Problem.UB = GetOption('highbounds',OPTIONS,DefaultOpt);
+Problem.Variables = length(X);
+if length(Problem.LB)~=length(Problem.UB)
+    error('Lower bound and upper bound arrays length mismatch.');
+end
+
+% Start clock
+tic;
+
+% Initialize options. GetOption returns the user specified value, if the
+% option exists. Otherwise returns the default option.
+
+% These are local options. Not needed for the subrotines
+MaxIterations=GetOption('maxiter',OPTIONS,DefaultOpt);
+MaxEvals=GetOption('maxfunevals',OPTIONS,DefaultOpt);
+InerciaInitial=GetOption('InerciaInitialWeight',OPTIONS,DefaultOpt);
+InerciaFinal=GetOption('InerciaFinalWeight',OPTIONS,DefaultOpt);
+Cognitial=GetOption('Cognitial',OPTIONS,DefaultOpt);
+Social=GetOption('Social',OPTIONS,DefaultOpt);
+
+% These are global options. Need to be available to subrotines.
+Problem.Verbose=~GetOption('silent', OPTIONS, DefaultOpt);
+Problem.IncreaseDelta=GetOption('DeltaIncreaseFactor',OPTIONS,DefaultOpt);
+Problem.DecreaseDelta=GetOption('DeltaDecreaseFactor',OPTIONS,DefaultOpt);
+Problem.Tolerance=GetOption('CPTolerance', OPTIONS, DefaultOpt);
+
+% Compute minimum delta for pattern search
+% The minimum delta available should be at least twice the Tolerance
+InitialDelta=min(Problem.UB-Problem.LB);
+InitialDelta = InitialDelta / GetOption('InitialDeltaFactor', ...
+    OPTIONS, DefaultOpt);
+if InitialDelta < 2*Problem.Tolerance
+    InitialDelta = 2*Problem.Tolerance;
+end
+
+
+% compute the maximum allowed velocity. High velocities will be "pushing"
+% particle to the border.
+MaxVelocityVect=(Problem.UB(1:Problem.Variables)-Problem.LB(1:Problem.Variables))*...
+    GetOption('MaxVelocityFactor',OPTIONS,DefaultOpt);
+
+disp('pswarmIQM: In case of a publication that was prepared using the pswarm');
+disp('users are asked to cite the following publication:');
+disp('A. I. F. Vaz and L. N. Vicente, A particle swarm pattern search method');
+disp('for bound constrained global optimization, Journal of Global Optimization,');
+disp('39 (2007) 197-219.');
+
+if Problem.Verbose
+    disp(' Nr Iter    Nr Fun Eval         Min function');
+end
+
+
+% Initialize counters
+% Iteration counter
+Problem.Stats.IterCounter=0;
+% How many consecutive iterations without success (progress in the leader
+% particle).
+IterUnsuccess=0;
+% Maximum velcity among all perticles velocity
+MaxVelocity=+Inf;
+
+
+% Initialize statistics counters
+
+% Number of objective function calls. This is the number of calls to
+% Problem.ObjFunction. Since particle swarm relies in a infinite penalty
+% function strategy the penalty number of evaluation may be different.
+Problem.Stats.ObjFunCounter=0;
+
+% Number of Poll steps taken
+Problem.Stats.PollSteps=0;
+
+% How many poll step had success
+Problem.Stats.SuccPollSteps=0;
+
+% Keep track of what direction had success in the last poll step. The Delta
+% parameter is incremented only of a success occours twice in the same
+% direction.
+Problem.Poll.LastSuccess=[];
+
+
+% Generate initial population. Include initial population provided by user
+%  if available
+[Problem,Population]=InitPopulation(Problem, InitialPopulation, ...
+    GetOption('popsize', OPTIONS, DefaultOpt));
+
+% Delta for the pattern search.
+Population.Delta=InitialDelta;
+
+% Initialize patter search. Initialize the coordinate search directions.
+Problem=InitPatternSearch(Problem);
+
+% Main cycle of the algorithm
+% Run pattern search until no success is attained. Call for a poll step in
+% the leader particle whenever no success is recorded.
+
+% Stop if the maximum number of iterations or objective function
+% evaluations is reached.
+while(Problem.Stats.IterCounter<MaxIterations && Problem.Stats.ObjFunCounter<MaxEvals && stopOptimization == 0),
+
+    % Stop also if particle swarm velocity is bellow Tolerance and pattern
+    % search Delta is bellow Tolerance
+    if MaxVelocity<Problem.Tolerance && Population.Delta<Problem.Tolerance
+        disp('Stopping due to velocity and tolerance');
+        break;
+    end
+    
+    % Stop if the number of active particles is equal to 1 and pattern
+    % search Tolerance was attained.
+    if Population.ActiveParticles <=1 && Population.Delta<Problem.Tolerance
+        disp('Stopping due to single particle and tolerance');
+        break;
+    end
+    
+    % Increment iteration counter.    
+    Problem.Stats.IterCounter=Problem.Stats.IterCounter+1;
+
+    % No success iteration at begining
+    Success=false;
+    
+    % For all particles in the swarm
+    for i=1:Population.popsize
+        % If particle is active
+        if(Population.Active(i))
+            % Compute Objective function value
+            [Problem,ObjValue]=...
+                PenaltyEval(Problem, Population.x(i,:));
+            % Was progress attained for the current particle?
+            if Population.fy(i)>ObjValue
+                % Yes. Update best particle position
+                Population.fy(i)=ObjValue;
+                Population.y(i,:)=Population.x(i,:);
+                               
+                % Check if new leader is available
+                if Population.fy(Population.Leader)>Population.fy(i) || Population.Leader==i
+                    Population.Leader=i;
+                    % Particle swarm iteration declared as successful
+                    Success=true;
+                    % Reset last success direction for pattern search
+                    Problem.Poll.LastSuccess=[];
+                end
+            end
+        end
+    end
+    
+    % Successful iteration?
+    if ~Success
+        % No success in searh phase. Proceed to a poll step if possible.
+        if Population.Delta >= Problem.Tolerance
+            [Problem,Population]=PollStep(Problem,Population);
+            Problem.Stats.PollSteps=Problem.Stats.PollSteps+1;
+            % Reset on the number of unsuccessful iterations without a poll
+            % step
+            IterUnsuccess=0;
+        else
+            % An unsuccessful iteration without poll step
+            IterUnsuccess=IterUnsuccess+1;
+        end
+    else
+        % Success
+        IterUnsuccess=0;
+        % Leader changed.
+        % Increase Delta. Reset on the local search.
+        if Population.Delta<InitialDelta
+            Population.Delta=Population.Delta*Problem.IncreaseDelta;
+        end
+        % check for lower bounds
+        if Population.Delta<Problem.Tolerance
+            Population.Delta=2*Problem.Tolerance;
+        end
+    end
+    
+    
+    % Compute inercia.
+    Inercia = InerciaInitial - ...
+        (InerciaInitial-InerciaFinal)*Problem.Stats.IterCounter/MaxIterations;
+
+    % Update velocity and new particle positions
+    % For all particles
+    for i=1:Population.popsize
+        % Is active?
+        if Population.Active(i)
+            % Update velocity for real variables
+            Population.vx(i,:)=Projection(Inercia*Population.vx(i,:)+ ...
+                Cognitial*unifrndIQM(0,ones(1,Problem.Variables)).*...
+                  (Population.y(i,:)-Population.x(i,:))+...
+                Social*unifrndIQM(0,ones(1,Problem.Variables)).*...
+                  (Population.y(Population.Leader,:)-Population.x(i,:)),...
+                -MaxVelocityVect,MaxVelocityVect);
+            % Update particle position and check bound limits
+            Population.x(i,:)=Projection(Population.x(i,:)+Population.vx(i,:),...
+                Problem.LB(1:Problem.Variables), ...
+                Problem.UB(1:Problem.Variables));
+        end
+    end
+
+    % To compute population norm. Start with Leader.
+    MaxVelocity=norm(Population.x(Population.Leader));
+    
+    % Reset number of active particles.
+    Population.ActiveParticles=0;
+    for i=1:Population.popsize
+        % Check if particle is active and we do not want to remove the
+        % leader.
+        if Population.Active(i) && Population.Leader~=i
+            % compute particle velocity norm (for the stopping criteria.
+            VelocityNorm=norm(Population.vx(i,:));
+            Distance=norm(Population.x(i,:)-Population.x(Population.Leader,:));
+            if Distance<Population.Delta && VelocityNorm<Population.Delta
+                % Is neighbour
+                Population.Active(i)=false;
+            else
+                % Is integer, but not real neighbour
+                MaxVelocity=MaxVelocity+VelocityNorm;
+            end
+        end
+        % Account for active particles.
+        if Population.Active(i)
+            Population.ActiveParticles=Population.ActiveParticles+1;
+        end
+    end
+    
+    if Problem.Verbose,
+        disp(sprintf(' %5.0f        %5.0f           %12.6g            %s', Problem.Stats.IterCounter, Problem.Stats.ObjFunCounter, Population.fy(Population.Leader)));
+    end
+
+end
+
+
+% End of main cycle ...
+
+% print final time
+toc;
+
+% Print if it was stopped due to the maximum of iterations or objective
+% function evaluations
+if Problem.Stats.IterCounter>=MaxIterations || Problem.Stats.ObjFunCounter>=MaxEvals
+    disp('Maximum number of iterations or objective function evaluations reached');
+end
+
+if stopOptimization == 1,
+    disp('User Interrupt.');
+end
+
+% return leader position and objective function value
+BestParticle=[Population.y(Population.Leader,:)];
+BestParticleObj=Population.fy(Population.Leader);
+RunData=Problem.Stats;
+
+if Problem.Verbose
+    % display some statistics
+    disp(Problem.Stats);
+end
+X = BestParticle;
+FVAL = BestParticleObj;
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% subrotine InitPopulation
+%    Randomly initialize the population
+%    Include initial guesses, if provided by the user
+%
+% Input:
+%   Problem - problem data
+%   InitialPopulation - Inicial population provided by user
+%   popsize - Requested size for the population
+%
+% Output:
+%   Problem - problem data (problem data may be update)
+%   Population - population data
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [Problem,Population]=InitPopulation(Problem, ...
+    InitialPopulation, popsize)
+% Check if user provides a valid initial population
+if ~isempty(InitialPopulation) && ~isstruct(InitialPopulation)
+    error('pswarm:InitPopulation:InitialPopulation', 'Initial population must be defined in a structure.');
+else
+    % Check for size
+    if length(InitialPopulation)>popsize
+        % User provided an initial population greater then the population
+        % size
+        if Problem.Verbose
+            fprintf('Initial population is greater then population size. Incresing population size from ');
+            fprintf(popsize);
+            fprintf(' to ');
+            fprintf(length(InitialPopulation));
+        end
+        % Population size is increased to fit the number of initial guesses
+        Population.popsize=length(InitialPopulation);
+    else
+        % Otherwise just accept the proposed population size
+        Population.popsize=popsize;
+    end 
+    % Copy the initial population for the population and initialize them
+    for i=1:length(InitialPopulation)
+        % Particle position.
+        Population.x(i,:)=Projection(InitialPopulation(i).x,...
+                Problem.LB(1:Problem.Variables), ...
+                Problem.UB(1:Problem.Variables));
+        % Best particle position.
+        Population.y(i,:)=Population.x(i,:);
+        % Particle velocities.
+        Population.vx(i,:)=zeros(1,Problem.Variables);
+        % Particle is active at begining
+        Population.Active(i)=true;
+        [Problem,Population.fy(i)]=...
+            PenaltyEval(Problem, Population.x(i,:));
+    end
+end
+% Ramdomly generate the remaining population
+for i=length(InitialPopulation)+1:Population.popsize
+    % Particle positions.
+    Population.x(i,:)=unifrndIQM(Problem.LB(1:Problem.Variables),...
+        Problem.UB(1:Problem.Variables));
+    % Best particle position.
+    Population.y(i,:)=Population.x(i,:);
+    % Particle velocities
+    Population.vx(i,:)=zeros(1,Problem.Variables);
+    % Particle active or inactive
+    Population.Active(i)=true;
+    [Problem,Population.fy(i)]=...
+        PenaltyEval(Problem, Population.x(i,:));
+end
+Population.ActiveParticles=Population.popsize;
+Population.Leader=1;
+return;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%  subrotine GetOption
+%
+%  Input:
+%    Option - option to get the value
+%    OPTIONS - a list of options provided by user
+%    DefaultOpt -  a list of default options
+%
+%  Output:
+%    Value - The value specified by user for Option or the default
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [Value]=GetOption(Option, OPTIONS, DefaultOpt)
+% Check for user provided options
+if isempty(OPTIONS) || ~isstruct(OPTIONS)
+    % User does not provides OPTIONS
+    Value=DefaultOpt.(Option);
+    return;
+end
+% Try the option provided by user
+try
+    Value=OPTIONS.(Option);
+catch
+    Value=[];
+end
+% Option not provided by user
+if isempty(Value)
+    Value=DefaultOpt.(Option);    
+end
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/optimization/simannealingIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/optimization/simannealingIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..217d228158aa3355a96167f18c7c44f5de57cef8
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/optimization/simannealingIQM.m	
@@ -0,0 +1,428 @@
+function [X,FVAL,EXITFLAG] = simannealingIQM(varargin)
+% simannealingIQM: Minimization by simulated annealing. Algorithm partly 
+% based on section 10.4 in "Numerical Recipes in C", ISBN 0-521-43108-5.
+% The implementation of this simmulated annealing method uses a nonlinear
+% simplex search as basis. The algorithm has been modified in order to be
+% able to take into account simple box constraints on parameter values.
+%
+% If global variable stopOptimization is set to 1, the optimization is
+% stopped. This allows for stopping parameter estimation functions on user
+% request. 
+% 
+% USAGE:
+% ======
+% [info] = simannealingIQM()
+% [X,FVAL,EXITFLAG] = simannealingIQM(FUN,X,OPTIONS)
+%
+% FUN: Function to optimize
+% X: Starting Guess
+% OPTIONS: structure containing options for the algorithm:
+%        OPTIONS.tempstart: Starting temperature (should be around the
+%           order of magnitude (or higher) than the cost function at the
+%           initial guess)
+%        OPTIONS.tempend: Ending temperature (When performed all iterations
+%           for this temperature, the temperature is set to 0 and the
+%           simannealingIQM function converges to a normal simplex search)
+%        OPTIONS.tempfactor: Reduction factor for temperature after running
+%           through all iterations for current temperature
+%        OPTIONS.maxitertemp: Number of iterations to carry put for each
+%           non-zero temperature
+%        OPTIONS.maxitertemp0: Number of iterations to carry out for 0
+%           temperature
+%        OPTIONS.maxtime: Maximum time (in minutes) for optimization
+%        OPTIONS.tolx: Tolerance for max difference between the coordinates
+%           of the vertices.
+%        OPTIONS.tolfun: Tolerance for difference between best and worst
+%           function evaluation in simplex
+%        OPTIONS.highbounds: vector containing upper bounds for parameters
+%           Instead of a vector highbounds can also be a scalar > 1. In the
+%           latter case the highbounds are determined by multiplying this
+%           scalar to the initial parameter guess X. This latter case works
+%           only for positive X(i) ... if negative present then the user
+%           needs to specify a whole highbounds vector. 
+%        OPTIONS.lowbounds: vector containing lower bounds for parameters.
+%           Instead of a vector lowbounds can also be a scalar < 1. In the
+%           latter case the lowbounds are determined by multiplying this
+%           scalar to the initial parameter guess X. This latter case works
+%           only for positive X(i) ... if negative present then the user
+%           needs to specify a whole lowbounds vector. 
+%        OPTIONS.outputFunction: string with output function name. If
+%           not given or if empty then no output function will be used.
+%           This output function can be used to display data, or to 
+%           save optimization information to a file. The function needs
+%           to be in the MATLAB path. Its calling syntax is:
+%                   'outputFunction'(bestparameters,bestfunctionvalue,currentsimplex)
+%        OPTIONS.silent: =0: output of info, =1: no output
+%
+% DEFAULT VALUES:
+% ===============
+% OPTIONS.tempstart = 10*magnitude of function value at initial guess
+% OPTIONS.tempend = 0.1
+% OPTIONS.tempfactor = chosen such that 10 reductions of temperature
+% OPTIONS.maxitertemp = 50*numberVariables
+% OPTIONS.maxitertemp0 = 200*numberVariables
+% OPTIONS.maxtime = 120
+% OPTIONS.tolx = 1e-10
+% OPTIONS.tolfun = 1e-10
+% OPTIONS.lowbounds:    0.1  => lowbounds = 0.1*X 
+% OPTIONS.highbounds:    10  => highbounds = 10*X 
+% OPTIONS.outputFunction: no output function ('')
+% OPTIONS.silent:         0 (no output of info)
+%
+% Output Arguments:
+% =================
+% info: calling the function w/o input argument returns information about
+%       the options and a flag indicating if the algorithm can handle
+%       constraints or not
+% X: Found solution
+% FVAL: Value of the function FUN at X
+% EXITFLAG: 1=success, 0=not found
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GLOBAL VARIABLES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+global ndim nfunk Xguess lowbounds highbounds Temp ybest pbest tempstart stopOptimization
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin == 0,
+    X = [];
+    X.name = 'simannealingIQM';
+    X.constrained = 1;
+    X.description = 'Simulated annealing based on Nelder-Mead (global)';       
+    X.defaultOptions.names = {'tempstart','tempend','tempfactor','maxitertemp', 'maxitertemp0', 'maxtime'};
+    X.defaultOptions.values = {'1000','0.1','0.2','1000','1000','500'};
+    X.defaultOptions.description = {'Starting temperature', 'Ending temperature before assuming T=0', 'Reduction factor for temperature', 'Number of iterations if T~=0', 'Number of iterations if T==0','Maximum time in minutes'};
+    FVAL = [];
+    EXITFLAG = [];
+    return
+elseif nargin == 2,
+    FUN = varargin{1};
+    X = varargin{2};
+    OPTIONS = [];
+elseif nargin == 3,
+    FUN = varargin{1};
+    X = varargin{2};
+    OPTIONS = varargin{3};
+else
+    error('Incorrect number of input arguments.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Set default values
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+EXITFLAG = 1;
+ndim = length(X);
+tempstart = -1;     % default value calculation later
+tempend = 0.1;
+tempfactor = -1;    % default value calculation later
+maxitertemp = 50*ndim;
+maxitertemp0 = 200*ndim;
+maxtime = 120;
+tolx = 1e-10;
+tolfun = 1e-10;
+lowbounds = 0.1*X;
+highbounds = 10*X;
+outputFunction = '';
+silent = 0;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE OPTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% silent
+if isfield(OPTIONS,'silent'),
+    if ~isempty(OPTIONS.silent),
+        silent = OPTIONS.silent;
+    end
+end
+% tolfun
+if isfield(OPTIONS,'tolfun'),
+    if ~isempty(OPTIONS.tolfun),
+        tolfun = OPTIONS.tolfun;
+    end
+end
+% tolx
+if isfield(OPTIONS,'tolx'),
+    if ~isempty(OPTIONS.tolx),
+        tolx = OPTIONS.tolx;
+    end
+end
+% maxtime
+if isfield(OPTIONS,'maxtime'),
+    if ~isempty(OPTIONS.maxtime),
+        maxtime = OPTIONS.maxtime;
+    end
+end
+% maxitertemp0
+if isfield(OPTIONS,'maxitertemp0'),
+    if ~isempty(OPTIONS.maxitertemp0),
+        maxitertemp0 = OPTIONS.maxitertemp0;
+    end
+end
+% maxitertemp
+if isfield(OPTIONS,'maxitertemp'),
+    if ~isempty(OPTIONS.maxitertemp),
+        maxitertemp = OPTIONS.maxitertemp;
+    end
+end
+% tempfactor
+if isfield(OPTIONS,'tempfactor'),
+    if ~isempty(OPTIONS.tempfactor),
+        tempfactor = OPTIONS.tempfactor;
+    end
+end
+% tempend
+if isfield(OPTIONS,'tempend'),
+    if ~isempty(OPTIONS.tempend),
+        tempend = OPTIONS.tempend;
+    end
+end
+% tempstart
+if isfield(OPTIONS,'tempstart'),
+    if ~isempty(OPTIONS.tempstart),
+        tempstart = OPTIONS.tempstart;
+    end
+end
+% outputFunction
+outputFunction = '';
+if isfield(OPTIONS,'outputFunction'),
+    if ~isempty(OPTIONS.outputFunction),
+        outputFunction = OPTIONS.outputFunction;
+    end
+end
+% low and highbounds:
+[lowbounds, highbounds] = handleLowHighBoundsIQM(OPTIONS,X,lowbounds,highbounds);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INITIALIZE EMPTY SIMPLEX DATA
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+p = zeros(ndim+1,ndim);     % vertice vectors in rows
+y = zeros(ndim+1,1);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EVALUATE FUNCTION IN INITIAL GUESS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ybest = inf;
+pbest = X(:)';
+ybest = costFunction(FUN,pbest);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DETERMINE START TEMP AND TEMPFACTOR (if not given by the user)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if tempstart < 0,
+    % tempstart not given by the user => determine here a default value
+    tempstart = 10*abs(ybest);
+end
+if tempfactor < 0,
+    % tempfactor not given by the user => determine here a default value
+    tempfactor = (tempstart/tempend)^(-1/9);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% TEMPERATURE LOOP - STARTING FROM BEST POINT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+Temp = tempstart;
+tic % start timer
+nfunk = 1;
+nriterations = 0;
+while(1),
+    if Temp < tempend,
+        Temp = 0;
+        MAXITERTEMP = maxitertemp0;
+    else 
+        MAXITERTEMP = maxitertemp;
+    end
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % FIRST POINT OF INITIAL SIMPLEX
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    if ~silent,
+        disp(sprintf(' Current best estimation: [%s]',sprintf('%g ', pbest)));
+    end
+    Xguess = pbest;
+    p(1,:) = Xguess;
+    y(1) = costFunction(FUN,Xguess);
+    if ~silent,
+        disp(' Nr Iter  Nr Fun Eval    Min function       Best function       Temp      Algorithm Step');
+        if Temp == tempstart,
+            disp(sprintf(' %5.0f   %5.0f       %12.6g       %12.6g   %12.6g       %s', nriterations, nfunk, y(1), ybest, Temp, 'initial guess'));
+        else
+            disp(sprintf(' %5.0f   %5.0f       %12.6g       %12.6g   %12.6g       %s', nriterations, nfunk, y(1), ybest, Temp, 'best point'));
+        end
+    end
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % REMAINING POINTS OF INITIAL SIMPLEX
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % construct vertices by modifying one element each
+    % relative changes in case that elements are non-zero,
+    % absolute changes in case that elements are zero
+    relativeDelta = 0.25;
+    absoluteDelta = 0.5;
+    for k = 1:ndim
+        Xmodify = Xguess;
+        if Xmodify(k) == 0
+            % absolute change
+            if highbounds(k) > absoluteDelta,
+                Xmodify(k) = absoluteDelta;
+            else 
+                Xmodify(k) = -absoluteDelta;
+            end
+        else
+            % relative change
+            Xmodify(k) = (1 + relativeDelta)*Xmodify(k);
+        end
+        p(k+1,:) = Xmodify;
+        y(k+1) = costFunction(FUN,Xmodify);
+    end
+    algostep = 'initial simplex';
+    nriterations = nriterations + 1;
+    nfunk = nfunk + ndim + 1;
+    
+    % if output function given then run output function to plot
+    % intermediate result
+    if length(outputFunction) ~= 0,
+        feval(outputFunction,p(1,:), y(1),p);
+    end
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % MAIN ALGORITHM
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % reorder y and p so that the first row corresponds to the
+    % lowest function value
+    for itertemp = 1:MAXITERTEMP,
+        % add random thermal fluctuations
+        yfluct = y + Temp*abs(log(rand(ndim+1,1)));
+        % do sorting instead of determining the indices of the best, worst,
+        % next worst
+        help = sortrows([yfluct,y,p],1);
+        yfluct = help(:,1);
+        y = help(:,2);
+        p = help(:,3:end);
+        if ~silent,
+            disp(sprintf(' %5.0f   %5.0f       %12.6g       %12.6g   %12.6g       %s', nriterations, nfunk, y(1), ybest, Temp, algostep));
+        end
+        % if output function given then run output function to plot
+        % intermediate result
+        if length(outputFunction) ~= 0,
+            feval(outputFunction,p(1,:), y(1),p);
+        end
+        % end the optimization if the difference between best and worst
+        % function evaluation in simplex is smaller than tolfun and the
+        % max difference between the coordinates of the verttices is less than
+        % tolx
+        if abs(max(y)-min(y)) < tolfun && max(max(abs(p(2:ndim+1)-p(1:ndim)))) < tolx,
+            break;
+        end
+        % check number of iterations
+        if toc/60 > maxtime,
+            EXITFLAG = 0;
+            disp('Exceeded maximum time.');
+            break;
+        end
+        if stopOptimization == 1,
+            disp('User Interrupt.');
+            break;
+        end
+        % Begin a new iteration. First extrapolate by a factor -1 through the face of the simplex
+        % across from the high point, i.e., reflect the simplex from the high point.
+        [yftry, ytry,ptry] = amotry(FUN, p, -1);
+        % check the result
+        if yftry <= yfluct(1),
+            % Gives a result better than the best point, so try an additional
+            % extrapolation by a factor 2.
+            [yftryexp, ytryexp,ptryexp] = amotry(FUN, p, -2);
+            if yftryexp < yftry,
+                p(end,:) = ptryexp;
+                y(end) = ytryexp;
+                algostep = 'extrapolation';
+            else
+                p(end,:) = ptry;
+                y(end) = ytry;
+                algostep = 'reflection';
+            end
+        elseif yftry >= yfluct(ndim),
+            % The reflected point is worse than the second-highest, so look
+            % for an intermediate lower point, i.e., do a one-dimensional
+            % contraction.
+            [yftrycontr,ytrycontr,ptrycontr] = amotry(FUN, p, -0.5);
+            if yftrycontr < yfluct(end),
+                p(end,:) = ptrycontr;
+                y(end) = ytrycontr;
+                algostep = 'one dimensional contraction';
+            else
+                % Can’t seem to get rid of that high point. Better contract
+                % around the lowest (best) point.
+                x = ones(ndim,ndim)*diag(p(1,:));
+                p(2:end,:) = 0.5*(p(2:end,:)+x);
+                for k=2:ndim,
+                    y(k) = costFunction(FUN,p(k,:));
+                end
+                algostep = 'contraction around best point';
+            end
+        else
+            % if ytry better than second-highest point then use this point
+            p(end,:) = ptry;
+            y(end) = ytry;
+            algostep = 'reflection';
+        end
+        nriterations = nriterations + 1;
+    end
+    % Break because of max number iterations, max time, minimum found
+    % (tolerances)
+    if itertemp < MAXITERTEMP,
+        break;
+    end
+    Temp = Temp*tempfactor;
+    % Break because 0 temperature has been run
+    if Temp == 0,
+        break;
+    end
+end
+X = pbest;
+FVAL = ybest;
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% AMOTRY FUNCTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [yftry,ytry,ptry] = amotry(FUN, p, fac)
+% Extrapolates by a factor fac through the face of the simplex across from 
+% the high point, tries it, and replaces the high point if the new point is 
+% better.
+global ndim nfunk Temp lowbounds highbounds tempstart
+psum = sum(p(1:ndim,:))/ndim;
+ptry = psum*(1-fac) + p(end,:)*fac;
+
+% Deal with low and high parameter bounds
+indexXhi = find(ptry > highbounds);
+indexXlo = find(ptry < lowbounds);
+for k=1:length(indexXhi),
+    ptry(indexXhi(k)) = highbounds(indexXhi(k))-rand(1)*(highbounds(indexXhi(k))-lowbounds(indexXhi(k)))*Temp/tempstart;
+end
+for k=1:length(indexXlo),
+    ptry(indexXlo(k)) = lowbounds(indexXlo(k))+rand(1)*(highbounds(indexXlo(k))-lowbounds(indexXlo(k)))*Temp/tempstart;
+end
+
+% Evaluate the function at the trial point.
+ytry = costFunction(FUN,ptry);
+yftry = ytry - Temp*abs(log(rand(1)));
+nfunk = nfunk + 1;
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% COST FUNCTION EVALUATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [ytry] = costFunction(FUN,ptry)
+global ybest pbest lowbounds highbounds
+ytry = feval(FUN,ptry);
+% save the best point ever (only if it is feasible, that is it fits the
+% high and low bounds)
+indexXhi = find(ptry > highbounds);
+indexXlo = find(ptry < lowbounds);
+if ytry < ybest && isempty(indexXhi) && isempty(indexXlo),
+    ybest = ytry;
+    pbest = ptry;
+end    
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/optimization/simplexIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/optimization/simplexIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..e144d648fc9a899bdfa0215a722b353c23c2f36b
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/optimization/simplexIQM.m	
@@ -0,0 +1,391 @@
+function [X,FVAL,EXITFLAG] = simplexIQM(varargin)
+% simplexIQM: Downhill Simplex Method in Multidimensions. Algorithm based on
+% section 10.4 in "Numerical Recipes in C", ISBN 0-521-43108-5.
+% The algorithm has been modified in order to be able to take into account
+% simple box constraints on parameter values. 
+%
+% If global variable stopOptimization is set to 1, the optimization is
+% stopped. This allows for stopping parameter estimation functions on user
+% request. 
+% 
+% USAGE:
+% ======
+% [info] = simplexIQM()
+% [X,FVAL,EXITFLAG] = simplexIQM(FUN,X,OPTIONS)
+%
+% FUN: Function to optimize
+% X: Starting Guess
+% OPTIONS: structure containing options for the algorithm:
+%        OPTIONS.maxfunevals: Maximum number of function evaluations
+%        OPTIONS.maxiter: Maximum number of iterations
+%        OPTIONS.maxtime: Maximum time (in minutes) for optimization
+%        OPTIONS.tolfun: Tolerance for difference between best and worst
+%                        function evaluation in simplex
+%        OPTIONS.tolx: Tolerance for max difference between the coordinates of
+%                      the vertices.
+%        OPTIONS.highbounds: vector containing upper bounds for parameters
+%           Instead of a vector highbounds can also be a scalar > 1. In the
+%           latter case the highbounds are determined by multiplying this
+%           scalar to the initial parameter guess X. This latter case works
+%           only for positive X(i) ... if negative present then the user
+%           needs to specify a whole highbounds vector. 
+%           If argument is empty ([]) then highbounds are set to +Inf;
+%        OPTIONS.lowbounds: vector containing lower bounds for parameters.
+%           Instead of a vector lowbounds can also be a scalar < 1. In the
+%           latter case the lowbounds are determined by multiplying this
+%           scalar to the initial parameter guess X. This latter case works
+%           only for positive X(i) ... if negative present then the user
+%           needs to specify a whole lowbounds vector. 
+%           If argument is empty ([]) then lowbounds are set to -Inf;
+%        OPTIONS.outputFunction: string with output function name. If
+%               not given or if empty then no output function will be used.
+%               This output function can be used to display data, or to 
+%               save optimization information to a file. The function needs
+%               to be in the MATLAB path. Its calling syntax is:
+%                   'outputFunction'(bestparameters,bestfunctionvalue,currentsimplex)
+%        OPTIONS.silent: =0: output of info, =1: no output
+%
+% DEFAULT VALUES:
+% ===============
+% OPTIONS.maxfunevals:    200*numberVariables
+% OPTIONS.maxiter:        200*numberVariables
+% OPTIONS.maxtime:        120
+% OPTIONS.tolx:           1e-10
+% OPTIONS.tolfun:         1e-10
+% OPTIONS.lowbounds:      1e-3  => lowbounds = 1e-3*X 
+% OPTIONS.highbounds:     1e3   => highbounds = 1e3*X 
+% OPTIONS.outputFunction: no output function ('')
+% OPTIONS.silent:         0 (no output of info)
+%
+% Output Arguments:
+% =================
+% info: calling the function w/o input argument returns information about
+%       the options and a flag indicating if the algorithm can handle
+%       constraints or not
+% X: Found solution
+% FVAL: Value of the function FUN at X
+% EXITFLAG: 1=success, 0=not found
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GLOBAL VARIABLES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+global ndim nfunk Xguess lowbounds highbounds stopOptimization
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin == 0,
+    X = [];
+    X.name = 'simplexIQM';
+    X.constrained = 1;
+    X.description = 'Nelder-Mead nonlinear simplex (local)';    
+    X.defaultOptions.names = {'maxfunevals', 'maxiter', 'tolfun', 'tolx'};
+    X.defaultOptions.values = {'50000','20000','1e-10','1e-10'};
+    X.defaultOptions.description = {'Maximum number of function evaluations', 'Maximum number of iterations', 'Termination tolerance on the function value', 'Termination tolerance on X'};
+    FVAL = [];
+    EXITFLAG = [];
+    return
+elseif nargin == 2,
+    FUN = varargin{1};
+    X = varargin{2};
+    OPTIONS = [];
+elseif nargin == 3,
+    FUN = varargin{1};
+    X = varargin{2};
+    OPTIONS = varargin{3};
+else
+    error('Incorrect number of input arguments.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Set default values
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+EXITFLAG = 1;
+ndim = length(X);
+maxfunevals = 200*ndim;
+maxiter = 200*ndim;
+maxtime = 120;
+tolx = 1e-10;
+tolfun = 1e-10;
+outputFunction = '';
+lowbounds = 1e-3*X;
+highbounds = 1e3*X;
+silent = 0;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle OPTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% silent
+if isfield(OPTIONS,'silent'),
+    if ~isempty(OPTIONS.silent),
+        silent = OPTIONS.silent;
+    end
+end
+% tolfun
+if isfield(OPTIONS,'tolfun'),
+    if ~isempty(OPTIONS.tolfun),
+        tolfun = OPTIONS.tolfun;
+    end
+end
+% tolx
+if isfield(OPTIONS,'tolx'),
+    if ~isempty(OPTIONS.tolx),
+        tolx = OPTIONS.tolx;
+    end
+end
+% maxiter
+if isfield(OPTIONS,'maxtime'),
+    if ~isempty(OPTIONS.maxtime),
+        maxtime = OPTIONS.maxtime;
+    end
+end
+% maxiter
+if isfield(OPTIONS,'maxiter'),
+    if ~isempty(OPTIONS.maxiter),
+        maxiter = OPTIONS.maxiter;
+    end
+end
+% maxfunevals
+if isfield(OPTIONS,'maxfunevals'),
+    if ~isempty(OPTIONS.maxfunevals),
+        maxfunevals = OPTIONS.maxfunevals;
+    end
+end
+% outputFunction
+outputFunction = '';
+if isfield(OPTIONS,'outputFunction'),
+    if ~isempty(OPTIONS.outputFunction),
+        outputFunction = OPTIONS.outputFunction;
+    end
+end
+% low and highbounds:
+[lowbounds, highbounds] = handleLowHighBoundsIQM(OPTIONS,X,lowbounds,highbounds);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INITIALIZE EMPTY SIMPLEX DATA
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+p = zeros(ndim+1,ndim);     % vertice vectors in rows
+y = zeros(ndim+1,1);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% FIRST POINT OF INITIAL SIMPLEX
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+Xguess = X(:)'; 
+p(1,:) = Xguess;    
+y(1) = feval(FUN,Xguess);
+
+if ~silent,
+    disp(' Nr Iter    Nr Fun Eval         Min function          Algorithm Step');
+    disp(sprintf(' %5.0f        %5.0f           %12.6g            %s', 0, 1, y(1), 'initial guess'));
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% RESTART MODIFICATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+finished = 0;
+ndimmult = 20;  % factor for ndim to get the number of iterations to do until restart (adapted later)
+OLDmeanimprovement = 1/eps;
+nriterations = 1;
+nfunk = ndim+1;
+
+while ~finished,
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % REMAINING POINTS OF INITIAL SIMPLEX
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % construct vertices by modifying one element each
+    % relative changes in case that elements are non-zero,
+    % absolute changes in case that elements are zero
+    relativeDelta = 0.05;
+    absoluteDelta = 0.00025;
+    for k = 1:ndim
+        Xmodify = p(1,:);
+        if Xmodify(k) == 0
+            % absolute change
+            if highbounds(k) > absoluteDelta,
+                Xmodify(k) = absoluteDelta;
+            else
+                Xmodify(k) = -absoluteDelta;
+            end
+        else
+            % relative change
+            Xmodify(k) = (1 + relativeDelta)*Xmodify(k);
+        end
+        p(k+1,:) = Xmodify;
+        y(k+1) = feval(FUN,Xmodify);
+    end
+    algostep = 'initial simplex';
+
+    % if output function given then run output function to plot
+    % intermediate result
+    if ~isempty(outputFunction),
+        feval(outputFunction,p(1,:), y(1),p);
+    end
+
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % MAIN ALGORITHM
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % reorder y and p so that the first row corresponds to the
+    % lowest function value
+    tic % start timer
+counter = 1;    
+fvalues_history = [];    
+    while(1),
+        % do sorting instead of determining the indices of the best, worst,
+        % next worst
+        help = sortrows([y,p],1);
+        y = help(:,1);
+        p = help(:,2:end);
+        if ~silent,
+            disp(sprintf(' %5.0f        %5.0f           %12.6g            %s', nriterations, nfunk, y(1), algostep));
+        end
+        
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE THE RESTART OF THE SIMPLEX
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% collect information about the improvement in the last 2*ndim iterations
+fvalues_history(end+1) = y(1);
+if counter > ndimmult*ndim,
+    meanimprovement = mean(fvalues_history(end-2*ndim:end-1)-fvalues_history(end-2*ndim+1:end));
+    if OLDmeanimprovement-100*eps(OLDmeanimprovement) >= meanimprovement,
+        ndimmult = ndimmult*1.5;
+%        disp('Restart later')
+    else
+        ndimmul = ndimmult*0.9;
+%        disp('Restart earlier');
+    end   
+    OLDmeanimprovement = meanimprovement;
+    finished = 0; % make a restart at current optimum
+    break;
+end
+counter = counter + 1;
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE THE RESTART OF THE SIMPLEX - END
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        
+        % if output function given then run output function to plot
+        % intermediate result
+        if ~isempty(outputFunction),
+            feval(outputFunction,p(1,:), y(1),p);
+        end
+        % end the optimization if the difference between best and worst
+        % function evaluation in simplex is smaller than tolfun and the
+        % max difference between the coordinates of the verttices is less than
+        % tolx
+        if abs(y(end)-y(1)) < tolfun && max(max(abs(p(2:ndim+1)-p(1:ndim)))) < tolx,
+            finished = 1; % exit also the restart loop
+            break;
+        end
+        % check number of function evaluations
+        if nfunk >= maxfunevals,
+            EXITFLAG = 0;
+            if ~silent,
+                disp('Exceeded maximum number of function evaluations.');
+            end
+            finished = 1; % exit also the restart loop
+            break;
+        end
+        % check number of iterations
+        if nriterations >= maxiter,
+            EXITFLAG = 0;
+            if ~silent,
+                disp('Exceeded maximum number of iterations.');
+            end
+            finished = 1; % exit also the restart loop
+            break;
+        end
+        if toc/60 > maxtime,
+            EXITFLAG = 0;
+            if ~silent,
+                disp('Exceeded maximum time.');
+            end
+            finished = 1; % exit also the restart loop
+            break;
+        end
+        if stopOptimization == 1,
+            EXITFLAG = 0;
+            disp('User Interrupt.');
+            finished = 1; % exit also the restart loop
+            break;
+        end
+        % Begin a new iteration. First extrapolate by a factor -1 through the face of the simplex
+        % across from the high point, i.e., reflect the simplex from the high point.
+        [ytry,ptry] = amotry(FUN, p, y, -1);
+        % check the result
+        if ytry <= y(1),
+            % Gives a result better than the best point, so try an additional
+            % extrapolation by a factor 2.
+            [ytryexp,ptryexp] = amotry(FUN, p, y, -2);
+            if ytryexp < ytry,
+                p(end,:) = ptryexp;
+                y(end) = ytryexp;
+                algostep = 'extrapolation';
+            else
+                p(end,:) = ptry;
+                y(end) = ytry;
+                algostep = 'reflection';
+            end
+        elseif ytry >= y(ndim),
+            % The reflected point is worse than the second-highest, so look
+            % for an intermediate lower point, i.e., do a one-dimensional
+            % contraction.
+            [ytrycontr,ptrycontr] = amotry(FUN, p, y, -0.5);
+            if ytrycontr < y(end),
+                p(end,:) = ptrycontr;
+                y(end) = ytrycontr;
+                algostep = 'one dimensional contraction';
+            else
+                % Can�t seem to get rid of that high point. Better contract
+                % around the lowest (best) point.
+                x = ones(ndim,ndim)*diag(p(1,:));
+                p(2:end,:) = 0.5*(p(2:end,:)+x);
+                for k=2:ndim,
+                    y(k) = feval(FUN,p(k,:));
+                    nfunk = nfunk+1;
+                end
+                algostep = 'contraction around best point';
+            end
+        else
+            % if ytry better than second-highest point then use this point
+            p(end,:) = ptry;
+            y(end) = ytry;
+            algostep = 'reflection';
+        end
+        nriterations = nriterations + 1;
+    end
+    % do the sorting a last time
+    help = sortrows([y,p],1);
+    y = help(:,1);
+    p = help(:,2:end);
+end
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% RESTART MODIFICATION END
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+X = p(1,:);
+FVAL = y(1);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% AMOTRY FUNCTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [ytry,ptry] = amotry(FUN, p, y, fac)
+% Extrapolates by a factor fac through the face of the simplex across from 
+% the high point, tries it, and replaces the high point if the new point is 
+% better.
+global ndim nfunk lowbounds highbounds
+psum = sum(p(1:ndim,:))/ndim;
+ptry = psum*(1-fac) + p(end,:)*fac;
+
+% Deal with low and high parameter bounds
+indexXhi = find(ptry > highbounds);
+indexXlo = find(ptry < lowbounds);
+ptry(indexXhi) = highbounds(indexXhi);
+ptry(indexXlo) = lowbounds(indexXlo);
+
+% Evaluate the function at the trial point.
+ytry = feval(FUN,ptry);
+nfunk = nfunk + 1;
+return
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMbarplotErrors.m b/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMbarplotErrors.m
new file mode 100644
index 0000000000000000000000000000000000000000..8652ceafacbc454bced3e7096c486b7c1bcc7b2e
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMbarplotErrors.m	
@@ -0,0 +1,254 @@
+function [bar_xtick,hb,he]=IQMbarplotErrors(bar_input,errorbar_input,varargin)
+% IQMbarplotErrors: grouped bar plot with error bars, customizable.
+%
+% IQMbarplotErrors(bar_input,errorbar_input) produces a bar plot of matrix
+% bar_input. Each column corresponds to one group and each element in a
+% column to one bar. The bars are
+% grouped together, similar to the plot produced by BAR(Y,'grouped').
+%
+% If a row vector is passed, it is converted to a column vector to avoid
+% grouping => single group then also used.
+%
+% It then overlays an error bar plot of errorbar_input, the size of which
+% must match that of bar_input. Error bars are assumed to be symmetric
+% around the values of the bar plot, similar to the plot produced by
+% ERRORBAR(Y,E). Note that, if all the values of errorbar_input are set to
+% zero, the function skips plotting the error bars.
+%
+% IQMbarplotErrors(bar_input,errorbar_lower,errorbar_upper) allows
+% the lower and upper bounds of the error bars to be asymmetric around the
+% values of the bar plot, similar to the plot produced by ERRORBAR(Y,L,U).
+%
+% Note that it is impossible to input the X coordinates of the bars using
+% this function.
+%
+% bar_xtick = IQMbarplotErrors(...) returns the X coordinates for the center
+% of each group of bars.
+%
+% [...,hb,he] = IQMbarplotErrors(...) returns the handles to the bars
+% (produced by BAR) and the error bars (produced by ERRORBAR).
+%
+% IQMbarplotErrors(...,'ParameterName',ParameterValue) allows customizing
+% the display.
+%
+% 'bar_width': scalar determining bar width. Must be between 0 and 1. A
+% bar_width value of 1 causes all the bars to touch each other. This
+% parameter is identical to the optional width parameter of BAR. Default
+% value: 0.9.
+%
+% 'errorbar_width': scalar determining error bar width, expressed as a
+% fraction of the width of the bars themselves. Default value: 0.75.
+%
+% 'bar_colors': N-by-3 matrix determing the RGB values for bar colors. You
+% must provide at least as many colors as there are groups in your plot.
+% Default values: from IQMgetcolors()
+%
+% 'errorbar_colors': N-by-3 matrix determining the RGB values for error bar
+% colors. You must provide at least as many colors as there are groups in
+% your plot. Default value: the error bar colors are set to black.
+%
+% 'optional_bar_arguments': cell array containing any 'PropertyName' -
+% 'PropertyValue' input argument pair that you would like to pass on to
+% BAR. Default value: no further input arguments are passed to BAR.
+%
+% 'optional_errorbar_arguments': cell array containing any 'PropertyName' -
+% 'PropertyValue' input argument pair that you would like to pass on to
+% ERRORBAR. Default value: {'LineStyle','none','Marker','none'}
+% (causes ERRORBAR to plot no line between error bars, and no marker at the
+% center of each error bar)
+%
+% 'bar_names': cell string array containing labels to apply to each group
+% of bars. You must provide at least as many labels as there are bars in
+% your plot. Default value: the bars are numbered consecutively, starting
+% from 1.
+%
+% Examples:
+%
+% Basic usage:
+%   bar_input=rand(3,8)/2+0.5;
+%   errorbar_input=rand(3,8)/8;
+%   IQMbarplotErrors(bar_input,errorbar_input);
+%
+% Set the lower bound of the error bars to 0, effectively plotting only the
+% upper bound:
+%   bar_input=rand(4,6)/2+0.5;
+%   errorbar_lower=zeros(size(bar_input));
+%   errorbar_upper=rand(4,6)/8;
+%   IQMbarplotErrors(bar_input,errorbar_lower,errorbar_upper);
+%
+% When plotting fewer groups and bars, the plot might look better with
+% thinner bars and error bars. This also shows how to input custom names
+% for the groups of bars:
+%   bar_input=rand(2,4)/2+0.5;
+%   errorbar_input=rand(2,4)/8;
+%   IQMbarplotErrors(bar_input,errorbar_input, ...
+%       'bar_width',0.75,'errorbar_width',0.5, ...
+%       'bar_names',{'A','B','C','D'});
+%
+% Here is how to pass optional input arguments to BAR and ERRORBAR:
+%   bar_input=rand(2,4)/2+0.5;
+%   errorbar_input=rand(2,4)/8;
+%   IQMbarplotErrors(bar_input,errorbar_input, ...
+%       'bar_width',0.75,'errorbar_width',0.5, ...
+%       'optional_bar_arguments',{'LineWidth',1.5}, ...
+%       'optional_errorbar_arguments',{'LineStyle','none','Marker','none','LineWidth',1.5});
+
+% Author of this function: pierre.megevand@gmail.com
+% Changes to work with R2014B by Henning Schmidt
+%
+% change log:
+% 2014/07/16 -- first uploaded to the MATLAB File Exchange. Does not
+% do anything with the 'grp_names' optional input yet.
+% 2014/07/18 -- The x axis is now adjusted to fit the plot.
+% 2014/07/28 -- With David Groppe's help, added optional figure and axes
+% handles.
+% 2014/08/19 -- Simplified how default parameters are defined. Added option
+% to skip plotting the error bars altogether.
+
+% Make column vector if row vectors
+if isvector(bar_input),
+    bar_input = bar_input(:);
+end
+if isvector(errorbar_input),
+    errorbar_input = errorbar_input(:);
+end
+
+% Interface to function by transposing
+bar_input = bar_input';
+errorbar_input = errorbar_input';
+
+% init defaults for parameters
+[N_grps,N_bars]             = size(bar_input);
+bar_width                   = 0.8;
+errorbar_width              = 0.75;
+bar_colors                  = IQMgetcolors();
+
+% get some distinguishable colors for the bars!
+errorbar_colors             = zeros(N_grps,3); % default errorbar color is black
+optional_bar_arguments      = {}; % there are no default optional arguments for bar
+optional_errorbar_arguments = {'LineStyle','none','Marker','none'}; % default optional arguments for errorbar
+bar_names                   = strtrim(cellstr(num2str((1:N_bars)')));
+grp_names                   = strtrim(cellstr(num2str((1:N_grps)')));
+
+% deal with the input arguments
+if nargin<2 % the indispensable input arguments are not provided
+    error('You need to provide at least ''bar_input'' and ''errorbar_input''.');
+else
+    errorbar_lower=errorbar_input;
+    errorbar_upper=errorbar_input;
+    if any(size(bar_input)~=size(errorbar_input)) % the indispensable input arguments must have the exact same size
+        error('The size of ''bar_input'' and ''errorbar_input'' must be the same.');
+    else
+        if numel(varargin)>0 % optional input arguments are provided
+            if ~ischar(varargin{1}) % if the first optional input argument is not a character array, then by design it must be the upper bound of the error bars, or an error is thrown
+                errorbar_lower=errorbar_input;
+                errorbar_upper=varargin{1};
+                % Adjust errorbar_upper as the other two input arguments above
+                if isvector(errorbar_upper),
+                    errorbar_upper = errorbar_upper(:);
+                end
+                % Interface to function by transposing
+                errorbar_upper = errorbar_upper';
+                if any(size(errorbar_lower)~=size(errorbar_upper))
+                    error('The size of ''errorbar_input_low'' and ''errorbar_input_high'' must be the same.');
+                end
+                varargin(1)=[]; % the first optional argument has been dealt with -- remove...
+            end
+            while ~isempty(varargin)
+                if numel(varargin)<2
+                    error('You need to provide optional input arguments as ''ParameterName''-''ParameterValue'' pairs.');
+                end
+                switch varargin{1}
+                    case 'bar_width'
+                        bar_width=varargin{2};
+                    case 'errorbar_width'
+                        errorbar_width=varargin{2};
+                    case 'bar_colors'
+                        bar_colors=varargin{2};
+                    case 'errorbar_colors'
+                        errorbar_colors=varargin{2};
+                    case 'optional_bar_arguments'
+                        optional_bar_arguments=varargin{2};
+                    case 'optional_errorbar_arguments'
+                        optional_errorbar_arguments=varargin{2};
+                    case 'bar_names'
+                        bar_names=varargin{2};
+                    case 'grp_names'
+                        grp_names=varargin{2};
+                    otherwise
+                        error('Unexpected ''ParameterName'' input: %s\n',varargin{1});
+                end
+                varargin(1:2)=[]; % this pair of optional input arguments has been dealt with -- remove...
+            end
+        end
+    end
+end
+
+% init group width and bar shift
+shift_span                  = (1-bar_width)*(N_grps-1);
+bar_shift                   = linspace(-shift_span/2,+shift_span/2,N_grps);
+
+% compute position of group x ticks
+bar_xtick                   = N_grps/2+0.5:N_grps:N_bars*N_grps-N_grps/2+0.5;
+
+% init handles vectors
+hb                          = zeros(N_grps,1);
+he                          = zeros(N_grps,1);
+
+% Clear current axes ... or create new figure
+cla
+hold on;
+
+% plot the bars themselves
+for grp=1:N_grps
+    hb(grp)=bar( ...
+        (grp:N_grps:N_bars*N_grps-(N_grps-grp))-bar_shift(grp), ... % this is the x position for each bar
+        bar_input(grp,:),  ... % this is the y position for each bar
+        bar_width/N_grps, ... % this is the width of each bar
+        'FaceColor',bar_colors(grp,:), ... % color parameter
+        optional_bar_arguments{:}); % extra parameters
+end
+
+% plot the error bars
+if ~all(all(errorbar_lower==0))&&~all(all(errorbar_upper==0))
+    
+    for grp=1:N_grps
+        he(grp)=errorbar( ...
+            (grp:N_grps:N_bars*N_grps-(N_grps-grp))-bar_shift(grp), ... % this is the x position for each bar
+            bar_input(grp,:),  ... % this is the y position for each bar
+            errorbar_lower(grp,:), ... % this is the error low value for each bar
+            errorbar_upper(grp,:), ... % this is the error high value for each bar
+            'Color',errorbar_colors(grp,:), ... % color parameter
+            optional_errorbar_arguments{:}); % extra parameters
+    end
+        
+    % Set the errorbar widths    
+    if verLessThan('matlab', '8.4'),
+        % Before R2014B
+        he_c=get(he,'Children');
+        if ~iscell(he_c)
+            temp=he_c;
+            he_c=cell(1,1);
+            he_c{1}=temp;
+            clear temp;
+        end
+        for grp=1:N_grps
+            he_xdata=get(he_c{grp}(2),'XData');
+            he_xdata(4:9:end)=he_xdata(1:9:end)-errorbar_width*bar_width/2;
+            he_xdata(7:9:end)=he_xdata(1:9:end)-errorbar_width*bar_width/2;
+            he_xdata(5:9:end)=he_xdata(1:9:end)+errorbar_width*bar_width/2;
+            he_xdata(8:9:end)=he_xdata(1:9:end)+errorbar_width*bar_width/2;
+            set(he_c{grp}(2),'XData',he_xdata);
+        end
+    else
+        % From R2014B
+        % Keep as is for now ... can not find in the objects
+    end
+end
+
+% set the x tick labels
+set(gca,'XTick',bar_xtick,'XTickLabel',bar_names);
+
+% cosmetic fine-tuning of the figure
+set(gca,'XLim',[0 bar_xtick(end)+bar_xtick(1)]); % adjusts the x axis to the plot
+hold off;
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplot2GUI/IQMplot2.fig b/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplot2GUI/IQMplot2.fig
new file mode 100644
index 0000000000000000000000000000000000000000..f5c9c0ad1fdc288991f62739753a4b86fa804194
Binary files /dev/null and b/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplot2GUI/IQMplot2.fig differ
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplot2GUI/IQMplot2.m b/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplot2GUI/IQMplot2.m
new file mode 100644
index 0000000000000000000000000000000000000000..d510ab5a872e76ecce0d849f28da79dc9484b82d
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplot2GUI/IQMplot2.m	
@@ -0,0 +1,529 @@
+function varargout = IQMplot2(varargin)
+% IQMplot2 - plots bar diagrams for given data.
+%
+% USAGE:
+% ======
+%
+% [] = IQMplot2(datastruct1)
+% [] = IQMplot2(datastruct1,datastruct2)
+% [] = IQMplot2(datastruct1,datastruct2, ..., datastruct10)
+%
+% datastruct1-10: structure with datasets information. IQMplot2 can accept up
+%   to  10 different datastructures which can be displayed. The structure
+%   of the input arguments is defined as follows:
+%
+%       datastruct.name                 descriptive name for the
+%                                       datastructure
+%       datastruct.xnames:              cell-array with names of x-axis data
+%       datastruct.ynames:              cell-array with names of y-axis data 
+%       datastruct.data:                matrix with y-axis data in rows and
+%                                       x-axis data in columns 
+%       datastruct.title:               a title for the plot
+%       datastruct.xlabel:              label for the x-axis
+%       datastruct.xaxistitle:          text describing the x-axis
+%                                       selection box 
+%       datastruct.yaxistitle:          text describing the y-axis
+%                                       selection box 
+%
+%   All fields of the structure need to be correctly initialized
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+% Begin initialization code - DO NOT EDIT
+gui_Singleton = 1;
+gui_State = struct('gui_Name',       mfilename, ...
+                   'gui_Singleton',  gui_Singleton, ...
+                   'gui_OpeningFcn', @IQMplot2_OpeningFcn, ...
+                   'gui_OutputFcn',  @IQMplot2_OutputFcn, ...
+                   'gui_LayoutFcn',  [] , ...
+                   'gui_Callback',   []);
+if nargin && ischar(varargin{1})
+    gui_State.gui_Callback = str2func(varargin{1});
+end
+if nargout
+    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
+else
+    gui_mainfcn(gui_State, varargin{:});
+end
+% End initialization code - DO NOT EDIT
+
+% --- Executes just before IQMplot2 is made visible.
+function IQMplot2_OpeningFcn(hObject, eventdata, handles, varargin)
+% determine number of arguments passed to IQMplot2 by the
+% user. Each argument is assumed to correspond to one datastructure
+nvarargin = nargin-3;
+% process variable arguments
+if nvarargin > 10,
+    error('To many input arguments (max. is 10).');
+end
+handles.dataSets = varargin;            % save all datasets in handles
+handles = switchDataSet(handles,1);     % switch to first dataset
+% Initialize datasets pulldown menu
+datasetnames = {};
+for k = 1:length(handles.dataSets),
+    datasetnames{k} = handles.dataSets{k}.name;
+end
+set(handles.datasets,'String',datasetnames);
+% Initialize export figure handle
+handles.exportFigureHandle = [];
+% do not plot magnitudes per default
+handles.magnitudeFlag = 1;
+set(handles.magnitude,'Value',1);
+% no grid per default 
+handles.grid = 0;
+% set plot option data
+set(handles.minmax,'Value',1);
+set(handles.mean,'Value',0);
+set(handles.median,'Value',1);
+set(handles.ordered,'Value',0);
+% Initialize figure with minmax data
+set(handles.xaxisselection,'Value',[1:length(handles.xnames)]);
+set(handles.yaxisselection,'Value',[1:length(handles.ynames)]);
+handles.plotType = 'MinMax';
+doAllPlot(handles);
+% Initialize output of function
+handles.output = hObject;
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% OUTPUT FUNCTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function varargout = IQMplot2_OutputFcn(hObject, eventdata, handles) 
+varargout{1} = handles.output;
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DATASETS SELECTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function datasets_Callback(hObject, eventdata, handles)
+dataSetIndex = get(handles.datasets,'Value');
+handles = switchDataSet(handles,dataSetIndex); 
+set(handles.xaxisselection,'Value',[1:length(handles.xnames)]);
+set(handles.yaxisselection,'Value',[1:length(handles.ynames)]);
+handles.plotType = 'MinMax';
+doAllPlot(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% X-AXIS SELECTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function xaxisselection_Callback(hObject, eventdata, handles)
+doAllPlot(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Y-AXIS SELECTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function yaxisselection_Callback(hObject, eventdata, handles)
+doAllPlot(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% MIN-MAX PLOT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function minmaxplot_Callback(hObject, eventdata, handles)
+if strcmp(handles.plotType,'MinMax'),
+    handles.plotType = 'Plot';
+else
+    handles.plotType = 'MinMax';
+end
+doAllPlot(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% ALLOW MIN MAX BARS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function minmax_Callback(hObject, eventdata, handles)
+doAllPlot(handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% ALLOW MEAN VALUES PLOTTED
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function mean_Callback(hObject, eventdata, handles)
+doAllPlot(handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% ALLOW MEAN VALUES PLOTTED
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function median_Callback(hObject, eventdata, handles)
+doAllPlot(handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% ORDER PLOT VALUES 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function ordered_Callback(hObject, eventdata, handles)
+orderedFlag = get(handles.ordered,'Value');
+if orderedFlag == 1,
+    set(handles.ordered,'Value',1)
+else
+    set(handles.ordered,'Value',0)
+end
+doAllPlot(handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% TOGGLE MAGNITUDE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function magnitude_Callback(hObject, eventdata, handles)
+if handles.magnitudeFlag == 1,
+    handles.magnitudeFlag = 0;
+else
+    handles.magnitudeFlag = 1;
+end
+doAllPlot(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% TOGGLE ZOOM
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function zoombutton_Callback(hObject, eventdata, handles)
+% toogle the zoom in the figure
+zoom
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% TOGGLE GRID
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function gridbutton_Callback(hObject, eventdata, handles)
+% toogle the grid in the figure
+grid
+if handles.grid == 1,
+    handles.grid = 0;
+else 
+    handles.grid = 1;
+end
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EXPORT FIGURE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function export_Callback(hObject, eventdata, handles)
+if isempty(handles.exportFigureHandle),
+    figH = figure;
+    handles.exportFigureHandle = figH;
+    % Update handles structure
+    guidata(hObject, handles);
+else
+    figH = handles.exportFigureHandle;
+    figure(figH);
+end
+nrow = str2num(get(handles.nrow,'String'));
+ncol = str2num(get(handles.ncol,'String'));
+nnumber = str2num(get(handles.nnumber,'String'));
+subplot(nrow,ncol,nnumber);
+doAllPlot(handles);
+titlestring = handles.titletext;
+if strcmp(handles.plotType,'MinMax'),
+    titlestring = sprintf('%s (MinMax View)',titlestring);
+end
+if handles.magnitudeFlag == 1,
+    titlestring = sprintf('Magnitude of %s',titlestring);
+end
+hlhlx = title(titlestring);
+set(hlhlx,'Interpreter','none');
+if handles.grid == 1,
+    grid;
+end
+hlhlx = xlabel(handles.xlabeltext);
+set(hlhlx,'Interpreter','none');
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% REQUEST NEW EXPORT FIGURE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function newexportfigure_Callback(hObject, eventdata, handles)
+handles.exportFigureHandle = [];
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% SWITCH GIVEN DATASETS 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [handles] = switchDataSet(handles,indexDataSet)
+dataSet = handles.dataSets{indexDataSet};
+handles.name = dataSet.name;
+handles.xnames = dataSet.xnames;
+handles.ynames = dataSet.ynames;
+handles.data = dataSet.data;
+handles.titletext = dataSet.title;
+handles.xlabeltext = dataSet.xlabel;
+handles.xaxistitle = dataSet.xaxistitle;
+handles.yaxistitle = dataSet.yaxistitle;
+% set information in the selection fields and figure descriptions
+set(handles.xaxisselection,'String',handles.xnames);
+set(handles.yaxisselection,'String',handles.ynames);
+set(handles.xaxistext,'Title',handles.xaxistitle);
+set(handles.yaxistext,'Title',handles.yaxistitle);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GLOBAL PLOT FUNCTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function doAllPlot(handles)
+if strcmp(handles.plotType,'MinMax'),
+    set(handles.ordered,'Visible','on');
+    set(handles.minmaxplot,'Value',1);
+    set(handles.minmax,'Visible','on');
+    set(handles.mean,'Visible','on');
+    set(handles.median,'Visible','on');
+    doPlotMinMax(handles);
+else
+    nx = length(get(handles.xaxisselection,'Value'));
+    ny = length(get(handles.yaxisselection,'Value'));
+    if nx == 1 || ny == 1,
+        set(handles.ordered,'Visible','on');
+    else
+        set(handles.ordered,'Visible','off');
+    end
+    set(handles.minmaxplot,'Value',0);
+    set(handles.minmax,'Visible','off');
+    set(handles.mean,'Visible','off');
+    set(handles.median,'Visible','off');
+    doPlot(handles);
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PLOT FUNCTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function doPlot(handles)
+hold off;
+colormap default;
+if handles.magnitudeFlag == 1,
+    set(handles.title,'String',sprintf('Magnitude of %s',handles.titletext));
+else
+    set(handles.title,'String',handles.titletext);
+end
+set(handles.xlabel,'String',handles.xlabeltext);
+xnames = handles.xnames;
+ynames = handles.ynames;
+data = handles.data;
+% use magnitudes if desired
+if handles.magnitudeFlag == 1,
+    data = abs(data);
+end
+% get variables that are chosen for the y-axis
+xindex = get(handles.xaxisselection,'Value');
+n = length(xindex);
+% get variables that are chosen for the y-axis
+yindex = get(handles.yaxisselection,'Value');
+% get corresponding data values
+xydata = data(yindex,xindex);
+% adjust for the case where single parameter chosen (bar function then has
+% problems)
+if n == 1,
+    xindex = [xindex xindex+1];
+    xydata = [xydata zeros(size(xydata))];
+    n = 2;
+    nold = 1;
+else
+    nold = n;
+end
+% check if ordering necessary
+orderedVisible = get(handles.ordered,'Visible');
+orderedFlag = get(handles.ordered,'Value');
+nx = length(get(handles.xaxisselection,'Value'));
+ny = length(get(handles.yaxisselection,'Value'));
+xindexordered = xindex;
+yindexordered = yindex;
+if strcmp(orderedVisible,'on') && orderedFlag == 1 && ~( nx == 1 && ny == 1 ),
+    % do order the data for display
+    if ny == 1,
+        ordering = [[1:nx]',xydata'];
+        ordering = sortrows(ordering,-2);
+        neworder = ordering(:,1)';
+        xydata = ordering(:,2:end)';
+        xindexordered = xindex(neworder);
+        yindexordered = yindex;
+    end
+    if nx == 1,
+        ordering = [[1:ny]',xydata];
+        ordering = sortrows(ordering,-2);
+        neworder = ordering(:,1)';
+        xydata = ordering(:,2:end);
+        xindexordered = xindex;
+        yindexordered = yindex(neworder);
+    end
+end
+bar([1:n], xydata');
+% draw a legend
+hlhlx=legend(ynames{yindexordered});
+set(hlhlx,'Interpreter','none');
+% get axes handle
+axesH = gca;
+% use magnitudes if desired
+if handles.magnitudeFlag == 1,
+    yMax = 1.5*max(max(xydata));
+    yMin = 0;
+else
+    yMax = 1.5*max(max(xydata));
+    yMin = 1.5*min(min(xydata));
+end
+if yMax == 0, yMax = yMin+1; end
+axis([0 n+1 yMin yMax]);
+set(axesH,'XTick',1:n);
+if nold == 1,
+    set(axesH,'XTickLabel',{xnames{xindex(1)}, ''});
+else 
+    set(axesH,'XTickLabel',xnames(xindexordered));
+end
+set(axesH,'YScale','linear');
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% MinMax PLOT FUNCTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function doPlotMinMax(handles)
+hold off;
+if handles.magnitudeFlag == 1,
+    set(handles.title,'String',sprintf('Magnitude of %s (MinMax View)',handles.titletext));
+else
+    set(handles.title,'String',sprintf('%s (MinMax View)',handles.titletext));
+end
+set(handles.xlabel,'String',handles.xlabeltext);
+% plot min max and median value for all given data
+xnames = handles.xnames;
+ynames = handles.ynames;
+data = handles.data;
+% get variables that are chosen for the y-axis
+xindex = get(handles.xaxisselection,'Value');
+xnames = xnames(xindex);
+% get variables that are chosen for the y-axis
+yindex = get(handles.yaxisselection,'Value');
+ynames = ynames(yindex);
+% get corresponding data values
+data = data(yindex,xindex);
+if length(ynames) == 1,
+    ynames = {ynames, ''};
+    data = [data; zeros(1,length(data))];
+    nold = 1;
+else
+    nold = length(ynames);
+end
+% use magnitudes if desired
+if handles.magnitudeFlag == 1,
+    data = abs(data);
+    yMax = 1.5*max(max(data));
+    yMin = 0;
+else
+    yMax = 1.5*max(max(data));
+    yMin = 1.5*min(min(data));
+end 
+if yMax == 0, yMax = yMin+1; end
+% determine min, max, ans median values of the data for each point on the x-axis
+% catch the case where only one row of data (corresponds to one component only)
+% then need to multiply all values by 2
+maxData = max(data);
+minData = min(data);
+medianData = median(data);
+meanData = mean(data);
+if nold == 1,
+    maxData = 2*maxData;
+    minData = 2*minData;
+    medianData = 2*medianData;
+    meanData = 2*meanData;
+end
+% check if ordering necessary
+orderedVisible = get(handles.ordered,'Visible');
+orderedFlag = get(handles.ordered,'Value');
+nx = length(xnames);
+ny = length(ynames);
+xindexordered = 1:nx;
+if strcmp(orderedVisible,'on') && orderedFlag == 1 && nx > 1 && ny > 1,
+    % do order the data for display
+    ordering = [[1:nx]' maxData(:) minData(:) medianData(:) meanData(:)];
+    % sort after mean value if mean and median or nothing checked
+    % otherwise sort after the checked one
+    meanFlag = get(handles.mean,'Value');
+    medianFlag = get(handles.median,'Value');
+    if (meanFlag == 1 && medianFlag == 1) || (meanFlag == 0 && medianFlag == 0)
+        % sort after mean value
+        ordering = sortrows(ordering,-5);
+    elseif meanFlag == 1,
+        % sort after mean value
+        ordering = sortrows(ordering,-5);
+    else
+        % sort after median value
+        ordering = sortrows(ordering,-4);
+    end
+    neworder = ordering(:,1);
+    maxData = ordering(:,2);
+    minData = ordering(:,3);
+    medianData = ordering(:,4);
+    meanData = ordering(:,5);
+    xindexordered = xindexordered(neworder);
+end
+if nold == 1,
+    maxData = meanData;
+    minData = meanData;
+    medianData = meanData;
+end
+% do the plotting
+n = length(maxData);
+axesH = gca;
+mybar(minData,medianData,meanData,maxData,handles);
+axis([0 n+1 yMin yMax]);
+set(axesH,'XTick',1:n);
+set(axesH,'XTickLabel',xnames(xindexordered));
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% mybar plot function
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [] = mybar(minData,medianData,meanData,maxData,handles)
+n = length(minData);
+% plot the bars indicating min and max values of the sensitivities
+minmaxFlag = get(handles.minmax,'Value');
+meanFlag = get(handles.mean,'Value');
+medianFlag = get(handles.median,'Value');
+if minmaxFlag,
+    for k = 1:n,
+        fill([k-0.4,k+0.4,k+0.4,k-0.4],[minData(k) minData(k) maxData(k) maxData(k)],[1 0.9 0.8]); hold on;
+    end
+end
+if medianFlag,
+    for k = 1:n,
+        plot([k-0.4 k+0.4],[medianData(k) medianData(k)],'r'); hold on;
+    end
+end
+if meanFlag,
+    for k = 1:n,
+        plot([k-0.4 k+0.4],[meanData(k) meanData(k)],'b'); hold on;
+    end
+end
+return
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplotCatCat.m b/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplotCatCat.m
new file mode 100644
index 0000000000000000000000000000000000000000..7f35f3058d2da729bc2a0b99bf30d1d2db7601c8
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplotCatCat.m	
@@ -0,0 +1,444 @@
+function [] = IQMplotCatCat(data,catNames,compareNames,options)
+% This function plots a "bubble" plot for categorical data. This allows to
+% at least graphically explore correlations between different categorical
+% covariates. Areas of circles are proportional to the fraction.
+%
+% There are 2 cases. Either all categorical covariates are compared to each
+% other (only catNames provided). Or categorical covariates are compared to
+% categorical covariates, defined by compareNames.
+%
+% [SYNTAX]
+% [] = IQMplotCatCat(data,catNames)
+% [] = IQMplotCatCat(data,catNames,compareNames)
+% [] = IQMplotCatCat(data,catNames,compareNames,options)
+%
+% [INPUT]
+% data:         Matlab dataset. Each column corresponds to a variable
+%               and each row to a sample. The columns with the names
+%               defined in "catNames" need to be present in
+%               the dataset and contain numerical categorical data.
+% catNames:     Cell-array with names of categorical variables
+% compareNames: Cell-array with names of categorical variables to compare
+%               with the categorical covariates in catNames
+% options:      Matlab structure with additional options
+%       options.percent: Show percentages instead of numbers. Percentages
+%                        are calculated relative to the number in the bins
+%                        of the catNames and only displayed if compared to
+%                        compareNames. =0 do show numbers and percent. =1 show
+%                        percent (default) =2 show numbers and percent.
+%       options.bubbleSize: Factor to change size of bubbles (default: 500)
+%       options.fontSizeText: Fontsize for the number and percent text
+%                             (default: 10)
+%       options.hideFirstRow: Hides first row with bars in case
+%                             compareNames is used. =0: not hide (default),
+%                             =1: hide (default)
+%       options.color:  Color of bubbles default: 0.4*[1 1 1]
+%
+% [OUTPUT]
+% Plot
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+% Check if data is table
+if ~istable(data),
+    error('Input data needs to be provided as MATLAB table.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check which case it is and handle each case completely separately
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin==2,
+    compareNames = {};
+    options = [];
+end
+if nargin==3,
+    options = [];
+end
+
+try percentFlag = options.percent; catch, percentFlag = 1; end
+try bubbleSize  = options.bubbleSize; catch, bubbleSize  = 500; end
+try fontSizeText  = options.fontSizeText; catch, fontSizeText  = 10; end
+try hideFirstRow  = options.hideFirstRow; catch, hideFirstRow  = 0; end
+try color  = options.color; catch, color = 0.4*[1 1 1]; end
+
+% Subindex properties
+Spacing = 0.0005;
+Padding = 0.001;
+Margin  = .1;
+
+% Define fontsize
+if length(catNames)<=6,
+    FONTSIZE = 10;
+else
+    FONTSIZE = 10;
+end
+
+if isempty(compareNames),
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Handle first case (compare all catNames with each other)
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Check if dataset contains defined columns
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    for k=1:length(catNames),
+        try
+            data.(catNames{k});
+        catch
+            error(sprintf('Please check if "%s" is a column in the dataset!',catNames{k}));
+        end
+    end
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Keep only selected columns
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    data = data(:,catNames);
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % If is table then convert to double
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    if istable(data),
+        data = table2array(data);
+    end
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Keep only selected columns
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+       
+    clf;
+    n = length(catNames);
+    for ir=1:n
+        ystr = catNames{ir};
+        y = data(:,ir);
+        for ic=1:ir
+            xstr = catNames{ic};
+            x = data(:,ic);
+            ip = (ir-1)*n+ic;
+            subaxis(n,n,ip,'Spacing',Spacing,'Padding',Padding,'Margin',Margin);
+            if ir==ic % plot "histogram"
+                
+                xu = unique(x);
+                xu = xu(~isnan(xu));
+                b  = zeros(size(xu));
+                nu = length(xu);
+                for i=1:nu
+                    b(i) = sum(x==xu(i));
+                end
+                h = bar(1:nu,b,0.5);
+                
+                % Write out numbers
+                for knr=1:length(b),
+                    aaa = get(gca,'YLim');
+                    text(knr,b(knr)+max(aaa)*0.02,sprintf('%d',b(knr)),'VerticalAlign','bottom','HorizontalAlign','center','FontSize',fontSizeText+2);
+                end
+                
+                set(h,'FaceColor',color)
+                set(gca,'XLim',[0.5 nu+.5]);
+                title(xstr,'Interpreter','none')
+                set(gca,'YTick',[]);
+                set(gca,'XTick',[]);
+                set(gca,'YLim',[0 max(b)*1.3]);
+                set(gca,'FontSize',fontSizeText);
+                              
+                if ir==1,
+                    ylabel('#','FontSize',8);
+                end
+                
+                if ir==n
+                    xlabel(xstr,'Interpreter','none','FontSize',fontSizeText);
+                    set(gca,'XTick',1:length(xu))
+                    set(gca,'XTickLabel',xu);
+                end
+                
+            else % plot bubble plot
+                % Exchange x categories for numbers 1:N
+                xu = unique(x);
+                iu = {};
+                for k=1:length(xu),
+                    iu{k} = find(x==xu(k));
+                end
+                xn = NaN(size(x));
+                for k=1:length(iu),
+                    xn(iu{k}) = k;
+                end
+                
+                % Exchange y categories for numbers 1:N
+                yu = unique(y);
+                iu = {};
+                for k=1:length(yu),
+                    iu{k} = find(y==yu(k));
+                end
+                yn = NaN(size(y));
+                for k=1:length(iu),
+                    yn(iu{k}) = k;
+                end
+                
+                % Find unique pairs of xn and yn (these will be plotted in the
+                % bubble plot
+                [pairs,~,b] = unique([xn yn],'rows');
+                
+                % Determine number of rows in [xn yn] with these pairs
+                nr_pairs = NaN(size(pairs,1),1);
+                
+                for k=1:size(pairs,1),
+                    nr_pairs(k) = sum(b==k);
+                end
+                
+                % Determine relative number of pairs in fraction
+                nr_pairs_fraction = nr_pairs/sum(nr_pairs);
+                
+                % Determine size based on fraction
+                use_size = bubbleSize*nr_pairs_fraction;
+                
+                % Determine default color
+                color_use = color(ones(1,length(nr_pairs)),:);
+                
+                % Plot
+                scatter(pairs(:,1),pairs(:,2), use_size, color_use, 'filled', 'MarkerEdgeColor', 'none');
+                
+                % Annotate
+                set(gca,'XLim',[min(xn)-0.5 max(xn)+0.5])
+                set(gca,'YLim',[min(yn)-0.5 max(yn)+0.5])
+                
+                % Write out percentage as text
+                for knr=1:size(pairs,1),
+                    text(pairs(knr,1)+0.025,pairs(knr,2)+0.2,sprintf('%d',nr_pairs(knr)),'FontSize',FONTSIZE);
+                end
+                
+                set(gca,'XTick',1:length(xu))
+                set(gca,'YTick',1:length(yu))
+                set(gca,'FontSize',fontSizeText);
+                
+                if ic==1
+                    ylabel(ystr,'Interpreter','none','FontSize',fontSizeText);
+                    set(gca,'YTickLabel',yu);
+                else
+                    set(gca,'YTickLabel',[]);
+                end
+                
+                if ir==n
+                    xlabel(xstr,'Interpreter','none','FontSize',fontSizeText);
+                    set(gca,'XTickLabel',xu);
+                else
+                    set(gca,'XTickLabel',[]);
+                end
+                
+                grid on;
+                
+            end
+        end
+    end
+    
+else
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Handle second case (compare all catNames with compareNames)
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Check if dataset contains defined columns
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    for k=1:length(catNames),
+        try
+            data.(catNames{k});
+        catch
+            error(sprintf('Please check if "%s" is a column in the dataset!',catNames{k}));
+        end
+    end
+    
+    for k=1:length(compareNames),
+        try
+            data.(compareNames{k});
+        catch
+            error(sprintf('Please check if "%s" is a column in the dataset!',compareNames{k}));
+        end
+    end
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Keep only selected columns
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    dataCompare = data(:,compareNames);
+    data        = data(:,catNames);
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % If is table then convert to double
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    if istable(data),
+        data = table2array(data);
+    end
+    if istable(dataCompare),
+        dataCompare = table2array(dataCompare);
+    end
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Options / fontsizes
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+       
+    clf;
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % First row is frequencies of catNames
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    if hideFirstRow==0,
+        ncols = length(catNames);
+        nrows = 1+length(compareNames);
+        for ir=1:ncols
+            ystr = catNames{ir};
+            y = data(:,ir);
+            xstr = catNames{ir};
+            x = data(:,ir);
+            ip = ir;
+            subaxis(nrows,ncols,ip,'Spacing',Spacing,'Padding',Padding,'Margin',Margin);
+            % Plot frequencies
+            xu = unique(x);
+            xu = xu(~isnan(xu));
+            b  = zeros(size(xu));
+            nu = length(xu);
+            for i=1:nu
+                b(i) = sum(x==xu(i));
+            end
+            h = bar(1:nu,b,0.5);
+            grid on
+            set(gca,'FontSize',fontSizeText);
+            
+            % Write out numbers
+            for knr=1:length(b),
+                aaa = get(gca,'YLim');
+                text(knr,b(knr)+max(aaa)*0.02,sprintf('%d',b(knr)),'VerticalAlign','bottom','HorizontalAlign','center','FontSize',fontSizeText+2);
+            end
+            
+            set(h,'FaceColor',color)
+            set(gca,'XLim',[0.5 nu+.5]);
+            title(xstr,'Interpreter','none')
+%             set(gca,'YTick',[]);
+            if ir>1,
+                set(gca,'YTickLabel','');
+            end
+            set(gca,'XTick',[]);
+            set(gca,'YLim',[0 max(b)*1.3]);
+            
+            if ir==1,
+                ylabel('#','FontSize',8);
+            end
+        end
+        offset = 1;
+    else
+        ncols = length(catNames);
+        nrows = length(compareNames);
+        offset = 0;
+    end
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Next rows is correlation of catNames with compareNames
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Cycle through compareNames
+    for kcompare=1:length(compareNames),
+        ir = kcompare+offset;
+        ystr = compareNames{kcompare};
+        y = dataCompare(:,kcompare);
+        
+        % Cycle through covNames
+        for kcov=1:length(catNames),
+            ic = kcov;
+            xstr = catNames{ic};
+            x = data(:,ic);
+            ip = (ir-1)*ncols+ic;
+            subaxis(nrows,ncols,ip,'Spacing',Spacing,'Padding',Padding,'Margin',Margin);
+            
+            % plot bubble plot
+            % Exchange x categories for numbers 1:N
+            xu = unique(x);
+            iu = {};
+            for k=1:length(xu),
+                iu{k} = find(x==xu(k));
+            end
+            xn = NaN(size(x));
+            for k=1:length(iu),
+                xn(iu{k}) = k;
+            end
+            
+            % Exchange y categories for numbers 1:N
+            yu = unique(y);
+            iu = {};
+            for k=1:length(yu),
+                iu{k} = find(y==yu(k));
+            end
+            yn = NaN(size(y));
+            for k=1:length(iu),
+                yn(iu{k}) = k;
+            end
+            
+            % Find unique pairs of xn and yn (these will be plotted in the
+            % bubble plot
+            [pairs,~,b] = unique([xn yn],'rows');
+            
+            % Determine number of rows in [xn yn] with these pairs
+            nr_pairs = NaN(size(pairs,1),1);
+            
+            for k=1:size(pairs,1),
+                nr_pairs(k) = sum(b==k);
+            end
+            
+            % Determine relative number of pairs in fraction
+            nr_pairs_fraction = nr_pairs/sum(nr_pairs);
+            
+            % Determine size based on fraction
+            use_size = bubbleSize*nr_pairs_fraction;
+            
+            % Determine default color
+            color_use = color(ones(1,length(nr_pairs)),:);
+            
+            % Plot
+            scatter(pairs(:,1),pairs(:,2), use_size, color_use, 'filled', 'MarkerEdgeColor', 'none');
+            
+            % Annotate
+            set(gca,'XLim',[min(xn)-0.5 max(xn)+0.5])
+            set(gca,'YLim',[min(yn)-0.5 max(yn)+0.5])
+            
+            % Write out numbers as text 
+            for knr=1:size(pairs,1),
+                textShow = sprintf('%d',nr_pairs(knr));
+                text(pairs(knr,1)+0.025,pairs(knr,2)+0.2,textShow,'FontSize',FONTSIZE);
+            end
+            
+            set(gca,'XTick',1:length(xu))
+            set(gca,'YTick',1:length(yu))
+            set(gca,'FontSize',fontSizeText);
+            
+            if ic==1
+                ylabel(ystr,'Interpreter','none','FontSize',10);
+                set(gca,'YTickLabel',yu);
+            else
+                set(gca,'YTickLabel',[]);
+            end
+            
+            if ir==nrows
+                xlabel(xstr,'Interpreter','none','FontSize',fontSizeText);
+                set(gca,'XTickLabel',xu);
+            else
+                set(gca,'XTickLabel',[]);
+            end
+            
+            grid on;
+            
+        end
+    end
+    
+    % Adjust YLim on each row to same values
+    if length(catNames) > 1,
+        for krow=1:length(compareNames)+1,
+            YLimALL = [];
+            for kcol=1:length(catNames),
+                subaxis(length(compareNames)+1,length(catNames),(krow-1)*length(catNames)+kcol);
+                YLimALL = [YLimALL; get(gca,'YLim')];
+            end
+            YLimMin = min(YLimALL);
+            YLimMax = max(YLimALL);
+            for kcol=1:length(catNames),
+                subaxis(length(compareNames)+1,length(catNames),(krow-1)*length(catNames)+kcol);
+                set(gca,'YLim',[YLimMin(1) YLimMax(2)]);
+            end
+        end
+    end
+end
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplotCovarianceCat.m b/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplotCovarianceCat.m
new file mode 100644
index 0000000000000000000000000000000000000000..b654e36c88015bba572f5ddf4d9b181325b3dcd0
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplotCovarianceCat.m	
@@ -0,0 +1,181 @@
+function [] = IQMplotCovarianceCat(data,contNames,catNames,options)
+% This function plots the covariance relationship between a list of
+% continuous variables (contNames) and a list of categorical variables
+% (catNames), passed in "data".
+%
+% [SYNTAX]
+% [] = IQMplotCovarianceCat(data,contNames,catNames)
+% [] = IQMplotCovarianceCat(data,contNames,catNames,options)
+%
+% [INPUT]
+% data:         Matlab dataset. Each column corresponds to a variable
+%               and each row to a sample. The columns with the names
+%               defined in "contNames" and "catNames" need to be present in
+%               the dataset.
+% contNames:    Cell-array with names of continuous variables
+% catNames:     Cell-array with names of categorical variables
+% options:      MATLAB structure with optional arguments
+%
+%                   options.LogFlag:   =1 do log transform the variables,
+%                                      =0 do not transform (default: 0)
+%                   options.fontSizeText: Fontsize for the number and percent text
+%                                         (default: 10)
+%
+% [OUTPUT]
+% Plot
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+LogFlag = 0;
+try LogFlag = options.LogFlag; catch, end
+try fontSizeText = options.fontSizeText; catch, fontSizeText = 10; end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check if dataset contains defined columns
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for k=1:length(contNames),
+    try
+        data.(contNames{k});
+    catch,
+        error(sprintf('Please check if "%s" is a column in the dataset!',contNames{k}));
+    end
+end
+for k=1:length(catNames),
+    try
+        data.(catNames{k});
+    catch,
+        error(sprintf('Please check if "%s" is a column in the dataset!',catNames{k}));
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Settings for subaxis
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+Spacing = 0;
+Padding = 0;
+Margin  = .1;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Do the plotting
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ncat = length(catNames);  %rows are the categorical covariates
+ncts = length(contNames);
+for icat=1:ncat
+    xstr = catNames{icat};
+    x = data.(xstr);
+    
+    if ~isnumeric(x),
+        error('Covariate "%s" not of numeric type.',xstr);
+    end
+    
+    % Only plot if x not only NaN
+    if ~isempty(find(isnan(x)==0)),
+        
+        ip=icat;
+        subaxis(ncts+1,ncat,ip,'Spacing',Spacing,'Padding',Padding,'Margin',Margin);
+        grid on
+        
+        xu = unique(x);
+        xu = xu(~isnan(xu));
+        b  = zeros(size(xu));
+        nu = length(xu);
+        for i=1:nu
+            b(i) = sum(x==xu(i));
+        end
+        h = bar(1:nu,b,0.5);
+        set(h,'FaceColor',0.6*[1 1 1])
+        set(gca,'XLim',[0.5 nu+.5]);
+        set(gca,'FontSize',fontSizeText);
+        
+        grid on
+        
+        % Write out numbers
+        for knr=1:length(b),
+            aaa = get(gca,'YLim');
+            text(knr,b(knr)+max(aaa)*0.02,sprintf('%d',b(knr)),'VerticalAlign','bottom','HorizontalAlign','center','FontSize',fontSizeText+2);
+        end
+        
+        title(xstr,'Interpreter','none')
+        if icat==1
+            ylabel('#','Interpreter','none');
+        else
+            %             set(gca,'YTick',[]);
+            set(gca,'YTickLabel','');
+        end
+        
+        set(gca,'XTick',[]);
+        set(gca,'YLim',[0 max(b)*1.3]);
+        
+        for icts=1:ncts
+            ystr = contNames{icts};
+            y = data.(ystr);
+            
+            % Only plot if y not only NaN
+            if ~isempty(find(isnan(y)==0)),
+                if LogFlag==1
+                    y = log(y);
+                    ystr = {'log',ystr};
+                end
+                ip = icat + ncat + (icts-1)*ncat;
+                
+                subaxis(ncts+1,ncat,ip,'Spacing',Spacing,'Padding',Padding,'Margin',Margin);
+                
+                xx = unique(x);
+                xx = xx(~isnan(xx));
+                M  = NaN(length(y),length(xx));
+                for i=1:length(xx)
+                    M(x==xx(i),i) = y(x==xx(i));
+                end
+                OPTIONSbox.NumFlag = 0;
+                OPTIONSbox.BoxColor = 0.6*[1 1 1];
+                OPTIONSbox.BoxWidth = .5;
+                OPTIONSbox.MedianWidth = .7;
+                OPTIONSbox.OutlierColor = 0.4*[1 1 1];
+                OPTIONSbox.OutlierSize  = 5;
+                OPTIONSbox.MedianColor = [0 0 0];
+                plotboxIQM(M,1:length(xx),OPTIONSbox);
+                set(gca,'XLim',[.5 length(xx)+.5]);
+                grid on
+                set(gca,'FontSize',fontSizeText);
+                
+                set(gca,'XTick',1:length(xx));
+                if icts<ncts
+                    set(gca,'XTick',[]);
+                else
+                    xxx = unique(x);
+                    xxx = xxx(~isnan(xxx));
+                    set(gca,'XTickLabel',xxx)
+                    xlabel(xstr,'Interpreter','none');
+                end
+                if icat==1
+                    ylabel(ystr,'Interpreter','none');
+                else
+                    %                     set(gca,'YTick',[]);
+                    set(gca,'YTickLabel','');
+                end
+                %                 set(gca,'YTick',[]);
+                if min(y)~=max(y),
+                    set(gca,'YLim',[min(y) max(y)]);
+                else
+                    set(gca,'YLim',[min(y)-1 max(y)+1]);
+                end
+            end
+        end
+        %         set(gca,'YTick',[]);
+    end
+end
+
+% Adjust YLim on each row to same values
+for krow=1:ncts+1,
+    YLimALL = [];
+    for kcol=1:ncat,
+        subaxis(ncts+1,ncat,(krow-1)*ncat+kcol);
+        YLimALL = [YLimALL; get(gca,'YLim')];
+    end
+    YLimMin = min(YLimALL);
+    YLimMax = max(YLimALL);
+    for kcol=1:ncat,
+        subaxis(ncts+1,ncat,(krow-1)*ncat+kcol);
+        set(gca,'YLim',[min(YLimMin) max(YLimMax)]);
+    end    
+end
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplotGUI/IQMplot.fig b/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplotGUI/IQMplot.fig
new file mode 100644
index 0000000000000000000000000000000000000000..8ec9a519c78a0079fcd99618d4d40fde1619fa6b
Binary files /dev/null and b/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplotGUI/IQMplot.fig differ
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplotGUI/IQMplot.m b/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplotGUI/IQMplot.m
new file mode 100644
index 0000000000000000000000000000000000000000..c4bbd81887327562d2edea5bd4a7b4ddf934faee
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplotGUI/IQMplot.m	
@@ -0,0 +1,343 @@
+function varargout = IQMplot(varargin)
+% IQMplot - plots given data.
+%
+% USAGE:
+% ======
+% [] = IQMplot(time,data)
+% [] = IQMplot(time,data,names)
+% [] = IQMplot(time,data,names,name)
+% [] = IQMplot(time,data,names,legendtext,name)
+% [] = IQMplot(time,data,names,legendtext,marker,name)
+% [] = IQMplot(time,data,names,errorindices,minvalues,maxvalues,legendtext,marker,name)
+%
+% [] = IQMplot(datastruct1)
+% [] = IQMplot(datastruct1,datastruct2)
+% [] = IQMplot(datastruct1,datastruct2, ..., datastructN)
+%
+% The datastructures are created most easily using the function
+% createdatastructIQMplotIQM.
+%
+% time: column vector with time information
+% data: matrix with data where each row corresponds to one time point and
+%   each column to a different variable
+% names: cell-array with the names of the data variables
+% legendtext: cell-array of same length as names with text to be used for
+%   the legend.
+% marker: marker and line style for plot
+% errorindices: indices of the data for which errorbounds are available
+% minvalues: error bounds for data ... to be shown by error bars
+% maxvalues: error bounds for data ... to be shown by error bars
+% name: name describing the datastruct
+%
+% datastruct: datastructure with all the plotting data (allows for
+%   displaying several datastructs at a time in the same GUI).
+%
+% DEFAULT VALUES:
+% ===============
+% names: the plotted variables obtain the name 'x1', 'x2', ...
+% legendtext: same as names
+% marker: '-'
+% min/maxvalues: no errorbars shown
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+% Begin initialization code - DO NOT EDIT
+gui_Singleton = 1;
+gui_State = struct('gui_Name',       mfilename, ...
+                   'gui_Singleton',  gui_Singleton, ...
+                   'gui_OpeningFcn', @IQMplot_OpeningFcn, ...
+                   'gui_OutputFcn',  @IQMplot_OutputFcn, ...
+                   'gui_LayoutFcn',  [] , ...
+                   'gui_Callback',   []);
+if nargin && ischar(varargin{1})
+    gui_State.gui_Callback = str2func(varargin{1});
+end
+if nargout
+    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
+else
+    gui_mainfcn(gui_State, varargin{:});
+end
+% End initialization code - DO NOT EDIT
+
+% --- Executes just before IQMplot is made visible.
+function IQMplot_OpeningFcn(hObject, eventdata, handles, varargin)
+% check if datastructure or normal data as input
+if ~isstruct(varargin{1}),
+    % assume normal input arguments
+    runcmd = 'datastruct = createdatastructIQMplotIQM(';
+    for k=1:nargin-3,
+        runcmd = sprintf('%s varargin{%d},',runcmd,k);
+    end
+    runcmd = runcmd(1:end-1);
+    runcmd = [runcmd ');'];
+    eval(runcmd);
+    handles.dataSets = {datastruct};
+else
+    % Each argument is assumed to correspond to one datastructure
+    handles.dataSets = varargin;        % save all datastructs in handles
+end
+handles = switchDataSet(handles,1);     % switch to first datastruct
+% Initialize datastructs pulldown menu
+datastructnames = {};
+for k = 1:length(handles.dataSets),
+    datastructnames{k} = handles.dataSets{k}.name;
+end
+set(handles.datastructs,'String',datastructnames);
+% select plottype to start with
+handles.dataPlotType = 'plot';          
+% Initialize export figure handle
+handles.exportFigureHandle = [];
+handles.grid = 0;
+% Doing a first plot
+doPlot(handles);
+% Choose default command line output for IQMplot
+handles.output = hObject;
+% Update handles structure
+guidata(hObject, handles);
+return
+
+% --- Executes just before IQMplot is made visible.
+function Exit_Callback(hObject, eventdata, handles, varargin)
+clear global doRemoveZeroComponentFlag
+closereq
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% SWITCH GIVEN DATASTRUCTS 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [handles] = switchDataSet(handles,indexDataSet)
+dataSet = handles.dataSets{indexDataSet};
+% Set all the plot data also in the handles structure to be accessed by 
+% all callback functions
+% get number of yaxisdata in old plot
+if isfield(handles,'dataNames'),
+    ynumberold = length(handles.dataNames);
+else
+    ynumberold = 0;
+end
+handles.time = dataSet.time;
+handles.data = dataSet.data;
+handles.dataNames = dataSet.dataNames;
+handles.legentext = dataSet.legendtext;
+handles.marker = dataSet.marker;
+handles.errorindices = dataSet.errorindices;
+handles.minvalues = dataSet.minvalues;
+handles.maxvalues = dataSet.maxvalues;
+handles.name = dataSet.name;
+% update selection menu
+set(handles.xaxisselection,'String',{'TIME',dataSet.dataNames{:}});
+set(handles.yaxisselection,'String',dataSet.dataNames);
+set(handles.xaxisselection,'Value',1);
+% change selection only if unequal numbers of data in the sets
+if ynumberold ~= length(handles.dataNames),
+    set(handles.yaxisselection,'Value',1);
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DATASTRUCTS SELECTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function datastructs_Callback(hObject, eventdata, handles)
+dataSetIndex = get(handles.datastructs,'Value');
+handles = switchDataSet(handles,dataSetIndex);
+doPlot(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+% --- Outputs from this function are returned to the command line.
+function varargout = IQMplot_OutputFcn(hObject, eventdata, handles) 
+varargout{1} = handles.output;
+return
+
+% --- Executes on button press in zoombutton.
+function zoombutton_Callback(hObject, eventdata, handles)
+% toogle the zoom in the figure
+zoom
+return
+
+% --- Executes on selection change in xaxisselection.
+function xaxisselection_Callback(hObject, eventdata, handles)
+try
+    doPlot(handles);
+catch
+    errordlg('This selection is not possible.','Error','on');               
+end
+% Update handles structure
+guidata(hObject, handles);
+return
+
+% --- Executes on selection change in yaxisselection.
+function yaxisselection_Callback(hObject, eventdata, handles)
+try
+    doPlot(handles);
+catch
+    errordlg('This selection is not possible.','Error','on');               
+end
+% Update handles structure
+guidata(hObject, handles);
+return
+
+% --- Executes on button press in gridbutton.
+function gridbutton_Callback(hObject, eventdata, handles)
+% toogle the grid in the figure
+grid
+if handles.grid == 1,
+    handles.grid = 0;
+else
+    handles.grid = 1;
+end
+% Update handles structure
+guidata(hObject, handles);
+return
+
+% --- From R2014B the radiobutton groups are handled differently ...
+function plotAxesSelection_SelectionChangeFcn(hObject, eventdata, handles)
+handles.dataPlotType = eventdata.NewValue.String;
+% Update handles structure
+guidata(hObject, handles);
+doPlot(handles);
+return
+
+
+% --- Executes on button press in plot.
+function plot_Callback(hObject, eventdata, handles)
+handles.dataPlotType = 'plot';
+% Update handles structure
+guidata(hObject, handles);
+doPlot(handles);
+return
+
+% --- Executes on button press in loglog.
+function semilogx_Callback(hObject, eventdata, handles)
+handles.dataPlotType = 'semilogx';
+% Update handles structure
+guidata(hObject, handles);
+doPlot(handles);
+return
+
+% --- Executes on button press in semilogx.
+function semilogy_Callback(hObject, eventdata, handles)
+handles.dataPlotType = 'semilogy';
+% Update handles structure
+guidata(hObject, handles);
+doPlot(handles);
+return
+
+% --- Executes on button press in loglog.
+function loglog_Callback(hObject, eventdata, handles)
+handles.dataPlotType = 'loglog';
+% Update handles structure
+guidata(hObject, handles);
+doPlot(handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EXPORT FIGURE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function export_Callback(hObject, eventdata, handles)
+warning off;
+if isempty(handles.exportFigureHandle),
+    figH = figure;
+    handles.exportFigureHandle = figH;
+    % Update handles structure
+    guidata(hObject, handles);
+else
+    figH = handles.exportFigureHandle;
+    figure(figH);
+end
+nrow = str2num(get(handles.nrow,'String'));
+ncol = str2num(get(handles.ncol,'String'));
+nnumber = str2num(get(handles.nnumber,'String'));
+subplot(nrow,ncol,nnumber);
+doPlot(handles);
+if handles.grid == 1,
+    grid;
+end
+% set axes
+XLim = get(handles.plotarea,'Xlim');
+YLim = get(handles.plotarea,'Ylim');
+axis([XLim, YLim]);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% REQUEST NEW EXPORT FIGURE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function newexportfigure_Callback(hObject, eventdata, handles)
+handles.exportFigureHandle = [];
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PLOT FUNCTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function doPlot(handles)
+warning off;
+colorvector = {'b','g','r','c','m','y','k'};
+time = handles.time;
+data = handles.data;
+dataNames = handles.dataNames;
+errorindices = handles.errorindices;
+maxvalues = handles.maxvalues;
+minvalues = handles.minvalues;
+xaxis = handles.xaxisselection;
+yaxis = handles.yaxisselection;
+% get variable that is chosen for the x-axis
+indexX = get(xaxis,'Value');
+% get variables that are chosen for the y-axis
+indexY = get(yaxis,'Value');
+if indexX == 1,
+    if size(time,2) == 1,
+        xvariable = time;
+    else
+        xvariable = time(:,indexY);
+    end
+else
+    xvariable = data(:,indexX-1);
+end
+yvariables = data(:,indexY);
+yvariablesNames = dataNames(indexY);
+
+% select linewidth
+if ~isempty(errorindices),
+    % wider line in case of data with error bounds
+    addOption = sprintf(',''linewidth'',2');
+else
+    addOption = '';
+end
+
+% plot
+eval(sprintf('feval(handles.dataPlotType,xvariable,yvariables,handles.marker%s);',addOption))
+
+% plot error bounds 
+hold on;
+if indexX == 1,
+    % only if time on X-axis
+    for k=1:length(errorindices),
+        if ~isempty(find(indexY==errorindices(k))),
+            color = find(indexY==errorindices(k));
+            color = colorvector{mod(color(1)-1,7)+1};
+            for k1 = 1:size(xvariable,1),
+                feval(handles.dataPlotType,[xvariable(k1),xvariable(k1)],[minvalues(k1,k),maxvalues(k1,k)],['.:',color]);
+            end
+        end
+    end
+end
+hold off;
+
+hlhlx = legend(handles.legentext(indexY)); 
+set(hlhlx,'Interpreter','none');
+% write axis labels
+if indexX == 1,
+    xlabel('Time');
+else
+    hlhlx = xlabel(dataNames(indexX-1));
+    set(hlhlx,'Interpreter','none');
+end
+% write title (name)
+hlhlx = title(handles.name);
+set(hlhlx,'Interpreter','none');
+return
+
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplotGUI/createdatastruct2IQMplotIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplotGUI/createdatastruct2IQMplotIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..1541cddeb58cbba931032383f3b4cdd9e5d5be1c
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplotGUI/createdatastruct2IQMplotIQM.m	
@@ -0,0 +1,56 @@
+function [datastruct] = createdatastruct2IQMplotIQM(simdata,varargin)
+% createdatastruct2IQMplotIQM: Converts simulation data, 
+% returned from IQMsimulate or IQMPsimulate to a datastruct that 
+% can be passed to IQMplot for plotting.
+%
+% USAGE:
+% ======
+% [datastruct] = createdatastruct2IQMplotIQM(simdata)
+% [datastruct] = createdatastruct2IQMplotIQM(simdata,name)
+%
+% simdata: simulation data returned by IQMsimulate and IQMPsimulate
+% name: name for the datastruct
+%  
+% DEFAULT SETTINGS:
+% =================
+% name: 'unnamed'
+%
+% Output Arguments:
+% =================
+% datastruct: structure that can be displayed by IQMplot   (>> IQMplot(datastruct))
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle variable input arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+name = 'untitled';
+if nargin == 2,
+    name = varargin{1};
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CONVERT SIMDATA TO DATASTRUCT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+time = simdata.time;
+datanames = {};
+dataindex = 1;
+for k = 1:length(simdata.states),
+    datanames{dataindex} = sprintf('%s (state)',simdata.states{k});
+    dataindex = dataindex + 1;
+end
+if isfield(simdata,'variables'),
+    for k = 1:length(simdata.variables),
+        datanames{dataindex} = sprintf('%s (variable)',simdata.variables{k});
+        dataindex = dataindex + 1;
+    end
+    for k = 1:length(simdata.reactions),
+        datanames{dataindex} = sprintf('%s (reaction rate)',simdata.reactions{k});
+        dataindex = dataindex + 1;
+    end
+    datavalues = [simdata.statevalues, simdata.variablevalues, simdata.reactionvalues];
+else
+    datavalues = [simdata.statevalues];
+end
+datastruct = createdatastructIQMplotIQM(time(:),datavalues,datanames,name);
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplotGUI/createdatastructIQMplotIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplotGUI/createdatastructIQMplotIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..64831fda57b297f4b5a6cc5e1f579d9ec42d9e87
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplotGUI/createdatastructIQMplotIQM.m	
@@ -0,0 +1,98 @@
+function [datastruct] = createdatastructIQMplotIQM(varargin)
+% createdatastructIQMplotIQM: Creates a datastruct for the IQMplot function
+%
+% USAGE:
+% ======
+% [datastruct] = createdatastructIQMplotIQM(time,data)
+% [datastruct] = createdatastructIQMplotIQM(time,data,names)
+% [datastruct] = createdatastructIQMplotIQM(time,data,names,name)
+% [datastruct] = createdatastructIQMplotIQM(time,data,names,legendtext,name)
+% [datastruct] = createdatastructIQMplotIQM(time,data,names,legendtext,marker,name)
+% [datastruct] = createdatastructIQMplotIQM(time,data,names,errorindices,minvalues,maxvalues,legendtext,marker,name)
+%
+% time: column vector with time information
+% data: matrix with data where each row corresponds to one time point and
+%       each column to a different variable
+% names: cell-array with the names of the data variables
+%
+% name: name for the datastruct
+%
+% legendtext: cell-array of same length as names with text to be used for
+%             the legend.
+% marker: marker and line style for plot
+% errorindices: indices of the data for which errorbounds are available
+% minvalues: error bounds for data ... to be shown by error bars
+% maxvalues: error bounds for data ... to be shown by error bars
+%  
+% DEFAULT data:
+% ===============
+% names: the plotted variables obtain the name 'x1', 'x2', ...
+% legendtext: same as names
+% marker: '-'
+% min/maxvalues: no errorbars shown
+% name: 'unnamed'
+%
+% Output Arguments:
+% =================
+% datastruct: structure that can be displayed by IQMplot   (>> IQMplot(datastruct))
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% initializing the datastruct structure and setting default values
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+datastruct = [];
+datastruct.time = varargin{1};
+datastruct.data = varargin{2};
+datastruct.name = 'unnamed';
+datastruct.dataNames = {};
+for k = 1:size(datastruct.data,2);
+    datastruct.dataNames{end+1} = sprintf('x%d',k);
+end
+datastruct.errorindices = [];
+datastruct.minvalues = [];
+datastruct.maxvalues = [];
+datastruct.marker = '-';
+
+if nargin == 2,
+    % do nothing ... all done already
+    datastruct.legendtext = datastruct.dataNames;
+elseif nargin == 3,
+    datastruct.dataNames = varargin{3};
+    datastruct.legendtext = datastruct.dataNames;
+elseif nargin == 4,
+    datastruct.dataNames = varargin{3};
+    datastruct.name = varargin{4};
+    datastruct.legendtext = datastruct.dataNames;
+elseif nargin == 5,
+    datastruct.dataNames = varargin{3};
+    datastruct.legendtext = varargin{4};
+    datastruct.name = varargin{5};
+elseif nargin == 6,
+    datastruct.dataNames = varargin{3};
+    datastruct.legendtext = varargin{4};
+    datastruct.marker = varargin{5};
+    datastruct.name = varargin{6};
+elseif nargin == 9,
+    datastruct.dataNames = varargin{3};
+    datastruct.errorindices = varargin{4};
+    datastruct.minvalues = varargin{5};
+    datastruct.maxvalues = varargin{6};
+    datastruct.legendtext = varargin{7};
+    datastruct.marker = varargin{8};
+    datastruct.name = varargin{9};
+else
+    error('Wrong number of input arguments.');
+end
+if isempty(datastruct.legendtext),
+    datastruct.legendtext = datastruct.dataNames;
+end
+
+
+% Check data consistency
+if size(datastruct.time,1) ~= size(datastruct.data,1),
+    error('Different number of time points and time points in data.');
+end
+if length(datastruct.dataNames) ~= size(datastruct.data,2),
+    error('Different number of variable data and variable names.');
+end
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplotHistogram.m b/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplotHistogram.m
new file mode 100644
index 0000000000000000000000000000000000000000..02cb15150915668832ef65335d176e2e6dbdc39c
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplotHistogram.m	
@@ -0,0 +1,218 @@
+function [] = IQMplotHistogram(Xdata,varargin)
+% This function plots histograms of the data provided in X. X can be a vector
+% or a matrix. If a matrix, then histograms are plotted for each column in 
+% separate box-plots. Data can be grouped, resulting in several histograms in the 
+% same plot. The grouping vector needs to have same length as X and consist 
+% of some discrete values. Additionally, standard normal curves can be added,
+% -2,2 range lines also, the number of samples in % outside the -2,2 interval can 
+% be displayed. 
+%
+% [SYNTAX]
+% [] = IQMplotHistogram(X)
+% [] = IQMplotHistogram(X,options)
+%
+% [INPUT]
+% X:            Vector or Matrix or MATLAB dataset containing the values to plot the 
+%               histograms for (In columns).
+% options:      MATLAB structure with optional arguments
+%
+%                   options.group:    Vector or MATLAB dataset containing discrete information.
+%                                     For each value in it the analysis is grouped and the plots
+%                                     are done in different colors.
+%                   options.groupName: Name of the group variable
+%                   options.Nbins:    Number of bins for the histogram (default: 20)
+%                   options.show2lines: =1: do show the lines at -2 and 2, =0: dont (default: 0)
+%                                     Disabled if groups selected
+%                   options.stdNorm:  =1: show standard normal curve, =0: dont (default: 0)
+%                   options.names:    Cell-array with names of the variables to be plotted.
+%                   options.color:    =1: color, 0: black and white (default: 1)
+%
+% [OUTPUT]
+% Histogram plots
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% colors
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[colors,lines,dots,bwcolors] = IQMgetcolors();
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle varargins
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+options = [];
+if nargin == 1,
+elseif nargin == 2,
+    options = varargin{1};
+else
+    error('Incorrect number of input arguments.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle options
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+group = [];
+Nbins = 20;
+show2lines = 0;
+stdNorm = 0;
+names = {};
+color = 1;
+groupName = 'GROUP';
+
+try group = options.group; catch, end
+try Nbins = options.Nbins; catch, end
+try show2lines = options.show2lines; catch, end
+try stdNorm = options.stdNorm; catch, end
+try names = options.names; catch, end
+try color = options.color; catch, end
+try groupName = options.groupName; catch, end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle names
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ischar(names),
+    names = {names};
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Convert possible datasets to double
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+Xdata = double(Xdata); 
+group = double(group); 
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Find size of Xdata to determine need for number of subplots
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[nRows,nCols] = size(Xdata);
+% Determine subplot structure
+nTotal = nCols;
+nsubplotCols = ceil(sqrt(nTotal));
+nsubplotRows = ceil(nTotal/nsubplotCols);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Open new Figure
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+figure; clf;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Cycle through all columns and do the plotting
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for kk = 1:nCols,
+    subplot(nsubplotRows, nsubplotCols,kk);
+    
+    XdataColk = Xdata(:,kk);
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Do the plot if group not defined
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    if isempty(group),
+%        NbinsUse = max(Nbins,ceil(Nbins/3*((max(XdataColk)-min(XdataColk)))));
+        NbinsUse = Nbins;
+        [h,x] = hist(XdataColk,NbinsUse);
+        if color == 1,
+            bar(x,h,1,'FaceColor',colors(1,:),'EdgeColor',colors(1,:)); hold on;
+        else
+            bar(x,h,1,'FaceColor',bwcolors(1,:),'EdgeColor',bwcolors(1,:)); hold on;
+        end
+        % Add standard normal curve
+        if stdNorm,
+            maxHIST = max(hist(XdataColk,NbinsUse));
+            XLim = get(gca,'XLim');
+            if XLim(1) > -5,
+                XLim(1) = -5;
+            end
+            if XLim(2) < 5,
+                XLim(2) = 5;
+            end
+            delta = (XLim(2)-XLim(1))/1000;
+            x = [XLim(1):delta:XLim(2)];
+            y = normpdfIQM(x,0,1)/0.4*maxHIST;
+            plot(x,y,'--','Linewidth',2,'Color','black');
+        end
+    else
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        % Do the plot if group is defined
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        % Get unique group values
+        groupall = unique(group);
+        maxHIST = [];
+        % Cycle through all group values
+        for k=1:length(groupall),
+            % Get group value to be handled
+            groupk = groupall(k);
+            % Get all Xdata in this group
+            XdataColkk = XdataColk(group==groupk);
+            % Calculate the histogram
+%             NbinsUse = max(Nbins,ceil(Nbins/3*((max(XdataColkk)-min(XdataColkk)))));
+            NbinsUse = Nbins;            [h,x] = hist(XdataColkk,NbinsUse);
+            % Plot the histogram
+            if color == 1,
+                bar(x,h,1,'FaceColor',colors(k,:),'EdgeColor',colors(k,:)); hold on;
+            else
+                bar(x,h,1,'FaceColor',bwcolors(k,:),'EdgeColor',bwcolors(k,:)); hold on;
+            end                
+            h = findobj(gca,'Type','Patch');
+            if k>1,
+                set(h(1),'FaceAlpha',0.5)
+            end
+            % Determine for std norm curve:
+            maxHIST(end+1) = max(hist(XdataColkk,NbinsUse));
+        end
+        % Add standard normal curve
+        if stdNorm,
+            for k=1:length(groupall),
+                % Add standard normal curve
+                XLim = get(gca,'XLim');
+                if XLim(1) > -5,
+                    XLim(1) = -5;
+                end
+                if XLim(2) < 5,
+                    XLim(2) = 5;
+                end
+                delta = (XLim(2)-XLim(1))/1000;
+                x = [XLim(1):delta:XLim(2)];
+                y = normpdfIQM(x,0,1)/0.4*maxHIST(k);
+                if color == 1,
+                    plot(x,y,'--','Linewidth',2,'Color',colors(k,:));
+                else
+                    plot(x,y,'--','Linewidth',2,'Color',bwcolors(k,:));
+                end
+            end
+        end
+    end
+    
+    % Title etc.
+    name = ['Xdata #' num2str(kk)];
+    if ~isempty(names),
+        try
+            name = names{kk};
+        catch
+        end
+    end        
+    title(['Histogram of ' name],'FontSize',14,'FontWeight','bold','Interpreter','none');
+    xlabel(name,'FontSize',14,'Interpreter','none');
+    ylabel('Number per bin','FontSize',14,'Interpreter','none');
+    set(gca,'FontSize',12) 
+        
+    % -2/2 lines - only if no groups defined
+    if show2lines && isempty(group),
+        YLim = get(gca,'YLim');
+        plot([-2 -2],YLim,'k--');
+        plot([2 2],YLim,'k--');
+        % Get info about % samples outside -2,2 interval and show in plot
+        XLim = get(gca,'XLim');
+        percentXdatakOutside2 = round(length(find(abs(XdataColk) > 2))./length(find(abs(XdataColk) <= 2))*100*10)/10;
+        text(XLim(1)+0.1*(XLim(2)-XLim(1)),0.9*YLim(2),sprintf('Samples outside\n[-2,2] interval:\n%g %%',percentXdatakOutside2),'FontSize',12);
+    end
+
+    % Legend if groups
+    if ~isempty(group),
+        legendtext = {};
+        groupall = unique(group);
+        for k=1:length(groupall),
+            legendtext{end+1} = sprintf('%s: %g',groupName,groupall(k));
+        end
+        legend(legendtext{:},'Location','NorthWest');
+    end
+    
+end
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplotKM.m b/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplotKM.m
new file mode 100644
index 0000000000000000000000000000000000000000..200b517a248d53976ccfad91737f7847eecf6709
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplotKM.m	
@@ -0,0 +1,101 @@
+function [ST50_output_cellTable,ST50_output] = IQMplotKM(TIME,CENS,color,line,type,marksFlag,CIflag)
+% Plots a Kaplan Meier curve.
+%
+% [SYNTAX]
+% [ST50_output] = IQMplotKM(TIME,CENS)
+% [ST50_output] = IQMplotKM(TIME,CENS,color)
+% [ST50_output] = IQMplotKM(TIME,CENS,color,line)
+% [ST50_output] = IQMplotKM(TIME,CENS,color,line,type)
+% [ST50_output] = IQMplotKM(TIME,CENS,color,line,type,marksFlag)
+% [ST50_output] = IQMplotKM(TIME,CENS,color,line,type,marksFlag,CIflag)
+%
+% [INPUT]
+% TIME:         vector with time information for time to event
+% CENS:         vector with censoring information (0: uncensored, 1: right censored)
+% color:        [r g b] color default: black
+% line:         Line style (default: "-")
+% type:         "Survivor" (default) or "cumulative hazard" or "cdf"
+% marksFlag:    =1: censoring marks are plotted (default). =0 not plotted
+% CIflag:       =1: plots 95% CI. =0 not plotted (default)
+%
+% [OUTPUT]
+% ST50_output: [50% survival time, 95% CI - lower and upper bound]
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+if nargin<3,
+    color = [0 0 0];
+end
+if nargin<4,
+    line = '-';
+end
+if nargin<5,
+    type = 'survivor';
+end
+if nargin<6,
+    marksFlag = 1;
+end
+if nargin<7,
+    CIflag = 0;
+end
+
+% Remove NaN values from TIME and CENS (paired)
+ixNAN           = find(isnan(TIME));
+TIME(ixNAN)     = [];
+CENS(ixNAN)     = [];
+
+% Plot KM curve
+[f,x,flo,fup]   = ecdf(TIME,'censoring',CENS,'function',type);
+stairs(x,f,line,'LineWidth',1,'Color',color,'LineWidth',2); hold on;
+
+% Plot marks for censored data
+if marksFlag,
+    xi = TIME(logical(CENS));
+    [~,~,step] = histcounts(xi,x);
+    step(xi>max(TIME)) = length(x);
+    ixstep0 = find(step==0);
+    xi(ixstep0) = [];
+    step(ixstep0) = [];
+    fi = f(step);
+    plot(xi,fi, 's','MarkerEdgeColor','white','MarkerFaceColor','white','MarkerSize',8)
+    plot(xi,fi, 'b+','color',color,'MarkerSize',8,'LineWidth',1)
+end
+
+% Plot 95% confidence interval
+if CIflag,
+    IQMplotfill(x,flo,fup,color,0.1); hold on
+end
+
+% Annotate
+grid on
+set(gca,'FontSize',12);
+xlabel('Time','FontSize',14);
+ylabel('Probability','FontSize',14);
+set(gca,'YLim',[-0.05 1.05]);
+
+% Determine 50% survival time and 95% CI
+ix = find(f-0.5<0);
+if isempty(ix),
+    ST50 = NaN;
+else
+    ST50 = x(ix(1));
+end
+
+ix = find(flo-0.5<0);
+if isempty(ix),
+    ST50_CI_lo = NaN;
+else
+    ST50_CI_lo = x(ix(1));
+end
+
+ix = find(fup-0.5<0);
+if isempty(ix),
+    ST50_CI_up = NaN;
+else
+    ST50_CI_up = x(ix(1));
+end
+
+ST50_output = [ST50, ST50_CI_lo, ST50_CI_up];
+
+ST50_output_cellTable(1,1:3) = {'<TH>' '50% Survival Time' '95% CI'};
+ST50_output_cellTable(2,1:3) = {'<TR>' sprintf('%1.3g',ST50) sprintf('[%1.3g, %1.3g]',ST50_CI_lo,ST50_CI_up)};
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplotPercentStratified.m b/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplotPercentStratified.m
new file mode 100644
index 0000000000000000000000000000000000000000..4e51adcc17ad93076c9e98b7fc2c2f3b28d4cd3b
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplotPercentStratified.m	
@@ -0,0 +1,200 @@
+function [yn_all_percent] = IQMplotPercentStratified(data,catNames,compareNames,options)
+% This function plots column plots / stacked bar plots for categorical outcomes (percent
+% of occurrence) stratified by categorical compare variables in
+% compareNames.
+%
+% Works for one catName and one compareName for now.
+%
+% [SYNTAX]
+% [] = IQMplotPercentStratified(data,catNames,compareNames)
+%
+% [INPUT]
+% data:         Matlab dataset. Each column corresponds to a variable
+%               and each row to a sample. The columns with the names
+%               defined in "catNames" need to be present in
+%               the dataset and contain numerical categorical data.
+% catNames:     Cell-array with names of categorical variables
+% compareNames: Cell-array with names of categorical variables to compare
+%               with the categorical covariates in catNames
+% options:      Matlab structure with additional options
+%       options.percent: Show percentages instead of numbers. Percentages
+%                        are calculated relative to the number in the bins
+%                        of the catNames and only displayed if compared to
+%                        compareNames. =0 do show numbers and percent. =1 show
+%                        percent (default) =2 show numbers and percent.
+%       options.fontSizeText: Fontsize for the number and percent text
+%                             (default: 10)
+%       options.color:  Color of bubbles default: 0.4*[1 1 1]
+%
+% [OUTPUT]
+% Plot
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+% Check if data is table
+if ~istable(data),
+    error('Input data needs to be provided as MATLAB table.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check which case it is and handle each case completely separately
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin==3,
+    options = [];
+end
+
+try fontSizeText  = options.fontSizeText; catch, fontSizeText  = 10; end
+try hideFirstRow  = options.hideFirstRow; catch, hideFirstRow  = 0; end
+try color  = options.color; catch, color = 0.4*[1 1 1]; end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check if dataset contains defined columns
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for k=1:length(catNames),
+    try
+        data.(catNames{k});
+    catch
+        error(sprintf('Please check if "%s" is a column in the dataset!',catNames{k}));
+    end
+end
+
+for k=1:length(compareNames),
+    try
+        data.(compareNames{k});
+    catch
+        error(sprintf('Please check if "%s" is a column in the dataset!',compareNames{k}));
+    end
+end
+
+if length(catNames)>1 || length(compareNames)>1,
+    error('Only single entry in catNames and compareNames allowed.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Generate the plot
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Keep only selected columns
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+dataCompare = data(:,compareNames);
+data        = data(:,catNames);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% If is table then convert to double
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if istable(data),
+    data = table2array(data);
+end
+if istable(dataCompare),
+    dataCompare = table2array(dataCompare);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Options / fontsizes
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Subindex properties
+Spacing = 0.00;
+Padding = 0.0005;
+Margin  = .1;
+
+% Define fontsize
+if length(catNames)<=6,
+    FONTSIZE = 10;
+else
+    FONTSIZE = 8;
+end
+
+% Define ncols and 
+ncols = length(catNames);
+nrows = length(compareNames);
+
+% Cycle through compareNames
+for kcompare=1:length(compareNames),
+    ir = kcompare;
+    ystr = compareNames{kcompare};
+    y = dataCompare(:,kcompare);
+    
+    % Cycle through covNames
+    for kcov=1:length(catNames),
+        ic = kcov;
+        xstr = catNames{ic};
+        x = data(:,ic);
+        ip = (ir-1)*ncols+ic;
+%         subaxis(nrows,ncols,ip,'Spacing',Spacing,'Padding',Padding,'Margin',Margin);
+        
+        % Exchange x categories for numbers 1:N
+        xu = unique(x);
+        % Find positions where the unique items are listed (to obtain
+        % number 1...N) ... stored in xn
+        iu = {};
+        for k=1:length(xu),
+            iu{k} = find(x==xu(k));
+        end
+        xn = NaN(size(x));
+        for k=1:length(iu),
+            xn(iu{k}) = k;
+        end
+        
+        % Exchange y categories for numbers 1:N
+        yu = unique(y);
+        iu = {};
+        for k=1:length(yu),
+            iu{k} = find(y==yu(k));
+        end
+        yn = NaN(size(y));
+        for k=1:length(iu),
+            yn(iu{k}) = k;
+        end
+        
+        % Find numbers of unique yn in unique xn
+        yn_all_percent = [];
+        for k=1:max(xn),
+            % Get number of xn values in bin k
+            NR_xnk = length(xn(xn==k));
+            % Get number of different yn values in bin k
+            yn_all = [];
+            for k2=1:max(yn),
+                ynk = sum(xn==k & yn==k2);
+                yn_all(k2) = ynk;
+            end
+            % Determine percent
+            yn_all_percent = [yn_all_percent; 100*yn_all/NR_xnk];
+        end
+        
+        % Plot
+        hp = bar(1:max(xn),yn_all_percent,'stacked');
+        
+%         hatch_combinations = {
+%         'fill'       0
+%         'single'     0
+%         'single'     45
+%         'single'     90
+%         'cross'      0
+%         'cross'      45
+%         };
+%     
+%         for k=1:min(length(hp),6),
+%             hatchfill2(hp(k),hatch_combinations{k,1},'HatchAngle',hatch_combinations{k,2});
+%         end
+        
+        % Annotate
+        if ic==1
+            ylabel('Percentage of x-bin','Interpreter','none','FontSize',12);
+        else
+            set(gca,'YTickLabel',[]);
+        end
+        
+        if ir==nrows
+            xlabel(xstr,'Interpreter','none','FontSize',FONTSIZE);
+            set(gca,'XTickLabel',xu);
+        else
+            set(gca,'XTickLabel',[]);
+        end
+        
+        set(gca,'YLim',[0 100]);
+        grid on;
+        
+    end
+end
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplotQQ.m b/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplotQQ.m
new file mode 100644
index 0000000000000000000000000000000000000000..0ad98d3c99ed8356f08d87c1ab1abf4e163d11aa
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplotQQ.m	
@@ -0,0 +1,86 @@
+function [] = IQMplotQQ(Xdata,varargin)
+% QQ plot for provided input data.
+%
+% [SYNTAX]
+% [] = IQMplotQQ(X)
+% [] = IQMplotQQ(X,options)
+%
+% [INPUT]
+% X:            Vector or Matrix or MATLAB dataset containing the values to plot the 
+%               QQplot for (In columns).
+% options:      MATLAB structure with optional arguments
+%
+%                   options.names:    Cell-array with names of the variables to be plotted.
+%
+% [OUTPUT]
+% QQ plot
+ 
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle varargins
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+options = [];
+if nargin == 1,
+elseif nargin == 2,
+    options = varargin{1};
+else
+    error('Incorrect number of input arguments.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle options
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+names = {};
+try names = options.names; catch, end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle names
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ischar(names),
+    names = {names};
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Convert possible datasets to double
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+Xdata = double(Xdata); 
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Find size of Xdata to determine need for number of subplots
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[nRows,nCols] = size(Xdata);
+% Determine subplot structure
+nTotal = nCols;
+nsubplotCols = ceil(sqrt(nTotal));
+nsubplotRows = ceil(nTotal/nsubplotCols);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Open new Figure
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+figure; clf;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Cycle through all columns and do the plotting
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for kk = 1:nCols,
+    subplot(nsubplotRows, nsubplotCols,kk);
+    
+    XdataColk = Xdata(:,kk); 
+    % Do the plot 
+    qqplotIQM(XdataColk);
+
+    % Title etc.
+    name = ['Xdata #' num2str(kk)];
+    if ~isempty(names),
+        try
+            name = names{kk};
+        catch
+        end
+    end
+    
+    title(['QQplot of ' name],'FontSize',14,'FontWeight','bold','Interpreter','none');
+    xlabel('Standard Normal Quantiles','FontSize',14,'Interpreter','none');
+    ylabel(['Quantiles of ' name],'FontSize',14,'Interpreter','none');
+    set(gca,'FontSize',12)
+end
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplotXY.m b/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplotXY.m
new file mode 100644
index 0000000000000000000000000000000000000000..0bd3c6914342ac906e6566b9f39b9d4e2b7b31f3
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplotXY.m	
@@ -0,0 +1,502 @@
+function [] = IQMplotXY(data,nameX,nameY,options)
+% This function plots pairwise Ydata vs. Xdata. Several optional settings
+% are possible (see below)
+%
+% [SYNTAX]
+% [] = IQMplotXY(data,nameX,nameY)
+% [] = IQMplotXY(data,nameX,nameY,options)
+%
+% [INPUT]
+% data:         Matlab dataset
+% nameX:        Column name in dataset to plot on X axis
+% nameY:        Cell-array with column names in dataset to plot on Y axis (if more than one name, then do subplots)
+% options:      Structure with optional settings as follows:
+%   options.xlabelText          = String with xlabel text. Default: nameX
+%   options.ylabelText          = Cell-array with names of ylabels instead of nameY
+%   options.nameColorGroup      = Column name in dataset for coloring a certain group differently
+%   options.nameSubGroup        = Column name in dataset for subgrouping
+%   options.logX                = 0 if lin, 1 if log X axis (default: 0)
+%   options.logY                = 0 if lin, 1 if log Y axis (default: 0)
+%                               Can be vector for different nameYs
+%   options.linetype            = String with MATLAB linetype (default: '.')
+%   options.linecolor           = Color for lines (default: [0.6 0.6 0.6])
+%   options.showmarkers         = 1 shows different linestyles with markers, =0 uses linstyle setting
+%   options.markersize          = numeric value for markersizes (default: 10)
+%   options.linecolorsCustom    = Matrix with 3 comlumns and arbitrary rows. Defines custom color settings to use for color grouping
+%   options.linetypesCustom     = Cell-array with linestyle strings (e.g.: {'x','-.','--'}). If defined it overrides the standard lines from IQMgetcolors (only active if color group selected)
+%                                 Only active if "options.showmarkers=1".
+%   options.linewidth           = Numeric value 1-5 (default: 1)
+%   options.sameaxes            = If 0 (default) subplot axes will be scaled to best fit the data, if 1 all axes will have same scaling
+%   options.showgrid            = 0: no grid, 1: grid (no minor grid lines) (default: 1)
+%   options.colortitlebar       = Vector with three values between 0 and 1 to set he titlebar color (default: [1 1 0.8])
+%   options.heighttitlebar      = Height of the titlebar in fraction of subplot (default: 0.04)
+%   options.showtitlebar        = 0: do not show titlebar, 1: show titlebar (default)
+%   options.showmedian           = 0 (default): do not show a median line per group, 1: do show it
+%   options.NbinsMedian          = value between 0 and 100% defining the range of data to take into account (default: 15)
+%   options.showregressionline  = 1: shwows a linear regression line, 0 does not (default)
+%
+%   options.showloessline       = 1: shwows a loess line (10% range), 0 does not (default)
+%
+%   options.showslope1line      = 1: shows a slope 1 line, 0 (default) does not
+%   options.slope1linecolor     = color of slope1line (default: [0.4 0.4 0.4]) 
+%   options.slope1linestyle     = style of slope1line (default: '--')
+%   options.squareaxes          = sets X and Y limits to same values 
+%   options.showzeroLines       = 1: shows lines at 0X and 0Y, 0 (default) does not   
+%   options.zeroLinescolor      = color of zero lines (default: [0.4 0.4 0.4])  
+%   options.zeroLinesstyle      = style of zero lines (default: '--'))  
+%   options.showlegend          = 0: do not show a legend, 1 (default): show a legend for the color grouping
+%   options.labeltextsize       = Fontsize for x and y labels (default: 10)
+%   options.maxlegendentries    = If more elements in colorgroup then do not show legend (becomes messy). Default: 10
+%   options.ticklabeltextsize   = Fontsize for axes number (default: 10)
+%   options.legendtextsize      = Fontsize for legend (default: 10)
+%   options.nrows               = Number of rows per subplot (default: all groups in one figure)
+%   options.ncols               = Number of columns per subplot (default: all groups in one figure)
+%   options.ylabelfirstonly     = 1: show the ylabel only for first subplot in figure, 0: show for all first in row subplots
+%   options.nameText            = Column name in dataset (text in column) to display next to datapoints
+%   options.nameTextLines       = 1: show lines additional to text (if nameText is defined). 0: do not show lines (if nameText is defined).
+%   options.textFontsize        = Fontsize for additional text (default: 10)
+%   options.filename            = Filename for PS (windows) or PDF (unix) output
+%   options.axescolor           = Sets the color of axes and grid (default: [0.2 0.2 0.2])
+%   options.windowcolor         = color definition for outside frame of window (default: [1 1 1])
+%   options.removeNaNs          = 1: no breaks in lines due to NaN. =0: breaks in lines (default)
+%   options.titleText           = String with title text (default: '')
+
+% [OUTPUT]
+% Figure with Y vs. X plots
+ 
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check inputs
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ischar(nameY),
+    nameY = {nameY};
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get default colors and linestyles
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[colorsDefault,notused,linesDefault] = IQMgetcolors();
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get optional variables and set defaults if undefined
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try xlabelText          = options.xlabelText;               catch, xlabelText           = nameX;            end; %#ok<*CTCH>
+try ylabelText          = options.ylabelText;               catch, ylabelText           = nameY;            end;
+try nameSubGroup        = options.nameSubGroup;             catch, nameSubGroup        = '';                end; 
+try nameColorGroup      = options.nameColorGroup;           catch, nameColorGroup       = '';               end; % also used for coloring
+try logX                = options.logX;                     catch, logX                 = 0;                end;
+try logY                = options.logY;                     catch, logY                 = [];               end;
+try linetype            = options.linetype;                 catch, linetype             = '.';              end; 
+try linecolor           = options.linecolor;                catch, linecolor            = [0.6 0.6 0.6];    end;
+try showmarkers         = options.showmarkers;              catch, showmarkers          = 0;                end;
+try markersize          = options.markersize;               catch, markersize          = 20;                end;
+try linecolorsCustom    = options.linecolorsCustom;         catch, linecolorsCustom     = colorsDefault;    end;
+try linetypesCustom     = options.linetypesCustom;          catch, linetypesCustom      = linesDefault;     end;
+try linewidth           = options.linewidth;                catch, linewidth            = 1;                end;
+try sameaxes            = options.sameaxes;                 catch, sameaxes             = 0;                end;
+try showgrid            = options.showgrid;                 catch, showgrid             = 1;                end;
+try colortitlebar       = options.colortitlebar;            catch, colortitlebar        = [1 1 0.8];        end;
+try heighttitlebar      = options.heighttitlebar;           catch, heighttitlebar       = 0.04;             end;
+try showtitlebar        = options.showtitlebar;             catch, showtitlebar         = 1;                end;
+try showmedian          = options.showmedian;               catch, showmedian            = 0;               end;
+try NbinsMedian         = options.NbinsMedian;              catch, NbinsMedian           = 15;              end;
+try showregressionline  = options.showregressionline;       catch, showregressionline   = 0;                end;
+
+try showloessline       = options.showloessline;            catch, showloessline        = 0;                end;
+
+try showlegend          = options.showlegend;               catch, showlegend           = 1;                end;
+try labeltextsize       = options.labeltextsize;            catch, labeltextsize        = 10;               end;
+try ticklabeltextsize   = options.ticklabeltextsize;        catch, ticklabeltextsize    = 10;               end;
+try legendtextsize      = options.legendtextsize;           catch, legendtextsize       = 10;               end;
+try nrows               = options.nrows;                    catch, nrows                = NaN;              end;
+try ncols               = options.ncols;                    catch, ncols                = NaN;              end;
+try maxlegendentries    = options.maxlegendentries;         catch, maxlegendentries     = 15;               end;
+try nameText            = options.nameText;                 catch, nameText             = '';               end;
+try nameTextLines       = options.nameTextLines;            catch, nameTextLines        = 1;                end;
+try textFontsize        = options.textFontsize;             catch, textFontsize         = 10;               end;
+try axescolor           = options.axescolor;                catch, axescolor            = 0.2*[1 1 1];      end;
+try windowcolor         = options.windowcolor;              catch, windowcolor          = 1*[1 1 1];        end;
+try showslope1line      = options.showslope1line;           catch, showslope1line       = 0;                end;
+try slope1linecolor     = options.slope1linecolor;          catch, slope1linecolor      = 0.4*[1 1 1];      end;
+try slope1linestyle     = options.slope1linestyle;          catch, slope1linestyle      = '--';             end;
+try squareaxes          = options.squareaxes;               catch, squareaxes           = 0;                end;
+try showzeroLines       = options.showzeroLines;            catch, showzeroLines        = 0;                end;
+try zeroLinescolor      = options.zeroLinescolor;           catch, zeroLinescolor       = 0.4*[1 1 1];      end;
+try zeroLinesstyle      = options.zeroLinesstyle;           catch, zeroLinesstyle       = '--';             end;
+try removeNaNs          = options.removeNaNs;               catch, removeNaNs           = 0;                end;
+try titleText           = options.titleText;                catch, titleText            = '';               end;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle nameY as char def
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ischar(nameY),
+    nameY = {nameY};
+end
+
+% Handle logY
+if isempty(logY),
+    logY = zeros(1,length(nameY));
+end
+if length(logY) == 1,
+    logY = logY*ones(1,length(nameY));
+end
+if length(logY)~=length(nameY),
+    error('logY has wrong length');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% If logX remove negative X values
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if logX,
+    % Remove entries in data with negative X values
+    data(data.(nameX)<=0,:) = [];
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Other options
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ylabelfirstonly = 0;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Settings for making plots nicer when same axes are chosen
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if sameaxes,
+    SpacingHoriz = 0.05;
+    SpacingVert  = 0.05;
+    Padding      = 0.0;
+    Margin       = 0.1;
+else
+    SpacingHoriz = 0.05;
+    SpacingVert  = 0.05;
+    Padding      = 0.0;
+    Margin       = 0.1;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Format the data to match the grouping
+% Each nameY is one element in the group
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get plot data alone
+dataPlot            = table();
+for k=1:length(nameY),
+    dataPlotk = table();
+    dataPlotk.X          = data.(nameX);
+    dataPlotk.Y          = data.(nameY{k});
+   
+    if ~isempty(nameText),
+        dataPlotk.(nameText) = data.(nameText);
+    end
+    % No group name definition - it is via Yname definition
+    dataPlotk.group  = k*ones(height(dataPlotk),1);
+    % Handle subgrouping
+    if isempty(nameSubGroup),
+        dataPlotk.subgroup = ones(height(dataPlotk),1);
+    else
+        dataPlotk.subgroup = data.USUBJID;
+    end
+    % Handle color group
+    if ~isempty(nameColorGroup),
+        dataPlotk.colorgroup = data.(nameColorGroup);
+        dataPlotk.color      = -1*ones(height(dataPlotk),1);
+        allGROUPcolor       = unique(dataPlotk.colorgroup);
+        for k=1:length(allGROUPcolor),
+            dataPlotk.color(ixdataIQM(dataPlotk,'colorgroup',allGROUPcolor(k))) = k;
+        end
+    else
+        % colorgroup same as subgroup
+        dataPlotk.colorgroup = -1*ones(height(dataPlotk),1);
+        dataPlotk.color      = -1*ones(height(dataPlotk),1);
+    end
+    
+    % If logY remove negative Y values
+    if logY,
+        % Remove entries in data with negative X values
+        dataPlotk(dataPlotk.Y<=0,:) = [];
+    end
+    
+    dataPlot = [dataPlot; dataPlotk];
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Determine the x and y axes ranges if sameaxes selected and
+% adjust the maxY part of the axes settings to allow for title bar
+% Goal is to increase the range of minY to maxY by a fraction of
+% heighttitlebar
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if sameaxes,
+    % Adjust for logY
+    if logY,
+        ix0 = find(dataPlot.X==0);
+        dataPlot(ix0,:) = [];
+        ix0 = find(dataPlot.Y==0);
+        dataPlot(ix0,:) = [];
+    end
+    
+	minX = min(dataPlot.X);
+	maxX = max(dataPlot.X);
+    minY = min(dataPlot.Y);
+    maxY = max(dataPlot.Y);
+        
+    % Adjust maxY for titlebar
+    if logY==1,
+        rangenew =  1/(1-heighttitlebar-0.01)*(log10(maxY)-log10(minY));
+        maxY     = 10.^(log10(minY) + rangenew);
+    else
+        rangenew =  1/(1-heighttitlebar-0.01)*(maxY-minY);
+        maxY     = minY + rangenew;
+    end
+    % handle squareaxes
+    if squareaxes,
+        minX = min(minX,minY);
+        minY = minX;
+        maxX = max(maxX,maxY);
+        maxY = maxX;        
+    end
+    % Define axes limits
+    sameAxesLimits = [minX maxX minY maxY];
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get different group elements - for each subplot
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+allGROUP = unique(dataPlot.group);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get number of possible elements in sub group
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+allGROUPsub = unique(dataPlot.subgroup);    
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get number of possible elements in color group
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+allGROUPcolor = unique(dataPlot.colorgroup);    
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Determine number of subplot rows/cols per figure
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+nAllGroups = length(allGROUP);
+if isnan(ncols) || isnan(nrows),
+    ncols = ceil(sqrt(nAllGroups));
+    nrows = ceil(nAllGroups/ncols);
+end
+nSubplots = ncols*nrows;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Determine number of figures needed for the plotting
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+nFigures = ceil(nAllGroups/nSubplots);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Plot the data
+% Plot moving median line if desired
+% moving median is done in each subplot for data within the same color group
+% Subgroup is not considered
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for k=1:length(allGROUP),
+
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    % Handle multiple figures and subplots
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    
+    plotFigure  = ceil(k/nSubplots);
+    plotSubplot = mod(k-1,nSubplots)+1;  
+
+    % Clear figure if first subplot going to be plotted and set windowcolor
+    if plotSubplot==1, 
+        hfig = figure(); 
+        set(gcf,'Color',windowcolor);
+    else
+        figure(hfig); 
+    end
+    % Choose subplot
+    subaxis(nrows,ncols,plotSubplot,'SpacingVert',SpacingVert,'SpacingHoriz',SpacingHoriz,'Padding',Padding,'Margin',Margin);
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    % Get group data for each subplot
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    
+    datak = dataPlot(dataPlot.group==allGROUP(k),:);
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    % Handle logY  
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    options.logY = logY(plotSubplot);
+    
+    % If logY than remove negative Y values
+    if options.logY,
+        datak(datak.Y<=0,:) = [];     
+    end
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    % Plot single plot using general auxiliary function
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    if isempty(titleText),
+        options.titleText = sprintf('%s vs %s',nameY{plotSubplot},nameX);
+    else
+        options.titleText = sprintf('%s (%s)',titleText,nameY{plotSubplot});
+    end
+    
+    if sameaxes,
+        options.axesLimits = sameAxesLimits;
+    else
+        minX = min(datak.X);
+        maxX = max(datak.X);
+        minY = min(datak.Y);
+        maxY = max(datak.Y);
+        
+        % handle squareaxes
+        if squareaxes,
+            minX = min(minX,minY);
+            minY = minX;
+            maxX = max(maxX,maxY);
+            maxY = maxX;     
+        end
+        % Adjust maxY for titlebar
+        if options.logY==1,
+            rangenew =  1/(1-heighttitlebar-0.01)*(log10(maxY)-log10(minY));
+            maxY     = 10.^(log10(minY) + rangenew);
+        else
+            rangenew =  1/(1-heighttitlebar-0.01)*(maxY-minY);
+            maxY     = minY + rangenew;
+        end
+        options.axesLimits = [minX maxX minY maxY];
+    end
+    options.linetype            = linetype;
+    options.markersize          = markersize;
+    options.linetypesCustom     = linetypesCustom;
+    options.heighttitlebar      = heighttitlebar;
+    options.NbinsMedian         = NbinsMedian;
+    options.sameaxes            = sameaxes;
+    options.axescolor           = axescolor;
+    
+    if removeNaNs,
+        datak(isnan(datak.X),:) = [];
+        datak(isnan(datak.Y),:) = [];        
+    end
+       
+    plotgeneralIQM(datak,'X','Y',options);     
+ 
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    % Handle x labels
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    
+    if plotFigure < nFigures,
+        % All subplots used => xlabel for the last ncols subplots
+        if plotSubplot > nSubplots-ncols,
+            xlabel(xlabelText,'FontUnits','points','FontSize',labeltextsize,'Interpreter','none');
+        end
+    else
+        % Figure only partially filled with subplots - only labels for
+        % the last ncols subplots
+        if k > nAllGroups-ncols,
+            xlabel(xlabelText,'FontUnits','points','FontSize',labeltextsize,'Interpreter','none');
+        end
+    end
+        
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    % Handle y labels
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    
+    ylabel(ylabelText{k},'FontUnits','points','FontSize',labeltextsize,'Interpreter','none');
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    % Handle legend - simplistic one
+    % Only do so for color group and median plots
+    % Only show legend if less than maxlegendentries
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    
+    if showlegend && plotSubplot==1 && length(allGROUPcolor)<=maxlegendentries,
+        legendText = {};
+        legendColor = {};
+        % Check if color group chosen
+        if allGROUPcolor(1) ~= -1,
+            for kleg=1:length(allGROUPcolor),
+                % Get text part
+                legendText{kleg} = sprintf('%s=%g',nameColorGroup,allGROUPcolor(kleg));
+                % Get color part
+                legendColor{kleg} = linecolorsCustom(mod(kleg-1,length(linecolorsCustom))+1,:);
+                % Get marker part
+                if showmarkers,
+                    legendText{kleg} = sprintf('%s %s',linetypesCustom{   mod(kleg-1,length(linetypesCustom))+1},legendText{kleg});
+                end
+            end
+        end
+        % Check if moving median lines are shown
+        if showmedian,
+            legendText{end+1} = 'Binned Median'; %#ok<*AGROW>
+            legendColor{end+1} = [0 0 0];
+        end
+        % Check if regression lines are shown
+        if showregressionline,
+            legendText{end+1} = 'Regression line'; %#ok<*AGROW>
+            legendColor{end+1} = [0 0 0];
+        end
+        % Check if loess lines are shown
+        if showloessline,
+            legendText{end+1} = 'Loess line'; %#ok<*AGROW>
+            legendColor{end+1} = [0 0 0];
+        end
+        
+        % Determine y locations
+        nlegend = length(legendText);
+        YLim = get(gca,'YLim');
+        XLim = get(gca,'XLim');
+        
+        if options.logY==1,
+            textY = 10.^(log10(YLim(1))+((maxlegendentries:-1:1)/(maxlegendentries+1)-heighttitlebar)*(log10(YLim(2))-log10(YLim(1))));
+        else
+            textY = YLim(1)+((maxlegendentries:-1:1)/(maxlegendentries+1)-heighttitlebar)*(YLim(2)-YLim(1));
+        end
+        if logX==1,
+            textX = 10.^(log10(XLim(1))+0.02*(log10(XLim(2))-log10(XLim(1))));
+        else
+            textX = XLim(1)+0.02*(XLim(2)-XLim(1));
+        end
+        for klegend=1:nlegend,
+            text(textX,textY(klegend),legendText{klegend},'Color',legendColor{klegend},'FontWeight','bold','FontUnits','points','FontSize',legendtextsize,'HorizontalAlignment','Left','Interpreter','none');
+        end
+    end
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    % Handle showslope1line
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    
+    if showslope1line,
+        XLim = get(gca,'XLim');
+        YLim = get(gca,'YLim');
+        % Adjust maxY for titlebar
+        maxY = YLim(2);
+        minY = YLim(1);
+        if options.logY==1,
+            rangenew =  (1-heighttitlebar)*(log10(maxY)-log10(minY));
+            maxY     = 10.^(log10(minY) + rangenew);
+        else
+            rangenew =  (1-heighttitlebar)*(maxY-minY);
+            maxY     = minY + rangenew;
+        end         
+        plot([min(XLim(1),YLim(1)) min(max(XLim(2),maxY),maxY)], [min(XLim(1),YLim(1)) min(max(XLim(2),maxY),maxY)],slope1linestyle,'Color',slope1linecolor,'LineWidth',2);
+    end
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    % Handle showzeroLines
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+
+    if showzeroLines,
+        XLim = get(gca,'XLim');
+        YLim = get(gca,'YLim');
+        % Adjust maxY for titlebar
+        maxY = YLim(2);
+        minY = YLim(1);
+        if options.logY==1,
+            rangenew =  (1-heighttitlebar)*(log10(maxY)-log10(minY));
+            maxY     = 10.^(log10(minY) + rangenew);
+        else
+            rangenew =  (1-heighttitlebar)*(maxY-minY);
+            maxY     = minY + rangenew;
+        end 
+        plot([0 0],[minY maxY],zeroLinesstyle,'Color',zeroLinescolor,'LineWidth',1)
+        plot(XLim,[0 0],zeroLinesstyle,'Color',zeroLinescolor,'LineWidth',1)
+    end
+    
+end
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplotfacetgrid.m b/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplotfacetgrid.m
new file mode 100644
index 0000000000000000000000000000000000000000..0c5a8837b1b0ce705a2df0777559093d82075143
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplotfacetgrid.m	
@@ -0,0 +1,537 @@
+function [] = IQMplotfacetgrid(data,nameX,nameY,nameGroupX,nameGroupY,options)
+% This function plots a matrix version of a trellis plot.
+%
+% [SYNTAX]
+% [] = IQMplotfacetgrid(data,nameX,nameY,nameGroupX,nameGroupY)
+% [] = IQMplotfacetgrid(data,nameX,nameY,nameGroupX,nameGroupY,options)
+%
+% [INPUT]
+% data:         Matlab dataset
+% nameX:        Column name in dataset to plot on X axis
+% nameY:        Column name in dataset to plot on Y axis
+% nameGroupX:   Column name in dataset to use as group variable for each column. 
+% nameGroupY:   Column name in dataset to use as group variable for each row. 
+% options:      Structure with optional settings as follows:
+%   options.xlabelText          = String with xlabel text. Default: nameX
+%   options.ylabelText          = Cell-array with as many entries as groups in nameGroupY
+%   options.nameSubGroup        = Column name in dataset for subgrouping within a group/subplot (nicer line drawing and used for moving median line);
+%   options.nameColorGroup      = Column name in dataset for coloring a certain group differently
+%   options.logX                = 0 if lin, 1 if log X axis (default: 0)
+%   options.logY                = 0 or 1, alternatively a vector with as many 0 or 1 as elements in nameGroupY - allows to set axes differentlty for different nameGroupY elements
+%   options.linetype            = String with MATLAB linetype (default: '.-')
+%   options.linecolor           = Color for lines (default: [0.2 0.2 0.2])
+%   options.showmarkers         = 1 shows different linestyles with markers, =0 uses linstyle setting
+%   options.markersize          = numeric value for markersizes (default: 10)
+%   options.linecolorsCustom    = Matrix with 3 comlumns and arbitrary rows. Defines custom color settings to use for color grouping
+%   options.linetypesCustom     = Cell-array with linestyle strings (e.g.: {'x','-.','--'}). If defined it overrides the standard lines from IQMgetcolors (only active if color group selected)
+%                                 Only active if "options.showmarkers=1".
+%   options.linewidth           = Numeric value 1-5 (default: 1)
+%   options.sameaxes            = If 0 (default) all subplot axes will be scaled to best fit the data, if 1 all axes will have same scaling 
+%                                 All rows will always be on same Y axes, as will be all columns on same X axes
+%   options.showgrid            = 0: no grid, 1: grid (no minor grid lines) (default: 1)
+%   options.colortitlebar       = Vector with three values between 0 and 1 to set he titlebar color (default: [1 1 0.8])
+%   options.heighttitlebarX     = Height of the titlebar on top in fraction of subplot (default: determined automatically)
+%   options.widthtitlebarY      = Width of the titlebar on the right in fraction of subplot (default: determined automatically)
+%   options.showmedian           = 0 (default): do not show a moving median line per group, 1: do show it
+%   options.showmean            = 0 (default): do not show a moving mean line per group, 1: do show it
+%   options.NbinsMedian          = value between 0 and 100 defining the range of data to take into account (default: 15)
+%   options.showlegend          = 0: do not show a legend, 1 (default): show a legend for the color grouping
+%   options.labeltextsize       = Fontsize for x and y labels (default: 10)
+%   options.maxlegendentries    = If more elements in colorgroup then do not show legend (becomes messy). Default: 10
+%   options.ticklabeltextsize   = Fontsize for axes number (default: 10)
+%   options.legendtextsize      = Fontsize for legend (default: 10)
+%   options.nameText            = Column name in dataset (text in column) to display next to datapoints
+%   options.nameTextLines       = 1: show lines additional to text (if nameText is defined). 0: do not show lines (if nameText is defined).
+%   options.textFontsize        = Fontsize for additional text (default: 10)
+%   options.axescolor           = Sets the color of axes and grid (default: [0.2 0.2 0.2])
+%   options.windowcolor         = color definition for outside frame of window (default: [1 1 1])
+%   options.titlefontsize       = Fontsize for title bars (default: 8)
+% 
+% [OUTPUT]
+% This function creates a new figure. 
+%
+% [ASSUMPTIONS]
+% Data for X and Y axes and all groups needs to be numeric. 
+ 
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get default colors and linestyles
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[colorsDefault,linesDefault] = IQMgetcolors();
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get optional variables and set defaults if undefined
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try options             = options;                          catch, options              = [];               end;
+try xlabelText          = options.xlabelText;               catch, xlabelText           = nameX;            end; %#ok<*CTCH>
+try ylabelText          = options.ylabelText;               catch, ylabelText           = NaN;              end; % handled later
+try nameSubGroup        = options.nameSubGroup;             catch, nameSubGroup         = '';               end;
+try nameColorGroup      = options.nameColorGroup;           catch, nameColorGroup       = '';               end;
+try logX                = options.logX;                     catch, logX                 = 0;                end;
+try logY                = options.logY;                     catch, logY                 = 0;                end; % Can be vector
+try linetype            = options.linetype;                 catch, linetype             = '.-';             end; %#ok<*NASGU>
+try linecolor           = options.linecolor;                catch, linecolor            = [0.2 0.2 0.2];    end;
+try showmarkers         = options.showmarkers;              catch, showmarkers          = 0;                end;
+try markersize          = options.markersize;               catch, markersize           = 10;               end;
+try linecolorsCustom    = options.linecolorsCustom;         catch, linecolorsCustom     = colorsDefault;    end;
+try linetypesCustom     = options.linetypesCustom;          catch, linetypesCustom      = linesDefault;     end;
+try linewidth           = options.linewidth;                catch, linewidth            = 1;                end;
+try sameaxes            = options.sameaxes;                 catch, sameaxes             = 1;                end;
+try showgrid            = options.showgrid;                 catch, showgrid             = 1;                end;
+try colortitlebar       = options.colortitlebar;            catch, colortitlebar        = [1 1 0.8];        end;
+try heighttitlebarX     = options.heighttitlebarX;          catch, heighttitlebarX      = NaN;              end;
+try widthtitlebarY      = options.widthtitlebarY;           catch, widthtitlebarY       = NaN;              end;
+try showmedian          = options.showmedian;               catch, showmedian           = 0;                end;
+try showmean            = options.showmean;                 catch, showmean             = 0;                end;
+try NbinsMedian         = options.NbinsMedian;              catch, NbinsMedian           = 15;              end;
+try showlegend          = options.showlegend;               catch, showlegend           = 1;                end;
+try labeltextsize       = options.labeltextsize;            catch, labeltextsize        = 10;               end;
+try ticklabeltextsize   = options.ticklabeltextsize;        catch, ticklabeltextsize    = 10;               end;
+try legendtextsize      = options.legendtextsize;           catch, legendtextsize       = 10;               end;
+try maxlegendentries    = options.maxlegendentries;         catch, maxlegendentries     = 10;               end;
+try nameText            = options.nameText;                 catch, nameText             = '';               end;
+try nameTextLines       = options.nameTextLines;            catch, nameTextLines        = 1;                end;
+try textFontsize        = options.textFontsize;             catch, textFontsize         = 10;               end;
+try axescolor           = options.axescolor;                catch, axescolor            = 0.2*[1 1 1];      end;
+try windowcolor         = options.windowcolor;              catch, windowcolor          = 1*[1 1 1];        end;
+try titlefontsize       = options.titlefontsize;            catch, titlefontsize        = 8;               end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Settings for making plots nicer when same axes are chosen
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SpacingHoriz = 0.002;
+SpacingVert  = 0.003;
+Padding      = 0;
+Margin       = 0.1;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get group information
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(nameGroupX),
+    allGroupX = -1;
+else
+    allGroupX = unique(data.(nameGroupX));
+end
+if isempty(nameGroupY),
+    allGroupY = -1;
+else
+    allGroupY = unique(data.(nameGroupY));
+end
+if ~isempty(nameColorGroup),
+    allGROUPcolor   = unique(data.(nameColorGroup));
+    data.colorgroup = data.(nameColorGroup);
+else
+    allGROUPcolor   = -1;
+    data.colorgroup = -1*ones(height(data),1);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Adjust logY settings
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if length(logY)==1,
+    logY = logY*ones(1,length(allGroupY));
+elseif length(logY)~=length(allGroupY),
+    error('options.logY needs to be 0 or 1, or a vector with 0 or 1 of same length as number of Y groups.');
+end
+% If sameaxes, use first setting of logY
+if sameaxes,
+    logY = logY(1)*ones(1,length(allGroupY));
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Define ylabeltext if not given as option
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~iscell(ylabelText),
+    if isnan(ylabelText),
+        ylabelText = {};
+        for k=1:length(allGroupY),
+            ylabelText{k} = sprintf('%s (%s=%g)',nameY,nameGroupY,allGroupY(k));
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Define subplot information
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ncols       = length(allGroupX);
+nrows       = length(allGroupY);
+nSubplots   = nrows*ncols;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle title bar sizes
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isnan(heighttitlebarX),
+    heighttitlebarX = 0.04+0.02*nrows;
+end
+if isnan(widthtitlebarY),
+    widthtitlebarY = 3/4*heighttitlebarX/nrows*ncols;
+    if widthtitlebarY > 0.5,
+        widthtitlebarY = 0.5;
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Run through the group X and Y, define subplot settings, color settings
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+dataPlot            = table();
+for kX=1:length(allGroupX),
+    if ~isempty(nameGroupX),
+        dataX = subsetIQM(data,nameGroupX,allGroupX(kX));
+    else
+        dataX = data;
+    end
+    
+    for kY=1:length(allGroupY),
+        if ~isempty(nameGroupY),
+            dataXY = subsetIQM(dataX,nameGroupY,allGroupY(kY));
+        else
+            dataXY = dataX;
+        end
+        
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        % If log X or Y, remove <=0 data from respective parts
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        if ~isempty(dataXY),
+            if logX == 1,
+                dataXY(dataXY.(nameX)<=0,:) = [];
+            end
+            if logY(kY) == 1,
+                dataXY(dataXY.(nameY)<=0,:) = [];
+            end
+            
+            for kC=1:length(allGROUPcolor),
+                dataXYC = subsetIQM(dataXY,'colorgroup',allGROUPcolor(kC));
+                
+                if ~isempty(dataXYC),
+                    datatemp = table();
+                    datatemp.(nameX)        = dataXYC.(nameX);
+                    datatemp.(nameY)        = dataXYC.(nameY);
+                    if isnumeric(allGroupX(kX)),
+                        datatemp.groupX         = allGroupX(kX)*ones(height(datatemp),1);
+                    else
+                        datatemp.groupX         = cell(height(datatemp),1);
+                        datatemp.groupX(1:end)  = {allGroupX{kX}};
+                    end
+                    if isnumeric(allGroupY(kY)),
+                        datatemp.groupY         = allGroupY(kY)*ones(height(datatemp),1);
+                    else
+                        datatemp.groupY         = cell(height(datatemp),1);
+                        datatemp.groupY(1:end)  = {allGroupY{kY}};
+                    end
+                    datatemp.plotSubplot    = ( (kY-1)*ncols + kX )*ones(height(datatemp),1);
+                    datatemp.colorgroup     = dataXYC.colorgroup;
+                    if ~isempty(nameSubGroup),
+                        datatemp.subgroup   = dataXYC.(nameSubGroup);
+                    else
+                        datatemp.subgroup   = ones(height(datatemp),1);
+                    end
+                    if isnumeric(dataXYC.colorgroup(1)),
+                        if dataXYC.colorgroup(1) == -1,
+                            datatemp.color      = -1*ones(height(datatemp),1);
+                        else
+                            datatemp.color      = find(allGROUPcolor==dataXYC.colorgroup(1))*ones(height(datatemp),1);
+                        end
+                    else
+                        datatemp.color      = find(strcmp(allGROUPcolor,dataXYC.colorgroup{1}))*ones(height(datatemp),1);
+                    end
+                    if ~isempty(nameText),
+                        datatemp.(nameText) = dataXYC.(nameText);
+                    end
+                    dataPlot = [dataPlot; datatemp];
+                end
+            end
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Determine the x and y axes ranges if sameaxes selected and
+% adjust the maxY and maxX part of the axes settings to allow for title bar
+% on the X and Y axes.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+minX = min(dataPlot.(nameX));
+maxX = max(dataPlot.(nameX));
+minY = min(dataPlot.(nameY));
+maxY = max(dataPlot.(nameY));
+% Adjust maxY for titlebarX
+if logY(1)==1,
+    rangenew =  1/(1-heighttitlebarX-0.01)*(log10(maxY)-log10(minY));
+    maxY     = 10.^(log10(minY) + rangenew);
+else
+    rangenew =  1/(1-heighttitlebarX-0.01)*(maxY-minY);
+    maxY     = minY + rangenew;
+end
+% Adjust maxX for titlebarY
+if logX==1,
+    rangenew =  1/(1-widthtitlebarY-0.01)*(log10(maxX)-log10(minX));
+    maxX     = 10.^(log10(maxX) + rangenew);
+else
+    rangenew =  1/(1-widthtitlebarY-0.01)*(maxX-minX);
+    maxX     = minX + rangenew;
+end
+sameAxesLimits = [minX maxX minY maxY];
+
+% Determine the axes limits for each row (for each row it should at
+% least be the same) Only for Y axis. X the same as under sameaxes
+rowAxesLimits = [];
+for krow=1:length(allGroupY),
+    datarow = subsetIQM(dataPlot,'groupY',allGroupY(krow));
+    if ~isempty(datarow),
+        minY = min(datarow.(nameY));
+        maxY = max(datarow.(nameY));
+    else
+        minY = eps;
+        maxY = 1;
+    end
+    if minY==maxY,
+        % could happen if all data 0 for a row
+        maxY = minY+1;
+    end
+    % Adjust maxY for titlebarX
+    if logY(krow)==1,
+        rangenew =  1/(1-heighttitlebarX-0.01)*(log10(maxY)-log10(minY));
+        maxY     = 10.^(log10(minY) + rangenew);
+    else
+        rangenew =  1/(1-heighttitlebarX-0.01)*(maxY-minY);
+        maxY     = minY + rangenew;
+    end
+    rowAxesLimits = [rowAxesLimits; sameAxesLimits(1:2) minY maxY];
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Open new figure
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+figure;
+set(gcf,'Color',windowcolor);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Plot the data in the order of subplots
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+for kSubplot=1:nSubplots,
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    % Choose subplot
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    
+    subaxis(nrows,ncols,kSubplot,'SpacingVert',SpacingVert,'SpacingHoriz',SpacingHoriz,'Padding',Padding,'Margin',Margin);
+
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    % Get subplot data
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+        
+    dataSk = dataPlot(dataPlot.plotSubplot==kSubplot,:);
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    % Plot single plot using general auxiliary function
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+            
+    if ~isempty(dataSk),
+        
+        optionsplotgeneral = options;
+        if ~isempty(nameGroupX),
+            if isnumeric(dataSk.groupX(1)),
+                optionsplotgeneral.titleText = sprintf('%s=%s',nameGroupX,num2str(dataSk.groupX(1)));
+            else
+                optionsplotgeneral.titleText = sprintf('%s=%s',nameGroupX,dataSk.groupX{1});
+            end
+        else
+            optionsplotgeneral.titleText = 'All Data';
+        end
+        if sameaxes,
+            optionsplotgeneral.axesLimits = sameAxesLimits;
+        else
+            subplotrow = ceil(kSubplot/ncols);
+            optionsplotgeneral.axesLimits = rowAxesLimits(subplotrow,:);
+        end
+        optionsplotgeneral.showtitlebar = 0;
+        optionsplotgeneral.sameaxes     = 1;
+        optionsplotgeneral.logY = logY(ceil(kSubplot/ncols));
+        
+        plotgeneralIQM(dataSk,nameX,nameY,optionsplotgeneral);
+
+    else
+        if sameaxes, axis(sameAxesLimits);
+        else subplotrow = ceil(kSubplot/ncols); axis(rowAxesLimits(subplotrow,:)); end
+        hold on
+        if logX, set(gca,'XScale','log'); end
+        if logY(ceil(kSubplot/ncols)), set(gca,'YScale','log'); end
+        if showgrid, grid on; end
+        set(gca,'XMinorGrid','off')
+        set(gca,'YMinorGrid','off')
+        set(gca,'XColor',axescolor);
+        set(gca,'YColor',axescolor);
+        set(gca,'FontUnits','points','FontSize',ticklabeltextsize);    
+    end
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    % Switch off xtick and ytick 
+    % labels if sameaxes is chosen
+    %%%%%%%%%%%%%%%%%%%%%%%%%   
+    
+    if mod(kSubplot-1,ncols)+1 > 1,
+        set(gca,'YtickLabel','');
+    end
+    
+    if kSubplot <= nSubplots-ncols,
+        set(gca,'XtickLabel','');
+    end
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    % Handle x labels
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    
+    if kSubplot > nSubplots-ncols,
+        xlabel(xlabelText,'FontUnits','points','FontSize',labeltextsize,'Interpreter','none');
+    end
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    % Handle y labels
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    
+    if mod(kSubplot-1,ncols)+1 == 1,
+        nrow = ceil(kSubplot/ncols);
+        ylabel(ylabelText{nrow},'FontUnits','points','FontSize',labeltextsize,'Interpreter','none');       
+    end
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    % Handle titlebarX
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    
+    if kSubplot<=ncols,
+        % Get axes limits
+        XLim = get(gca,'XLim');
+        YLim = get(gca,'YLim');
+        % Get X position for text
+        if logX==1,
+            X = 10^(log10(XLim(1)) + 0.5*(log10(XLim(2))-log10(XLim(1))));
+        else
+            X = XLim(1) + 0.5*(XLim(2)-XLim(1));
+        end
+        % Get Y position for text and title bar
+        if logY(ceil(kSubplot/ncols))==1,
+            Y = 10^(log10(YLim(1)) + (1-heighttitlebarX/2)*(log10(YLim(2))-log10(YLim(1))));
+            YtitlebarDN = 10^(log10(YLim(1)) + (1-heighttitlebarX)*(log10(YLim(2))-log10(YLim(1))));
+            YtitlebarUP = 10^(log10(YLim(1)) + 1*(log10(YLim(2))-log10(YLim(1))));
+        else
+            Y = YLim(1) + (1-heighttitlebarX/2)*(YLim(2)-YLim(1));
+            YtitlebarDN = YLim(1) + (1-heighttitlebarX)*(YLim(2)-YLim(1));
+            YtitlebarUP = YLim(1) + 1*(YLim(2)-YLim(1));
+        end
+        % Create a title bar background
+        filled = [YtitlebarUP*[1 1],YtitlebarDN*[1 1]];
+        xpoints=[XLim,fliplr(XLim)];
+        h = fill(xpoints,filled,colortitlebar);
+        set(h,'EdgeColor',axescolor);
+        % Print the title text
+        if length(allGroupX)==1,
+            text(X,Y,'All Data','FontWeight','bold','FontSize',titlefontsize,'HorizontalAlignment','Center');
+        else
+            if isnumeric(allGroupX(1)),
+                text(X,Y,sprintf('%s\n%g',nameGroupX,allGroupX(kSubplot)),'FontWeight','bold','FontSize',titlefontsize,'HorizontalAlignment','Center');
+            else
+                text(X,Y,sprintf('%s\n%s',nameGroupX,allGroupX{kSubplot}),'FontWeight','bold','FontSize',titlefontsize,'HorizontalAlignment','Center','Interpreter','none');
+            end
+        end
+    end
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    % Handle titlebarY
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    
+    if  mod(kSubplot-1,ncols)+1==ncols,
+        % Get axes limits
+        XLim = get(gca,'XLim');
+        YLim = get(gca,'YLim');
+        % Get Y position for text
+        if logY(ceil(kSubplot/ncols)) == 1,
+            Y = 10^(log10(YLim(1)) + 0.5*(log10(YLim(2))-log10(YLim(1))));
+        else
+            Y = YLim(1) + 0.5*(YLim(2)-YLim(1));
+        end
+        % Get X position for text and title bar
+        if logX==1,
+            X = 10^(log10(XLim(1)) + (1-widthtitlebarY/2)*(log10(XLim(2))-log10(XLim(1))));
+            XtitlebarDN = 10^(log10(XLim(1)) + (1-widthtitlebarY)*(log10(XLim(2))-log10(XLim(1))));
+            XtitlebarUP = 10^(log10(XLim(1)) + 1*(log10(XLim(2))-log10(XLim(1))));
+        else
+            X = XLim(1) + (1-widthtitlebarY/2)*(XLim(2)-XLim(1));
+            XtitlebarDN = XLim(1) + (1-widthtitlebarY)*(XLim(2)-XLim(1));
+            XtitlebarUP = XLim(1) + 1*(XLim(2)-XLim(1));
+        end
+        % Create a title bar background
+        xpoints = [XtitlebarUP*[1 1],XtitlebarDN*[1 1]];
+        filled=[YLim,fliplr(YLim)];
+        h = fill(xpoints,filled,colortitlebar);
+        set(h,'EdgeColor',axescolor);
+        % Print the title text
+        if length(allGroupY)==1,
+            h = text(X,Y,'All Data','FontWeight','bold','FontSize',titlefontsize,'HorizontalAlignment','Center','Rotation',270);
+        else
+            if isnumeric(allGroupY(1)),
+                h = text(X,Y,sprintf('%s\n%g',nameGroupY,allGroupY(ceil(kSubplot/ncols))),'FontWeight','bold','FontSize',titlefontsize,'HorizontalAlignment','Center','Rotation',270);
+            else
+                h = text(X,Y,sprintf('%s\n%s',nameGroupY,allGroupY{ceil(kSubplot/ncols)}),'FontWeight','bold','FontSize',titlefontsize,'HorizontalAlignment','Center','Rotation',270,'Interpreter','none');
+            end
+        end
+    end
+     
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    % Handle legend - simplistic one
+    % Only do so for color group and median plots
+    % Only show legend if less than maxlegendentries
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    
+    if showlegend && kSubplot==1 && length(allGROUPcolor)<=maxlegendentries,
+        legendText = {};
+        legendColor = {};
+        % Check if color group chosen
+        if allGROUPcolor(1) ~= -1,
+            for kleg=1:length(allGROUPcolor),
+                % Get text part
+                legendText{kleg} = sprintf('%s=%g',nameColorGroup,allGROUPcolor(kleg));
+                % Get color part
+                legendColor{kleg} = linecolorsCustom(mod(kleg-1,length(linecolorsCustom))+1,:);
+                % Get marker part
+                if showmarkers,
+                    legendText{kleg} = sprintf('%s %s',linetypesCustom{   mod(kleg-1,length(linetypesCustom))+1},legendText{kleg});
+                end
+            end
+        end
+        % Check if moving median lines are shown
+        if showmedian,
+            legendText{end+1} = 'Binned median'; %#ok<*AGROW>
+            legendColor{end+1} = [0 0 0];
+        end
+
+        if showmean,
+            legendText{end+1} = 'Binned mean'; %#ok<*AGROW>
+            legendColor{end+1} = [0 0 0];
+        end
+        
+        % Determine y locations
+        nlegend = length(legendText);
+        YLim = get(gca,'YLim');
+        XLim = get(gca,'XLim');
+        
+        if logY==1,
+            textY = 10.^(log10(YLim(1))+((maxlegendentries:-1:1)/(maxlegendentries+1)-heighttitlebarX)*(log10(YLim(2))-log10(YLim(1))));
+        else
+            textY = YLim(1)+((maxlegendentries:-1:1)/(maxlegendentries+1)-heighttitlebarX)*(YLim(2)-YLim(1));
+        end
+        if logX==1,
+            textX = 10.^(log10(XLim(1))+0.98*(log10(XLim(2))-log10(XLim(1))));
+        else
+            textX = XLim(1)+0.98*(XLim(2)-XLim(1));
+        end
+        for klegend=1:nlegend,
+            text(textX,textY(klegend),legendText{klegend},'Color',legendColor{klegend},'FontWeight','bold','FontUnits','points','FontSize',legendtextsize,'HorizontalAlignment','Right','Interpreter','none');
+        end
+    end
+    
+end
+    
+  
+
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplotfill.m b/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplotfill.m
new file mode 100644
index 0000000000000000000000000000000000000000..e3b4780ed2955d338aa438139d900529bf4af476
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplotfill.m	
@@ -0,0 +1,112 @@
+function [fillhandle] = IQMplotfill(x,lower,upper,color,transparency,logY,logX,edgeColor)
+% This function will fill a region with a color between the two vectors 
+% provided using the Matlab fill command. With the logY and logX flags
+% correct handling of the data will be done, allowing to correctly plot the
+% filled area. 
+%
+% [SYNTAX]
+% [fillhandle] = IQMplotfill(x,lower,upper)
+% [fillhandle] = IQMplotfill(x,lower,upper,color)
+% [fillhandle] = IQMplotfill(x,lower,upper,color,transparency)
+% [fillhandle] = IQMplotfill(x,lower,upper,color,transparency,logY)
+% [fillhandle] = IQMplotfill(x,lower,upper,color,transparency,logY,logX)
+% [fillhandle] = IQMplotfill(x,lower,upper,color,transparency,logY,logX,edgeColor)
+%
+% [INPUT]
+% x             = The horizontal data points. Note: length(upper)
+%                 must equal length(lower)and must equal length(x)!
+% upper         = the upper curve values 
+% lower         = the lower curve values 
+% color         = the color of the filled area (default: [0.8 0.8 0.8])
+% transparency  = is a value ranging from 1 for opaque to 0 for invisible for
+%                 the filled color only (default: 1)
+% logY:         = 1: set log y-axis, =0: set lin y-axis (Default: 0 if no figure, otherwise take settings from current axes)
+% logX:         = 1: set log x-axis, =0: set lin x-axis (Default: 0 if no figure, otherwise take settings from current axes)
+% edgeColor:    = the color around the edge of the filled area (default: none)
+%
+% [OUTPUT]
+% fillhandle is the returned handle to the filled region in the plot.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+% Handle variable input arguments
+if nargin<4,
+    color = [0.8 0.8 0.8];
+end
+if nargin<5,
+    transparency = 1;
+end
+if nargin<6,
+    logY = 0;
+    % Set YScale according to current plot
+    if strcmp(get(gca,'YScale'),'log'),
+        logY = 1;
+    end
+end
+if nargin<7,
+    logX = 0;
+    % Set XScale according to current plot
+    if strcmp(get(gca,'XScale'),'log'),
+        logX = 1;
+    end
+end
+if nargin<8,
+    edgeColor = [];
+end
+
+% Check that inputs are vectors
+if ~isvector(x),
+    error('x needs t be a vector.');
+end
+if ~isvector(lower),
+    error('lower needs t be a vector.');
+end
+if ~isvector(upper),
+    error('upper needs t be a vector.');
+end
+
+% Force inputs to row vectors
+x               = x(:)';
+upper           = upper(:)';
+lower           = lower(:)';
+
+% Find NaN values and remove
+ix              = find(isnan(upper)); x(ix) = []; upper(ix) = []; lower(ix) = [];
+ix              = find(isnan(lower)); x(ix) = []; upper(ix) = []; lower(ix) = [];
+ix              = find(isnan(x));     x(ix) = []; upper(ix) = []; lower(ix) = [];
+
+% Find <=0 values in x and remove (only remove if logX==1)
+if logX,
+    ix              = find(x<=0); x(ix) = []; upper(ix) = []; lower(ix) = [];
+end
+
+% Find <=0 values in upper and lower remove (only remove if logY==1)
+if logY,
+    ix              = find(upper<=0); x(ix) = []; upper(ix) = []; lower(ix) = [];
+    ix              = find(lower<=0); x(ix) = []; upper(ix) = []; lower(ix) = [];
+end
+
+% Plot the filled area
+fillhandle = fill( [x fliplr(x)],  [upper fliplr(lower)], color);
+
+% Set transparency
+set(fillhandle,'FaceAlpha',transparency);
+
+% Set edge color if defined
+if ~isempty(edgeColor),
+    set(fillhandle,'EdgeColor',edgeColor,'EdgeAlpha',transparency);
+else
+    set(fillhandle,'EdgeColor',color,'EdgeAlpha',transparency);
+end    
+
+% Set axes transformation
+if logX,
+    set(gca,'XScale','log');
+else
+    set(gca,'XScale','linear');
+end
+if logY,
+    set(gca,'YScale','log');
+else
+    set(gca,'YScale','linear');
+end
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplotpairwiseCorr.m b/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplotpairwiseCorr.m
new file mode 100644
index 0000000000000000000000000000000000000000..ac2f85b795f90949c21a00a1ac4ec60665d18f3b
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplotpairwiseCorr.m	
@@ -0,0 +1,167 @@
+function [] = IQMplotpairwiseCorr(data,OPTIONS)
+% This function plots the pairwise correlation between variables passed in
+% columns of a matrix or passed as a dataset.
+%
+% [SYNTAX]
+% [] = IQMplotpairwiseCorr(data)
+% [] = IQMplotpairwiseCorr(data,OPTIONS)
+%
+% [INPUT]
+% data:         Matrix or dataset. Each column corresponds to a variable
+%               and each row to a sample
+% OPTIONS:      MATLAB structure with optional arguments
+%
+%                   options.names:     cell-array with variable names. In
+%                       case of data as dataset names will be taken from the
+%                       header but can be overwritten with this option. If
+%                       variable values are provided in a matrix, it is better
+%                       to provide the names using this option
+%                   options.LogFlag:   =1 do log transform the variables,
+%                                      =0 do not transform (default: 0)
+%                   options.CorrThres:   Value between 0 and 1 indicating the
+%                       threshold for the Pearson correlation coefficient from which on a
+%                       different color as background should be used (default:
+%                       0.3)
+%                   options.AxisColor:  [r g b] numeric values to use as color 
+%                       for background if Corr>CorrThres =1 do log transform
+%                       the variables (default: [1 0.2 0.2])
+%
+% [OUTPUT]
+% Pairwise correlation plots.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+% Check if dataset or if matrix
+% If dataset ten use columnnames as default values for names
+if istable(data),
+    names = data.Properties.VariableNames;
+    % Make a matrix out of it
+    data = table2array(data);
+elseif strcmp(class(data),'double'),
+    names = {};
+    for k=1:size(data,2),
+        names{k} = sprintf('Data#%d',k);
+    end
+end
+
+% Default settings
+% Flag to take log of values
+LogFlag = 0;
+% Coloring
+CorrThres = 0.3; % Pearson correlation coefficient threshold for different background color
+AxisColor = [1 .4 .4]; %color of axis when 
+
+% Get optional values if defined
+try names = OPTIONS.names; catch, end;
+try LogFlag = OPTIONS.LogFlag; catch, end;
+try CorrThres = OPTIONS.CorrThres; catch, end;
+try AxisColor = OPTIONS.AxisColor; catch, end;
+
+% Subindex properties
+Spacing = 0;
+Padding = 0;
+Margin  = .1;
+    
+clf;
+n = length(names);
+for ir=1:n
+    ystr = names{ir};
+    y = data(:,ir);
+    if LogFlag==1
+        y = log(y);
+        ystr = {'log',ystr}; %#ok<*AGROW>
+    end
+    for ic=1:ir
+        xstr = names{ic};
+        x = data(:,ic);
+        if LogFlag==1
+            x = log(x);
+            xstr = {'log',xstr};
+        end
+        ip = (ir-1)*n+ic;
+        subaxis(n,n,ip,'Spacing',Spacing,'Padding',Padding,'Margin',Margin);
+        if ir==ic %plot histogram 
+            % Only do this if not only NaN values are present
+            if ~isempty(find(isnan(x)==0)),
+                [b xbin] = hist(x,20);
+                h = bar(xbin,b,1);
+                if min(x)~=max(x),
+                    set(gca,'XLim',[min(x) max(x)]);
+                else
+                    set(gca,'XLim',[min(x)-1 max(x)+1]);
+                end                    
+            end
+            set(h,'FaceColor',0.4*[1 1 1],'LineStyle','none')
+            title(xstr,'Interpreter','none')
+        else %plot correlation
+            % Remove pairs if at least one is NaN
+            xuse = x;
+            yuse = y;
+            ixx = find(isnan(xuse));
+            xuse(ixx) = []; yuse(ixx) = [];
+            ixx = find(isnan(yuse));
+            xuse(ixx) = []; yuse(ixx) = [];
+            if ~isempty(xuse),
+                % Determine pearsons coefficient of correlation
+                [rho,pval]  = corrcoef(xuse,yuse);
+                rho         = rho(1,2);
+                pval        = pval(1,2);
+
+                % Plot
+                if abs(rho)>CorrThres
+                    optcorr.Color     = AxisColor;
+                else
+                    optcorr.Color     = 0.6*[1 1 1];
+                end
+                optcorr.LineColor = [0 0 0];
+                optcorr.TitleType = 'none';
+                optcorr.LineStyle = '-';
+                optcorr.LineWidth = 2;
+                optcorr.MarkerSize = 10;
+                plotcorrIQM(xuse,yuse,optcorr);
+                
+                xt = (min(xuse)+max(xuse))/2;
+                yt = min(yuse)+.6*(max(yuse)-min(yuse));
+                if abs(rho)>=0.01
+                    if pval>=0.01,
+                        str = sprintf('corr=%1.2f\np=%1.2f',rho,pval);
+                    else
+                        str = sprintf('corr=%1.2f\np<0.01',rho);
+                    end
+                else
+                    str = '|corr|<0.01';
+                end
+                text(xt,yt,str,'Color',[0 0 0],'Hor','Right','Ver','Middle','FontWeight','Bold','Interpreter','none');
+                
+                if min(xuse)~=max(xuse),
+                set(gca,'XLim',[min(xuse) max(xuse)]);
+                else
+                set(gca,'XLim',[min(xuse)-1 max(xuse)+1]);
+                end
+                if min(yuse)~=max(yuse),
+                    set(gca,'YLim',[min(yuse) max(yuse)]);
+                else
+                    set(gca,'YLim',[min(yuse)-1 max(yuse)+1]);
+                end
+            end
+        end
+        
+        % Define fontsize
+        if length(names)<=6,
+            FONTSIZE = 10;
+        else
+            FONTSIZE = 8;
+        end
+        
+        if ic==1
+            ylabel(ystr,'Interpreter','none','FontSize',FONTSIZE);
+        end
+        set(gca,'YTick',[]);
+        
+        if ir==n
+            xlabel(xstr,'Interpreter','none','FontSize',FONTSIZE);
+        end
+        set(gca,'XTick',[]);
+        
+    end
+end
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplotselected.m b/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplotselected.m
new file mode 100644
index 0000000000000000000000000000000000000000..ebd12fae4bbf00ac5b5b14b53626ae98b06f6ced
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplotselected.m	
@@ -0,0 +1,100 @@
+function IQMplotselected(simdata,plotcomponents,varargin)
+% IQMplotselected: Takes a simulation result as input. Additionally, the
+% names of states, variables, and reactions can be defined for which the
+% values should be plotted. 
+%
+% USAGE:
+% ======
+% IQMplotselected(simdata,plotcomponents)
+% IQMplotselected(simdata,plotcomponents,headers)
+%
+% simdata: Simulation results returned, e.g. from IQMsimulate
+% plotcomponents: cell-array with component names to plot (states,
+%   variables and/or reactions). Alternatively, the cell-array can contain 
+%   only cell-arrays of component names. This allows to define
+%   plot-subgroups, which can be selected using the pulldown menu in the
+%   upper left corner of the IQMplot window.
+% headers: if plotcomponents contains only cell-arrays, then this input
+%   argument contains the names to be displayed in the pull-down menu.
+%
+% DEFAULT VALUES:
+% ===============
+% headers: {'plot 1', 'plot 2', ...}
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check plotcomponents argument
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~iscell(plotcomponents),
+    error('IQMplotselected:componentsNotCellArray','Second input argument needs to be a cell-array.');
+end
+charfound = 0;
+cellfound = 0;
+for k=1:length(plotcomponents),
+    if ischar(plotcomponents{k}),
+        charfound = 1;
+    elseif iscell(plotcomponents{k}),
+        cellfound = 1;
+    end
+end
+if charfound == 1 && cellfound == 1,
+    error('IQMplotselected:charCellMix','Second input argument needs to contain either chars or cells. Not both!');
+end
+% convert char to cell model
+if charfound == 1,
+    plotcomponents = {plotcomponents};
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+headers = {};
+for k=1:length(plotcomponents),
+    headers{k} = sprintf('plot %d',k);
+end
+if nargin == 3,
+    headers = varargin{1};
+end
+if length(headers) ~= length(plotcomponents),
+    error('IQMplotselected:wrongHeadersLength','Wrong number of elements in third input argument.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Prepare the different plot structures
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+plotstructures = {};
+states = simdata.states; sind = 1:length(states);
+variables = simdata.variables; vind = 1:length(variables);
+reactions = simdata.reactions; rind = 1:length(reactions);
+for k=1:length(plotcomponents),
+    comp = plotcomponents{k};
+    simdatak = simdata;
+    sind_keep = [];
+    vind_keep = [];
+    rind_keep = [];
+    for k2=1:length(comp),
+        % reduce simulation results to only contain the components in comp
+        sind_keep = [sind_keep strmatchIQM(comp{k2},states,'exact')];
+        vind_keep = [vind_keep strmatchIQM(comp{k2},variables,'exact')];
+        rind_keep = [rind_keep strmatchIQM(comp{k2},reactions,'exact')];
+    end
+    simdatak.states = simdatak.states(sind_keep);
+    simdatak.statevalues = simdatak.statevalues(:,sind_keep);
+    simdatak.variables = simdatak.variables(vind_keep);
+    simdatak.variablevalues = simdatak.variablevalues(:,vind_keep);
+    simdatak.reactions = simdatak.reactions(rind_keep);
+    simdatak.reactionvalues = simdatak.reactionvalues(:,rind_keep);
+    % convert to plot structure 
+    plotstructures{k} = createdatastruct2IQMplotIQM(simdatak,headers{k}); 
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Construct IQMplot command and plot
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+plotcommand = 'IQMplot(';
+for k=1:length(plotstructures),
+    plotcommand = sprintf('%splotstructures{%d},',plotcommand,k);
+end
+plotcommand = [plotcommand(1:end-1) ')'];
+eval(plotcommand)
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplottrellis.m b/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplottrellis.m
new file mode 100644
index 0000000000000000000000000000000000000000..e2a3ca46426d79cee0fca744452a45e71bf212ea
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/plots/IQMplottrellis.m	
@@ -0,0 +1,528 @@
+function [] = IQMplottrellis(data,nameGroup,nameX,nameY,options)
+% This function plots a Trellis plot. Plenty of options available.
+%
+% [SYNTAX]
+% [] = IQMplottrellis(data,nameGroup,nameX,nameY)
+% [] = IQMplottrellis(data,nameGroup,nameX,nameY,options)
+%
+% [INPUT]
+% data:         Matlab table
+% nameGroup:    Column name in dataset to use as group variable. If empty,
+%               then no grouping is done.
+% nameX:        Column name in dataset to plot on X axis
+% nameY:        Column name in dataset to plot on Y axis
+% options:      Structure with optional settings as follows:
+%   options.xlabelText          = String with xlabel text. Default: nameX
+%   options.ylabelText          = String with ylabel text. Default: nameY
+%   options.nameSubGroup        = Column name in dataset for subgrouping within a group/subplot (nicer line drawing and used for moving median line);
+%   options.nameColorGroup      = Column name in dataset for coloring a certain group differently
+%   options.logX                = 0 if lin, 1 if log X axis (default: 0)
+%   options.logY                = 0 if lin, 1 if log Y axis (default: 0)
+%   options.linetype            = String with MATLAB linetype (default: '.-')
+%   options.linecolor           = Color for lines (default: [0.2 0.2 0.2])
+%   options.showmarkers         = 1 shows different linestyles with markers, =0 uses linstyle setting
+%   options.markersize          = numeric value for markersizes (default: 10)
+%   options.linecolorsCustom    = Matrix with 3 comlumns and arbitrary rows. Defines custom color settings to use for color grouping
+%   options.linetypesCustom     = Cell-array with linestyle strings (e.g.: {'x','-.','--'}). If defined it overrides the standard lines from IQMgetcolors (only active if color group selected)
+%                                 Only active if "options.showmarkers=1".
+%   options.linewidth           = Numeric value 1-5 (default: 1)
+%   options.sameaxes            = If 0 (default) subplot axes will be scaled to best fit the data, if 1 all axes will have same scaling
+%   options.showgrid            = 0: no grid, 1: grid (no minor grid lines) (default: 1)
+%   options.colortitlebar       = Vector with three values between 0 and 1 to set he titlebar color (default: [1 1 0.8])
+%   options.heighttitlebar      = Height of the titlebar in fraction of subplot (default: 0.08)
+%   options.showtitlebar        = 0: do not show titlebar, 1: show titlebar (default)
+%   options.showmedian           = 0 (default): do not show a moving median line per group, 1: do show it
+%   options.NbinsMedian          = value between 0 and 100 defining the range of data to take into account (default: 15)
+%   options.showlegend          = 0: do not show a legend, 1 (default): show a legend for the color grouping
+%   options.labeltextsize       = Fontsize for x and y labels (default: 10)
+%   options.maxlegendentries    = If more elements in colorgroup then do not show legend (becomes messy). Default: 10
+%   options.ticklabeltextsize   = Fontsize for axes number (default: 10)
+%   options.legendtextsize      = Fontsize for legend (default: 10)
+%   options.nrows               = Number of rows per subplot (default: all groups in one figure)
+%   options.ncols               = Number of columns per subplot (default: all groups in one figure)
+%   options.ylabelfirstonly     = 1: show the ylabel only for first subplot in figure, 0: show for all first in row subplots
+%   options.nameText            = Column name in dataset (text in column) to display next to datapoints
+%   options.nameTextLines       = 1: show lines additional to text (if nameText is defined). 0: do not show lines (if nameText is defined).
+%   options.textFontsize        = Fontsize for additional text (default: 10)
+%   options.filename            = Filename for PS (windows) or PDF (unix) output
+%   options.axescolor           = Sets the color of axes and grid (default: [0.2 0.2 0.2])
+%   options.windowcolor         = color definition for outside frame of window (default: [1 1 1])
+%   options.titlefontsize       = Fontsize for title bars (default: 8)
+% 
+%   The "Vertical Line" option allows to draw vertical lines in subplots in
+%   certain places. Practical, e.g., when plotting PK data and wanting to
+%   plot the dosing times additionally. Several lines can be plotted in a
+%   single subplot. A numeric value needs to be provided for each such
+%   line. The maximum value will correspond to a line covering the whole
+%   range. Smaller values will lead to a shorter line. It is possible to
+%   plot the numeric value next to the top of each line.
+%   options.verticallines.linestyle = linestyle string for the vertical line (default: '--')
+%   options.verticallines.linecolor = color vector for the vertical line (default: [0 0 0])
+%   options.verticallines.data      = dataset with info for vertical lines.
+%       This dataset needs:
+%           - same nameGroup column as main data
+%           - same nameX column as main data
+%           - additionally a nameDataVertical to be used to determine the height of the line
+%   options.verticallines.nameDataVertical = string, specifying the column to use to determine the height of the line
+%   options.verticallines.showtext  = 1: shows the value of "nameDataVertical" column next to the top of the line, =1: does not
+%   options.verticallines.textsize  = text size for the printed value (default: 10)
+%   options.verticallines.shownameDataVertical = 1: prints also the name of "nameDataVertical", =0 does not
+%
+% [OUTPUT]
+% This function creates a new figure. If a filename is provided it also can
+% export plots in a PS (windows) or PDF (unix) document.
+%
+% [ASSUMPTIONS]
+% Data for X and Y axes and all groups needs to be numeric. 
+ 
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get default colors and linestyles
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[colorsDefault,linesDefault] = IQMgetcolors();
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get optional variables and set defaults if undefined
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try xlabelText          = options.xlabelText;               catch, xlabelText           = nameX;            end; %#ok<*CTCH>
+try ylabelText          = options.ylabelText;               catch, ylabelText           = nameY;            end;
+try nameSubGroup        = options.nameSubGroup;             catch, nameSubGroup         = '';               end;
+try nameColorGroup      = options.nameColorGroup;           catch, nameColorGroup       = '';               end;
+try logX                = options.logX;                     catch, logX                 = 0;                end;
+try logY                = options.logY;                     catch, logY                 = 0;                end;
+try linetype            = options.linetype;                 catch, linetype             = '.-';             end; %#ok<*NASGU>
+try linecolor           = options.linecolor;                catch, linecolor            = [0.2 0.2 0.2];    end;
+try showmarkers         = options.showmarkers;              catch, showmarkers          = 0;                end;
+try markersize          = options.markersize;               catch, markersize           = 10;                end;
+try linecolorsCustom    = options.linecolorsCustom;         catch, linecolorsCustom     = colorsDefault;    end;
+try linetypesCustom     = options.linetypesCustom;          catch, linetypesCustom      = linesDefault;     end;
+try linewidth           = options.linewidth;                catch, linewidth            = 1;                end;
+try sameaxes            = options.sameaxes;                 catch, sameaxes             = 1;                end;
+try showgrid            = options.showgrid;                 catch, showgrid             = 1;                end;
+try colortitlebar       = options.colortitlebar;            catch, colortitlebar        = [1 1 0.8];        end;
+try heighttitlebar      = options.heighttitlebar;           catch, heighttitlebar       = 0.08;             end;
+try showtitlebar        = options.showtitlebar;             catch, showtitlebar         = 1;                end;
+try showmedian          = options.showmedian;               catch, showmedian           = 0;                end;
+try NbinsMedian         = options.NbinsMedian;              catch, NbinsMedian          = 15;               end;
+try showlegend          = options.showlegend;               catch, showlegend           = 1;                end;
+try labeltextsize       = options.labeltextsize;            catch, labeltextsize        = 10;               end;
+try ticklabeltextsize   = options.ticklabeltextsize;        catch, ticklabeltextsize    = 10;               end;
+try legendtextsize      = options.legendtextsize;           catch, legendtextsize       = 10;               end;
+try nrows               = options.nrows;                    catch, nrows                = NaN;              end;
+try ncols               = options.ncols;                    catch, ncols                = NaN;              end;
+try ylabelfirstonly     = options.ylabelfirstonly;          catch, ylabelfirstonly      = 0;                end;
+try maxlegendentries    = options.maxlegendentries;         catch, maxlegendentries     = 10;               end;
+try nameText            = options.nameText;                 catch, nameText             = '';               end;
+try nameTextLines       = options.nameTextLines;            catch, nameTextLines        = 1;                end;
+try textFontsize        = options.textFontsize;             catch, textFontsize         = 10;               end;
+try filename            = options.filename;                 catch, filename             = '';               end;
+try axescolor           = options.axescolor;                catch, axescolor            = 0.2*[1 1 1];      end;
+try windowcolor         = options.windowcolor;              catch, windowcolor          = 1*[1 1 1];        end;
+try verticallines_linestyle             = options.verticallines.linestyle;              catch, verticallines_linestyle              = '--';             end;
+try verticallines_linecolor             = options.verticallines.linecolor;              catch, verticallines_linecolor              = [0 0 0];          end;
+try verticallines_data                  = options.verticallines.data;                   catch, verticallines_data                   = [];               end;
+try verticallines_nameDataVertical      = options.verticallines.nameDataVertical;       catch, verticallines_nameDataVertical       = [];               end;
+try verticallines_showtext              = options.verticallines.showtext;               catch, verticallines_showtext               = 1;                end;
+try verticallines_textsize              = options.verticallines.textsize;               catch, verticallines_textsize               = 10;               end;
+try verticallines_shownameDataVertical  = options.verticallines.shownameDataVertical;   catch, verticallines_shownameDataVertical   = 0;                end;
+try titlefontsize                       = options.titlefontsize;            catch, titlefontsize        = 8;               end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% If logY chosen then remove all <=0 data
+% Same for logX
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if logY==1,
+    data(data.(nameY)<=0,:) = [];
+end
+if logX==1,
+    data(data.(nameX)<=0,:) = [];
+end
+ 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% If NaN in nameX then remove
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+data(isnan(data.(nameY)),:) = [];
+data(isnan(data.(nameX)),:) = [];
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Settings for making plots nicer when same axes are chosen
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if sameaxes,
+    SpacingHoriz = 0.002;
+    SpacingVert  = 0.003;
+    Padding      = 0;
+    Margin       = 0.1;
+else
+    SpacingHoriz = 0.05;
+    SpacingVert  = 0.05;
+    Padding      = 0.0;
+    Margin       = 0.1;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Format the data to match the grouping
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get plot data alone
+dataPlot            = table();
+dataPlot.(nameX)    = data.(nameX);
+dataPlot.(nameY)    = data.(nameY);
+if ~isempty(nameText),
+    dataPlot.(nameText) = data.(nameText);
+end
+if ~isempty(nameGroup)
+    dataPlot.group  = data.(nameGroup);
+else
+    dataPlot.group  = ones(length(dataPlot),1);
+end
+if ~isempty(nameSubGroup),
+    dataPlot.subgroup = data.(nameSubGroup);
+else
+    dataPlot.subgroup = ones(length(dataPlot),1);
+end
+if ~isempty(nameColorGroup),
+    dataPlot.colorgroup = data.(nameColorGroup);
+    dataPlot.color      = -1*ones(height(dataPlot),1);
+    allGROUPcolor       = unique(dataPlot.colorgroup);    
+    for k=1:length(allGROUPcolor),
+        dataPlot.color(ixdataIQM(dataPlot,'colorgroup',allGROUPcolor(k))) = k;
+    end
+else
+    dataPlot.colorgroup = -1*ones(height(dataPlot),1);
+    dataPlot.color      = -1*ones(height(dataPlot),1);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Determine the x and y axes ranges if sameaxes selected and
+% adjust the maxY part of the axes settings to allow for title bar
+% Goal is to increase the range of minY to maxY by a fraction of
+% heighttitlebar
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if sameaxes,
+	minX = min(dataPlot.(nameX));
+	maxX = max(dataPlot.(nameX));
+	minY = min(dataPlot.(nameY));
+	maxY = max(dataPlot.(nameY));
+    % Adjust maxY for titlebar
+    if logY==1,
+        rangenew =  1/(1-heighttitlebar-0.01)*(log10(maxY)-log10(minY));
+        maxY     = 10.^(log10(minY) + rangenew);
+    else
+        rangenew =  1/(1-heighttitlebar-0.01)*(maxY-minY);
+        maxY     = minY + rangenew;
+    end
+    sameAxesLimits = [minX maxX minY maxY];
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get different group elements - for each subplot
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+allGROUP = unique(dataPlot.group);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get number of possible elements in sub group
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+allGROUPsub = unique(dataPlot.subgroup);    
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get number of possible elements in color group
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+allGROUPcolor = unique(dataPlot.colorgroup);    
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Determine number of subplot rows/cols per figure
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+nAllGroups = length(allGROUP);
+if isnan(ncols) || isnan(nrows),
+    ncols = ceil(sqrt(nAllGroups));
+    nrows = ceil(nAllGroups/ncols);
+end
+nSubplots = ncols*nrows;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Determine number of figures needed for the plotting
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+nFigures = ceil(nAllGroups/nSubplots);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% If output to file desired then start here the file
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(filename),
+    IQMstartNewPrintFigure(filename);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Plot the data
+% Plot moving median line if desired in each subplot for data within the same color group
+% Subgroup is not considered
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for k=1:length(allGROUP),
+
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    % Handle multiple figures and subplots
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    
+    plotFigure  = ceil(k/nSubplots);
+    plotSubplot = mod(k-1,nSubplots)+1;  
+
+    % Clear figure if first subplot going to be plotted and set windowcolor
+    if plotSubplot==1, 
+        try close(plotFigure); catch, end
+        figure(plotFigure); 
+        set(gcf,'Color',windowcolor);
+    else
+        figure(plotFigure); 
+    end
+    % Choose subplot
+    subaxis(nrows,ncols,plotSubplot,'SpacingVert',SpacingVert,'SpacingHoriz',SpacingHoriz,'Padding',Padding,'Margin',Margin);
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    % Get group data for each subplot
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    datak = subsetIQM(dataPlot,'group',allGROUP(k));
+        
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    % Handle correct XLim in case of vertical lines
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    if ~isempty(verticallines_data),
+        dataVLk = subsetIQM(verticallines_data,nameGroup,allGROUP(k));
+        
+        if ~isempty(dataVLk),
+            % Get data - check if available in verticallines_data
+            try
+                XVLk = dataVLk.(nameX);
+            catch
+                error(sprintf('Please check settings for vertical lines - nameX and options.verticallines.nameDataVertical\nneed to be set correctly and be present in options.verticallines.data.')); %#ok<SPERR>
+            end
+            % Get X axis if needed because of vertical lines
+            XLimMin = [min(XVLk) max(XVLk)];
+        else
+            XLimMin = [];
+        end
+    else
+        XLimMin = [];
+    end        
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    % Plot single plot using general auxiliary function
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    if ~isempty(nameGroup),
+        if isnumeric(allGROUP),
+            options.titleText = sprintf('%s=%s',nameGroup,num2str(allGROUP(k)));
+        else
+            options.titleText = sprintf('%s',allGROUP{k});
+        end
+    else
+        options.titleText = 'All Data';
+    end    
+    if sameaxes,
+        options.axesLimits = sameAxesLimits;
+    else
+        options.axesLimits = [];
+    end
+    % Set minimum X-axes in options
+    options.XLimMin = XLimMin;
+    
+    % Set axes color
+    options.axescolor = axescolor;
+    
+    options.titlefontsize = titlefontsize;
+    
+    plotgeneralIQM(datak,nameX,nameY,options);
+ 
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    % Switch off xtick and ytick 
+    % labels if sameaxes is chosen
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    if sameaxes,
+        % xticklabels
+        if plotFigure < nFigures,
+            % All subplots used => remove xticklabels in all but last row
+            if plotSubplot <= nSubplots-ncols,
+                set(gca,'XtickLabel','');
+            end
+        else
+            % Figure only partially filled with subplots - only labels for
+            % the last ncols subplots
+            if k <= nAllGroups-ncols,
+                set(gca,'XtickLabel','');
+            end
+        end
+        % yticklabels
+        if mod(plotSubplot-1,ncols)+1 > 1,
+            set(gca,'YtickLabel','');
+        end
+    end
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    % Handle x labels
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    
+    if plotFigure < nFigures,
+        % All subplots used => xlabel for the last ncols subplots
+        if plotSubplot > nSubplots-ncols,
+            xlabel(xlabelText,'FontUnits','points','FontSize',labeltextsize,'Interpreter','none','Color',axescolor);
+        end
+    else
+        % Figure only partially filled with subplots - only labels for
+        % the last ncols subplots
+        if k > nAllGroups-ncols,
+            xlabel(xlabelText,'FontUnits','points','FontSize',labeltextsize,'Interpreter','none','Color',axescolor);
+        end
+    end
+        
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    % Handle y labels
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    
+    if ylabelfirstonly && plotSubplot==1 && nrows > 1,
+        ylabel(ylabelText,'FontUnits','points','FontSize',labeltextsize,'HorizontalAlignment','Right','Interpreter','none','Color',axescolor);
+    elseif nrows == 1,
+        if plotSubplot==1,
+            ylabel(ylabelText,'FontUnits','points','FontSize',labeltextsize,'Interpreter','none','Color',axescolor);     
+        end
+    elseif ~ylabelfirstonly && mod(plotSubplot-1,ncols)+1==1,
+        ylabel(ylabelText,'FontUnits','points','FontSize',labeltextsize,'Interpreter','none','Color',axescolor);       
+    end
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    % Handle legend - simplistic one
+    % Only do so for color group and median plots
+    % Only show legend if less than maxlegendentries
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    
+    if showlegend && plotSubplot==1 && length(allGROUPcolor)<=maxlegendentries,
+        legendText = {};
+        legendColor = {};
+        % Check if color group chosen
+        if isnumeric(allGROUPcolor(1)),
+            if allGROUPcolor(1)~= -1,
+                for kleg=1:length(allGROUPcolor),
+                    % Get text part
+                    legendText{kleg} = sprintf('%s=%g',nameColorGroup,allGROUPcolor(kleg));
+                    % Get color part
+                    legendColor{kleg} = linecolorsCustom(mod(kleg-1,length(linecolorsCustom))+1,:);
+                    % Get marker part
+                    if showmarkers,
+                        legendText{kleg} = sprintf('%s %s',linetypesCustom{   mod(kleg-1,length(linetypesCustom))+1},legendText{kleg});
+                    end
+                end
+            end
+        else
+            for kleg=1:length(allGROUPcolor),
+                % Get text part
+                legendText{kleg} = sprintf('%s=%s',nameColorGroup,allGROUPcolor{kleg});
+                % Get color part
+                legendColor{kleg} = linecolorsCustom(mod(kleg-1,length(linecolorsCustom))+1,:);
+                % Get marker part
+                if showmarkers,
+                    legendText{kleg} = sprintf('%s %s',linetypesCustom{   mod(kleg-1,length(linetypesCustom))+1},legendText{kleg});
+                end
+            end
+        end
+                
+        % Check if moving median lines are shown
+        if showmedian,
+            legendText{end+1} = 'Binned median'; %#ok<*AGROW>
+            legendColor{end+1} = [0 0 0];
+        end
+        
+        % Determine y locations
+        nlegend = length(legendText);
+        YLim = get(gca,'YLim');
+        XLim = get(gca,'XLim');
+        
+        if logY==1,
+            textY = 10.^(log10(YLim(1))+((maxlegendentries:-1:1)/(maxlegendentries+1)-heighttitlebar)*(log10(YLim(2))-log10(YLim(1))));
+        else
+            textY = YLim(1)+((maxlegendentries:-1:1)/(maxlegendentries+1)-heighttitlebar)*(YLim(2)-YLim(1));
+        end
+        if logX==1,
+            textX = 10.^(log10(XLim(1))+0.98*(log10(XLim(2))-log10(XLim(1))));
+        else
+            textX = XLim(1)+0.98*(XLim(2)-XLim(1));
+        end
+        for klegend=1:nlegend,
+            text(textX,textY(klegend),legendText{klegend},'Color',legendColor{klegend},'FontWeight','bold','FontUnits','points','FontSize',legendtextsize,'HorizontalAlignment','Right','Interpreter','none');
+        end
+    end
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    % Handle and plot vertical lines if specified
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    
+    if ~isempty(verticallines_data),
+        dataVLk = subsetIQM(verticallines_data,nameGroup,allGROUP(k));
+        if ~isempty(dataVLk),
+            
+            % Get data - check if available in verticallines_data
+            try
+                XVLk = dataVLk.(nameX);
+                DVLk = dataVLk.(verticallines_nameDataVertical);
+            catch
+                error(sprintf('Please check settings for vertical lines - nameX and options.verticallines.nameDataVertical\nneed to be set correctly and be present in options.verticallines.data.')); %#ok<SPERR>
+            end
+            % Normalize DVLk - and handle also titlebar
+            DVLknorm = (1-heighttitlebar-0.01)* DVLk/max(DVLk);
+            % Determine Y range for plot
+            YLim = get(gca,'YLim');
+            Ydn = YLim(1);
+            if logY==1,
+                Yup = 10.^(log10(YLim(1))+DVLknorm*(log10(YLim(2))-log10(YLim(1))));
+                Ytext = 10.^(log10(YLim(1))+(DVLknorm-0.05)*(log10(YLim(2))-log10(YLim(1))));
+            else
+                Yup = YLim(1)+DVLknorm*(YLim(2)-YLim(1));
+                Ytext = YLim(1)+(DVLknorm-0.05)*(YLim(2)-YLim(1));
+            end
+            % Plot the lines
+            for kVL=1:length(Yup),
+                plot([XVLk(kVL),XVLk(kVL)],[Ydn,Yup(kVL)],verticallines_linestyle,'Color',verticallines_linecolor);
+            end
+            % Show text if desired - but only first and then when changes
+            if verticallines_showtext,
+                for kVL=1:length(Yup),
+                    if kVL==1,
+                        if verticallines_shownameDataVertical,
+                            text(XVLk(kVL),Ytext(kVL),[' ' verticallines_nameDataVertical '=' num2str(DVLk(kVL))],'Color',verticallines_linecolor,'FontSize',verticallines_textsize,'BackgroundColor',windowcolor);
+                        else
+                            text(XVLk(kVL),Ytext(kVL),[' ' num2str(DVLk(kVL))],'Color',verticallines_linecolor,'FontSize',verticallines_textsize,'BackgroundColor',windowcolor);
+                        end
+                    elseif Ytext(kVL)~=Ytext(kVL-1),
+                        if verticallines_shownameDataVertical,
+                            text(XVLk(kVL),Ytext(kVL),[' ' verticallines_nameDataVertical '=' num2str(DVLk(kVL))],'Color',verticallines_linecolor,'FontSize',verticallines_textsize,'BackgroundColor',windowcolor);
+                        else
+                            text(XVLk(kVL),Ytext(kVL),[' ' num2str(DVLk(kVL))],'Color',verticallines_linecolor,'FontSize',verticallines_textsize,'BackgroundColor',windowcolor);
+                        end
+                    end
+                end
+            end
+        end
+    end
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    % If figure finished and output to file desired then do that
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    if ~isempty(filename),
+        if plotFigure < nFigures,
+            if plotSubplot == nSubplots,
+                IQMprintFigure(gcf,filename);
+                close(plotFigure);
+            end
+        else
+            if k == nAllGroups,
+                IQMprintFigure(gcf,filename);
+                close(plotFigure);
+            end
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%
+% If output to file desired then convert to pdf
+%%%%%%%%%%%%%%%%%%%%%%%%%
+IQMconvert2pdf(filename);
+
+
+
+
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/plots/auxiliary/plotboxIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/plots/auxiliary/plotboxIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..25e9b678bd46d1a3179659d584191956ddc5b8cd
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/plots/auxiliary/plotboxIQM.m	
@@ -0,0 +1,147 @@
+function [h] = plotboxIQM(Y,tm,OPTIONS)
+% This function plots boxplots of time course stored in Y structure.
+%
+% This function is an auxiliary function, called by
+% IQMplotCovarianceCat
+%
+% [SYNTAX]
+% [h] = plotboxIQM(Y,tm,OPTIONS)
+%
+% [INPUT]
+% Y can either be a matrix of size Nxlength(tm) or a structure with
+%    Y(i).t = time variable
+%    Y(i).y = y variable
+% tm     = bin centers
+% OPTIONS:      Structure with optional settings as follows:
+%   OPTIONS.HorOffset = 0
+%   OPTIONS.MedianColor = [0 0 .5]
+%   OPTIONS.MedianWidth = 0.2
+%   OPTIONS.MedianLineWidth = 1
+%   OPTIONS.BoxColor = [0 0 1]
+%   OPTIONS.BoxWidth = 0.1
+%   OPTIONS.LineWidth = 3
+%   OPTIONS.Perc = 10
+%   OPTIONS.OutlierColor = [0 0 1]
+%   OPTIONS.OutlierSize = 6
+%   OPTIONS.NumFlag = 1
+%   OPTIONS.NumColor = 'k'
+%   OPTIONS.NumTextY = 1
+%   OPTIONS.FontColor = 'k'
+%   OPTIONS.XLabel = []
+%   OPTIONS.YLabel = []
+%   OPTIONS.XTick = []
+%   OPTIONS.XLim = []
+%
+% [OUTPUT]
+% Plot
+ 
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle options and default values
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%positioning properties
+try HorOffset = OPTIONS.HorOffset;              catch,  HorOffset = 0;                  end
+%median line
+try MedianColor = OPTIONS.MedianColor;          catch, MedianColor = [0 0 .5];          end
+try MedianWidth = OPTIONS.MedianWidth;          catch, MedianWidth = 0.2;               end
+try MedianLineWidth = OPTIONS.MedianLineWidth;  catch, MedianLineWidth = 1;             end
+%box properties 25%-75%
+try BoxColor = OPTIONS.BoxColor;                catch, BoxColor = [0 0 1];              end
+try BoxWidth = OPTIONS.BoxWidth;                catch, BoxWidth = 0.1;                  end
+%line properties Perc%-100-Perc%
+try LineWidth = OPTIONS.LineWidth;              catch, LineWidth = 3;                   end %10-90% Line
+try Perc = OPTIONS.Perc;                        catch, Perc = 10;                       end
+%outlier properties
+try OutlierColor = OPTIONS.OutlierColor;        catch, OutlierColor = [0 0 1];          end 
+try OutlierSize = OPTIONS.OutlierSize;          catch, OutlierSize = 6;                 end     
+%text properties (number of pts)
+try NumFlag = OPTIONS.NumFlag;                  catch, NumFlag = 1;                     end 
+try NumColor = OPTIONS.NumColor;                catch, NumColor = 'k';                  end 
+try NumTextY = OPTIONS.NumTextY;                catch, NumTextY = 1;                    end     
+%axis properties
+try FontColor = OPTIONS.FontColor;              catch, FontColor = 'k';                 end 
+try XLabel = OPTIONS.XLabel;                    catch, XLabel = [];                     end 
+try YLabel = OPTIONS.YLabel;                    catch, YLabel = [];                     end 
+try XTick = OPTIONS.XTick;                      catch, XTick = [];                      end 
+try XLim = OPTIONS.XLim;                        catch, XLim = [];                       end 
+
+%bin the variable   
+if isstruct(Y)
+    dt = mean(diff(tm));
+    YY = NaN(length(Y),length(tm));
+    for i=1:length(Y)
+        t = Y(i).t;
+        y = Y(i).y;
+        for j=1:length(tm)
+            [dtij ind] = min(abs(t-tm(j)));
+            if dtij<=dt/2
+                YY(i,j) = y(ind);
+            end
+        end
+    end
+else
+    YY = Y;
+end
+
+%draw the boxplot   
+    hold on
+    for i=1:length(tm)
+        t  = tm(i)+HorOffset;
+        y = YY(:,i);
+            
+        %draw the line (p1%-100-p1%)        
+            y1 = prctileIQM(y,Perc);
+            y2 = prctileIQM(y,100-Perc);        
+            plot([t t],[y1 y2],'Color',BoxColor,'LineWidth',LineWidth);
+
+        %draw the outliers
+            ii = find(y<y1 | y>y2);
+            plot(t*ones(size(ii)),y(ii),'+','Color',OutlierColor,'MarkerSize',OutlierSize);    
+
+        %draw the box (25%-75%)
+            t1 = t-BoxWidth/2;
+            t2 = t+BoxWidth/2;
+
+            y1 = prctileIQM(y,25);
+            y2 = prctileIQM(y,75);
+
+            tt = [t1 t2 t2 t1 t1];
+            yy = [y1 y1 y2 y2 y1];
+
+            h = fill(tt,yy,BoxColor,'LineStyle','none');
+            
+        %draw the line at 50%
+            yi = prctileIQM(y,50);
+            t1= t-MedianWidth/2;
+            t2= t+MedianWidth/2;
+            plot([t1 t2],[yi yi],'Color',MedianColor,'LineWidth',MedianLineWidth);                        
+            
+            
+        %number of patients
+            if NumFlag==1
+                if i==1
+                    s = 'n=';
+                else
+                    s = '';
+                end
+                text(t,NumTextY,sprintf('%s%d',s,sum(~isnan(y))),'Horiz','Center','Color',NumColor,'FontWeight','Bold')        
+            end
+    end
+
+%plot labels        
+    hold on
+    xlim = get(gca,'XLim');
+    
+    if ~isempty(XLabel)
+        xlabel(XLabel,'Color',FontColor,'Interpreter','none')
+    end
+    if ~isempty(YLabel)
+        ylabel(YLabel,'Color',FontColor,'Interpreter','none')
+    end
+    if ~isempty(XTick)
+        set(gca,'XTick',XTick);
+    end
+    if ~isempty(XLim)
+        set(gca,'XLim',XLim);
+    end
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/plots/auxiliary/plotcorrIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/plots/auxiliary/plotcorrIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..c618aa8bf92f250dd75812eb57f78d2438213a1a
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/plots/auxiliary/plotcorrIQM.m	
@@ -0,0 +1,125 @@
+function[R2 pval slope yint] = plotcorrIQM(xvar,yvar,OPTIONS)
+% This function plots correlation of x variable and y variable.
+%
+% This function is an auxiliary function, called by
+% IQMplotpairwiseCorr
+%
+% [SYNTAX]
+% [] = plotcorrIQM(xvar,yvar,props)
+%
+% [INPUT]
+% xvar:         Vector with x data
+% yvar:         Vector with y data
+% OPTIONS:      Structure with optional settings as follows:
+%     OPTIONS.Color = 'b';
+%     OPTIONS.TitleType = 'all';
+%     OPTIONS.LineColor = 'k';
+%     OPTIONS.LineStyle = '-';
+%     OPTIONS.LineWidth = 2;
+%     OPTIONS.Marker    = '.';
+%     OPTIONS.MarkerSize = 6;
+%     OPTIONS.MarkerFaceColor = 'none';
+%     OPTIONS.XLabel = '';
+%     OPTIONS.YLabel = '';
+%     OPTIONS.XLim   = [];
+%     OPTIONS.YLim   = [];
+%
+% [OUTPUT]
+% Plot
+%
+% [ASSUMPTIONS]
+% Data for X and Y axes and all groups needs to be numeric. 
+ 
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%set default values
+    Color = 'b';
+    TitleType = 'all';
+    LineColor = 'k';
+    LineStyle = '-';
+    LineWidth = 2;
+    Marker    = '.';
+    MarkerSize = 6;
+    MarkerFaceColor = 'none';
+    XLabel = '';
+    YLabel = '';
+    XLim   = [];
+    YLim   = [];
+
+    try Color = OPTIONS.Color; catch, end;
+    try TitleType = OPTIONS.TitleType; catch, end;
+    try LineColor = OPTIONS.LineColor; catch, end;
+    try LineStyle = OPTIONS.LineStyle; catch, end;
+    try LineWidth = OPTIONS.LineWidth; catch, end;
+    try Marker = OPTIONS.Marker; catch, end;
+    try MarkerSize = OPTIONS.MarkerSize; catch, end;
+    try MarkerFaceColor = OPTIONS.MarkerFaceColor; catch, end;
+    try XLabel = OPTIONS.XLabel; catch, end;
+    try YLabel = OPTIONS.YLabel; catch, end;
+    try XLim = OPTIONS.XLim; catch, end;
+    try YLim = OPTIONS.YLim; catch, end;
+    
+plot(xvar,yvar,Marker,'Color',Color,'MarkerSize',MarkerSize,'MarkerFaceColor',MarkerFaceColor);    
+hold on
+% Do linear regression
+[b,bint,r,rint,stats] = regressIQM(yvar,[ones(size(xvar)) xvar]);
+xx = linspace(min(xvar),max(xvar),100);
+plot(xx,b(1)+b(2)*xx,'Color',LineColor,'LineWidth',LineWidth,'LineStyle',LineStyle)    
+slope = b(2);
+yint  = b(1);
+
+R2 = stats(1); % R2 = corrcoeff^2 for linear regression
+pval = stats(3);
+switch TitleType
+    case 'all'
+        if b(2)>.0005 && b(2) < 1000 
+            tstr{1} = sprintf('m = %1.3f',b(2));
+        else
+            tstr{1} = sprintf('m = %1.2e',b(2));
+        end
+        if pval > .0001
+            tstr{2} = sprintf('R^2 = %1.3f, pval = %1.4f',R2,pval);%,'Color',Color);
+        else
+            tstr{2} =sprintf('R^2 = %1.3f, pval < .0001',R2);%,'Color',Color);
+        end    
+    case 'p'
+        tstr = sprintf('p=%1.4f',pval);
+    case 'r'
+        tstr = sprintf('R^2=%1.3f',R2);
+    case {'rp','pr'}
+        tstr = sprintf('p=%1.4f, R^2=%1.2f',pval,R2);
+    case {'mr','rm'}
+        tstr = sprintf('m=%1.3f, R^2=%1.2f',b(2),R2);
+    case {'pm','mp'}
+        if pval > .01    
+            tstr = (sprintf('p=%1.2f, m=%1.3f',pval,b(2)));    
+        elseif pval > .001
+            tstr = (sprintf('p<0.01, m=%1.3f',b(2)));    
+        elseif pval > .0001
+            tstr = (sprintf('p<0.001, m=%1.3f',b(2)));    
+        else
+            tstr = (sprintf('p<0.0001, m=%1.3f',b(2)));    
+        end
+    case {'none'}
+        tstr = '';
+    otherwise
+        error('invalid TitleType')
+end    
+title(tstr,'Interpreter','none');
+
+xlabel(XLabel,'Interpreter','none')
+ylabel(YLabel,'Interpreter','none')
+if ~isempty(XLim)
+    set(gca,'XLim',props.XLim) 
+elseif min(xvar)~=max(xvar),
+    set(gca,'XLim',[min(xvar) max(xvar)]);
+else
+    set(gca,'XLim',[min(xvar)-1 max(xvar)+1]);
+end    
+if ~isempty(YLim)
+    set(gca,'YLim',props.YLim) 
+elseif min(yvar)~=max(yvar),
+    set(gca,'YLim',[min(yvar) max(yvar)]);
+else
+    set(gca,'YLim',[min(yvar)-1 max(yvar)+1]);
+end    
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/plots/auxiliary/plotgeneralIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/plots/auxiliary/plotgeneralIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..1d65309da87393609674fee1f15bee2d84fdedbe
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/plots/auxiliary/plotgeneralIQM.m	
@@ -0,0 +1,553 @@
+function [] = plotgeneralIQM(datak,nameX,nameY,options)
+% This function plots x,y data in different ways. Used as the plot base for
+% IQMplottrellis and IQMplotXY
+%
+% [SYNTAX]
+% [] = plotgeneralIQM(data,nameX,nameY)
+% [] = plotgeneralIQM(data,nameX,nameY,options)
+%
+% [INPUT]
+% datak:        Dataset to plot
+%               It is assumed that datak contains a column "subgroup" with
+%               numeric identifiers about different groupings. Also it is
+%               assumed that datak contains a column "colorgroup" with
+%               numeric identifiers selecting the color (-1 being the
+%               default color).
+% nameX:        Column name in dataset to plot on X axis
+% nameY:        Column name in dataset to plot on Y axis
+% options:      Structure with optional settings as follows:
+%   options.logX                = 0 if lin, 1 if log X axis (default: 0)
+%   options.logY                = 0 if lin, 1 if log Y axis (default: 0)
+%   options.linetype            = String with MATLAB linetype (default: '.-')
+%   options.linecolor           = Color for lines (default: [0.6 0.6 0.6])
+%   options.showmarkers         = 1 shows different linestyles with markers, =0 uses linstyle setting
+%   options.markersize          = numeric value for markersizes (default: 10)
+%   options.linecolorsCustom    = Matrix with 3 comlumns and arbitrary rows. Defines custom color settings to use for color grouping
+%   options.linetypesCustom     = Cell-array with linestyle strings (e.g.: {'x','-.','--'}). If defined it overrides the standard lines from IQMgetcolors (only active if color group selected)
+%                                 Only active if "options.showmarkers=1".
+%   options.linewidth           = Numeric value 1-5 (default: 1)
+%   options.axesLimits          = [minX maxX minY maxY] can be passed as axes limits. By default the axes are adjusted to the data
+%   options.showgrid            = 0: no grid, 1: grid (no minor grid lines) (default: 1)
+%   options.colortitlebar       = Vector with three values between 0 and 1 to set he titlebar color (default: [1 1 0.8])
+%   options.heighttitlebar      = Height of the titlebar in fraction of subplot (default: 0.08)
+%   options.showtitlebar        = 0: do not show titlebar, 1: show titlebar (default)
+%   options.showmedian           = 0 (default): do not show a moving median line per group, 1: do show it
+%   options.showmean           = 0 (default): do not show a moving mean line per group, 1: do show it
+%   options.NbinsMedian          = value between 0 and 100 defining the range of data to take into account (default: 15)
+%   options.medianlinewidth      = width of moving median line (default: options.linewidth+1)
+%   options.showregressionline  = 1 shows a linear regression line, =0: does not (default)
+%   options.showloessline       = 1: shwows a loess line (10% range), 0 does not (default)
+%   options.showcorrelations    = 1 shows correlation info, =0 does not (default) - only done if options.showregressionline=1
+%   options.correlationstextsize= text size for correlation information (default: 10)
+%   options.ticklabeltextsize   = Fontsize for axes number (default: 10)
+%   options.nameText            = Column name in dataset (text or numeric values in column) to display instead of datapoints
+%   options.nameTextLines       = 1: show lines additional to text (if nameText is defined). 0: do not show lines (if nameText is defined).
+%   options.textFontsize        = Fontsize for additional text (default: 10)
+%   options.axescolor           = Sets the color of axes and grid (default: [0.2 0.2 0.2])
+%   options.titleText           = Text in the title bar (default: 'Title')
+%   options.titlefontsize       = FontSize for the title (default: 8)
+%   options.XLimMin             = minimal x-axis range (2 elements 1st: minX, 2nd: maxX)
+%
+% [OUTPUT]
+% This function creates a new figure. If a filename is provided it also can
+% export plots in a PS (windows) or PDF (unix) document.
+%
+% [ASSUMPTIONS]
+% Data for X and Y axes and all groups needs to be numeric.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get default colors and linestyles
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[colorsDefault,linesDefault] = IQMgetcolors();
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get optional variables and set defaults if undefined
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try logX                    = options.logX;                     catch, logX                 = 0;                end;
+try logY                    = options.logY;                     catch, logY                 = 0;                end;
+try linetype                = options.linetype;                 catch, linetype             = '.-';             end;
+try linecolor               = options.linecolor;                catch, linecolor            = [0.6 0.6 0.6];    end;
+try showmarkers             = options.showmarkers;              catch, showmarkers          = 0;                end;
+try markersize              = options.markersize;               catch, markersize           = 10;               end;
+try linecolorsCustom        = options.linecolorsCustom;         catch, linecolorsCustom     = colorsDefault;    end;
+try linetypesCustom         = options.linetypesCustom;          catch, linetypesCustom      = linesDefault;     end;
+try linewidth               = options.linewidth;                catch, linewidth            = 1;                end;
+try axesLimits              = options.axesLimits;               catch, axesLimits           = [];               end;
+try showgrid                = options.showgrid;                 catch, showgrid             = 1;                end;
+try colortitlebar           = options.colortitlebar;            catch, colortitlebar        = [1 1 0.8];        end;
+try heighttitlebar          = options.heighttitlebar;           catch, heighttitlebar       = 0.08;             end;
+try showtitlebar            = options.showtitlebar;             catch, showtitlebar         = 1;                end;
+try showmedian              = options.showmedian;               catch, showmedian           = 0;                end;
+try showmean                = options.showmean;                 catch, showmean             = 0;                end;
+try NbinsMedian             = options.NbinsMedian;              catch, NbinsMedian          = 15;               end;
+try medianlinewidth         = options.medianlinewidth;          catch, medianlinewidth      = linewidth+1;      end;
+try showregressionline      = options.showregressionline;       catch, showregressionline   = 0;                end;
+try showloessline           = options.showloessline;            catch, showloessline        = 0;                end;
+try showcorrelations        = options.showcorrelations;         catch, showcorrelations     = 0;                end;
+try correlationstextsize    = options.correlationstextsize;     catch, correlationstextsize = 10;               end;
+try ticklabeltextsize       = options.ticklabeltextsize;        catch, ticklabeltextsize    = 10;               end;
+try nameText                = options.nameText;                 catch, nameText             = '';               end;
+try nameTextLines           = options.nameTextLines;            catch, nameTextLines        = 1;                end;
+try textFontsize            = options.textFontsize;             catch, textFontsize         = 10;               end;
+try axescolor               = options.axescolor;                catch, axescolor            = 0.2*[1 1 1];      end;
+try titleText               = options.titleText;                catch, titleText            = 'title';          end;
+try legendIdentifier        = options.legendIdentifier;         catch, legendIdentifier     = 'ColorGroup';     end;
+try XLimMin                 = options.XLimMin;                  catch, XLimMin              = [];               end;
+try titlefontsize           = options.titlefontsize;            catch, titlefontsize        = 8;                end;
+
+if isempty(datak),
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    % Set axes color
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    
+    set(gca,'XColor',axescolor);
+    set(gca,'YColor',axescolor);
+    
+    return;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Other settings
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+allGROUPsub       = unique(datak.subgroup);
+allGROUPcolor     = unique(datak.colorgroup);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Define plottype
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if logY==1 && logX==1,
+    plottype = 'loglog';
+elseif logY==1 && logX==0,
+    plottype = 'semilogy';
+elseif logY==0 && logX==1,
+    plottype = 'semilogx';
+else
+    plottype = 'plot';
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%
+% Plot the data
+%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Get subgroup data
+for kk=1:length(allGROUPsub),
+    datakk = datak(ixdataIQM(datak,'subgroup',allGROUPsub(kk)),:);
+    
+    % Now plot, according to selected color group
+    for kkk=1:length(allGROUPcolor),
+        datakkk = datakk(ixdataIQM(datakk,'colorgroup',allGROUPcolor(kkk)),:);
+        
+        if ~isempty(datakkk),
+            % Get color
+            if datakkk.color(1) == -1,
+                color = linecolor;
+                line  = linetype;
+            else
+                color = linecolorsCustom(mod(datakkk.color(1)-1,length(linecolorsCustom))+1,:);
+                if showmedian,
+                    %                         color = 1.5*color;
+                end
+                if showmarkers,
+                    line  = linetypesCustom{   mod(datakkk.color(1)-1,length(linetypesCustom))+1};
+                else
+                    line = linetype;
+                end
+            end
+            if isempty(nameText),
+                % If labels undefined then plot according to "line"
+                % settings, defined elsewhere
+                feval(plottype,datakkk.(nameX),datakkk.(nameY),line,'Color',color,'LineWidth',linewidth,'MarkerSize',markersize); hold on
+            else
+                if isnumeric(datakkk.(nameText)),
+                    labels1 = cellstr( num2str(datakkk.(nameText), '%d') );
+                else
+                    labels1 = datakkk.(nameText);
+                end
+                % If nameText defined then plot lines only if
+                % nameTextLines=1 otherwise make them white and small
+                % and unseen to ensure correct axes.
+                if ~nameTextLines,
+                    % Do not show lines additional to the text
+                    feval(plottype,datakkk.(nameX),datakkk.(nameY),line,'Color','w','LineWidth',linewidth,'MarkerSize',1); hold on
+                    % Then write out the labels as text with defined color
+                    text(datakkk.(nameX),datakkk.(nameY), labels1, 'VerticalAlignment','middle', 'HorizontalAlignment','center', 'FontSize', 8,'Color',color,'Interpreter','none'); hold on
+                else
+                    % Do show lines additional to the text
+                    feval(plottype,datakkk.(nameX),datakkk.(nameY),line,'Color',color,'LineWidth',linewidth,'MarkerSize',markersize); hold on
+                    % Then write out the labels as text with defined color
+                    text(datakkk.(nameX),datakkk.(nameY), labels1, 'VerticalAlignment','bottom', 'HorizontalAlignment','left', 'FontSize', 8,'Color',color,'Interpreter','none'); hold on
+                end
+            end
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%
+% Plot the moving median line if desired
+%%%%%%%%%%%%%%%%%%%%%%%%%
+
+if showmedian,
+    % Get color group data
+    for kkk=1:length(allGROUPcolor),
+        datakkk = datak(ixdataIQM(datak,'colorgroup',allGROUPcolor(kkk)),:);
+        
+        if height(datakkk) > 1,
+            % Get X and Y data
+            Xdata = datakkk.(nameX);
+            Ydata = datakkk.(nameY);
+            
+            [XdataMedian,YdataMedian] = binnedmedianIQM(Xdata(:),Ydata(:),NbinsMedian,logX);
+            
+            % Handle color, etc.
+            if datakkk.color(1) == -1,
+                color = 0.6*linecolor;
+                line  = linetype;
+            else
+                color = linecolorsCustom(mod(datakkk.color(1)-1,length(linecolorsCustom))+1,:);
+                if showmarkers,
+                    line  = linetypesCustom{   mod(datakkk.color(1)-1,length(linetypesCustom))+1};
+                else
+                    line = '--';
+                end
+            end
+            % Adjust moving median linestyle in case its only dots
+            if length(line) == 1,
+                line = [line '--'];
+            end
+            % Plot moving median line
+            warning off %#ok<WNOFF>
+            feval(plottype,XdataMedian,YdataMedian,line,'LineWidth',medianlinewidth,'Color',color,'MarkerSize',markersize);
+            warning on %#ok<WNON>
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%
+% Plot the moving mean line if desired
+%%%%%%%%%%%%%%%%%%%%%%%%%
+
+if showmean,
+    % Get color group data
+    for kkk=1:length(allGROUPcolor),
+        datakkk = datak(ixdataIQM(datak,'colorgroup',allGROUPcolor(kkk)),:);
+        
+        if length(datakkk) > 1,
+            % Get X and Y data
+            Xdata = datakkk.(nameX);
+            Ydata = datakkk.(nameY);
+            
+            [XdataMean,YdataMean] = binnedmeanIQM(Xdata(:),Ydata(:),NbinsMedian,logX);
+            
+            % Handle color, etc.
+            if datakkk.color(1) == -1,
+                color = 0.6*linecolor;
+                line  = linetype;
+            else
+                color = linecolorsCustom(mod(datakkk.color(1)-1,length(linecolorsCustom))+1,:);
+                if showmarkers,
+                    line  = linetypesCustom{   mod(datakkk.color(1)-1,length(linetypesCustom))+1};
+                else
+                    line = '--';
+                end
+            end
+            % Adjust moving mean linestyle in case its only dots
+            if length(line) == 1,
+                line = [line '--'];
+            end
+            % Plot moving mean line
+            warning off %#ok<WNOFF>
+            feval(plottype,XdataMean,YdataMean,line,'LineWidth',medianlinewidth,'Color',color,'MarkerSize',markersize);
+            warning on %#ok<WNON>
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%
+% Plot the regression line if desired
+% Also determine correlations - to be plotted later after axes adjustment
+%%%%%%%%%%%%%%%%%%%%%%%%%
+
+if showregressionline,
+    corrText = {};
+    corrColor = {};
+    % Get color group data
+    for kkk=1:length(allGROUPcolor),
+        datakkk = datak(ixdataIQM(datak,'colorgroup',allGROUPcolor(kkk)),:);
+        
+        if ~isempty(datakkk),
+            % Get X and Y data
+            Xdata = datakkk.(nameX);
+            Ydata = datakkk.(nameY);
+            % Get XLim data
+            XLim = get(gca,'XLim');
+            % Linear regression
+            if logX==0 && logY==0,
+                B = regressIQM(Ydata,[Xdata ones(size(Xdata))]);
+                XdataRegress = XLim;
+                YdataRegress = B(2)+B(1)*XLim;
+                [rho,pcorr] = corrcoef(Ydata,Xdata);
+                rho = rho(1,2);
+                pcorr = pcorr(1,2);
+            elseif logX==1 && logY==0,
+                B = regressIQM(Ydata,[log(Xdata) ones(size(Xdata))]);
+                XdataRegress = XLim;
+                YdataRegress = B(2)+B(1)*log(XLim);
+                [rho,pcorr] = corrcoef(Ydata,log(Xdata));
+                rho = rho(1,2);
+                pcorr = pcorr(1,2);
+            elseif logX==0 && logY==1,
+                B = regressIQM(log(Ydata),[Xdata ones(size(Xdata))]);
+                XdataRegress = XLim;
+                YdataRegress = exp(B(2)+B(1)*XLim);
+                [rho,pcorr] = corrcoef(log(Ydata),Xdata);
+                rho = rho(1,2);
+                pcorr = pcorr(1,2);
+            else
+                B = regressIQM(log(Ydata),[log(Xdata) ones(size(Xdata))]);
+                XdataRegress = XLim;
+                YdataRegress = exp(B(2)+B(1)*log(XLim));
+                [rho,pcorr] = corrcoef(log(Ydata),log(Xdata));
+                rho = rho(1,2);
+                pcorr = pcorr(1,2);
+            end
+            % Handle color, etc.
+            if datakkk.color(1) == -1,
+                color = linecolor;
+                line  = linetype;
+            else
+                color = linecolorsCustom(mod(datakkk.color(1)-1,length(linecolorsCustom))+1,:);
+                if showmarkers,
+                    line  = linetypesCustom{   mod(datakkk.color(1)-1,length(linetypesCustom))+1};
+                else
+                    line = '-.';
+                end
+            end
+            % Adjust regression linestyle in case its only dots
+            if length(line) == 1,
+                line = [line '-'];
+            end
+            % Plot regression line
+            warning off %#ok<WNOFF>
+            feval(plottype,XdataRegress,YdataRegress,line,'LineWidth',linewidth+1,'Color',color,'MarkerSize',markersize);
+            warning on %#ok<WNON>
+            % Determine correlation text and color
+            corrText{end+1} = sprintf('corr=%1.4f (p=%1.4f)',rho,pcorr);
+            corrColor{end+1} = color;
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%
+% Plot the loess line if desired
+%%%%%%%%%%%%%%%%%%%%%%%%%
+if showloessline,
+    loessColor = {};
+    % Get color group data
+    for kkk=1:length(allGROUPcolor),
+        datakkk = datak(ixdataIQM(datak,'colorgroup',allGROUPcolor(kkk)),:);
+        
+        if ~isempty(datakkk),
+            
+            % Sort by Xdata
+            datakkk = sortrows(datakkk,nameX);
+            
+            % Get X and Y data
+            Xdata = datakkk.(nameX);
+            Ydata = datakkk.(nameY);
+            
+            % Get XLim data
+            XLim = get(gca,'XLim');
+            
+            % Generate loess smoothed line
+            if logX==0 && logY==0,
+                Ysmooth = smoothIQM(Xdata,Ydata,0.5,'loess');
+            elseif logX==1 && logY==0,
+                Ysmooth = smoothIQM(log(Xdata),Ydata,0.5,'loess');
+            elseif logX==0 && logY==1,
+                Ysmooth = exp(smoothIQM(Xdata,log(Ydata),0.5,'loess'));
+            else
+                Ysmooth = exp(smoothIQM(log(Xdata),log(Ydata),0.5,'loess'));
+            end
+            % Handle color, etc.
+            if datakkk.color(1) == -1,
+                color = 0.2*[1 1 1];
+                line  = linetype;
+            else
+                color = linecolorsCustom(mod(datakkk.color(1)-1,length(linecolorsCustom))+1,:);
+                if showmarkers,
+                    line  = linetypesCustom{   mod(datakkk.color(1)-1,length(linetypesCustom))+1};
+                else
+                    line = '-.';
+                end
+            end
+            % Adjust regression linestyle in case its only dots
+            if length(line) == 1,
+                line = [line '-'];
+            end
+            % Plot loess line
+            warning off %#ok<WNOFF>
+            feval(plottype,Xdata,Ysmooth,line,'LineWidth',linewidth+1,'Color',color,'MarkerSize',markersize);
+            warning on %#ok<WNON>
+            % Determine color
+            loessColor{end+1} = color;
+        end
+    end    
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%
+% Set Axes
+%%%%%%%%%%%%%%%%%%%%%%%%%
+
+warning off %#ok<WNOFF>
+if ~isempty(axesLimits),
+    % handle min X-axis limits if defined
+    if ~isempty(XLimMin),
+        if axesLimits(1) > XLimMin(1),
+            axesLimits(1) = XLimMin(1);
+        end
+        if axesLimits(2) < XLimMin(2),
+            axesLimits(2) = XLimMin(2);
+        end
+    end
+    xmin = axesLimits(1);
+    xmax = axesLimits(2);
+    ymin = axesLimits(3);
+    ymax = axesLimits(4);
+    if xmin==xmax,
+        xmax = xmin+1;
+    end
+    if ymin==ymax,
+        ymax = ymin+1;
+    end
+    axis([xmin xmax ymin ymax]);
+else
+    % Get max min values for x and y for each subplot
+    maxX = max(datak.(nameX));
+    minX = min(datak.(nameX));
+    maxY = max(datak.(nameY));
+    minY = min(datak.(nameY));
+    if minX==maxX,
+        maxX=minX+1;
+    end
+    if minY==maxY,
+        maxY=minY+1;
+    end
+    % Adjust maxY for titlebar
+    if logY==1,
+        rangenew =  1/(1-heighttitlebar-0.01)*(log10(maxY)-log10(minY));
+        maxY     = 10.^(log10(minY) + rangenew);
+    else
+        rangenew =  1/(1-heighttitlebar-0.01)*(maxY-minY);
+        maxY     = minY + rangenew;
+    end
+    
+    % handle min X-axis limits if defined
+    if ~isempty(XLimMin),
+        if minX > XLimMin(1),
+            minX = XLimMin(1);
+        end
+        if maxX < XLimMin(2),
+            maxX = XLimMin(2);
+        end
+    end
+    
+    % Set axes
+    if minX==maxX,
+        maxX = minX+1;
+    end
+    if isnan(minY),
+        minY = 0;
+    end
+    if isnan(maxY),
+        maxY = 0;
+    end
+    if minY==maxY,
+        maxY = minY+1;
+    end
+    axis([minX maxX minY maxY]);
+end
+warning on %#ok<WNON>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%
+% Set axes fontsize for ticklabels
+%%%%%%%%%%%%%%%%%%%%%%%%%
+
+set(gca,'FontUnits','points','FontSize',ticklabeltextsize);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%
+% Set axes color
+%%%%%%%%%%%%%%%%%%%%%%%%%
+
+set(gca,'XColor',axescolor);
+set(gca,'YColor',axescolor);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle grid setting - switch minor grid off
+%%%%%%%%%%%%%%%%%%%%%%%%%
+if showgrid,
+    grid on
+    set(gca,'XMinorGrid','off');
+    set(gca,'YMinorGrid','off');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle title (group)
+%%%%%%%%%%%%%%%%%%%%%%%%%
+if showtitlebar,
+    % Get axes limits
+    XLim = get(gca,'XLim');
+    YLim = get(gca,'YLim');
+    % Get X position for text
+    if logX==1,
+        X = 10^(log10(XLim(1)) + 0.5*(log10(XLim(2))-log10(XLim(1))));
+    else
+        X = XLim(1) + 0.5*(XLim(2)-XLim(1));
+    end
+    % Get Y position for text and title bar
+    if logY==1,
+        Y = 10^(log10(YLim(1)) + (1-heighttitlebar/2)*(log10(YLim(2))-log10(YLim(1))));
+        YtitlebarDN = 10^(log10(YLim(1)) + (1-heighttitlebar)*(log10(YLim(2))-log10(YLim(1))));
+        YtitlebarUP = 10^(log10(YLim(1)) + 1*(log10(YLim(2))-log10(YLim(1))));
+    else
+        Y = YLim(1) + (1-heighttitlebar/2)*(YLim(2)-YLim(1));
+        YtitlebarDN = YLim(1) + (1-heighttitlebar)*(YLim(2)-YLim(1));
+        YtitlebarUP = YLim(1) + 1*(YLim(2)-YLim(1));
+    end
+    % Create a title bar background
+    filled = [YtitlebarUP*[1 1],YtitlebarDN*[1 1]];
+    xpoints=[XLim,fliplr(XLim)];
+    fill(xpoints,filled,colortitlebar);
+    % Print the title text
+    text(X,Y,titleText,'FontWeight','bold','FontSize',titlefontsize,'HorizontalAlignment','Center','Interpreter','none');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%
+% Show correlations
+%%%%%%%%%%%%%%%%%%%%%%%%%
+
+if showcorrelations && showregressionline,
+    % Assume a maximum of 15 different lines (should be absolute max)
+    maxcorrtexts = 15; % Needed only for positioning
+    % Determine y locations
+    ncorrs = length(allGROUPcolor);
+    YLim = get(gca,'YLim');
+    XLim = get(gca,'XLim');
+    
+    if logY==1,
+        textY = 10.^(log10(YLim(1))+((1:maxcorrtexts)/(maxcorrtexts+1)-heighttitlebar)*(log10(YLim(2))-log10(YLim(1))));
+    else
+        textY = YLim(1)+((1:maxcorrtexts)/(maxcorrtexts+1)-heighttitlebar)*(YLim(2)-YLim(1));
+    end
+    if logX==1,
+        textX = 10.^(log10(XLim(1))+0.98*(log10(XLim(2))-log10(XLim(1))));
+    else
+        textX = XLim(1)+0.98*(XLim(2)-XLim(1));
+    end
+    for kcorr=1:ncorrs,
+        text(textX,textY(kcorr),corrText{kcorr},'Color',corrColor{kcorr},'FontWeight','bold','FontUnits','points','FontSize',correlationstextsize,'HorizontalAlignment','Right');
+    end
+end
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/publish/IQMpublish.m b/IQMtools V1.2.2.2/IQMlite/tools/publish/IQMpublish.m
new file mode 100644
index 0000000000000000000000000000000000000000..cd2aacf201b1bafe4c2a347d7acd0e4e1db4f801
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/publish/IQMpublish.m	
@@ -0,0 +1,145 @@
+function [] = IQMpublish(scriptname,outputpath)
+% This function allows to publish MATLAB scripts as HTML pages. It uses the publish 
+% function that is available in MATLAB, but improves its functionality considerably:
+%
+% - Creation of a table of contents
+% - Sections and subsections
+% - Nice URL links, well integrated into the flow of the text
+%
+% A Section is coded as follows:
+%      %% === Section name
+%
+% A subsection is coded as follows:
+%      %% Subsection name
+%
+% The main difference between sections and subsections is visible in the table of contents, where
+% the subsections are indented and not bold face.
+%
+% A link is coded as follows:
+%       #_#URL#_# 
+%       #_#Displayed Text|URL#_#
+%
+% where "URL" can be any local linkt to a file or a link to a webpage, etc. And the 
+% "Displayed Text" is text that is displayed instead of the link.
+%      
+% Examples:
+%       #_#GNU General Public License|http://www.gnu.org/licenses/#_#
+%       #_#http://www.sbtoolbox2.org#_#
+%
+% [SYNTAX]
+% IQMpublish(scriptname,outputpath)
+%
+% [INPUT]
+% scriptname:           Name of the script to convert to HTML
+% outputpath:           Path where to create the HTML file
+%
+% [OUTPUT]
+% HTML file with same name as the MATLAB script file but with an .html extension.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+outputname  = [scriptname '.html'];
+
+%% Publish script using MATLAB function
+options     = struct('format','html','outputDir',outputpath,'evalCode',false);
+publish(scriptname,options);
+try, movefile(fullfile(outputpath,[scriptname '.html']),fullfile(outputpath,outputname)); catch, end
+
+%% Postprocess
+content = fileread(fullfile(outputpath,outputname));
+
+% Remove the Source code
+ixstart = strfind(content,'##### SOURCE BEGIN #####');
+ixend   = strfind(content,'##### SOURCE END #####');
+content(ixstart-5:ixend+25) = [];
+content = strrep(content,'<p class="footer"><br><a href="http://www.mathworks.com/products/matlab/">Published with MATLAB&reg; R2013a</a><br></p>','');
+
+% Handle the Henning-Markup links
+while ~isempty(strfind(content,'#_#'))
+    ixLinks     = strfind(content,'#_#');
+    ixstart     = ixLinks(1);
+    ixend       = ixLinks(2)+2;
+    link        = content(ixstart:ixend);
+    link        = strrep(link,'#_#','');
+    linkterms   = explodePCIQM(link,'|');
+    if length(linkterms) == 1,
+        link = linkterms{1};
+        name = linkterms{1};
+    elseif length(linkterms) == 2,
+        link = linkterms{2};
+        name = linkterms{1};
+    else
+        error('Wrong Link');
+    end
+    linkText    = ['<a href="' link '" target="newwindow">' name '</a>'];
+    content = [content(1:ixstart-1) linkText content(ixend+1:end)];
+end
+
+%% Handle Table of contents Henning markup
+
+% Get the contents table elements
+ixContentsStart         = strfind(content,'<h2>Contents</h2>')+22;
+ixUL                    = strfind(content,'</ul>');
+ixContentsEnd           = ixUL(find(ixUL-ixContentsStart>0)); ixContentsEnd = ixContentsEnd(1)+4;
+contentsTextOriginal    = content(ixContentsStart:ixContentsEnd);
+contentsTextReplace     = contentsTextOriginal;
+% Remove <ul> tags
+contentsTextOriginal    = strrep(contentsTextOriginal,'<ul>','');
+contentsTextOriginal    = strrep(contentsTextOriginal,'</ul>','');
+% Remove </li> tags
+contentsTextOriginal    = strrep(contentsTextOriginal,'</li>','');
+% Remove first <li> tag
+contentsTextOriginal    = contentsTextOriginal(5:end);
+% EXCHANGE <li> tags
+contentsTextOriginal    = strrep(contentsTextOriginal,'<li>','$');
+% Get contents items
+terms = explodePCIQM(contentsTextOriginal,'$');
+% Piece them together again ... assume a === In the name means a main
+% section and not === means a subsection
+ix_main = [];
+for k=1:length(terms),
+    if ~isempty(strfind(terms{k},'===')),
+        ix_main = [ix_main k];
+    end
+end
+if isempty(ix_main),
+    error('At least one main section needs to be available.');
+end
+if ix_main(1)~=1,
+    error('The first section needs to be a main section.');
+end
+ix_sub = {};
+for k=2:length(ix_main),
+    ix_maincurrent  = ix_main(k);
+    ix_mainprevious = ix_main(k-1);
+    ix_subk = [ix_mainprevious+1:1:ix_maincurrent-1];
+    ix_sub{k-1} = ix_subk;
+end
+ix_sub{end+1} = ix_main(end)+1:1:length(terms);
+text = sprintf('<ul>\n');
+for k=1:length(ix_main),
+    text = sprintf('%s    <li>',text);
+    text = sprintf('%s<b>%s</b>\n',text,strtrim(strrep(upper(terms{ix_main(k)}),'===','')));
+    if ~isempty(ix_sub{k}),
+        text = sprintf('%s        <ul>\n',text);
+        for k2=1:length(ix_sub{k}),
+            text = sprintf('%s            <li>',text);
+            text = sprintf('%s%s',text,strtrim(strrep(terms{ix_sub{k}(k2)},'===','')));
+            text = sprintf('%s</li>\n',text);
+        end
+        text = sprintf('%s        </ul>\n',text);
+    end
+    text = sprintf('%s    </li>\n',text);
+end
+text = sprintf('%s</ul>\n',text);
+content = strrep(content,contentsTextReplace,text);
+content = strrep(content,'<h2>===','<h2>');
+
+% Save post-processed result
+fid = fopen(fullfile(outputpath,outputname),'w');
+fprintf(fid,'%s',content);
+fclose(fid);
+
+% %% Open result
+% oldpath = pwd(); cd(outputpath); path = pwd; cd(oldpath)
+% system(sprintf('"C:\\Program Files\\Internet Explorer\\iexplore" %s',fullfile(path,outputname)))
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/signal/centeredfftIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/signal/centeredfftIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..fff5ea7dadd5e65670d97fd008bd746320ca3021
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/signal/centeredfftIQM.m	
@@ -0,0 +1,26 @@
+function [X,freq]=centeredfftIQM(x,Fs)
+% centeredfftIQM: Uses the fft function of MATLAB to determine a two sided
+% spectrum of x, where te data in x have been sampled with the frequency 
+% Fs. 
+%
+% [X,freq] = centeredfftIQM(x,Fs)
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+% Get the length of the data vector x 
+N=length(x);
+
+% Determine the frequency axis
+if mod(N,2)==0
+    k = -N/2:N/2-1; % N even
+else
+    k = -(N-1)/2:(N-1)/2; % N odd
+end
+T = N/Fs;
+freq = k/T;  % Frequency axis
+
+% Determine the fft and normalize the result
+X = fft(x)/N; 
+% Shift the data in order to center it
+X = fftshift(X); 
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/signal/positivefftIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/signal/positivefftIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..45fb1fd5904e2bf960c8870462d33e510a9cbc77
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/signal/positivefftIQM.m	
@@ -0,0 +1,27 @@
+function [X,freq] = positivefftIQM(x,Fs)
+% positivefftIQM: Uses the fft function of MATLAB to determine a one sided
+% spectrum of x, where te data in x have been sampled with the frequency 
+% Fs. 
+%
+% [X,freq] = positivefftIQM(x,Fs)
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+% Get the length of the data vector x 
+N=length(x);
+
+% Create the frequency axis
+k=0:N-1;     
+T=N/Fs;      
+freq=k/T;    
+
+% Determine the fft and normalize it
+X=fft(x)/N; 
+ 
+% Remove the negative frequency part and double the result (one sided)
+cutOff = ceil(N/2); 
+X = 2*X(1:cutOff);
+freq = freq(1:cutOff);
+return
+
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/signal/postpadIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/signal/postpadIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..364bcabaa5a6a6a0bd8852c09d99b797d4ed417c
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/signal/postpadIQM.m	
@@ -0,0 +1,62 @@
+function y = postpadIQM(x, l, c, dim)
+% y = postpadIQM(x, l)
+% y = postpadIQM(x, l, c)
+% y = postpadIQM(x, l, c, dim)
+% postpadIQM: Appends value c (default: 0) until to extend vector x to a
+% length of l. Same with matrices x, where the dimension to extend is given
+% by dim (default: 1). 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+if (nargin < 2 || nargin > 4)
+    error('Incorrect number of input arguments.');
+end
+
+if (nargin < 3 || isempty (c))
+    c = 0;
+else
+    if (~isscalar (c))
+        error ('postpadIQM: third argument must be empty or a scalar');
+    end
+end
+
+nd = ndims (x);
+sz = size (x);
+if (nargin < 4)
+    % Find the first non-singleton dimension
+    dim  = 1;
+    while (dim < nd + 1 && sz (dim) == 1),
+        dim = dim + 1;
+    end
+    if (dim > nd)
+        dim = 1;
+    end
+else
+    if (~(isscalar (dim) && dim == round (dim)) && dim > 0 && dim < (nd + 1))
+        error ('postpadIQM: dim must be an integer and valid dimension');
+    end
+end
+
+if (~ isscalar (l) || l < 0)
+    error ('postpadIQM: second argument must be a positive scaler');
+end
+
+if (dim > nd)
+    sz(nd+1:dim) = 1;
+end
+
+d = sz (dim);
+
+if (d >= l)
+    idx = cell ();
+    for i = 1:nd
+        idx{i} = 1:sz(i);
+    end
+    idx{dim} = 1:l;
+    y = x(idx{:});
+else
+    sz (dim) = l - d;
+    y = cat (dim, x, c * ones (sz));
+end
+
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/signal/prepadIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/signal/prepadIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..a3867cb14dca685de0dcf31a2aa972fbe3c4126b
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/signal/prepadIQM.m	
@@ -0,0 +1,61 @@
+function y = prepadIQM(x, l, c, dim)
+% y = prepadIQM(x, l)
+% y = prepadIQM(x, l, c)
+% y = prepadIQM(x, l, c, dim)
+% prepadIQM: prepends value c (default: 0) until to extend vector x to a
+% length of l. Same with matrices x, where the dimension to extend is given
+% by dim (default: 1). 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+if (nargin < 2 || nargin > 4)
+    print_usage ();
+end
+
+if (nargin < 3 || isempty (c))
+    c = 0;
+else
+    if (~isscalar (c))
+        error ('prepadIQM: third argument must be empty or a scalar');
+    end
+end
+
+nd = ndims (x);
+sz = size (x);
+if (nargin < 4),
+    %% Find the first non-singleton dimension
+    dim  = 1;
+    while (dim < nd + 1 && sz (dim) == 1)
+        dim = dim + 1;
+    end
+    if (dim > nd)
+        dim = 1;
+    end
+else
+    if (~(isscalar (dim) && dim == round (dim)) && dim > 0 && dim < (nd + 1))
+        error ('prepadIQM: dim must be an integer and valid dimension');
+    end
+end
+
+if (~ isscalar (l) || l < 0)
+    error ('prepadIQM: second argument must be a positive scaler');
+end
+
+if (dim > nd)
+    sz(nd+1:dim) = 1;
+end
+
+d = sz (dim);
+
+if (d >= l)
+    idx = cell ();
+    for i = 1:nd
+        idx{i} = 1:sz(i);
+    end
+    idx{dim} = d-l+1:d;
+    y = x(idx{:});
+else
+    sz (dim) = l - d;
+    y = cat (dim, c * ones (sz), x);
+end
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/signal/resampleIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/signal/resampleIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..99de8e925636bb7326ee811550ca48465697e568
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/signal/resampleIQM.m	
@@ -0,0 +1,56 @@
+function [x2,t2] = resampleIQM(t1,x1,t2,method)
+% resampleIQM: resamples time series x1, which is sampled at the time
+% instances t1 to time series x2 using a sampling defined by t2.
+%
+% t2: scalar representing sampling interval or vector of sampling instances
+% method: 'zoh', 'linear', 'cubic'. The use of 'method' is optional.
+%         (default: 'linear')
+%
+% The output t2 is the vector that has been used for the resampling.
+%
+% [x2,t2] = resampleIQM(t1,x1,t2,method)
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+if nargin < 3 || nargin > 4,
+    error('Incorrect number of input arguments.');
+end
+
+if nargin == 3,
+    method = 'linear';
+end
+
+if length(t2) == 1,
+    t2 = [0:t2:t1(end)];
+end
+
+% Handle NaN data values
+t1end = t1(end);
+indnan = find(isnan(x1));
+x1(indnan) = [];
+t1(indnan) = [];
+% Handle the case when the last value is NaN
+if t1(end) ~= t1end,
+    t1(end) = t1end;
+end
+
+% Do the resampling
+x2 = zeros(1,length(t2));
+if strcmp(method,'linear'),
+    for k=1:length(t2),
+        x2(k) = interp1IQM(t1,x1,t2(k));
+    end
+elseif strcmp(method,'zoh'),
+    for k=1:length(t2),
+        x2(k) = interp0IQM(t1,x1,t2(k));
+    end    
+elseif strcmp(method,'cubic'),
+    for k=1:length(t2),
+        x2(k) = interpcsIQM(t1,x1,t2(k));
+    end    
+else
+    error('Wrong definition for ''method'' input argument.');
+end
+
+return
+    
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/signal/xcorrIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/signal/xcorrIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..6fec58bf54ebc4d166e6f0f96ddbe3e47dc94a15
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/signal/xcorrIQM.m	
@@ -0,0 +1,154 @@
+function [R, lags] = xcorrIQM(X, varargin)
+% Compute correlation R_xy of X and Y for various lags k:  
+%
+%    R_xy(k) = sum_{i=1}^{N-k}{x_i y_{i-k}}/(N-k),  for k >= 0
+%    R_xy(k) = R_yx(-k),  for k <= 0
+%
+% usage: [R, lag] = xcorrIQM(X)
+% usage: [R, lag] = xcorrIQM(X, Y)
+% usage: [R, lag] = xcorrIQM(X, Y, maxlag)
+% usage: [R, lag] = xcorrIQM(X, Y, maxlag, scale)
+%
+% Returns R(k+maxlag+1)=Rxy(k) for lag k=[-maxlag:maxlag].
+% Scale is one of:
+%    'biased'   for correlation=raw/N, 
+%    'unbiased' for correlation=raw/(N-|lag|), 
+%    'coeff'    for correlation=raw/(correlation at lag 0),
+%    'none'     for correlation=raw
+% If Y is omitted, compute autocorrelation.  
+% If maxlag is omitted, use N-1 where N=max(length(X),length(Y)).
+% If scale is omitted, use 'none'.
+%
+% If X is a matrix, computes the cross correlation of each column
+% against every other column for every lag.  The resulting matrix has
+% 2*maxlag+1 rows and P^2 columns where P is columns(X). That is,
+%    R(k+maxlag+1,P*(i-1)+j) == Rij(k) for lag k=[-maxlag:maxlag],
+% so
+%    R(:,P*(i-1)+j) == xcorr(X(:,i),X(:,j))
+% and
+%    reshape(R(k,:),P,P) is the cross-correlation matrix for X(k,:).
+%
+% xcorr computes the cross correlation using an FFT, so the cost is
+% dependent on the length N of the vectors and independent of the
+% number of lags k that you need.  If you only need lags 0:k-1 for 
+% vectors x and y, then the direct sum may be faster:
+%
+% unbiased:
+%  ( hankel(x(1:k),[x(k:N); zeros(k-1,1)]) * y ) ./ [N:-1:N-k+1](:)
+% biased:
+%  ( hankel(x(1:k),[x(k:N); zeros(k-1,1)]) * y ) ./ N
+%
+% If length(x) == length(y) + k, then you can use the simpler
+%    ( hankel(x(1:k),x(k:N-k)) * y ) ./ N
+%
+% Ref: Stearns, SD and David, RA (1988). Signal Processing Algorithms.
+%      New Jersey: Prentice-Hall.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+if (nargin < 1 || nargin > 4)
+    error('Incorrect number of input arguments.');
+end
+
+% assign arguments from list
+Y = [];
+maxlag = [];
+scale = 'none';
+N = length(X);
+if nargin==2
+    Y = varargin{1};
+    N = max(length(X),length(Y));
+elseif nargin==3
+    Y = varargin{1};
+    maxlag = varargin{2};
+elseif nargin == 4,
+    Y = varargin{1};
+    maxlag = varargin{2};
+    scale = varargin{3};
+end
+if isempty(maxlag),
+    maxlag = N-1;
+end
+
+% check argument values
+if isscalar(X) || ischar(X) || isempty(X),
+    error('xcorrIQM: X must be a vector or matrix');
+end
+if isscalar(Y) || ischar(Y) || (~isempty(Y) && ~isvector(Y)),
+    error('xcorrIQM: Y must be a vector');
+end
+if ~isvector(X) && ~isempty(Y),
+    error('xcorrIQM: X must be a vector if Y is specified');
+end
+if ~isscalar(maxlag) && ~isempty(maxlag)
+    error('xcorrIQM: maxlag must be a scalar');
+end
+if maxlag>N-1,
+    error('xcorrIQM: maxlag must be less than length(X)');
+end
+if isvector(X) && isvector(Y) && length(X) ~= length(Y) && ~strcmp(scale,'none')
+    error('xcorrIQM: scale must be ''none'' if length(X) ~= length(Y)')
+end
+
+P = size(X,2);
+M = 2^nextpow2(N + maxlag);
+if ~isvector(X)
+    % For matrix X, compute cross-correlation of all columns
+    R = zeros(2*maxlag+1,P^2);
+
+    % Precompute the padded and transformed `X' vectors
+    pre = fft (postpadIQM (prepadIQM (X, N+maxlag), M) );
+    post = conj (fft (postpadIQM (X, M)));
+
+    % For diagonal (i==j)
+    cor = ifft (post .* pre);
+    R(:, 1:P+1:P^2) = conj (cor (1:2*maxlag+1,:));
+
+    % For remaining i,j generate xcorr(i,j) and by symmetry xcorr(j,i).
+    for i=1:P-1
+        j = i+1:P;
+        cor = ifft (pre(:,i*ones(length(j),1)) .* post(:,j));
+        R(:,(i-1)*P+j) = conj (cor (1:2*maxlag+1, :));
+        R(:,(j-1)*P+i) = flipud (cor (1:2*maxlag+1, :));
+    end
+elseif isempty(Y)
+    % compute autocorrelation of a single vector
+    post = fft (postpadIQM(X,M));
+    cor = ifft (conj(post(:)) .* post(:));
+    R = [ conj(cor(maxlag+1:-1:2)) ; cor(1:maxlag+1) ];
+else
+    % compute cross-correlation of X and Y
+    post = fft (postpadIQM(Y,M));
+    pre = fft (postpadIQM(prepadIQM(X,N+maxlag),M));
+    cor = conj (ifft (conj(post(:)) .* pre(:)));
+    R = cor(1:2*maxlag+1);
+end
+
+% if inputs are real, outputs should be real, so ignore the
+% insignificant complex portion left over from the FFT
+if isreal(X) && (isempty(Y) || isreal(Y))
+    R=real(R);
+end
+
+% correct for bias
+if strcmp(scale, 'biased')
+    R = R ./ N;
+elseif strcmp(scale, 'unbiased')
+    R = R ./ ( [ N-maxlag:N-1, N, N-1:-1:N-maxlag ]' * ones(1,columns(R)) );
+elseif strcmp(scale, 'coeff')
+    R = R ./ ( ones(size(R,1),1) * R(maxlag+1, :) );
+elseif ~strcmp(scale, 'none')
+    error('xcorr: scale must be ''biased'', ''unbiased'', ''coeff'' or ''none''');
+end
+
+% correct the shape so that it is the same as the input vector
+if isvector(X) && P > 1
+    R = R';
+end
+
+% return the lag indices if desired
+if nargout == 2
+    lags = [-maxlag:maxlag];
+end
+
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/smoothing/binnedmeanIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/smoothing/binnedmeanIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..f52c58c87465972f8ff48597f2acedfea8e22dc7
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/smoothing/binnedmeanIQM.m	
@@ -0,0 +1,55 @@
+function [xbin,ybinmean] = binnedmeanIQM(x,y,numbins,FLAGlogX)
+% Simple function to calcuate binned means. Number of bins can be provided and 
+% it is possible to tell the function to do the binning on a log x axis.
+% The binning results might not be very nice. 
+%
+% [SYNTAX]
+% [xbin,ybinmean] = binnedmeanIQM(x,y)
+% [xbin,ybinmean] = binnedmeanIQM(x,y,numbins)
+% [xbin,ybinmean] = binnedmeanIQM(x,y,numbins,FLAGlogX)
+%
+% [INPUT]
+% x:           x - values
+% y:           y - values
+% numbins:     number of bins (default: 15)
+% FLAGlogX:    0: bin on linear axis (default), 1: bin on log axis
+%
+% [OUTPUT]
+% Bins in xbin and binned means in ybinmean
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+if nargin <= 2,
+    numbins = 15;
+    FLAGlogX = 0;
+elseif nargin<=3,
+    FLAGlogX = 0;
+end    
+
+if length(numbins)==1,
+    if FLAGlogX,
+        bins = logspace(log10(min(x)), log10(max(x)), numbins);
+    else
+        bins = linspace(min(x), max(x), numbins);
+    end
+else
+    bins = numbins;
+    numbins = length(bins);
+end
+
+[n,bin] = histc(x, bins); %#ok<ASGLU>
+mu = NaN*zeros(size(bins));
+for k = [1:numbins], %#ok<NBRAK>
+  ind = find(bin==k);
+  if (~isempty(ind))
+    mu(k) = mean(y(ind));
+  end
+end
+
+% Remove NaNs
+Z = [bins(:) mu(:)];
+Z(isnan(Z(:,2)),:) = [];
+
+% Assign outputs
+xbin = Z(:,1);
+ybinmean = Z(:,2);
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/smoothing/binnedmedianIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/smoothing/binnedmedianIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..db8917b3d569596ee90161d33f4299dd3fe456f5
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/smoothing/binnedmedianIQM.m	
@@ -0,0 +1,55 @@
+function [xbin,ybinmedian] = binnedmedianIQM(x,y,numbins,FLAGlogX)
+% Simple function to calcuate binned medians. Number of bins can be provided and 
+% it is possible to tell the function to do the binning on a log x axis.
+% The binning results might not be very nice. 
+%
+% [SYNTAX]
+% [xbin,ybinmedian] = binnedmedianIQM(x,y)
+% [xbin,ybinmedian] = binnedmedianIQM(x,y,numbins)
+% [xbin,ybinmedian] = binnedmedianIQM(x,y,numbins,FLAGlogX)
+%
+% [INPUT]
+% x:           x - values
+% y:           y - values
+% numbins:     number of bins (default: 15)
+% FLAGlogX:    0: bin on linear axis (default), 1: bin on log axis
+%
+% [OUTPUT]
+% Bins in xbin and binned medians in ybinmedian
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+if nargin <= 2,
+    numbins = 15;
+    FLAGlogX = 0;
+elseif nargin<=3,
+    FLAGlogX = 0;
+end    
+
+if length(numbins)==1,
+    if FLAGlogX,
+        bins = logspace(log10(min(x)), log10(max(x)), numbins);
+    else
+        bins = linspace(min(x), max(x), numbins);
+    end
+else
+    bins = numbins;
+    numbins = length(bins);
+end
+
+[n,bin] = histc(x, bins); %#ok<ASGLU>
+mu = NaN*zeros(size(bins));
+for k = [1:numbins], %#ok<NBRAK>
+  ind = find(bin==k);
+  if (~isempty(ind))
+    mu(k) = median(y(ind));
+  end
+end
+
+% Remove NaNs
+Z = [bins(:) mu(:)];
+Z(isnan(Z(:,2)),:) = [];
+
+% Assign outputs
+xbin = Z(:,1);
+ybinmedian = Z(:,2);
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/smoothing/binnedquantilesIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/smoothing/binnedquantilesIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..b9e87ddaff6091d1ca15f2347cde0ece386fdade
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/smoothing/binnedquantilesIQM.m	
@@ -0,0 +1,81 @@
+function [xbin,ybinquantile] = binnedquantilesIQM(x,y,quantile_value,binningInfo,FLAGlogX)
+% Simple function to calcuate binned quantiles. Number of bins can be provided and 
+% it is possible to tell the function to do the binning on a log x axis. Instead
+% of providing the number of bins it is also possible to provide the bins driectly along with 
+% some range around these values to use for binning.
+% 
+% [SYNTAX]
+% [xbin,ybinquantile] = binnedquantilesIQM(x,y,quantile_value)
+% [xbin,ybinquantile] = binnedquantilesIQM(x,y,quantile_value,numbins)
+% [xbin,ybinquantile] = binnedquantilesIQM(x,y,quantile_value,numbins,FLAGlogX)
+% [xbin,ybinquantile] = binnedquantilesIQM(x,y,quantile_value,binningInfo)
+% [xbin,ybinquantile] = binnedquantilesIQM(x,y,quantile_value,binningInfo,FLAGlogX)
+%
+% [INPUT]
+% x:           x - values
+% y:           y - values
+% quantileIQM:    quantileIQM to calculate
+% numbins:     number of bins (default: 15)
+% FLAGlogX:    0: bin on linear axis (default), 1: bin on log axis
+% binningInfo: Cell-array. The first element is a vector with centers of chosen bins. 
+%              The second element is a vector with ranges to look around left and right 
+%              from the chosen centers.
+%
+% [OUTPUT]
+% Bins in xbin and binned quantiles in ybinquantile
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+if nargin <= 3,
+    binningInfo = 15;  % number bins
+    FLAGlogX = 0;
+elseif nargin<=4,
+    FLAGlogX = 0;
+end    
+
+if length(binningInfo) == 1,
+    % Bin equidistantly
+    numbins = binningInfo;
+    if FLAGlogX,
+        bins = logspace(log10(min(x)), log10(max(x)), numbins);
+    else
+        bins = linspace(min(x), max(x), numbins);
+    end
+    
+    try
+        [n,bin] = histc(x, bins); %#ok<ASGLU>
+    catch
+        'error'
+    end
+    
+    mu = NaN*zeros(size(bins));
+    for k = [1:numbins], %#ok<NBRAK>
+        ind = find(bin==k);
+        if (~isempty(ind))
+            mu(k) = quantileIQM(y(ind),quantile_value);
+        end
+    end
+    
+    % Remove NaNs
+    Z = [bins(:) mu(:)];
+    Z(isnan(Z(:,2)),:) = [];
+    
+    % Assign outputs
+    xbin = Z(:,1);
+    ybinquantile = Z(:,2);
+else
+    % bin my mean binning value and look around range
+    bins_mean = binningInfo{1};
+    bins_lookaround = binningInfo{2};
+    
+    ybinquantile = [];
+    for k=1:length(bins_mean),
+        ix = find(x>=bins_mean(k)-bins_lookaround(k) & x<bins_mean(k)+bins_lookaround(k));
+        ybinquantile(k) = quantileIQM(y(ix),quantile_value);
+    end
+    xbin = bins_mean;
+    ix = find(isnan(ybinquantile));
+    xbin(ix) = [];
+    ybinquantile(ix) = [];
+end
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/smoothing/movingAverageIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/smoothing/movingAverageIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..75b4910bc5637820d782a012b393c947b4f0f5bc
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/smoothing/movingAverageIQM.m	
@@ -0,0 +1,73 @@
+function [y]=movingAverageIQM(x,range,fun)
+% movingAverageIQM will compute moving averages over a range, defined by the user.
+%
+% Usage: y = movingAverageIQM(x,range[,fun])
+% where 
+%      x:       is the input vector (or matrix) to be smoothed. 
+%      range: 	percentage of number of points in x to be used to average over
+%      y:       is output vector of same length as x
+%      fun:     (optional) is a custom function rather than moving averages
+%
+% Note:if x is a matrix then the smoothing will be done 'vertically'.
+% 
+%
+% Example:
+%
+% x=randn(300,1);
+% plot(x,'g.'); 
+% hold on;
+% plot(movingAverageIQM(x,10),'k'); 
+% plot(movingAverageIQM(x,30,'median'),'c');
+% plot(movingAverageIQM(x,7,@(x)max(x)),'b'); 
+% legend('x','10% range moving mean','30% range moving median','7% range moving max','location','best')
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+% Determine m based on range (in percent)
+m = length(x)*range/100;
+% make m odd, since it seems to be better
+m = 2*round(m/2)+1;
+
+if m==1
+    y=x;
+    return
+end
+if size(x,1)==1
+    x=x';
+end
+
+if nargin<3
+    fun=[];
+elseif ischar(fun)
+    fun=eval(['@(x)' fun '(x)']);
+end
+
+if isempty(fun)
+
+    f=zeros(m,1)+1/m;
+    n=size(x,1);
+    isodd=bitand(m,1);
+    m2=floor(m/2);
+
+
+    if (size(x,2)==1)
+        y=filter(f,1,x);
+        y=y([zeros(1,m2-1+isodd)+m,m:n,zeros(1,m2)+n]);
+    else
+        y=filter2(f,x);
+        y(1:(m2-~isodd),:)=y(m2+isodd+zeros(m2-~isodd,1),:);
+        y((n-m2+1):end,:)=y(n-m2+zeros(m2,1),:);
+    end
+
+else
+    y=zeros(size(x));
+    sx=size(x,2);
+    x=[nan(floor(m*.5),sx);x;nan(floor(m*.5),sx)];
+    m1=m-1;
+    for ii=1:size(y,1);
+        y(ii,:)=fun(x(ii+(0:m1),:));
+    end
+    
+end
+
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/smoothing/movingMedianIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/smoothing/movingMedianIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..75b4016baafa7bd66584eeaa5473804892fc4523
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/smoothing/movingMedianIQM.m	
@@ -0,0 +1,26 @@
+function [y]=movingMedianIQM(x,range)
+% movingMedianIQM will compute moving medians over a range, defined by the user.
+%
+% Usage: y = movingMedianIQM(x,range)
+% where 
+%      x:       is the input vector (or matrix) to be smoothed. 
+%      range: 	percentage of number of points in x to be used to average over
+%      y:       is output vector of same length as x
+%
+% Note:if x is a matrix then the smoothing will be done 'vertically'.
+%
+% This function is a wrapper for the movingAverageIQM function.
+% 
+% Examples:
+%   x=randn(300,1);
+%   plot(x,'g.'); 
+%   hold on;
+%   plot(movingMedianIQM(x,30),'k-');
+%   plot(movingQuantileIQM(x,30,0.5),'r--');
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+[y] = movingAverageIQM(x,range,'nanmedianIQM');
+
+
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/smoothing/movingQuantileIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/smoothing/movingQuantileIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..259f99c353dd45089994daa2963f5b9892a49726
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/smoothing/movingQuantileIQM.m	
@@ -0,0 +1,26 @@
+function [y]=movingQuantileIQM(x,range,q)
+% movingQuantileIQM will compute moving quantiles over a range, defined by the user.
+%
+% Usage: y = movingQuantileIQM(x,range,q)
+% where 
+%      x:       is the input vector (or matrix) to be smoothed. 
+%      range: 	percentage of number of points in x to be used to average over
+%      q:       quantileIQM to be calculated
+%      y:       is output vector of same length as x
+%
+% Note:if x is a matrix then the smoothing will be done 'vertically'.
+%
+% This function is a wrapper for the movingAverageIQM function.
+% 
+% Examples:
+%   x=randn(300,1);
+%   plot(x,'g.'); 
+%   hold on;
+%   plot(movingQuantileIQM(x,30,0.2),'r--');
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+[y] = movingAverageIQM(x,range,@(x)quantileIQM(x,q));
+
+
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/smoothing/smoothIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/smoothing/smoothIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..17bd74d4ed66ef56f4a90134026ee715a46e4bf9
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/smoothing/smoothIQM.m	
@@ -0,0 +1,812 @@
+function c = smoothIQM(x,y,span,method,iter,weighting)
+% Smoothes data using Robust or Non-robust Lowess smoother or with the
+% Savitzky-Golay smoother. 
+%
+% Usage: Z = smoothIQM(X,Y,span,method,iter,weighting)
+%        Z = smoothIQM(X,Y,span,'sgolay',degree)
+%
+% X,Y          input data
+% span         number of points used to compute each element in Z, default
+%              is 5 - smaller 1 its the fraction in the window
+% method       'loess', 'lowess' (default), 'mean', 'rloess', 'rlowess', or
+%              'rmean', 'sgolay'   
+% iter         number of robust iterations, default is 5
+% weighting    'tricubic' (default), 'gaussian' or 'linear'
+% degree       degree of the polynomial fit for the Savitzky-Golay smoother
+%
+% Note: The difference between 'lowess' and 'loess' is that 'lowess' uses a
+% linear model to do the local fitting (order = 1) whereas 'loess' uses a
+% quadratic model to do the local fitting (order = 2). 'mean' is just a
+% weighted local mean estimation (order = 0).
+
+outputAsRow = diff(size(y))>0;
+runSgolay = false;
+xIsOwnEnumeration = false;
+
+% Set x, y, and t
+y = y(:);
+t = numel(y);
+if isempty(x)
+    x = (1:t)';
+    xIsOwnEnumeration = true;
+elseif numel(x) == t
+    x = x(:)+min(x)+1; % for better conditioning
+else
+    error('X and Y must be the same length.');
+end
+
+% Set span
+if nargin<3 || isempty(span)
+    span = 5;     % default span
+elseif span <= 0  % span must be positive
+    error('SPAN must be positive.'); 
+elseif span < 1   % percent convention
+    span = ceil(span*t); 
+else              % span is given in samples, then round
+    span = round(span);
+end 
+
+% Set method
+if nargin<4 || isempty(method)
+    order = 1; % default method
+    robust = false; %default
+else
+    robust = method(1)=='r';
+    switch method
+        case {'loess','rloess'}
+            order = 2;
+        case {'lowess','rlowess'}
+            order = 1;
+        case {'mean','rmean'}  
+            order = 0;
+        case 'sgolay'
+            runSgolay = true;
+        otherwise
+            error('Unknown smoothing method.')
+    end
+end
+
+if runSgolay
+    if nargin<5 || isempty(iter)
+        degree = 2; %default degree for sgolay method
+    else
+        degree = iter;
+    end
+else % then it is any lowess method
+    % Set number of iterations for robust
+    if nargin<5 || isempty(iter)
+        iter = 5;
+    end
+    if robust
+        robust = iter;
+    else
+        robust = 0;
+    end
+end
+
+if runSgolay
+    if nargin>5
+        error('Too many input arguments for SGOLAY method.')
+    end
+else % the it is any lowess method
+    % Set weighting
+    if nargin<6 || isempty(weighting)
+        weighting = 3; % tricubic
+    else
+        switch weighting
+            case 'tricubic'
+                weighting = 3;
+            case 'gaussian'
+                weighting = 2;
+            case 'linear'
+                weighting = 1;
+            otherwise
+                error('Unknown weighting method.')
+        end
+    end
+end
+    
+% is x sorted ?
+if any(diff(x(~isnan(x)))<0)
+    [x,idx] = sort(x);
+    y = y(idx);
+    unSort = true;
+else
+    unSort = false;
+end
+
+c = NaN(size(y),class(y));
+xnotNaN = ~isnan(x);
+
+% high limit for span
+span = min(span,sum(xnotNaN));
+
+% does x have repeated values ?
+if xIsOwnEnumeration
+    repeatedX = false;
+else
+    diffX = diff(x(xnotNaN));
+    repeatedX = any(~diffX);
+end
+
+% are there NaN's in y ?
+yNaNs = any(isnan(y(xnotNaN)));
+
+% can we run 'Fast' Lowess/Sgolay instead ?
+runFAlg = ~repeatedX && ~yNaNs && (span>4);
+  % the fast alg 1) does not support repeated x values (otherwise the size
+  % of the sliding window changes), 2) does not supports NaNs in y
+  % (otherwise we need to check for NaN's in every window), and 3) does not
+  % allow span <= 4 (otherwise we would need to check for likely square
+  % matrices that generate singular solutions)
+  
+% can we run 'SuperFast' Lowess/Sgolay instead ?
+runSFAlg = runFAlg && (xIsOwnEnumeration||((max(diffX)-min(diffX))<(max(x(xnotNaN))*eps)));
+  % the super fast alg. is only for all above + equally distribited samples
+        
+if span == 1
+    c(xnotNaN) = y(xnotNaN);
+elseif runSgolay
+    if runSFAlg
+        c(xnotNaN) = sfsgolay(x(xnotNaN),y(xnotNaN),span,degree);
+    elseif runFAlg
+        c(xnotNaN) = fsgolay(x(xnotNaN),y(xnotNaN),span,degree);
+    else
+        c(xnotNaN) = sgolay(x(xnotNaN),y(xnotNaN),span,degree);
+    end
+else % then running Lowess Alg
+    if runSFAlg
+        c(xnotNaN) = sflowess(x(xnotNaN),y(xnotNaN),span,order,robust,weighting);
+    elseif runFAlg
+        c(xnotNaN) = flowess(x(xnotNaN),y(xnotNaN),span,order,robust,weighting);
+    else
+        c(xnotNaN) = lowess(x(xnotNaN),y(xnotNaN),span,order,robust,weighting);
+    end
+end
+
+if unSort
+    c(idx) = c;
+end
+
+if outputAsRow
+    c = c';
+end
+
+%--------------------------------------------------------------------
+function c = lowess(x,y,span,order,robust,weighting)
+% LOWESS  Smoothes data using Robust Lowess method.
+% 
+% x,y             input data
+% span            number of points used to compute each element in c
+% method          2 = 'loess', 1 = 'lowess', or 0 = 'mean'
+% robust          number of robust iterations, 0 means non-robust smoothing
+% weighting       3' = 'tricubic',  2 = 'gaussian', or 1 = 'linear'
+%
+% The 'slow' version of LOWESS can handle missing values in y (i.e. NaNs),
+% not evenly spaced x vector and repeated x values.
+
+n = length(y);
+c = zeros(size(y),class(y));
+
+if (weighting == 2) && (span-1 <= order)
+    span = order+2;
+    warning('Rank deficiency when SPAN-1 <= ORDER, changing SPAN to %d.',span)    
+elseif span-2 <= order
+    span = order+3;
+    warning('Rank deficiency when SPAN-2 <= ORDER, changing SPAN to %d.',span)
+end
+   
+ws = warning;
+warning('off');
+
+% pre-allocate space for lower and upper indices for each fit
+if robust>0
+    lbound = zeros(n,1);
+    rbound = zeros(n,1);
+    dmaxv = zeros(n,1);
+end
+
+% compute some constants out of the loop
+ynan = isnan(y);
+anyNans = any(ynan(:));
+seps = sqrt(eps);
+theDiffs = [1; diff(x);1];
+
+ll = 1;    % first window left point
+rr = span; % first window right point
+
+for i=1:n
+    % if x(i) and x(i-1) are equal we just use the old value.
+    if theDiffs(i) == 0
+        c(i) = c(i-1);
+        if robust>0
+            lbound(i) = lbound(i-1);
+            rbound(i) = rbound(i-1);
+            dmaxv(i) = dmaxv(i-1);
+        end    
+        continue;
+    end
+    
+    mx = x(i);                     % center
+   
+    while (rr<n) && (x(rr+1)-mx) < (mx-x(ll))
+        rr = rr + 1;
+        ll = ll + 1;
+    end
+
+    dmax = max(x(rr)-mx,mx-x(ll)); % maximum distance
+        
+    rrr=rr;                        % extend right limit ?
+    while (rrr<n) && dmax==(x(rrr+1)-mx)
+        rrr = rrr + 1;
+    end
+    lll=ll;                        % extend left limit ?
+    while (lll>1) && dmax==(mx-x(lll-1))
+        lll = lll - 1;
+    end
+    
+    idx = lll:rrr;                 % indices for this window
+   
+    if anyNans                     % are there NaN's in yl
+        idx = idx(~ynan(idx));     % remove them from my idx
+        if isempty(idx)            
+            c(i) = NaN;
+            continue
+        end
+    end
+    
+    if dmax==0, dmax = 1; end      % in case all x's are the same 
+       
+    if robust
+        lbound(i) = idx(1);
+        rbound(i) = idx(end);
+        dmaxv(i) = dmax;
+    end
+    
+    % setting the current window
+    xw = x(idx)-mx;     % centering to improve conditioning
+    
+    % outweight far samples
+    switch weighting
+        case 3 % tri-cubic weight
+            weight = (1 - (abs(xw)/dmax).^3).^1.5; 
+        case 2 % gaussian weight
+            weight = exp(-(abs(xw)/dmax*2).^2); 
+        case 1 % linear weight
+            weight = 1 - abs(xw)/dmax;
+    end
+    if all(weight<seps)
+        weight(:) = 1;    % if all weights are 0, just skip weighting
+    end
+    
+    % least squares regression
+    lw = length(xw);
+    switch order
+       case 2 % loess
+           v = weight(:,[1 1 1]).*[ones(lw,1) xw xw.*xw];
+       case 1 % lowess
+           v = weight(:,[1 1]).*[ones(lw,1) xw];
+       case 0 % local mean estimator
+           c(i) = (weight'*y(idx)) / sum(weight);
+           continue
+    end
+    
+    if lw==order+1  % Square v may give infs in the \ solution ...
+        b = [v;zeros(1,lw)]\[weight.*y(idx);0]; % ... so force least squares
+    else
+        b = v \ (weight.*y(idx));
+    end
+    c(i) = b(1);
+end
+
+% now that we have a non-robust fit, we can compute the residual and do
+% the robust fit if required
+maxabsyXeps = max(abs(y))*eps;
+for k = 1:robust
+    r = y-c;
+    for i=1:n
+        if theDiffs(i) == 0
+            c(i) = c(i-1);
+            continue;
+        end
+        if isnan(c(i)), continue; end
+        idx = lbound(i):rbound(i);
+        if anyNans
+            idx = idx(~ynan(idx));
+        end
+        mx = x(i);
+        xw = x(idx)-mx;  % centering to improve conditioning
+        rw = r(idx);
+
+        % outweight far samples
+        switch weighting
+            case 3 % tri-cubic weight
+                weight = (1 - (abs(xw)/dmaxv(i)).^3).^1.5;
+            case 2 % gaussian weight
+                weight = exp(-(abs(xw)/dmaxv(i)*2).^2);
+            case 1 % linear weight
+                weight = 1 - abs(xw)/dmax;
+        end
+        if all(weight<seps)
+            weight(:) = 1;    % if all weights 0, just skip weighting
+        end
+
+        % outweight outliers
+        rw = abs(rw-median(rw));
+        mad = median(rw);
+        if mad > maxabsyXeps
+            rw = 1-(rw./(6*mad)).^2;
+            rw(rw<0) = 0;
+            weight = weight .* rw; 
+        end
+        
+        % least squares regression
+        lw = length(xw);
+        % correct low rank problems
+        norder = min(order,sum(weight>0)-1);
+        switch norder
+           case 2 % loess
+               v = weight(:,[1 1 1]).*[ones(lw,1) xw xw.*xw];
+           case 1 % lowess
+               v = weight(:,[1 1]).*[ones(lw,1) xw];
+           case 0 % local mean estimator
+               c(i) = (weight'*y(idx)) / sum(weight);
+               continue
+        end
+    
+        if lw==norder+1  % Square v may give infs in the \ solution ...
+            b = [v;zeros(1,lw)]\[weight.*y(idx);0]; % ... so force least squares
+        else
+            b = v \ (weight.*y(idx));
+        end
+        c(i) = b(1);
+    end
+end
+
+warning(ws);
+
+%--------------------------------------------------------------------
+function c = flowess(x,y,span,order,robust,weighting)
+% FLOWESS  Smoothes data using Robust Lowess method.
+%
+% x,y             input data
+% span            number of points used to compute each element in c
+% method          2 = 'loess', 1 = 'lowess', or 0 = 'mean'
+% robust          number of robust iterations, 0 means non-robust smoothing
+% weighting       3' = 'tricubic',  2 = 'gaussian', or 1 = 'linear'
+%
+% The 'Fast' version of LOWESS assumes:
+%
+% 1) there are not repeated values in x, therefore the sliding window is
+% size fixed and its limits can be computed by updating the limits of the
+% previous window with a simple while-loop. 
+%
+% 2) there are not NaNs in the y vector, therefore there is not need to
+% check for NaNs in y and take appropiate measures.
+%
+% 3) span>4, therefore there is not need to check for for likely square
+% matrices that generate singular solutions.
+
+n = length(y);
+
+ws = warning('off');
+
+c = zeros(size(y),class(y));                 % allocate output
+               
+ll = 1;    % first window left point
+rr = span; % first window right point
+
+for i = 1:n
+    % update limits of the window
+    mx = x(i);
+    while (rr<n) && (x(rr+1)-mx) < (mx-x(ll))
+        rr = rr + 1;
+        ll = ll + 1;
+    end
+    if (rr<n) && (x(rr+1)-mx) == (mx-x(ll))
+        rrr = rr + 1;
+    else
+        rrr = rr;
+    end
+    
+    dmax = max(x(rrr)-mx,mx-x(ll));     % maximum value 
+    xw = x(ll:rrr) - mx;  % center around x(i) to improve conditioning 
+    
+    % outweight far samples
+    switch weighting
+        case 3 % tri-cubic weight
+            weight = (1 - (abs(xw)/dmax).^3).^1.5; 
+        case 2 % gaussian weight
+            weight = exp(-(xw/dmax*2).^2); 
+        case 1 % linear weight
+            weight = 1 - abs(xw)/dmax;
+    end
+    
+    % least squares regression
+    switch order
+        case 2 % Loess 
+            b = [weight weight.*xw weight.*xw.*xw] \ (weight.*y(ll:rrr));
+            c(i) = b(1); % put estimated point into output vector
+        case 1 % Lowess
+            b = [weight weight.*xw] \ (weight.*y(ll:rrr));
+            c(i) = b(1); % put estimated point into output vector
+        case 0 % Local mean estimator
+            c(i) = (weight'*y(ll:rrr)) / sum(weight);
+    end
+    
+end
+  
+% now that we have a non-robust fit, we can compute the residual and do
+% the robust fit if required
+maxabsyXeps = max(abs(y))*eps;
+for k = 1:robust
+    r = y-c;
+    ll = 1;
+    rr = span;
+    for i=1:n
+        mx = x(i);
+        while (rr<n) && (x(rr+1)-mx) < (mx-x(ll))
+            rr = rr + 1;
+            ll = ll + 1;
+        end
+        if (rr<n) && (x(rr+1)-mx) == (mx-x(ll))
+            rrr = rr + 1;
+        else
+            rrr = rr;
+        end
+        dmax = max(x(rrr)-mx,mx-x(ll));
+        xw = x(ll:rrr)-mx;  % centering for conditioning
+        rw = r(ll:rrr);
+
+        % outweight far samples
+        switch weighting
+            case 3 % tri-cubic weight
+                weight = (1 - (abs(xw)/dmax).^3).^1.5;
+            case 2 % gaussian weight
+                weight = exp(-(xw/dmax*2).^2);
+            case 1 % linear weight
+                weight = 1 - abs(xw)/dmax;
+        end
+
+        % outweight outliers
+        rw = abs(rw-median(rw));
+        mad = median(rw);
+        if mad > maxabsyXeps
+            rw = 1-(rw./(6*mad)).^2;
+            rw(rw<0) = 0;
+            weight = weight .* rw;
+        end
+
+        % correct low rank problems
+        norder = min(order,sum(weight>0)-1);
+        % least squares regression
+        switch norder
+            case 2 % Loess
+                b = [weight weight.*xw weight.*xw.*xw] \ (weight.*y(ll:rrr));
+                c(i) = b(1); % put estimated point into output vector
+            case 1 % Lowess
+                b = [weight weight.*xw] \ (weight.*y(ll:rrr));
+                c(i) = b(1); % put estimated point into output vector
+            case 0 % Local mean estimator
+                c(i) = (weight'*y(ll:rrr)) / sum(weight);
+        end
+        
+    end
+end
+
+warning(ws);
+
+%--------------------------------------------------------------------
+function c = sflowess(x,y,span,order,robust,weighting)
+% SFLOWESS  Smoothes data using Robust Lowess method.
+%
+% x,y             input data
+% span            number of points used to compute each element in c
+% method          2 = 'loess', 1 = 'lowess', or 0 = 'mean'
+% robust          number of robust iterations, 0 means non-robust smoothing
+% weighting       3' = 'tricubic',  2 = 'gaussian', or 1 = 'linear'
+%
+% The 'SuperFast' version of LOWESS assumes:
+%
+% 1) x is uniformely spaced, therefore a linear filter can be used.
+%
+% 2) there are not NaNs in the y vector, therefore there is not need to
+% check for NaNs in y and take appropiate measures.
+%
+% 3) span>4, therefore there is not need to check for for likely square
+% matrices that generate singular solutions.
+
+n = length(y);
+
+ws = warning('off');
+
+% For uniform data, an even span actually covers an odd number of
+% points.  For example, the four closest points to 5 in the
+% sequence 1:10 are {3,4,5,6}, but 7 is as close as 3.
+% Therfore force an odd span.
+halfw = floor(span/2);
+halfwp1 = halfw + 1;
+span = 2*halfw + 1;
+x1 = 1-halfw:halfw-1;
+
+switch weighting
+    case 3 % tri-cubic weight
+        weight = (1 - (abs(x1)/halfw).^3).^1.5;
+    case 2 % gaussian weight
+        weight = exp(-(x1/halfw*2).^2);
+    case 1 % linear weight
+        weight = 1 - abs(x1)/halfw;
+end
+% Set up weighted Vandermonde matrix using equally spaced X values
+switch order
+    case 2
+        V = [weight;weight.*x1;weight.*x1.*x1]';
+    case 1
+        V = [weight;weight.*x1]';
+    case 0
+        V = weight';
+end
+
+% Do QR decomposition
+[Q,R] = qr(V,0); %#ok
+
+% The projection matrix is Q*Q'. 
+alpha = Q(halfw,:)*Q';
+
+% Incorporate the weights into the coefficients of the linear combination,
+% then apply filter. 
+c = filter(alpha.*weight,1,y);
+
+% We need to slide the values into the center of the array.
+c(halfw+1:end-halfw) = c(span-1:end-1);
+
+% Now we have taken care of everything except the end effects.  Loop over
+% the points where we don't have a complete span.  Now the Vandermonde
+% matrix has span-1 points, because only 1 has zero weight.
+x1 = 1:span-1;
+switch order
+    case 2
+        V = [ones(1,span-1);x1;x1.*x1]';
+    case 1
+        V = [ones(1,span-1);x1]';
+    case 0
+        V = ones(span-1,1);
+end
+
+for j=1:halfw
+    % Compute weights based on deviations from the jth point,
+    % then compute weights and apply them as above.
+    switch weighting
+        case 3 % tri-cubic weight
+            weight = (1 - (abs((1:span-1) - j)/(span-j)).^3).^1.5;
+        case 2 % gaussian weight
+            weight = exp(-(abs((1:span-1) - j)/(span-j)*2).^2);
+        case 1 % linear weight
+            weight = 1 - abs((1:span-1) - j)/(span-j);
+    end
+    [Q,R] = qr(V.*repmat(weight(:),1,order+1),0);%#ok
+    alpha = (Q(j,:)*Q') .* weight;
+    c(j) = alpha * y(1:span-1);
+    c(end+1-j) = alpha * y(end:-1:end-span+2);
+end
+
+% now that we have a non-robust fit, we can compute the residual and do
+% the robust fit if required
+maxabsyXeps = max(abs(y))*eps;
+for k = 1:robust
+    r = y-c;
+    ll = 1;
+    rr = span;
+    for i=1:n
+        
+        if i>halfwp1 && rr<n
+            rr = rr + 1;
+            ll = ll + 1;
+        end
+        
+        % update windows and weights only close to the edges where xw
+        % changes, the weights at i==halfwp1 will be the ones used for all
+        % the center samples
+        if i<=halfwp1 || rr==n
+            mx = x(i);
+            dmax = max(x(rr)-mx,mx-x(ll));
+            xw = x(ll:rr)-mx;  % centering for conditioning
+            % outweight far samples
+            switch weighting
+                case 3 % tri-cubic weight
+                    weight = (1 - (abs(xw)/dmax).^3).^1.5;
+                case 2 % gaussian weight
+                    weight = exp(-(xw/dmax*2).^2);
+                case 1 % linear weight
+                    weight = 1 - abs(xw)/dmax;
+            end
+            if (order == 2)  
+                xws = xw .* xw;  
+            end
+        end
+
+        % outweight outliers
+        rw = r(ll:rr);
+        rw = abs(rw-median(rw));
+        mad = median(rw);
+        if mad > maxabsyXeps
+            rw = 1-(rw./(6*mad)).^2;
+            rw(rw<0) = 0;
+            rw = weight.*rw;
+        else
+            rw = weight;
+        end
+
+        % correct low rank problems
+        norder = min(order,sum(weight>0)-1);
+        % least squares regression
+        switch norder
+            case 2 % Loess
+                b = [rw rw.*xw rw.*xws] \ (rw.*y(ll:rr));
+                c(i) = b(1); % put estimated point into output vector
+            case 1 % Lowess
+                b = [rw rw.*xw] \ (rw.*y(ll:rr));
+                c(i) = b(1); % put estimated point into output vector
+            case 0 % Local mean estimator
+                c(i) = sum(rw.*y(ll:rr)) / sum(rw);
+        end
+    end
+end
+
+warning(ws);
+
+%--------------------------------------------------------------------
+function c = sgolay(x,y,span,degree)
+% SGOLAY  Smoothes data using Savitsky-Golay method.
+% 
+% x,y             input data
+% span            number of points used to compute each element in c
+% degree          degree of the polynomial fit
+%
+% The 'slow' version of SGOLAY can handle missing values in y (i.e. NaNs),
+% not evenly spaced x vector and repeated x values.
+
+n = length(y);
+c = zeros(size(y),class(y));
+ws = warning;
+warning('off');
+% compute some constants out of the loop
+ynan = isnan(y);
+anyNans = any(ynan(:));
+theDiffs = [1; diff(x);1];
+ll = 1;    % first window left point
+rr = span; % first window right point
+for i=1:n
+    % if x(i) and x(i-1) are equal we just use the old value.
+    if theDiffs(i) == 0
+        c(i) = c(i-1);
+        continue;
+    end
+    mx = x(i);                     % center
+    while (rr<n) && (x(rr+1)-mx) < (mx-x(ll))
+        rr = rr + 1;
+        ll = ll + 1;
+    end
+    dmax = max(x(rr)-mx,mx-x(ll)); % maximum distance
+    rrr=rr;                        % extend right limit ?
+    while (rrr<n) && dmax==(x(rrr+1)-mx)
+        rrr = rrr + 1;
+    end
+    lll=ll;                        % extend left limit ?
+    while (lll>1) && dmax==(mx-x(lll-1))
+        lll = lll - 1;
+    end
+    idx = lll:rrr;                 % indices for this window
+    if anyNans                     % are there NaN's in yl
+        idx = idx(~ynan(idx));     % remove them from my idx
+        if isempty(idx)            
+            c(i) = NaN;
+            continue
+        end
+    end
+    % centering and scaling to improve conditioning
+    xw = (x(idx)./mx-1);       
+    % least squares regression
+    vrank = 1 + sum(diff(xw)>0);
+    ncols = min(degree+1, vrank);
+    lw = length(xw);
+    v = ones(lw,ncols);
+    for j = 1:ncols-1
+        v(:,j+1) = xw.^j;
+    end
+    if lw==ncols
+        % Square v may give infs in the \ solution, so force least squares
+        b = [v;zeros(1,size(v,2))]\[y(idx);0];
+    else
+        b = v\y(idx);
+    end
+    c(i) = b(1);
+end
+warning(ws);
+
+%--------------------------------------------------------------------
+function c = fsgolay(x,y,span,degree)
+% FSGOLAY  Smoothes data using Savitsky-Golay method.
+% 
+% x,y             input data
+% span            number of points used to compute each element in c
+% degree          degree of the polynomial fit
+%
+% The 'Fast' version of SGOLAY assumes:
+%
+% 1) there are not repeated values in x, therefore the sliding window is
+% size fixed and its limits can be computed by updating the limits of the
+% previous window with a simple while-loop. 
+%
+% 2) there are not NaNs in the y vector, therefore there is not need to
+% check for NaNs in y and take appropiate measures.
+
+n = length(y);
+c = zeros(size(y),class(y));
+ncols = min(degree+1, span);
+ws = warning;
+warning('off');
+ll = 1;    % first window left point
+rr = span; % first window right point
+
+for i=1:n
+    % update the limits of the window
+    mx = x(i);                     % center
+    while (rr<n) && (x(rr+1)-mx) < (mx-x(ll))
+        rr = rr + 1;
+        ll = ll + 1;
+    end
+    if (rr<n) && (x(rr+1)-mx) == (mx-x(ll))
+        rrr = rr + 1;
+        lw = span + 1;
+    else
+        rrr = rr;
+        lw = span;
+    end
+    % centering and scaling to improve conditioning
+    xw = (x(ll:rrr)./mx-1);     
+    % least squares regression
+    v = ones(lw,ncols);
+    for j = 1:ncols-1
+        v(:,j+1) = xw.^j;
+    end
+    if lw==ncols
+        % Square v may give infs in the \ solution, so force least squares
+        b = [v;zeros(1,size(v,2))]\[y(ll:rrr);0];
+    else
+        b = v\y(ll:rrr);
+    end
+    c(i) = b(1);
+end
+warning(ws);
+
+%--------------------------------------------------------------------
+function c = sfsgolay(x,y,span,degree)  %#ok
+% SFSGOLAY  Smoothes data using Savitsky-Golay method.
+% 
+% x,y             input data
+% span            number of points used to compute each element in c
+% degree          degree of the polynomial fit
+%
+% The 'SuperFast' version of SGOLAY assumes:
+%
+% 1) x is uniformely spaced, therefore a linear filter can be used.
+%
+% 2) there are not NaNs in the y vector, therefore there is not need to
+% check for NaNs in y and take appropiate measures.
+
+n = length(y);
+span = min(n-1,span);      % set upper limit for span
+span = span+rem(span-1,2); % will add 1 if frame is even.
+halfw = (span-1)/2;
+
+V = ones(span,degree+1);
+xw=(-halfw:halfw)';
+for i=1:degree
+    V(:,i+1)=xw.^i;
+end
+[Q,R]=qr(V,0); %#ok
+ymid = filter(Q*Q(halfw+1,:)',1,y);
+ybegin = Q(1:halfw,:)*Q'*y(1:span);
+yend = Q((halfw+2):end,:)*Q'*y(n-span+1:n);
+c = [ybegin;ymid(span:end);yend];
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/solvers/fsolveIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/solvers/fsolveIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..6ef860e95275c4558d820c0ceb81da3ed2b63012
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/solvers/fsolveIQM.m	
@@ -0,0 +1,99 @@
+function [X,FVAL,EXITFLAG] = fsolveIQM(FUN,X,varargin)
+% fsolveIQM: attempts to solve equations of the form FUN(X)=0    
+% where FUN and X may be vectors. Newton iteration.
+% 
+% USAGE:
+% ======
+% [X,FVAL,EXITFLAG] = fsolveIQM(FUN,X)
+% [X,FVAL,EXITFLAG] = fsolveIQM(FUN,X,OPTIONS)
+%
+% FUN: Sunction to minimize/solve
+% X: Starting Guess
+% OPTIONS: structure containing options 
+%          OPTIONS.MaxIter: Maximum number of iterations
+%          OPTIONS.TolFun:  Tolerance for max element in function evaluation
+%          OPTIONS.Delta:   Step length for numerical differentiation to 
+%                           obtain the Jacobian
+%
+% DEFAULT VALUES:
+% ===============
+% OPTIONS.MaxIter: 1000
+% OPTIONS.TolFun: 1e-11
+% OPTIONS.Delta: 1e-8
+%
+% Output Arguments:
+% =================
+% X: Found solution
+% FVAL: Value of the equations FUN at X
+% EXITFLAG: 1=success, 0=not found
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+MaxIter = 1000;
+TolFun = 1e-11; 
+Delta = 1e-8;
+
+% Handle OPTIONS if given
+if nargin == 3,
+    OPTIONS = varargin{1};
+    % TolFun
+    if isfield(OPTIONS,'TolFun'),
+        if ~isempty(OPTIONS.TolFun),
+            TolFun = OPTIONS.TolFun;
+        end
+    end
+    % MaxIter
+    if isfield(OPTIONS,'MaxIter'),
+        if ~isempty(OPTIONS.MaxIter),
+            MaxIter = OPTIONS.MaxIter;
+        end
+    end
+    % Delta
+    if isfield(OPTIONS,'Delta'),
+        if ~isempty(OPTIONS.Delta),
+            Delta = OPTIONS.Delta;
+        end
+    end
+end
+
+EXITFLAG = 0;
+for k = 1:MaxIter,
+    FVAL = feval(FUN,X);
+    Jacobian = getJacobian(FUN,X,Delta);
+    X = X - 0.5*pinv(Jacobian)*FVAL;
+    if norm(FVAL) < TolFun,
+        EXITFLAG = 1;
+        break
+    end
+end
+
+if nargout < 3 && EXITFLAG == 0,
+    disp('IQMsteadystate/fsolveIQM: Exceeded maximum number of iterations - check options');
+    disp(sprintf('Last residual: %g',max(abs(FVAL))));
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET JACOBIAN AT GIVEN STATE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [Jacobian] = getJacobian(FUN,X,DELTA)
+% size of system
+n = length(X);          
+% initialize jacobian variable
+Jacobian = zeros(n,n);  
+% determine the Jacobian by numerical differentiation
+for k = 1:n,                
+    Xup = X;
+    Xup(k) = Xup(k)+DELTA;
+    Jacobian(:,k) = (FUN(Xup)'-FUN(X)')/DELTA;
+end
+return
+
+
+
+
+
+
+
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/statistic/auxiliary/common_size.m b/IQMtools V1.2.2.2/IQMlite/tools/statistic/auxiliary/common_size.m
new file mode 100644
index 0000000000000000000000000000000000000000..55b80e8db804c291e930c688c9fd43e8145712bb
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/statistic/auxiliary/common_size.m	
@@ -0,0 +1,55 @@
+function [errorcode, varargout] = common_size (varargin)
+% common_size: Determine if all input arguments are either scalar or of common
+% size.  If so, the output variable 'errorcode' is zero, and 'b' is a matrix 
+% of the common size with all entries equal to 'x' if this is a scalar or
+% x otherwise.  If the inputs cannot be brought to a common size,
+% errorcode is 1, and 'b' is 'x'.  For example,
+%
+% [errorcode, a, b] = common_size ([1 2; 3 4], 5)
+% 
+% results in:
+%               errorcode = 0
+%               a = [ 1, 2; 3, 4 ]
+%               b = [ 5, 5; 5, 5 ]
+%
+% USAGE:
+% ======
+% [errorcode, a, b] = common_size (x, y)
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+  if (nargin < 2)
+    error ('common_size: only makes sense if nargin >= 2');
+  end
+
+  len = 2;
+  for i = 1 : nargin
+    sz =  size (varargin{i});
+    if (length (sz) < len)
+      s(i,:) = [sz, ones(1,len - length(sz))];
+    else
+      if (length (sz) > len)
+	if (i > 1)
+	  s = [s, ones(size(s,1), length(sz) - len)];
+	end
+	len = length (sz);
+      end
+      s(i,:) = sz;
+    end
+  end
+
+  m = max (s);
+  if (any (any ((s ~= 1)') & any ((s ~= ones (nargin, 1) * m)')))
+    errorcode = 1;
+    varargout = varargin;
+  else
+    errorcode = 0;
+    for i = 1 : nargin
+      varargout{i} = varargin{i};
+      if (prod (s(i,:)) == 1)
+           varargout{i} = varargout{i}*ones (m);
+      end
+    end
+  end
+
+end
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/statistic/auxiliary/iscomplex.m b/IQMtools V1.2.2.2/IQMlite/tools/statistic/auxiliary/iscomplex.m
new file mode 100644
index 0000000000000000000000000000000000000000..2330a9169b4f933f0e158ddf8a1759f59f241095
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/statistic/auxiliary/iscomplex.m	
@@ -0,0 +1,10 @@
+function [result] = iscomplex (x)
+% Checks if number x is a complex number.
+%
+% USAGE:
+% ======
+% [result] = iscomplex (x)
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+result = ~isreal(x);
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/statistic/auxiliary/ismatrixIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/statistic/auxiliary/ismatrixIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..4516a8e9faf983c3849df42498628d6685a24038
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/statistic/auxiliary/ismatrixIQM.m	
@@ -0,0 +1,20 @@
+function [ out ] = ismatrixIQM( in )
+% ismatrixIQM: Checks if the given argument is a matrix. out=1 if yes and 0
+% if not.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+out = 1;
+if ~isnumeric(in),
+    out = 0;
+    return
+end
+
+dimvector = size(in);
+if min(dimvector) == 1,
+   out = 0;
+   return
+end
+
+return
+    
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/statistic/auxiliary/plot_dendrogram.m b/IQMtools V1.2.2.2/IQMlite/tools/statistic/auxiliary/plot_dendrogram.m
new file mode 100644
index 0000000000000000000000000000000000000000..8baf9a2f895e2f408a9cf3c7a4fc7168abfb1ce5
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/statistic/auxiliary/plot_dendrogram.m	
@@ -0,0 +1,121 @@
+function plot_dendrogram(topology,labels,fontsize)
+% DENDPLOT: Plots a dendrogram given a topology matrix.
+%
+%     Usage: dendplot(topology,{labels},{fontsize})
+%
+%         topology = [(n-1) x 4] matrix summarizing dendrogram topology:
+%                       col 1 = 1st OTU/cluster being grouped at current step
+%                       col 2 = 2nd OTU/cluster
+%                       col 3 = ID of cluster being produced
+%                       col 4 = distance at node
+%         labels =   optional cell-array with label names
+%         fontsize = optional font size for labels [default = 10].
+%
+
+% RE Strauss, 5/27/98
+%   8/20/99 - miscellaneous changes for Matlab v5.
+
+if (nargin<2)
+    labels = {};
+end;
+if (nargin < 3)
+    fontsize = [];
+end;
+
+if (isempty(fontsize))              % Default font size for labels
+    fontsize = 10;
+end;
+
+r = size(topology,1);
+n = r+1;                            % Number of taxa
+
+links = dendhier([],topology,n-1);  % Find dendrogram links (branches)
+otu_indx = find(links(:,1)<=n);     % Get sequence of OTUs
+otus = links(otu_indx,1);
+y = zeros(2*n-1,1);                 % Y-coords for plot
+y(otus) = 0.5:(n-0.5);
+for i = 1:(n-1)
+    y(topology(i,3)) = mean([y(topology(i,1)),y(topology(i,2))]);
+end;
+
+%  clf;                                % Begin plot
+hold on;
+
+for i = 1:(2*n-2)                   % Horizontal lines
+    desc = links(i,1);
+    anc =  links(i,2);
+    X = [links(i,3) links(i,4)];
+    Y = [y(desc) y(desc)];
+    plot(X,Y,'k');
+end;
+
+for i = (n+1):(2*n-1)               % Vertical lines
+    indx = find(links(:,2)==i);
+    X = [links(indx,4)];
+    Y = [y(links(indx(1),1)) y(links(indx(2),1))];
+    plot(X,Y,'k');
+end;
+
+maxdist = max(links(:,4));
+for i = 1:n                         % OTU labels
+    if (~isempty(labels))
+        h = text(-.02*maxdist,y(i),labels{i},'Interpreter','none');   % For OTUs on right
+        set(h,'fontsize',fontsize);
+    else
+        h = text(-.02*maxdist,y(i),num2str(i));  % For OTUs on right
+        set(h,'fontsize',fontsize);
+        %     text(-.06*maxdist,y(i),num2str(i)); % For UTOs on left
+    end;
+end;
+
+axis([0-abs(0.3*maxdist) maxdist+0.03*maxdist 0 n]); % Axes
+%axis('square');
+set(gca,'Ytick',[]);                % Suppress y-axis labels and tick marks
+set(gca,'Ycolor','w');              % Make y-axes invisible
+set(gca,'Xdir','reverse');          % For OTUs on right
+
+hold off;
+return;
+
+
+% DENDHIER: Recursive algorithm to find links and distance coordinates on a
+%             dendrogram, given the topology matrix.
+%
+%     Usage: [links,topology,node] = dendhier(links,topology,node)
+%
+%         links =     4-col matrix of descendants, ancestors, descendant
+%                       distances, and ancestor distances; pass to
+%                       function as null vector []
+%         topology =  dendrogram topology matrix
+%         node =      current node; pass as N-1
+%
+
+% RE Strauss, 7/13/95
+
+function [links,topology,node] = dendhier(links,topology,node)
+n = size(topology,1)+1;             % Number of OTUs
+
+c1 =   topology(node,1);
+c2 =   topology(node,2);
+clst = topology(node,3);
+dist = topology(node,4);
+
+if (c1 <= n)
+    links = [links; c1 clst 0 dist];
+else
+    prevnode = find(topology(:,3)==c1);
+    prevdist = topology(prevnode,4);
+    links = [links; c1 clst prevdist dist];
+    [links,topology,node] = dendhier(links,topology,prevnode);
+end;
+
+if (c2 <= n)
+    links = [links; c2 clst 0 dist];
+else
+    prevnode = find(topology(:,3)==c2);
+    prevdist = topology(prevnode,4);
+    links = [links; c2 clst prevdist dist];
+    [links,topology,node] = dendhier(links,topology,prevnode);
+end;
+
+return;
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/statistic/boxplotIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/statistic/boxplotIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..a635fd45eb0dd5fd94b83cc45a418c78e1537e8e
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/statistic/boxplotIQM.m	
@@ -0,0 +1,270 @@
+function boxplotIQM(data,varargin)
+% Plot a boxplot for given data.
+%
+% USAGE:
+% ======
+% boxplotIQM(data)        
+% boxplotIQM(data,group)        
+% boxplotIQM(data,OPTIONS)        
+% boxplotIQM(data,group,OPTIONS)        
+%
+% data:  Matrix where each column contains data for which one box is plotted
+%        Alternatively, data can also be a column vector. Depending on the
+%        group argument either one box is plotted or several, depending on
+%        the group information.
+% group: Column vector, defining the grouping (by distinct numerical
+%        values) of the data. In this case dara needs to be a column vector
+%        of the same size as group.
+%        
+% OPTIONS: structure containing options for the function
+%       OPTIONS.samplenames:        Cell-array with names or other information of the samples
+%       OPTIONS.boxWidth:           Width of the boxes to be drawn
+%       OPTIONS.filled:             Will fill the box (good for small boxWidth)
+%       OPTIONS.verticalFlag:       Flag determining if the boxes are oriented
+%                                   vertically (=1) or horizontally (=0)
+%       OPTIONS.outliers:           0: do not plot them, 1: do plot them
+%       OPTIONS.whiskerLength:      Whisker length relative to the length of the box
+%       OPTIONS.whiskerPercentiles: If this option is defined then the
+%                                   whiskers are not plotted based on
+%                                   whiskerLength but based on the provided
+%                                   percentiles in this option. Example:
+%                                   whiskerPercentiles = [2.5 97.5] will
+%                                   plot the whiskers at 2.5 and 97.5
+%                                   percentiles of the data.
+%       OPTIONS.axisij:             If plot is postprocessed with axisih
+%                                   then this option needs to be set to 1.
+%                                   Otherwise 0. 
+%
+% DEFAULT VALUES:
+% ===============
+% OPTIONS.samplenames:          Group/sample numbers
+% OPTIONS.boxWidth:             0.5
+% OPTIONS.filled:               0
+% OPTIONS.verticalFlag:         0 (plot horizontally)
+% OPTIONS.outliers:             1 (plot outliers)
+% OPTIONS.whiskerLength:        1.5 (standard)
+% OPTIONS.whiskerPercentiles:   [] (use whiskerLength)
+% OPTIONS.axisij:               0
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+% GLOBAL VARIABLES
+global verticalFlag boxWidth whiskerLength outliers whiskerPercentiles filled
+
+% Handle variable input arguments
+if nargin==1,
+    group   = [];
+    OPTIONS = [];
+elseif nargin==2,
+    if isstruct(varargin{1}),
+        OPTIONS = varargin{1};
+        group   = [];
+    else
+        OPTIONS = [];
+        group   = varargin{1};
+    end
+elseif nargin==3,
+    group   = varargin{1};
+    OPTIONS = varargin{2};
+else
+    error('Incorrect number of input arguments.');
+end
+
+if ~isempty(group),
+    % Handle definition of group
+    % If group defined then data needs to be a vector etc.
+    if ~isvector(data),
+        error('If group defined then data needs to be a vector of same size.');
+    end
+    % group nees to be a column vector
+    if ~isvector(group),
+        error('group needs to be a column vector.');
+    end
+    % data and group need to have same lengths
+    if length(data) ~= length(group),
+        error('data and group arguments need to have same length.');
+    end
+    % Enforce column vectors
+    data    = data(:);
+    group   = group(:);
+else
+    % Handle if group is not defined (then data can be vector or matrix)
+    data_stacked    = [];
+    group_stacked   = [];
+    for k=1:size(data,2),
+        data_stacked    = [data_stacked; data(:,k)];
+        group_stacked   = [group_stacked; k*ones(length(data(:,k)),1)];
+    end
+    data    = data_stacked;
+    group   = group_stacked;
+end
+
+% Determine number of samples (number groups) 
+ALLgroups = unique(group);
+nrgroups  = length(ALLgroups);
+
+% Handle options
+try samplenames             = OPTIONS.samplenames;          catch, samplenames          = {};   end
+try boxWidth                = OPTIONS.boxWidth;             catch, boxWidth             = 0.5;  end
+try filled                  = OPTIONS.filled;               catch, filled               = 0;    end
+try verticalFlag            = OPTIONS.verticalFlag;         catch, verticalFlag         = 0;    end
+try outliers                = OPTIONS.outliers;             catch, outliers             = 1;    end
+try whiskerLength           = OPTIONS.whiskerLength;        catch, whiskerLength        = 1.5;  end
+try whiskerPercentiles      = OPTIONS.whiskerPercentiles;   catch, whiskerPercentiles   = [];   end
+try FLAG_axisij             = OPTIONS.axisij;               catch, FLAG_axisij          = 0;    end
+
+% Option check
+if ~isempty(samplenames) && length(samplenames) ~= nrgroups,
+    error('Number of samplenames does not fit the number of samples.');
+end
+
+% Cycle through the groups and plot
+hold on
+for k=1:nrgroups
+    dataPlot = data(group==ALLgroups(k));
+    doplot(dataPlot,k);
+end
+
+% Annotate
+Ymin = min(min(data)); Ymax = max(max(data));
+DeltaY = 0.025*(Ymax-Ymin); % just a little bit of space on limits
+if verticalFlag
+    axis([[1-boxWidth, nrgroups+boxWidth] [(Ymin-DeltaY) (Ymax+DeltaY)]]);
+    set(gca,'XTick',[1:nrgroups]);
+    if ~isempty(samplenames), 
+        set(gca, 'XTickLabel',samplenames); 
+        try
+            set(gca,'XTickLabelRotation',45);
+        catch
+        end
+    else
+        set(gca, 'XTickLabel',ALLgroups)
+    end   
+    set(gca,'XLim',[1-0.5 nrgroups+0.5]);    
+else
+    axis([[(Ymin-DeltaY) (Ymax+DeltaY)] [1-boxWidth, nrgroups+boxWidth]]);
+    set(gca,'YTick',[1:nrgroups]);
+    if ~isempty(samplenames), 
+        set(gca, 'YTickLabel',samplenames); 
+    else
+        set(gca, 'YTickLabel',ALLgroups)
+    end
+    set(gca,'YLim',[1-0.5 nrgroups+0.5]);
+end
+% Whisker annotation if percentiles
+if ~isempty(whiskerPercentiles),
+    textWhiskers = sprintf('Whiskers: [%g%%, %g%%] of range',min(whiskerPercentiles),max(whiskerPercentiles));
+    XLim = get(gca,'XLim');
+    YLim = get(gca,'YLim');
+    if ~FLAG_axisij,
+        text(XLim(2),YLim(2),textWhiskers,'HorizontalAlign','Right','VerticalAlign','Top','FontSize',10);
+    else
+        text(XLim(2),YLim(1),textWhiskers,'HorizontalAlign','Right','VerticalAlign','Top','FontSize',10);
+    end
+end
+
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PLOT FUNCTION FOR PLOTTING A SINGLE BOX WITH WHISKERS AND OUTLIERS
+% THE FUNCTION ALSO NEEDS TO DETERMINE THE PERCENTILES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [] = doplot(sampledata,k)
+global verticalFlag boxWidth whiskerLength outliers whiskerPercentiles filled
+% Determine the percentiles
+prctiles = prctileIQM(sampledata,[25 50 75]);
+p25 = prctiles(1,:); p50 = prctiles(2,:); p75 = prctiles(3,:);
+% Determine the whiskers
+if isempty(whiskerPercentiles),
+    % Determine the upper whisker position (needs to be on a sampledata point)
+    index = find(sampledata <= p75+whiskerLength*(p75-p25));
+    if isempty(index),
+        upperWhisker = p75; % if no larger data points then use the 75 percentile
+    else
+        upperWhisker = max(sampledata(index)); % get the max sampledata point smaller than the 75% percentile
+    end
+    % Determine the upper whisker position (needs to be on a sampledata point)
+    index = find(sampledata >= p25-whiskerLength*(p75-p25));
+    if isempty(index),
+        lowerWhisker = p25; % if no smaller data points then use the 25 percentile
+    else
+        lowerWhisker = min(sampledata(index)); % get the min sampledata point larger than the 25% percentile
+    end
+else
+    % Determine whiskers based on percentiles
+    upperWhisker = prctileIQM(sampledata,max(whiskerPercentiles));
+    lowerWhisker = prctileIQM(sampledata,min(whiskerPercentiles));
+end
+% Determine the outliers
+% Outliers are all the data points that lie outside the whiskers
+outlier = sampledata([find(sampledata<lowerWhisker); find(sampledata > upperWhisker)]);
+% Determine the right and the left (in a vertical sense) values
+% for the box
+rightValue = k+0.5*boxWidth;
+leftValue = k-0.5*boxWidth;
+% All things are determined so now the messy plot :)
+if verticalFlag
+    % plot the whiskers
+    if ~filled,
+        plot([k-0.25*boxWidth k+0.25*boxWidth],[upperWhisker upperWhisker],'b'); % plot end half as wide as the box
+        plot([k-0.25*boxWidth k+0.25*boxWidth],[lowerWhisker lowerWhisker],'b'); % plot end half as wide as the box
+        plot([k k],[lowerWhisker p25],'k--'); 
+        plot([k k],[p75 upperWhisker],'k--');
+    else
+        plot([k k],[lowerWhisker p25],'k'); 
+        plot([k k],[p75 upperWhisker],'k');
+    end
+    % plot the median
+    if ~filled,
+        plot([leftValue rightValue],[p50 p50],'r');
+    else
+        plot([k-min(0.5*boxWidth*6,0.5) k+min(0.5*boxWidth*6,0.5)],[p50 p50],'r');
+    end
+    % plot the outliers
+    if outliers,
+        plot(k*ones(1,length(outlier)),outlier,'k.');
+    end
+    % plot the 4 sides of the box
+    if ~filled,
+        plot([leftValue rightValue],[p75 p75],'b');
+        plot([rightValue rightValue],[p75 p25],'b');
+        plot([rightValue leftValue],[p25 p25],'b');
+        plot([leftValue leftValue],[p25 p75],'b');
+    else
+         IQMplotfill([leftValue rightValue],[p25 p25],[p75 p75],[0 0 0],1); hold on;
+    end
+else
+    % plot the whiskers
+    if ~filled,
+        plot([upperWhisker upperWhisker],[k-0.25*boxWidth k+0.25*boxWidth],'b'); % plot end half as wide as the box
+        plot([lowerWhisker lowerWhisker],[k-0.25*boxWidth k+0.25*boxWidth],'b'); % plot end half as wide as the box
+        plot([lowerWhisker p25],[k k],'k--'); 
+        plot([p75 upperWhisker],[k k],'k--'); 
+    else
+        plot([lowerWhisker p25],[k k],'k'); 
+        plot([p75 upperWhisker],[k k],'k'); 
+    end
+    % plot the median
+    if ~filled,
+        plot([p50 p50],[leftValue rightValue],'r');
+    else
+        plot([p50 p50],[k-min(0.5*boxWidth*6,0.5) k+min(0.5*boxWidth*6,0.5)],'r');
+    end
+    
+    
+    % plot the outliers
+    if outliers,
+        plot(outlier,k*ones(1,length(outlier)),'k.');
+    end
+    % plot the 4 sides of the box
+    if ~filled,
+        plot([p75 p75],[leftValue rightValue],'b');
+        plot([p75 p25],[rightValue rightValue],'b');
+        plot([p25 p25],[rightValue leftValue],'b');
+        plot([p25 p75],[leftValue leftValue],'b');
+    else
+        IQMplotfill([p25 p75],[leftValue leftValue],[rightValue rightValue],[0 0 0],1); hold on
+    end
+    
+end
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/statistic/centerIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/statistic/centerIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..d1006c9c1538dbe9ae5751d16a4b8ce182103bce
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/statistic/centerIQM.m	
@@ -0,0 +1,39 @@
+function [retval] = centerIQM(x, varargin)
+% Center by subtracting means
+%
+% USAGE:
+% ======
+% retval = centerIQM(x)
+% retval = centerIQM(x,dim)
+%
+% If x is a vector, subtract its mean. If x is a matrix, do the above for
+% each column. If the optional argument dim is given, perform the above
+% operation along this dimension 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+if (nargin ~= 1 && nargin ~= 2)
+    print_usage ();
+end
+
+if (isvector (x))
+    retval = x - mean (x, varargin{:});
+elseif (ismatrixIQM (x))
+    if nargin < 2
+        dim = find (size (x) > 1, 1);
+        if isempty (dim),
+            dim=1;
+        end;
+    else
+        dim = varargin{1};
+    end
+    sz = ones (1, ndims (x));
+    sz (dim) = size (x, dim);
+    retval = x - repmat (mean (x, dim), sz);
+elseif (isempty (x))
+    retval = x;
+else
+    error ('centerIQM: x must be a vector or a matrix');
+end
+
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/statistic/clusteringIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/statistic/clusteringIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..4e931da9063b27994605e9c13e87bfdfdb741b32
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/statistic/clusteringIQM.m	
@@ -0,0 +1,115 @@
+function [varargout] = clusteringIQM(dist,varargin)
+% clusteringIQM: Performs UPGMA on distance matrix and produces a
+% denddrogram plot.
+% 
+% Initially, each object is in its own cluster. At each step, the nearest 2
+% clusters are combined into a higher-level cluster. The distance between 
+% any 2 clusters A and B is taken to be the average of all distances
+% between pairs of objects "a" in A and "b" in B. 
+%
+% USAGE:
+% ======
+% [] = clusteringIQM(dist,labels,fontsize)       
+% [topology] = clusteringIQM(dist,labels,fontsize)
+%
+% dist:     [n x n] symmetric distance matrix
+% labels:   optional cell-array with label names
+% fontsize: optional font size for labels [default = 10]
+
+% Output Arguments:
+% =================
+% If no output argument is specified the dendrogram is plotted.
+%
+%    topology   - [(n-1) x 4] matrix summarizing dendrogram topology:
+%                 col 1 = 1st OTU/cluster being grouped at current step
+%                 col 2 = 2nd OTU/cluster
+%                 col 3 = ID of cluster being produced
+%                 col 4 = distance at node
+
+% RE Strauss, 5/27/96
+%   9/7/99 - miscellaneous changes for Matlab v5.
+%   9/24/01 - check diagonal elements against eps rather than zero.
+%
+% Adapted for the Systems Biology Toolbox 2 for MATLAB by
+% Henning Schmidt, 01. January 2008
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle variable input arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+labels = [];
+fontsize = [];
+if nargin < 1 || nargin > 3,
+    error('Incorrect number of input arguments.');
+elseif nargin == 2,
+    labels = varargin{1};
+elseif nargin == 3,
+    labels = varargin{1};
+    fontsize = varargin{2};
+end
+    
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Some checks
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[n,p] = size(dist);
+if n~=p || any(diag(dist)>eps),
+    error('Input matrix is not a distance matrix - consider function "pdistIQM" to calculate it.');
+end
+if ~isempty(labels),
+    if size(labels,1) ~= n,
+        error('Numbers of taxa and taxon labels do not match');
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Do the clustering
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+clstsize = ones(1,n);               % Number of elements in clusters/otus
+id = 1:n;                           % Cluster IDs
+topology = zeros(n-1,4);            % Output dendrogram-topology matrix
+
+plug = 10e6;
+dist = dist + eye(n)*plug;          % Replace diagonal with plugs
+
+for step = 1:(n-1),                 % Clustering steps
+    min_dist = min(dist(:));            % Find minimum pairwise distance
+    [ii,jj] = find(dist==min_dist);     % Find location of minimum
+    k = 1;                              % Use first identified minimum
+    while (ii(k)>jj(k)),                 %   for which i<j
+        k = k+1;
+    end
+    i = ii(k);
+    j = jj(k);
+    if (id(i)<id(j)),
+        topology(step,:) = [id(i) id(j) n+step min_dist];
+    else
+        topology(step,:) = [id(j) id(i) n+step min_dist];
+    end
+    id(i) = n+step;
+    dist(i,j) = plug;
+    dist(j,i) = plug;
+
+    new_clstsize = clstsize(i) + clstsize(j);
+    alpha_i = clstsize(i) / new_clstsize;
+    alpha_j = clstsize(j) / new_clstsize;
+    clstsize(i) = new_clstsize;
+
+    for k = 1:n,                         % For all other clusters/OTUs,
+        if (k~=i && k~=j),                %   adjust distances to new cluster
+            dist(k,i) = alpha_i * dist(k,i) + alpha_j * dist(k,j);
+            dist(i,k) = alpha_i * dist(i,k) + alpha_j * dist(j,k);
+            dist(k,j) = plug;
+            dist(j,k) = plug;
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle output
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargout == 1,
+    varargout{1} = topology;
+else
+    figure; clf;
+    plot_dendrogram(topology,labels,fontsize);
+end    
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/betacdfIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/betacdfIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..59f521e415b34dad0991d54e080d6ae68e74df4c
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/betacdfIQM.m	
@@ -0,0 +1,47 @@
+function cdf_result = betacdfIQM(x, a, b)
+% Cumulative density function of the Beta distribution
+%
+% USAGE:
+% ======
+% cdf_result = betacdfIQM(x, a, b)
+%
+% For each element of 'x', returns the CDF at 'x' of the beta
+% distribution with parameters 'a' and 'b', i.e.,
+% PROB (beta ('a', 'b') <= 'x').
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+  if (nargin ~= 3)
+    error('Incorrect number of input arguments'); 
+  end
+
+  if (~isscalar (a) || ~isscalar(b))
+    [retval, x, a, b] = common_size (x, a, b);
+    if (retval > 0)
+      error ('x, a and b must be of common size or scalar');
+    end
+  end
+
+  sz = size(x);
+  cdf_result = zeros (sz);
+
+  k = find (~(a > 0) | ~(b > 0) | isnan (x));
+  if (any (k))
+    cdf_result (k) = NaN;
+  end
+
+  k = find ((x >= 1) & (a > 0) & (b > 0));
+  if (any (k))
+    cdf_result (k) = 1;
+  end
+
+  k = find ((x > 0) & (x < 1) & (a > 0) & (b > 0));
+  if (any (k))
+    if (isscalar (a) && isscalar(b))
+      cdf_result (k) = betainc(x(k), a, b);
+    else
+      cdf_result (k) = betainc(x(k), a(k), b(k));
+    end
+  end
+
+end
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/betainvIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/betainvIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..56da4a3eb440345bf6795bfac23f6ae6ee3361bc
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/betainvIQM.m	
@@ -0,0 +1,79 @@
+function inv = betainvIQM(x, a, b)
+% Quantile function of the Beta distribution
+%
+% USAGE:
+% ======
+% inv = betainvIQM(x, a, b)
+%
+% For each component of 'x', compute the quantile (the inverse of
+% the CDF) at 'x' of the Beta distribution with parameters 'a'
+% and 'b'.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+  if (nargin ~= 3)
+    error('Incorrect number of input arguments'); 
+  end
+
+  if (~isscalar (a) || ~isscalar(b))
+    [retval, x, a, b] = common_size (x, a, b);
+    if (retval > 0)
+      error ('x, a and b must be of common size or scalars');
+    end
+  end
+  
+  sz = size (x);
+  inv = zeros (sz);
+
+  k = find ((x < 0) | (x > 1) | ~(a > 0) | ~(b > 0) | isnan (x));
+  if (any (k))
+    inv (k) = NaN;
+  end
+
+  k = find ((x == 1) & (a > 0) & (b > 0));
+  if (any (k))
+    inv (k) = 1;
+  end
+
+  k = find ((x > 0) & (x < 1) & (a > 0) & (b > 0));
+  if (any (k))
+    if (~isscalar(a) || ~isscalar(b))
+      a = a (k);
+      b = b (k);
+      y = a ./ (a + b);
+    else
+      y = a / (a + b) * ones (size (k));
+    end
+    x = x (k);
+    l = find (y < eps);
+    if (any (l))
+      y(l) = sqrt (eps) * ones (length (l), 1);
+    end
+    l = find (y > 1 - eps);
+    if (any (l))
+      y(l) = 1 - sqrt (eps) * ones (length (l), 1);
+    end
+
+    y_old = y;
+    for i = 1 : 10000
+      h     = (betacdfIQM(y_old, a, b) - x) ./ betapdfIQM(y_old, a, b);
+      y_new = y_old - h;
+      ind   = find (y_new <= eps);
+      if (any (ind))
+        y_new (ind) = y_old (ind) / 10;
+      end
+      ind = find (y_new >= 1 - eps);
+      if (any (ind))
+        y_new (ind) = 1 - (1 - y_old (ind)) / 10;
+      end
+      h = y_old - y_new;
+      if (max (abs (h)) < sqrt (eps))
+        break;
+      end
+      y_old = y_new;
+    end
+
+    inv (k) = y_new;
+  end
+
+end
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/betapdfIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/betapdfIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..4253af60947a2cb4a0ef08756995874c6927c835
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/betapdfIQM.m	
@@ -0,0 +1,41 @@
+function pdf_result = betapdfIQM(x, a, b)
+% Probability density function of the Beta distribution
+%
+% USAGE:
+% ======
+% pdf_result = betapdfIQM(x, a, b)
+%
+% For each element of 'x', returns the PDF at 'x' of the beta
+% distribution with parameters 'a' and 'b'.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+  if (nargin ~= 3)
+    error('Incorrect number of input arguments'); 
+  end
+  
+  if (~isscalar (a) || ~isscalar(b))
+    [retval, x, a, b] = common_size (x, a, b);
+    if (retval > 0)
+      error ('x, a and b must be of common size or scalar');
+    end
+  end
+
+  sz = size (x);
+  pdf_result = zeros (sz);
+
+  k = find (~(a > 0) | ~(b > 0) | isnan (x));
+  if (any (k))
+    pdf_result (k) = NaN;
+  end
+
+  k = find ((x > 0) & (x < 1) & (a > 0) & (b > 0));
+  if (any (k))
+    if (isscalar(a) && isscalar(b))
+      pdf_result(k) = exp ((a - 1) .* log (x(k)) + (b - 1) .* log (1 - x(k))) ./ beta(a, b);
+    else
+      pdf_result(k) = exp ((a(k) - 1) .* log (x(k)) + (b(k) - 1) .* log (1 - x(k))) ./ beta(a(k), b(k));
+    end
+  end
+
+end
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/chi2cdfIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/chi2cdfIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..50526f646ca419228e53160c46583325b74b2a48
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/chi2cdfIQM.m	
@@ -0,0 +1,27 @@
+function cdf_result = chi2cdfIQM(x, n)
+% Cumulative density function of the chi-square distribution
+%
+% USAGE:
+% ======
+% cdf_result = chi2cdfIQM(x, n)
+%
+% For each element of 'x', compute the cumulative distribution
+% function (CDF) at 'x' of the chisquare distribution with 'n'
+% degrees of freedom.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+  if (nargin ~= 2)
+    error('Incorrect number of input arguments');
+  end
+
+  if (~isscalar (n) || ~isscalr)
+    [retval, x, n] = common_size (x, n);
+    if (retval > 0)
+      error ('x and n must be of common size or scalar');
+    end
+  end
+
+  cdf_result = gamcdfIQM(x, n / 2, 2);
+
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/chi2invIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/chi2invIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..b09bff366a2fd656320f91504ff0e16681531fdd
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/chi2invIQM.m	
@@ -0,0 +1,27 @@
+function inv = chi2invIQM(x, n)
+% Quantile function of the chi-square distribution
+%
+% USAGE:
+% ======
+% inv = chi2invIQM(x, n)
+%
+% For each element of 'x', compute the quantile (the inverse of the
+% CDF) at 'x' of the chisquare distribution with 'n' degrees of
+% freedom.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+  if (nargin ~= 2)
+    error('Incorrect number of input arguments'); 
+  end
+
+  if (~isscalar (n))
+    [retval, x, n] = common_size (x, n);
+    if (retval > 0)
+      error ('x and n must be of common size or scalar');
+    end
+  end
+
+  inv = gaminvIQM(x, n / 2, 2);
+
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/chi2pdfIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/chi2pdfIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..5c4ee05fc135d9422d61a2fcb113a436c02c81d0
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/chi2pdfIQM.m	
@@ -0,0 +1,27 @@
+function pdf_result = chi2pdfIQM(x, n)
+% Probability density function of the chi-square distribution
+%
+% USAGE:
+% ======
+% pdf_result = chi2pdfIQM(x, n)
+%
+% For each element of 'x', compute the probability density function
+% (PDF) at 'x' of the chisquare distribution with 'n' degrees
+% of freedom.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+  if (nargin ~= 2)
+    error('Incorrect number of input arguments'); 
+  end
+
+  if (~isscalar (n))
+    [retval, x, n] = common_size (x, n);
+    if (retval > 0)
+      error ('x and n must be of common size or scalar');
+    end
+  end
+
+  pdf_result = gampdfIQM(x, n / 2, 2);
+
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/fcdfIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/fcdfIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..632fdb1b6e3e4077110c33160cb4b5b95e15bd18
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/fcdfIQM.m	
@@ -0,0 +1,43 @@
+function [cdf_result] = fcdfIQM(x, m, n)
+% Cumulative density function of the f distribution.
+%
+% USAGE:
+% ======
+% cdf_result = fcdfIQM(x, m, n)
+%
+% For each element of x, compute the cumulative distribution function
+% (CDF) at x of the F distribution with m and n degrees of
+% freedom.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+if (~isscalar(m) || ~isscalar(n))
+    [retval, x, m, n] = common_size(x, m, n);
+    if (retval > 0)
+        error ('fcdf: X, M, and N must be of common size or scalars');
+    end
+end
+
+if (iscomplex (x) || iscomplex (m) || iscomplex (n))
+    error ('fcdf: X, M, and N must not be complex');
+end
+
+if (isa (x, 'single') || isa (m, 'single') || isa (n, 'single'))
+    cdf_result = zeros (size (x), 'single');
+else
+    cdf_result = zeros (size (x));
+end
+
+k = isnan (x) | ~(m > 0) | ~(m < Inf) | ~(n > 0) | ~(n < Inf);
+cdf_result(k) = NaN;
+
+k = (x == Inf) & (m > 0) & (m < Inf) & (n > 0) & (n < Inf);
+cdf_result(k) = 1;
+
+k = (x > 0) & (x < Inf) & (m > 0) & (m < Inf) & (n > 0) & (n < Inf);
+if (isscalar (m) && isscalar (n))
+    cdf_result(k) = 1 - betainc (1 ./ (1 + m * x(k) / n), n/2, m/2);
+else
+    cdf_result(k) = 1 - betainc (1 ./ (1 + m(k) .* x(k) ./ n(k)), n(k)/2, m(k)/2);
+end
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/finvIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/finvIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..c66d9cfab14cbe6f37c40b2e7a9962737df4e21d
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/finvIQM.m	
@@ -0,0 +1,39 @@
+function [inv] = finvIQM(x, m, n)
+% Quantile function of the f distribution
+%
+% USAGE:
+% ======
+% inv = finvIQM(x, m, n)
+%
+% For each element of x, compute the quantile (the inverse of the CDF)
+% at x of the F distribution with m and n degrees of freedom.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+if (~isscalar (m) || ~isscalar (n))
+    [retval, x, m, n] = common_size (x, m, n);
+    if (retval > 0)
+        error ('finvIQM: X, M, and N must be of common size or scalars');
+    end
+end
+
+if (iscomplex (x) || iscomplex (m) || iscomplex (n))
+    error ('finvIQM: X, M, and N must not be complex');
+end
+
+if (isa (x, 'single') || isa (m, 'single') || isa (n, 'single'))
+    inv = NaN (size (x), 'single');
+else
+    inv = NaN (size (x));
+end
+
+k = (x == 1) & (m > 0) & (m < Inf) & (n > 0) & (n < Inf);
+inv(k) = Inf;
+
+k = (x >= 0) & (x < 1) & (m > 0) & (m < Inf) & (n > 0) & (n < Inf);
+if (isscalar (m) && isscalar (n))
+    inv(k) = ((1 ./ betainv (1 - x(k), n/2, m/2) - 1) * n / m);
+else
+    inv(k) = ((1 ./ betainv (1 - x(k), n(k)/2, m(k)/2) - 1).* n(k) ./ m(k));
+end
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/fpdfIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/fpdfIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..1625b3c1e94782e0165ca47bdece7db3c646dc6b
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/fpdfIQM.m	
@@ -0,0 +1,41 @@
+function pdf_result = fpdfIQM(x, m, n)
+% Probability density function of the f distribution
+%
+% USAGE:
+% ======
+% pdf_result = fpdfIQM(x, m, n)
+%
+% For each element of @var{x}, compute the probability density function (PDF)
+% at x of the F distribution with m and n degrees of freedom.
+   
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+if (~isscalar (m) || ~isscalar (n))
+    [retval, x, m, n] = common_size (x, m, n);
+    if (retval > 0)
+        error ('fpdf: X, M, and N must be of common size or scalars');
+    end
+end
+
+if (iscomplex (x) || iscomplex (m) || iscomplex (n))
+    error ('fpdf: X, M, and N must not be complex');
+end
+
+if (isa (x, 'single') || isa (m, 'single') || isa (n, 'single'))
+    pdf_result = zeros (size (x), 'single');
+else
+    pdf_result = zeros (size (x));
+end
+
+k = isnan (x) | ~(m > 0) | ~(m < Inf) | ~(n > 0) | ~(n < Inf);
+pdf_result(k) = NaN;
+
+k = (x > 0) & (x < Inf) & (m > 0) & (m < Inf) & (n > 0) & (n < Inf);
+if (isscalar (m) && isscalar (n))
+    tmp = m / n * x(k);
+    pdf_result(k) = (exp ((m/2 - 1) * log (tmp) - ((m + n) / 2) * log (1 + tmp)) * (m / n) ./ beta (m/2, n/2));
+else
+    tmp = m(k) .* x(k) ./ n(k);
+    pdf_result(k) = (exp ((m(k)/2 - 1) .* log (tmp) - ((m(k) + n(k)) / 2) .* log (1 + tmp)) .* (m(k) ./ n(k)) ./ beta (m(k)/2, n(k)/2));
+end
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/gamcdfIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/gamcdfIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..5a77c41f3dd4f122fa8b1b1294ff3ef4143ea1eb
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/gamcdfIQM.m	
@@ -0,0 +1,42 @@
+function cdf_result = gamcdfIQM(x, a, b)
+% Cumulative density function of the Gamma distribution
+%
+% USAGE:
+% ======
+% cdf_result = gamcdfIQM(x, a, b)
+%
+% For each element of 'x', compute the cumulative distribution
+% function (CDF) at 'x' of the Gamma distribution with parameters
+% 'a' and 'b'.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+  if (nargin ~= 3)
+    error('Incorrect number of input arguments'); 
+  end
+
+  if (~isscalar (a) || ~isscalar(b))
+    [retval, x, a, b] = common_size (x, a, b);
+    if (retval > 0)
+      error ('x, a and b must be of common size or scalars');
+    end
+  end
+
+  sz = size (x);
+  cdf_result = zeros (sz);
+
+  k = find (~(a > 0) | ~(b > 0) | isnan (x));
+  if (any (k))
+    cdf_result (k) = NaN;
+  end
+
+  k = find ((x > 0) & (a > 0) & (b > 0));
+  if (any (k))
+    if (isscalar (a) && isscalar(b))
+      cdf_result (k) = gammainc(x(k) ./ b, a);
+    else
+      cdf_result (k) = gammainc(x(k) ./ b(k), a(k));
+    end
+  end
+
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/gaminvIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/gaminvIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..0b3d57d6393a1e1c649379d9381cf65e9ccabd10
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/gaminvIQM.m	
@@ -0,0 +1,71 @@
+function inv = gaminvIQM(x, a, b)
+% Quantile function of the Gamma distribution
+%
+% USAGE:
+% ======
+% inv = gaminvIQM(x, a, b)
+%
+% For each component of 'x', compute the quantile (the inverse of
+% the CDF) at 'x' of the Gamma distribution with parameters 'a'
+% and 'b'.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+  if (nargin ~= 3)
+    error('Incorrect number of input arguments'); 
+  end
+
+  if (~isscalar (a) || ~isscalar(b))
+    [retval, x, a, b] = common_size (x, a, b);
+    if (retval > 0)
+      error ('x, a and b must be of common size or scalars');
+    end
+  end
+
+  sz = size (x);
+  inv = zeros (sz);
+
+  k = find ((x < 0) | (x > 1) | isnan (x) | ~(a > 0) | ~(b > 0));
+  if (any (k))
+    inv (k) = NaN;
+  end
+
+  k = find ((x == 1) & (a > 0) & (b > 0));
+  if (any (k))
+    inv (k) = Inf;
+  end
+
+  k = find ((x > 0) & (x < 1) & (a > 0) & (b > 0));
+  if (any (k))
+    if (~isscalar(a) || ~isscalar(b))
+      a = a (k);
+      b = b (k);
+      y = a .* b;
+    else
+      y = a * b * ones (size (k));
+    end
+    x = x (k);
+    l = find (x < eps);
+    if (any (l))
+      y(l) = sqrt (eps) * ones (length (l), 1);
+    end
+
+    y_old = y;
+    for i = 1 : 100
+      h     = (gamcdfIQM(y_old, a, b) - x) ./ gampdfIQM(y_old, a, b);
+      y_new = y_old - h;
+      ind   = find (y_new <= eps);
+      if (any (ind))
+        y_new (ind) = y_old (ind) / 10;
+        h = y_old - y_new;
+      end
+      if (max (abs (h)) < sqrt (eps))
+        break;
+      end
+      y_old = y_new;
+    end
+
+    inv (k) = y_new;
+  end
+
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/gampdfIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/gampdfIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..897132b8a602492f0a9aa0a8b0b161b1189ca445
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/gampdfIQM.m	
@@ -0,0 +1,51 @@
+function pdf_result = gampdfIQM(x, a, b)
+% Probability density function of the Gamma distribution
+%
+% USAGE:
+% ======
+% pdf_result = gampdfIQM(x, a, b)
+%
+% For each element of 'x', return the probability density function
+% (PDF) at 'x' of the Gamma distribution with parameters 'a'
+% and 'b'.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+  if (nargin ~= 3)
+    error('Incorrect number of input arguments'); 
+  end
+
+  if (~isscalar (a) || ~isscalar(b))
+    [retval, x, a, b] = common_size (x, a, b);
+    if (retval > 0)
+      error ('x, a and b must be of common size or scalars');
+    end
+  end
+
+  sz = size(x);
+  pdf_result = zeros (sz);
+
+  k = find (~(a > 0) | ~(b > 0) | isnan (x));
+  if (any (k))
+    pdf_result (k) = NaN;
+  end
+
+  k = find ((x > 0) & (a > 0) & (a <= 1) & (b > 0));
+  if (any (k))
+    if (isscalar(a) && isscalar(b))
+      pdf_result(k) = (x(k) .^ (a - 1)) .* exp(- x(k) ./ b) ./ gamma(a) ./ (b .^ a);
+    else
+      pdf_result(k) = (x(k) .^ (a(k) - 1)) .* exp(- x(k) ./ b(k)) ./ gamma(a(k)) ./ (b(k) .^ a(k));
+    end
+  end
+
+  k = find ((x > 0) & (a > 1) & (b > 0));
+  if (any (k))
+    if (isscalar(a) && isscalar(b))
+      pdf_result(k) = exp (- a .* log (b) + (a-1) .* log (x(k)) - x(k) ./ b - gammaln(a));
+    else
+      pdf_result(k) = exp (- a(k) .* log (b(k)) + (a(k)-1) .* log (x(k)) - x(k) ./ b(k) - gammaln(a(k)));
+    end
+  end
+
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/normcdfIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/normcdfIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..d924f1990e64d3fbe701984026cdc6d4bc455e93
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/normcdfIQM.m	
@@ -0,0 +1,55 @@
+function cdf_result = normcdfIQM(x, m, s)
+% Cumulative densitiy function of the normal distribution
+%
+% USAGE:
+% ======
+% cdf_result = normcdfIQM(x, m, s)
+%
+% For each element of 'x', compute the cumulative distribution
+% function (CDF) at 'x' of the normal distribution with mean
+% 'm' and standard deviation 's'.
+%
+% Default values are 'm' = 0, 's' = 1.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+  if (~ ((nargin == 1) || (nargin == 3)))
+    error('Incorrect number of input arguments'); 
+  end
+
+  if (nargin == 1)
+    m = 0;
+    s = 1;
+  end
+
+  if (~isscalar (m) || ~isscalar (s))
+    [retval, x, m, s] = common_size(x, m, s);
+    if (retval > 0)
+      error ('x, m and s must be of common size or scalar');
+    end
+  end
+
+  sz = size (x);
+  cdf_result = zeros (sz);
+
+  if (isscalar (m) && isscalar(s))
+    if (find (isinf (m) | isnan (m) | ~(s >= 0) | ~(s < Inf)))
+      cdf_result = NaN * ones (sz);
+    else
+      cdf_result =  stdnormalcdfIQM((x - m) ./ s);
+    end
+  else
+    k = find (isinf (m) | isnan (m) | ~(s >= 0) | ~(s < Inf));
+    if (any (k))
+      cdf_result(k) = NaN;
+    end
+
+    k = find (~isinf (m) & ~isnan (m) & (s >= 0) & (s < Inf));
+    if (any (k))
+      cdf_result(k) = stdnormalcdfIQM((x(k) - m(k)) ./ s(k));
+    end
+  end
+
+  cdf_result((s == 0) & (x == m)) = 0.5;
+
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/norminvIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/norminvIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..9b8df51d498e75273291ce7c33f2a67d2bb5879a
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/norminvIQM.m	
@@ -0,0 +1,61 @@
+function inv = norminvIQM(x, m, s)
+% Quantile function of the normal distribution
+%
+% USAGE:
+% ======
+% pdf = norminvIQM(x, m, s)
+%
+% For each element of 'x', compute the quantile (the inverse of the
+% CDF) at 'x' of the normal distribution with mean 'm' and
+% standard deviation 's'.
+%
+% Default values are 'm' = 0, 's' = 1.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+  if (nargin ~= 1 && nargin ~= 3)
+    error('Incorrect number of input arguments'); 
+  end
+
+  if (nargin == 1)
+    m = 0;
+    s = 1;
+  end
+
+  if (~isscalar (m) || ~isscalar (s))
+    [retval, x, m, s] = common_size (x, m, s);
+    if (retval > 0)
+      error ('x, m and s must be of common size or scalars');
+    end
+  end
+
+  sz = size (x);
+  inv = zeros (sz);
+
+  if (isscalar (m) && isscalar (s))
+    if (find (isinf (m) | isnan (m) | ~(s > 0) | ~(s < Inf)))
+      inv = NaN * ones (sz);
+    else
+      inv =  m + s .* stdnormalinvIQM(x);
+    end
+  else
+    k = find (isinf (m) | isnan (m) | ~(s > 0) | ~(s < Inf));
+    if (any (k))
+      inv(k) = NaN;
+    end
+
+    k = find (~isinf (m) & ~isnan (m) & (s > 0) & (s < Inf));
+    if (any (k))
+      inv(k) = m(k) + s(k) .* stdnormalinvIQM (x(k));
+    end
+  end
+
+  k = find ((s == 0) & (x > 0) & (x < 1));
+  if (any (k))
+    inv(k) = m(k);
+  end
+
+  inv((s == 0) & (x == 0)) = -Inf;
+  inv((s == 0) & (x == 1)) = Inf;
+
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/normpdfIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/normpdfIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..3ae041353d9cae61904ab8306a698d1cc2d3bf72
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/normpdfIQM.m	
@@ -0,0 +1,56 @@
+function pdf_result = normpdfIQM(x, m, s)
+% Probability density function of the normal distribution
+%
+% USAGE:
+% ======
+% pdf_result = normpdfIQM(x, m, s)
+%
+% For each element of 'x', compute the probability density function
+% (PDF) at 'x' of the normal distribution with mean 'm' and
+% standard deviation 's'.
+%
+% Default values are 'm' = 0, 's' = 1.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+  if (nargin ~= 1 && nargin ~= 3)
+    error('Incorrect number of input arguments'); 
+  end
+
+  if (nargin == 1)
+    m = 0;
+    s = 1;
+  end
+
+  if (~isscalar (m) || ~isscalar (s))
+    [retval, x, m, s] = common_size (x, m, s);
+    if (retval > 0)
+      error ('x, m and s must be of common size or scalars');
+    end
+  end
+
+  sz = size (x);
+  pdf_result = zeros (sz);
+
+  if (isscalar (m) && isscalar (s))
+    if (find (isinf (m) | isnan (m) | ~(s >= 0) | ~(s < Inf)))
+      pdf_result = NaN * ones (sz);
+    else
+      pdf_result = stdnormalpdfIQM((x - m) ./ s) ./ s;
+    end
+  else
+    k = find (isinf (m) | isnan (m) | ~(s >= 0) | ~(s < Inf));
+    if (any (k))
+      pdf_result(k) = NaN;
+    end
+
+    k = find (~isinf (m) & ~isnan (m) & (s >= 0) & (s < Inf));
+    if (any (k))
+      pdf_result(k) = stdnormalpdfIQM((x(k) - m(k)) ./ s(k)) ./ s(k);
+    end
+  end
+
+  pdf_result((s == 0) & (x == m)) = Inf;
+  pdf_result((s == 0) & ((x < m) | (x > m))) = 0;
+
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/stdnormalcdfIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/stdnormalcdfIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..33cf49d1e74fb59ebd0849ea6fd74444149f6396
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/stdnormalcdfIQM.m	
@@ -0,0 +1,28 @@
+function cdf_result = stdnormalcdfIQM (x)
+% Cumulative density function of the standard normal distribution
+%
+% USAGE:
+% ======
+% cdf_result = stdnormalcdfIQM (x)
+%
+% For each component of 'x', compute the CDF of the standard normal
+% distribution at 'x'.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+  if (nargin ~= 1)
+    error('Incorrect number of input arguments'); 
+  end
+
+  sz = size (x);
+  if (numel(x) == 0)
+    error ('x must not be empty');
+  end
+
+  cdf_result = (ones (sz) + erf (x / sqrt (2))) / 2;
+
+return
+
+
+
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/stdnormalinvIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/stdnormalinvIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..6bdf19b0ebc9cc1c6a52bade5a8e32b5b7f51654
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/stdnormalinvIQM.m	
@@ -0,0 +1,19 @@
+function inv = stdnormalinvIQM(x)
+% Quantile function of the standard normal distribution
+%
+% USAGE:
+% ======
+% inv = stdnormalinvIQM(x)
+%
+% For each component of 'x', compute compute the quantile (the
+% inverse of the CDF) at 'x' of the standard normal distribution.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+  if (nargin ~= 1)
+    error('Incorrect number of input arguments'); 
+  end
+
+  inv = sqrt (2) * erfinv(2 * x - 1);
+
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/stdnormalpdfIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/stdnormalpdfIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..a1de1f5c12c29e250d1e79d2590b257e51f3e614
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/stdnormalpdfIQM.m	
@@ -0,0 +1,30 @@
+function pdf_result = stdnormalpdfIQM(x)
+% Probability density function of the standard normal distribution
+%
+% USAGE:
+% ======
+% pdf_result = stdnormalpdfIQM(x)
+%
+% For each element of 'x', compute the probability density function
+% (PDF) of the standard normal distribution at 'x'.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+  if (nargin ~= 1)
+    error('Incorrect number of input arguments'); 
+  end
+
+  sz = size(x);
+  pdf_result = zeros (sz);
+
+  k = find (isnan (x));
+  if (any (k))
+    pdf_result(k) = NaN;
+  end
+
+  k = find (~isinf (x));
+  if (any (k))
+    pdf_result (k) = (2 * pi)^(- 1/2) * exp (- x(k) .^ 2 / 2);
+  end
+
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/tcdfIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/tcdfIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..bf802c3a159d9b427d913a8543dcbc2266a01eaa
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/tcdfIQM.m	
@@ -0,0 +1,50 @@
+function cdf_result = tcdfIQM(x, n)
+% Cumulative density function of the t distribution
+%
+% USAGE:
+% ======
+% cdf_result = tcdfIQM(x, n)
+%
+% For each element of 'x', compute the CDF at 'x' of the
+% t (Student) distribution with 'n' degrees of freedom, i.e.,
+% PROB (t(n) <= x).
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+  if (nargin ~= 2)
+    error('Incorrect number of input arguments'); 
+  end
+
+  if (~isscalar (n))
+    [retval, x, n] = common_size (x, n);
+    if (retval > 0)
+      error ('x and n must be of common size or scalar');
+    end
+  end
+
+  cdf_result = zeros (size (x));
+
+  k = find (isnan (x) | ~(n > 0));
+  if (any (k))
+    cdf_result(k) = NaN;
+  end
+
+  k = find ((x == Inf) & (n > 0));
+  if (any (k))
+    cdf_result(k) = 1;
+  end
+
+  k = find ((x > -Inf) & (x < Inf) & (n > 0));
+  if (any (k))
+    if (isscalar (n))
+      cdf_result(k) = betainc(1 ./ (1 + x(k) .^ 2 ./ n), n / 2, 1 / 2) / 2;
+    else
+      cdf_result(k) = betainc(1 ./ (1 + x(k) .^ 2 ./ n(k)), n(k) / 2, 1 / 2) / 2;
+    end
+    ind = find (x(k) > 0);
+    if (any (ind))
+      cdf_result(k(ind)) = 1 - cdf_result(k(ind));
+    end
+  end
+
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/tinvIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/tinvIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..4240334c66b6b5cecddef5b6e456d2b18a562cc8
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/tinvIQM.m	
@@ -0,0 +1,57 @@
+function inv = tinvIQM(x, n)
+% Quantile function of the t distribution
+%
+% USAGE:
+% ======
+% inv = tinvIQM(x, n)
+%
+% For each component of 'x', compute the quantile (the inverse of
+% the CDF) at 'x' of the t (Student) distribution with parameter
+% 'n'.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+  if (nargin ~= 2)
+    error('Incorrect number of input arguments'); 
+  end
+
+  if (~isscalar (n))
+    [retval, x, n] = common_size (x, n);
+    if (retval > 0)
+      error ('x and n must be of common size or scalar');
+    end
+  end
+
+  inv = zeros (size (x));
+
+  k = find ((x < 0) | (x > 1) | isnan (x) | ~(n > 0));
+  if (any (k))
+    inv(k) = NaN;
+  end
+
+  k = find ((x == 0) & (n > 0));
+  if (any (k))
+    inv(k) = -Inf;
+  end
+
+  k = find ((x == 1) & (n > 0));
+  if (any (k))
+    inv(k) = Inf;
+  end
+
+  k = find ((x > 0) & (x < 1) & (n > 0) & (n < 10000));
+  if (any (k))
+    if (isscalar (n))
+      inv(k) = (sign (x(k) - 1/2) .* sqrt (n .* (1 ./ betainvIQM(2*min (x(k), 1 - x(k)), n/2, 1/2) - 1)));
+    else
+      inv(k) = (sign (x(k) - 1/2) .* sqrt (n(k) .* (1 ./ betainvIQM(2*min (x(k), 1 - x(k)), n(k)/2, 1/2) - 1)));
+    end
+  end
+
+  % For large n, use the quantiles of the standard normal
+  k = find ((x > 0) & (x < 1) & (n >= 10000));
+  if (any (k))
+    inv(k) = stdnormalinvIQM(x(k));
+  end
+
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/tpdfIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/tpdfIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..9c98fa2e844eed8a70a6dab4429973afb2f15917
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/statistic/distributions/tpdfIQM.m	
@@ -0,0 +1,41 @@
+function pdf_result = tpdfIQM(x, n)
+% Probability density function of the t distribution
+%
+% USAGE:
+% ======
+% pdf_result = tpdfIQM(x, n)
+%
+% For each element of 'x', compute the probability density function
+% (PDF) at 'x' of the t (Student) distribution with 'n'
+% degrees of freedom. 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+  if (nargin ~= 2)
+    error('Incorrect number of input arguments'); 
+  end
+
+  if (~isscalar (n))
+    [retval, x, n] = common_size (x, n);
+    if (retval > 0)
+      error ('x and n must be of common size or scalar');
+    end
+  end
+
+  pdf_result = zeros (size (x));
+
+  k = find (isnan (x) | ~(n > 0) | ~(n < Inf));
+  if (any (k))
+    pdf_result(k) = NaN;
+  end
+
+  k = find (~isinf (x) & ~isnan (x) & (n > 0) & (n < Inf));
+  if (any (k))
+    if (isscalar (n))
+      pdf_result(k) = (exp (- (n + 1) .* log (1 + x(k) .^ 2 ./ n)/2) / (sqrt (n) * beta(n/2, 1/2)));
+    else
+      pdf_result(k) = (exp (- (n(k) + 1) .* log (1 + x(k) .^ 2 ./ n(k))/2) ./ (sqrt (n(k)) .* beta(n(k)/2, 1/2)));
+    end
+  end
+
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/statistic/kurtosisIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/statistic/kurtosisIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..a1a9bd67812ff89d7fae20c90d125f383e05f57d
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/statistic/kurtosisIQM.m	
@@ -0,0 +1,50 @@
+function retval = kurtosisIQM(x, dim)
+% If 'x' is a vector of length 'N', return the kurtosis
+% of 'x'.  If 'x' is a matrix, return the kurtosis over the
+% first non-singleton dimension. The optional argument 'dim'
+% can be given to force the kurtosis to be given over that 
+% dimension.
+%
+% USAGE:
+% ======
+% retval = kurtosisIQM(x, dim)
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+  if (nargin ~= 1 && nargin ~= 2)
+    error('Incorrect number of input arguments'); 
+  end
+
+  nd = ndims (x);
+  sz = size (x);
+  if (nargin ~= 2)
+    % Find the first non-singleton dimension.
+    dim  = 1;
+    while (dim < nd + 1 && sz(dim) == 1)
+      dim = dim + 1;
+    end
+    if (dim > nd)
+      dim = 1;
+    end
+  else
+    if (~(isscalar (dim) && dim == round (dim)) && dim > 0	&& dim < (nd + 1))
+      error ('dim must be an integer and valid dimension');
+    end
+  end
+  
+  if (~ismatrixIQM(x) && ~isvector(x))
+    error ('x has to be a matrix or a vector');
+  end
+
+  c = sz(dim);
+  sz(dim) = 1;
+  idx = ones (1, nd);
+  idx(dim) = c;
+  x = x - repmat (mean (x, dim), idx);
+  retval = zeros (sz);
+  s = std (x, [], dim);
+  x = sum(x.^4, dim);
+  ind = find (s > 0);
+  retval(ind) = x(ind) / (c*s(ind) .^ 4);
+
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/statistic/mvnrndIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/statistic/mvnrndIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..d9351022dce5a5deaf1198fcab5afb98d3569299
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/statistic/mvnrndIQM.m	
@@ -0,0 +1,74 @@
+function [s] = mvnrndIQM(mu,Sigma,K)
+% Draw n random d-dimensional vectors from a multivariate Gaussian distribution
+% with mean mu and covariance matrix Sigma.
+%
+% USAGE:
+% ======
+% [s] = mvnrndIQM(mu,Sigma)
+% [s] = mvnrndIQM(mu,Sigma,K)
+%
+% K: number of samples
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+% If mu is column vector and Sigma not a scalar then assume user didn't read
+% help but let them off and flip mu. Don't be more liberal than this or it will
+% encourage errors (eg what should you do if mu is square?).
+if ((size(mu,2)==1) && (size(Sigma)~=[1,1])),
+	mu=mu';
+end
+
+% May 2004 take a third arg, cases. Makes it more compatible with Matlab's.
+if nargin==3
+	mu=repmat(mu,K,1);
+end
+
+[n,d]=size(mu);
+
+if (size(Sigma)~=[d,d])
+	error('Sigma must have dimensions dxd where mu is nxd.');
+end
+
+try
+	U=chol(Sigma);
+catch
+	[E,Lambda]=eig(Sigma);
+% 	if (min(diag(Lambda))<0),error('Sigma must be positive semi-definite.'),end
+	U = sqrt(Lambda)*E';
+end
+
+s = randn(n,d)*U + mu;
+
+% {{{ END OF CODE --- Guess I should provide an explanation:
+% 
+% We can draw from axis aligned unit Gaussians with randn(d)
+% 	x ~ A*exp(-0.5*x'*x)
+% We can then rotate this distribution using
+% 	y = U'*x
+% Note that
+% 	x = inv(U')*y
+% Our new variable y is distributed according to:
+% 	y ~ B*exp(-0.5*y'*inv(U'*U)*y)
+% or
+% 	y ~ N(0,Sigma)
+% where
+% 	Sigma = U'*U
+% For a given Sigma we can use the chol function to find the corresponding U,
+% draw x and find y. We can adjust for a non-zero mean by just adding it on.
+% 
+% But the Cholsky decomposition function doesn't always work...
+% Consider Sigma=[1 1;1 1]. Now inv(Sigma) doesn't actually exist, but Matlab's
+% mvnrnd provides samples with this covariance st x(1)~N(0,1) x(2)=x(1). The
+% fast way to deal with this would do something similar to chol but be clever
+% when the rows aren't linearly independent. However, I can't be bothered, so
+% another way of doing the decomposition is by diagonalising Sigma (which is
+% slower but works).
+% if
+% 	[E,Lambda]=eig(Sigma)
+% then
+% 	Sigma = E*Lambda*E'
+% so
+% 	U = sqrt(Lambda)*E'
+% If any Lambdas are negative then Sigma just isn't even positive semi-definite
+% so we can give up.
+% }}}
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/statistic/nanmeanIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/statistic/nanmeanIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..f4c16e2befc08e9aa5c99ed68f06f284ecc8772e
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/statistic/nanmeanIQM.m	
@@ -0,0 +1,18 @@
+function [v] = nanmeanIQM(X,varargin)
+% Determines the mean of x along the dimension dim by treating NaNs as
+% missing values.
+%
+% USAGE:
+% ======
+% output = nanmeanIQM(x)
+% output = nanmeanIQM(x,dim)
+%
+% If x is a matrix and dim not defined then determine mean across rows
+% (dim=1). 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+n           = sum (~isnan(X), varargin{:});
+n(n == 0)   = NaN;
+X(isnan(X)) = 0;
+v           = sum (X, varargin{:}) ./ n;
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/statistic/nanmedianIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/statistic/nanmedianIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..c8e3d8f651c5b0006904a8575e981da72ed1129c
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/statistic/nanmedianIQM.m	
@@ -0,0 +1,56 @@
+function v = nanmedianIQM(X,varargin)
+% Determines the median of x along the dimension dim by treating NaNs as
+% missing values.
+%
+% USAGE:
+% ======
+% output = nanmedianIQM(x)
+% output = nanmedianIQM(x,dim)
+%
+% If x is a matrix and dim not defined then determine mean across rows
+% (dim=1). 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+if nargin < 1 || nargin > 2
+    error('Incorrect number of input arguments');
+end
+
+if nargin < 2
+    dim = min(find(size(X)>1));
+    if isempty(dim), dim=1; end;
+else
+    dim = varargin{:};
+end
+
+sz = size (X);
+if (prod (sz) > 1)
+    % Find lengths of datasets after excluding NaNs; valid datasets
+    % are those that are not empty after you remove all the NaNs
+    n = sz(dim) - sum (isnan(X),varargin{:});
+    
+    % When n is equal to zero, force it to one, so that median
+    % picks up a NaN value below
+    n (n==0) = 1;
+    
+    % Sort the datasets, with the NaN going to the end of the data
+    X = sort (X, varargin{:});
+    
+    % Determine the offset for each column in single index mode
+    colidx = reshape((0:(prod(sz) / sz(dim) - 1)), size(n));
+    colidx = floor(colidx / prod(sz(1:dim-1))) * prod(sz(1:dim)) + mod(colidx,prod(sz(1:dim-1)));
+    stride = prod(sz(1:dim-1));
+    
+    % Average the two central values of the sorted list to compute
+    % the median, but only do so for valid rows.  If the dataset
+    % is odd length, the single central value will be used twice.
+    % E.g.,
+    %   for n==5, ceil(2.5+0.5) is 3 and floor(2.5+0.5) is also 3
+    %   for n==6, ceil(3.0+0.5) is 4 and floor(3.0+0.5) is 3
+    % correction made for stride of data "stride*ceil(2.5-0.5)+1"
+    v = (X(colidx + stride*ceil(n./2-0.5) + 1)  + X(colidx + stride*floor(n./2-0.5) + 1)) ./ 2;
+elseif (prod (sz) == 1)
+    v = X;
+else
+    error ('nanmedianIQM: invalid matrix argument');
+end
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/statistic/nanstdIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/statistic/nanstdIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..5ed6cdc1752a18c34100bad7242a939e1568d74f
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/statistic/nanstdIQM.m	
@@ -0,0 +1,55 @@
+function v = nanstdIQM(X, varargin)
+% Determines the std of x along the dimension dim by treating NaNs as
+% missing values.
+%
+% USAGE:
+% ======
+% output = nanstdIQM(x)
+% output = nanstdIQM(x,dim)
+%
+% If x is a matrix and dim not defined then determine mean across rows
+% (dim=1). 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+if nargin < 1 || nargin > 2
+    error('Incorrect number of input arguments');
+end
+
+if nargin < 2
+    dim = min(find(size(X)>1));
+    if isempty(dim), dim=1; end;
+else
+    dim = varargin{1};
+end
+opt = 0;
+
+% determine the number of non-missing points in each data set
+n = sum (~isnan(X), varargin{:});
+
+% replace missing data with zero and compute the mean
+X(isnan(X)) = 0;
+meanX = sum (X, varargin{:}) ./ n;
+
+% subtract the mean from the data and compute the sum squared
+sz = ones(1,length(size(X)));
+sz(dim) = size(X,dim);
+v = sum((X - repmat(meanX,sz)).^2, varargin{:});
+
+% because the missing data was set to zero each missing data
+% point will contribute (-meanX)^2 to sumsq, so remove these
+v = v - (meanX .^ 2) .* (size(X,dim) - n);
+
+if (opt == 0)
+    % compute the standard deviation from the corrected sumsq using
+    % max(n-1,1) in the denominator so that the std for a single point is 0
+    v = sqrt ( v ./ max(n - 1, 1) );
+elseif (opt == 1)
+    % compute the standard deviation from the corrected sumsq
+    v = sqrt ( v ./ n );
+else
+    error ('nanstdIQM: unrecognized normalization type');
+end
+
+% make sure that we return a real number
+v = real (v);
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/statistic/pdistIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/statistic/pdistIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..48f9d3b4611a4c55fd0b4d2eec7e62575eef12eb
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/statistic/pdistIQM.m	
@@ -0,0 +1,71 @@
+function [D] = pdistIQM(datamatrix,varargin)
+% pdistIQM: Determines the distance matrix for a set of points whose
+% coordinates are given as row-vectors in the data matrix.
+%
+% USAGE:
+% ======
+% D = pdistIQM(datamatrix) 
+% D = pdistIQM(datamatrix, method) 
+%
+% datamatrix: datamatrix is an NxP matrix of coordinates for N points in P dimensions
+% method: is an integer between 1 and 3 representing the chosen
+%         method for computing the distance matrix (see note below)
+%
+% DEFAULT VALUES:
+% ===============
+% method: method chosen problem size dependend if not specified
+%
+% Output Arguments:
+% =================
+% D: An NxN matrix, where the value of DMAT(i,j) corresponds to
+%           the distance from datamatrix(i,:) to datamatrix(j,:)
+% Note:
+% =====
+% method=1: Usually fastest for small inputs. Takes advantage of the symmetric
+%           property of distance matrices to perform half as many calculations
+% method=2: Usually fastest for medium inputs. Uses a fully vectorized method
+% method=3: Usually fastest for large inputs. Uses a partially vectorized
+%           method with relatively small memory requirement
+
+% Author: Joseph Kirk
+% Email: jdkirk630 at gmail dot com
+% Release: 1.0
+% Release Date: 5/29/07
+%
+% Adapted for the Systems Biology Toolbox 2 for MATLAB by
+% Henning Schmidt, 01. January 2008
+
+% Handle variable input arguments and select the method
+if nargin < 1 || nargin > 2,
+    error('Incorrect number of input arguments.');
+end
+if nargin == 2,
+    method = varargin{1};
+else
+    [n,dims] = size(datamatrix);
+    numels = n*n*dims;
+    method = 2; 
+    if numels > 5e4, 
+        method = 3; 
+    elseif n < 20, 
+        method = 1; 
+    end
+end
+
+% distance matrix calculation options
+switch method
+    case 1 % half as many computations (symmetric upper triangular property)
+        [k,kk] = find(triu(ones(n),1));
+        D = zeros(n);
+        D(k+n*(kk-1)) = sqrt(sum((datamatrix(k,:) - datamatrix(kk,:)).^2,2));
+        D(kk+n*(k-1)) = D(k+n*(kk-1));
+    case 2 % fully vectorized calculation (very fast for medium inputs)
+        a = reshape(datamatrix,1,n,dims);
+        b = reshape(datamatrix,n,1,dims);
+        D = sqrt(sum((a(ones(n,1),:,:) - b(:,ones(n,1),:)).^2,3));
+    case 3 % partially vectorized (smaller memory requirement for large inputs)
+        D = zeros(n,n);
+        for k = 1:n
+            D(k,:) = sqrt(sum((datamatrix(k*ones(n,1),:) - datamatrix).^2,2));
+        end
+end
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/statistic/prctileIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/statistic/prctileIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..c4548d0e5dbdde000cb6a6082ae768b314b85426
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/statistic/prctileIQM.m	
@@ -0,0 +1,20 @@
+function [Q] = prctileIQM(Y,q,DIM)
+% prctileIQM calculates the percentiles of histograms and sample arrays.  
+%
+% USAGE:
+% ======
+% Q = prctileIQM(Y,q)
+% Q = prctileIQM(Y,q,DIM)
+%
+% Returns the q-th percentile along dimension DIM of sample array Y.
+% size(Q) is equal size(Y) except for dimension DIM which is size(Q,DIM)=length(Q)
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+if nargin==2,
+	Q = quantileIQM(Y,q/100); 
+elseif nargin==3,
+	Q = quantileIQM(Y,q/100,DIM); 
+else
+    error('Incorrect number of input arguments.');
+end
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/statistic/princompIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/statistic/princompIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..37b8902fbe47257a3b23f66aed6723cfc4b4cbc8
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/statistic/princompIQM.m	
@@ -0,0 +1,20 @@
+function [pc,z,w,Tsq] = princompIQM(X)
+% princompIQM: Compute principal components of X
+%
+% USAGE:
+% ======
+% [pc,z,w,Tsq] = princomp(X)
+%
+% pc:  the principal components
+% z:   the transformed data
+% w:   the eigenvalues of the covariance matrix
+% Tsq: Hotelling's T^2 statistic for the transformed data
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+C = cov(X);
+[U,D,pc] = svd(C);
+z = centerIQM(X)*pc;
+w = diag(D);
+Tsq = sumsqIQM(zscoreIQM(z),2);
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/statistic/qqplotIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/statistic/qqplotIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..58cb954e3a2ff376d31dc3a5a87894ceac5d626e
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/statistic/qqplotIQM.m	
@@ -0,0 +1,57 @@
+function [q,s] = qqplotIQM(x)
+% Perform a QQ-plot (quantile plot). Only for comparison to standard normal
+% distribution.
+%
+% USAGE:
+% ======
+% [] = qqplotIQM(x)
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+if ~isvector(x),
+    error ('qqplotIQM: x must be a vector');
+end
+
+s = sort (x);
+n = length (x);
+t = ((1 : n)' - .5) / n;
+if (nargin == 1)
+    f = 'stdnormalinvIQM';
+else
+    f = str2func (sprintf ('%s_inv', dist));
+end
+
+if (nargin <= 2)
+    q = feval (f, t);
+    q_label = f;
+else
+    param_string = sprintf ('%g', varargin{1});
+    for k = 2 : (nargin - 2);
+        param_string = sprintf ('%s, %g', param_string, varargin{k});
+    end
+    q = eval (sprintf ('%s (t, %s);', f, param_string));
+    q_label = sprintf ('%s with parameter(s) %s', func2str (f), param_string);
+end
+
+% colors
+colors = IQMgetcolors();
+
+% Compute the line the y=x line
+dx = prctileIQM(q, 75) - prctileIQM(q, 25);
+dy = prctileIQM(s, 75) - prctileIQM(s, 25);
+b = dy./dx;                                % slope
+xc = (prctileIQM(q, 25) + prctileIQM(q, 75))/2;  % center points
+yc = (prctileIQM(s, 25) + prctileIQM(s, 75))/2;  % ...
+ymax = yc + b.*(max(q)-xc);
+ymin = yc - b.*(xc-min(q));
+
+% Plot the qqplot
+plot (q,s,'x','Color',colors(1,:),'MarkerSize',12,'LineWidth',2); hold on
+plot([min(q); max(q)], [ymin; ymax],'k--','LineWidth',2); 
+
+% Annotate
+xlabel (q_label);
+ylabel ('Sample points');
+grid on
+
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/statistic/quantileIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/statistic/quantileIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..265d21fafc6e5aad52e902de51c612fada1d1afa
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/statistic/quantileIQM.m	
@@ -0,0 +1,74 @@
+function [Q] = quantileIQM(Y,q,DIM)
+% quantileIQM calculates the quantiles of histograms and sample arrays.
+%
+% USAGE:
+% ======
+% Q = quantileIQM(Y,q)
+% Q = quantileIQM(Y,q,DIM)
+%
+% Returns the q-th quantile along dimension DIM of sample array Y.
+% size(Q) is equal size(Y) except for dimension DIM which is size(Q,DIM)=length(Q)
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+if nargin<3,
+    DIM = [];
+end
+if isempty(DIM),
+    DIM = find(size(Y)>1,1);
+    if isempty(DIM), DIM = 1; end
+end
+
+[q, rix]  = sort(q(:)'); 	% sort quantile values
+[tmp,rix] = sort(rix);	% generate reverse index
+
+if isnumeric(Y),
+    sz = size(Y);
+    if DIM>length(sz),
+        sz = [sz,ones(1,DIM-length(sz))];
+    end
+    
+    f  = zeros(1,length(q));
+    f( (q < 0) | (1 < q) ) = NaN;
+    D1 = prod(sz(1:DIM-1));
+    D3 = prod(sz(DIM+1:length(sz)));
+    Q  = repmat(nan,[sz(1:DIM-1),length(q),sz(DIM+1:length(sz))]);
+    for k = 0:D1-1,
+        for l = 0:D3-1,
+            xi = k + l * D1*sz(DIM) + 1 ;
+            xo = k + l * D1*length(q) + 1;
+            t  = Y(xi:D1:xi+D1*sz(DIM)-1);
+            t  = t(~isnan(t));
+            N  = length(t);
+            
+            if (N==0)
+                f(:) = NaN;
+            else
+                t  = sort(t);
+                t2(1:2:2*length(t)) = t;
+                t2(2:2:2*length(t)) = t;
+                x = floor((1:2*length(t))/2);
+                %f(q < 0 | 1 < q) = NaN;  % for efficiency its defined outside loop
+                f(q==0) = t2(1);
+                f(q==1) = t2(end);
+                
+                n = 1;
+                for k2 = find( (0 < q) & (q < 1) )
+                    while (q(k2)*N > x(n)),
+                        n = n+1;
+                    end
+                    
+                    if q(k2)*N==x(n)
+                        % mean of upper and lower bound
+                        f(k2) = (t2(n) + t2(n+1))/2;
+                    else
+                        f(k2) = t2(n);
+                    end
+                end
+            end
+            Q(xo:D1:xo + D1*length(q) - 1) = f(rix);
+        end
+    end
+else
+    fprintf(2,'Error quantileIQM: invalid input argument\n');
+end
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/statistic/regressIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/statistic/regressIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..85fd4f515cffa7d80f475bd04408af26cd6c7e85
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/statistic/regressIQM.m	
@@ -0,0 +1,120 @@
+function [b, bint, r, rint, stats] = regressIQM(y, X, alpha)
+% Multiple Linear Regression using Least Squares Fit of y on X
+% with the model y = X * beta + e.
+%
+% USAGE:
+% ======
+% [b, bint, r, rint, stats] = regressIQM(y, X, alpha)
+% [b, bint, r, rint, stats] = regressIQM(y, X, alpha)
+% [b, bint, r, rint, stats] = regressIQM(y, X, alpha)
+%
+% y:        Column vector of observed values
+% X:        Matrix of regressors, with the first column filled with
+%           the constant value 1
+% b:        Column vector of regression parameters
+% e:        Column vector of random errors
+% alpha:    Significance level used to calculate the confidence
+%           intervals bint and rint. If not specified, ALPHA defaults to
+%           0.05 
+%
+% bint:     Confidence interval for b
+% r:        Column vector of residuals
+% rint:     Confidence interval for r
+% stats:    Row vector containing:
+%               The R^2 statistic
+%               The F statistic
+%               The p value for the full model
+%               The estimated error variance
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+if (nargin < 2 || nargin > 3)
+    error('Incorrect number of input arguments.');
+end
+
+if (~ismatrix (y))
+    error ('regressIQM: y must be a numeric matrix');
+end
+if (~ismatrix (X))
+    error ('regressIQM: X must be a numeric matrix');
+end
+
+if (size(y,2) ~= 1)
+    error ('regressIQM: y must be a column vector');
+end
+
+if (size(y,1) ~= size(X,1))
+    error ('regressIQM: y and X must contain the same number of rows');
+end
+
+if (nargin < 3)
+    alpha = 0.05;
+elseif (~isscalar (alpha))
+    error ('regressIQM: alpha must be a scalar value')
+end
+
+notnans = ~logical (sum (isnan ([y X]), 2));
+y = y(notnans);
+X = X(notnans,:);
+
+[Xq Xr] = qr (X, 0);
+pinv_X = Xr \ Xq';
+
+b = pinv_X * y;
+
+if (nargout > 1)
+    
+    n = size(X,1);
+    p = size(X,2);
+    dof = n - p;
+    t_alpha_2 = tinvIQM(alpha / 2, dof);
+    
+    r = y - X * b; % added -- Nir
+    SSE = sum (r .^ 2);
+    v = SSE / dof;
+    
+    % c = diag(inv (X' * X)) using (economy) QR decomposition
+    % which means that we only have to use Xr
+    c = diag (inv (Xr' * Xr));
+    
+    db = t_alpha_2 * sqrt (v * c);
+    
+    bint = [b + db, b - db];
+    
+end
+
+if (nargout > 3)
+    
+    dof1 = n - p - 1;
+    h = sum(X.*pinv_X', 2); %added -- Nir (same as diag(X*pinv_X), without doing the matrix multiply)
+    
+    % From Matlab's documentation on Multiple Linear Regression,
+    %   sigmaihat2 = norm (r) ^ 2 / dof1 - r .^ 2 / (dof1 * (1 - h));
+    %   dr = -tinv (1 - alpha / 2, dof) * sqrt (sigmaihat2 .* (1 - h));
+    % Substitute
+    %   norm (r) ^ 2 == sum (r .^ 2) == SSE
+    %   -tinv (1 - alpha / 2, dof) == tinv (alpha / 2, dof) == t_alpha_2
+    % We get
+    %   sigmaihat2 = (SSE - r .^ 2 / (1 - h)) / dof1;
+    %   dr = t_alpha_2 * sqrt (sigmaihat2 .* (1 - h));
+    % Combine, we get
+    %   dr = t_alpha_2 * sqrt ((SSE * (1 - h) - (r .^ 2)) / dof1);
+    
+    dr = t_alpha_2 * sqrt ((SSE * (1 - h) - (r .^ 2)) / dof1);
+    
+    rint = [r + dr, r - dr];
+    
+end
+
+if (nargout > 4)
+    
+    R2 = 1 - SSE / sum ((y - mean (y)) .^ 2);
+    %    F = (R2 / (p - 1)) / ((1 - R2) / dof);
+    F = dof / (p - 1) / (1 / R2 - 1);
+    pval = 1 - fcdfIQM(F, p - 1, dof);
+    
+    stats = [R2 F pval v];
+    
+end
+
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/statistic/sumsqIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/statistic/sumsqIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..7c15fef400ad4af286be4bc8495bce9ef80ca2bd
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/statistic/sumsqIQM.m	
@@ -0,0 +1,27 @@
+function [ sumsq ] = sumsqIQM( x, varargin )
+% sumsqIQM: Sum of squares of elements along dimension dim. 
+%
+% USAGE:
+% ======
+% sumsq = sumsqIQM(x)
+% sumsq = sumsqIQM(x,dim)
+%
+% If dim is omitted, it defaults to 1 (column-wise sum of squares).
+% As a special case if x is a vector and dim is omitted, return the sum of
+% squares of its elements.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+if nargin == 1,
+    dim = 1;
+elseif nargin == 2,
+    dim = varargin{1};
+else
+    error('Incorrect number of input arguments.');
+end
+
+if isvector(x),
+    sumsq = sum(x.^2);
+else
+    sumsq = sum(x.^2,dim);
+end
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/statistic/swtestIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/statistic/swtestIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..a8c4feeeba8601bc6c081e393ba9c3cf57f4081b
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/statistic/swtestIQM.m	
@@ -0,0 +1,224 @@
+function [H, pValue, W] = swtestIQM(x, alpha, tail)
+% swtestIQM: Shapiro-Wilk parametric hypothesis test of composite normality.
+%
+% USAGE:
+% ======
+% [H, pValue, SWstatistic] = swtestIQM(x)
+% [H, pValue, SWstatistic] = swtestIQM(x, alpha)
+% [H, pValue, SWstatistic] = swtestIQM(x, alpha, tail)
+%
+% This function performs the Shapiro-Wilk test to determine if the null 
+% hypothesis of composite normality is a reasonable assumption regarding 
+% the population distribution of a random sample x. The desired 
+% significance level, alpha, is an optional scalar input (default = 0.05).
+% tail indicates the type of test (default = 1).
+%
+% The Shapiro-Wilk hypotheses are: 
+% Null Hypothesis: x is normal with unspecified mean and variance.
+%    For tail =  0 (2-sided test), alternative: x is not normal.
+%    For tail =  1 (1-sided test), alternative: x is upper the normal.
+%    For tail = -1 (1-sided test), alternative: x is lower the normal.
+%
+% This is an omnibus test, and is generally considered relatively
+% powerful against a variety of alternatives.
+% Shapiro-Wilk test is better than the Shapiro-Francia test for
+% Platykurtic sample. Conversely, Shapiro-Francia test is better than the
+% Shapiro-Wilk test for Leptokurtic samples.
+%
+% When the series 'x' is Leptokurtic, swtestIQM performs the Shapiro-Francia
+% test, else (series 'x' is Platykurtic) swtestIQM performs the
+% Shapiro-Wilk test.
+% 
+% Inputs:
+%   x - a vector of deviates from an unknown distribution. The observation
+%       number must exceed 3 and be less than 5000.
+%
+% Optional inputs:
+%   alpha - The significance level for the test (default = 0.05).
+%   tail  - The type of the test (default = 1).
+% 
+% Outputs:
+%  SWstatistic - The test statistic (non normalized).
+%
+%  pValue - is the p-value, or the probability of observing the given
+%           result by chance given that the null hypothesis is true. Small
+%           values of pValue cast doubt on the validity of the null hypothesis.
+%
+%     H = 0 => Do not reject the null hypothesis at significance level alpha.
+%     H = 1 => Reject the null hypothesis at significance level alpha.
+%
+% References: Royston P. "Algorithm AS R94", Applied Statistics (1995) Vol. 44, No. 4.
+%   AS R94 -- calculates Shapiro-Wilk normality test and P-value
+%   for sample sizes 3 <= n <= 5000. Handles censored or uncensored data.
+%   Corrects AS 181, which was found to be inaccurate for n > 50.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%
+% Ensure the sample data is a VECTOR.
+%
+if numel(x) == length(x)
+    x  =  x(:);               % Ensure a column vector.
+else
+    error('Input sample ''x'' must be a vector.');
+end
+
+%
+% Remove missing observations indicated by NaN's and check sample size.
+%
+x  =  x(~isnan(x));
+if length(x) < 3
+   error('Sample vector ''x'' must have at least 3 valid observations.');
+end
+
+if length(x) > 5000
+    warning('Shapiro-Wilk test might be inaccurate due to large sample size ( > 5000).');
+end
+
+%
+% Ensure the significance level, alpha, is a 
+% scalar, and set default if necessary.
+%
+if (nargin >= 2) && ~isempty(alpha)
+   if numel(alpha) > 1
+      error('Significance level ''Alpha'' must be a scalar.');
+   end
+   if (alpha <= 0 || alpha >= 1)
+      error('Significance level ''Alpha'' must be between 0 and 1.'); 
+   end
+else
+   alpha  =  0.05;
+end
+
+%
+% Ensure the type-of-test indicator, tail, is a scalar integer from 
+% the allowable set {-1 , 0 , 1}, and set default if necessary.
+%
+if (nargin >= 3) && ~isempty(tail)
+   if numel(tail) > 1
+      error('Type-of-test indicator ''Tail'' must be a scalar.');
+   end
+   if (tail ~= -1) && (tail ~= 0) && (tail ~= 1)
+      error('Type-of-test indicator ''Tail'' must be -1, 0, or 1.');
+   end
+else
+   tail  =  1;
+end
+
+% First, calculate the a's for weights as a function of the m's
+% See Royston (1995) for details in the approximation.
+x       =   sort(x); % Sort the vector x in ascending order.
+n       =   length(x);
+mtilde  =   norminvIQM(((1:n)' - 3/8) / (n + 0.25));
+weights =   zeros(n,1); % Preallocate the weights.
+
+if kurtosisIQM(x) > 3
+    % The Shapiro-Francia test is better for leptokurtic samples.
+    weights =   1/sqrt(mtilde'*mtilde) * mtilde;
+    %
+    % The Shapiro-Francia statistic W is calculated to avoid excessive rounding
+    % errors for W close to 1 (a potential problem in very large samples).
+    %
+    W   =   (weights' * x) ^2 / ((x - mean(x))' * (x - mean(x)));
+    nu      =   log(n);
+    u1      =   log(nu) - nu;
+    u2      =   log(nu) + 2/nu;
+    mu      =   -1.2725 + (1.0521 * u1);
+    sigma   =   1.0308 - (0.26758 * u2);
+    newSFstatistic  =   log(1 - W);
+    
+    
+    %
+    % Compute the normalized Shapiro-Francia statistic and its p-value.
+    %
+    NormalSFstatistic =   (newSFstatistic - mu) / sigma;
+    % the next p-value is for the tail = 1 test.
+    pValue   =   1 - normcdfIQM(NormalSFstatistic, 0, 1);
+else
+    % The Shapiro-Wilk test is better for platykurtic samples.
+    c    =   1/sqrt(mtilde'*mtilde) * mtilde;
+    u    =   1/sqrt(n);
+    PolyCoef_1   =   [-2.706056 , 4.434685 , -2.071190 , -0.147981 , 0.221157 , c(n)];
+    PolyCoef_2   =   [-3.582633 , 5.682633 , -1.752461 , -0.293762 , 0.042981 , c(n-1)];
+    PolyCoef_3   =   [-0.0006714 , 0.0250540 , -0.39978 , 0.54400];
+    PolyCoef_4   =   [-0.0020322 , 0.0627670 , -0.77857 , 1.38220];
+    PolyCoef_5   =   [0.00389150 , -0.083751 , -0.31082 , -1.5861];
+    PolyCoef_6   =   [0.00303020 , -0.082676 , -0.48030];
+    PolyCoef_7   =   [0.459 , -2.273];
+    weights(n)   =   polyval(PolyCoef_1 , u);
+    weights(1)   =   -weights(n);
+
+    % Special attention when n=3 (this is a special case).
+    if n == 3
+        weights(1)  =   0.707106781;
+        weights(n)  =   -weights(1);
+    end
+    if n >= 6
+        weights(n-1) =   polyval(PolyCoef_2 , u);
+        weights(2)   =   -weights(n-1);
+        count  =   3;
+        phi    =   (mtilde'*mtilde - 2 * mtilde(n)^2 - 2 * mtilde(n-1)^2) / (1 - 2 * weights(n)^2 - 2 * weights(n-1)^2);
+    else
+        count  =   2;
+        phi    =   (mtilde'*mtilde - 2 * mtilde(n)^2) /  (1 - 2 * weights(n)^2);
+    end
+
+    %
+    % The vector 'WEIGHTS' obtained next corresponds to the same coefficients
+    % listed by Shapiro-Wilk in their original test for small samples.
+    %
+    weights(count : n-count+1)  =  mtilde(count : n-count+1) / sqrt(phi);
+
+    %
+    % The Shapiro-Wilk statistic W is calculated to avoid excessive rounding
+    % errors for W close to 1 (a potential problem in very large samples).
+    %
+    W   =   (weights' * x) ^2 / ((x - mean(x))' * (x - mean(x)));
+
+    %
+    % Calculate the significance level for W (exact for n=3).
+    %
+
+    newn    =   log(n);
+    if (n > 3) && (n <= 11)
+        mu      =   polyval(PolyCoef_3 , n);
+        sigma   =   exp(polyval(PolyCoef_4 , n));    
+        gam     =   polyval(PolyCoef_7 , n);
+        newSWstatistic  =   -log(gam-log(1-W));
+    elseif n >= 12
+        mu      =   polyval(PolyCoef_5 , newn);
+        sigma   =   exp(polyval(PolyCoef_6 , newn));
+        newSWstatistic  =   log(1 - W);
+    elseif n == 3
+        mu      =   0;
+        sigma   =   1;
+        newSWstatistic  =   0;
+    end
+
+    %
+    % Compute the normalized Shapiro-Wilk statistic and its p-value.
+    %
+    NormalSWstatistic       =   (newSWstatistic - mu) / sigma;
+    % The next p-value is for the tail = 1 test.
+    pValue       =   1 - normcdfIQM(NormalSWstatistic, 0, 1);
+    % Special attention when n=3 (this is a special case).
+    if n == 3
+        pValue  =   1.909859 * (asin(sqrt(W)) - 1.047198);
+        NormalSWstatistic =   norminvIQM(pValue, 0, 1);
+    end
+end
+
+% The p-value just found is for the tail = 1 test.
+if tail == 0
+    pValue = 2 * min(pValue, 1-pValue);
+elseif tail == -1
+    pValue = 1 - pValue;
+end
+
+%
+% To maintain consistency with existing Statistics Toolbox hypothesis
+% tests, returning 'H = 0' implies that we 'Do not reject the null 
+% hypothesis at the significance level of alpha' and 'H = 1' implies 
+% that we 'Reject the null hypothesis at significance level of alpha.'
+%
+H  = (alpha >= pValue);
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/statistic/zscoreIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/statistic/zscoreIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..640afb99a094ffafdf4e758b3004f1eb513f09f8
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/statistic/zscoreIQM.m	
@@ -0,0 +1,29 @@
+function A = zscoreIQM(X,varargin)
+% zscoreIQM: Compute the z-score of each element of X relative to the data
+% in the columns of X. The z-score for a single data point x_i is:
+% (x_i - mean(x))/std(x)
+%
+% USAGE:
+% ======
+% A = zscoreIQM(x)
+% A = zscoreIQM(x,dim)
+%
+% default dimension: 1
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+if (nargin ~= 1 && nargin ~= 2)
+    error('Incorrect number of input arguments.');
+end
+if (nargin == 2)
+    dim = varargin{1};
+else
+    dim = min(find(size(X)>1));
+    if isempty(dim), 
+        dim=1; 
+    end
+end
+sz = ones(1,length(size(X)));
+sz(dim) = size(X,dim);
+A = (X - repmat(mean(X,varargin{:}),sz)) ./ repmat(std(X,varargin{:}),sz);
+return
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/stringhandling/cell2wraptextIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/stringhandling/cell2wraptextIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..8ecbc228ee9a75767abba028bdeb7712d7b3efb2
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/stringhandling/cell2wraptextIQM.m	
@@ -0,0 +1,42 @@
+function [text] = cell2wraptextIQM(input,rowmax,varargin)
+% cell2wraptextIQM: Takes a cell-array of strings and formats it into a 
+% string. The separator characters can be chosen and the maximum number of
+% elements in a row.
+%
+% USAGE:
+% ======
+% [text] = cell2wraptextIQM(input,rowmax)
+% [text] = cell2wraptextIQM(input,rowmax,separator)
+%
+% input:  cell-array with string elements
+% rowmax: maximum number of elements per line of text
+% separator: separating characters between the elements
+%
+% DEFAULT VALUES:
+% ===============
+% separator: ', '
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+if nargin == 2,
+    separator = ', ';
+elseif nargin == 3,
+    separator = varargin{1};
+else
+    error('Incorrect number of input arguments.');
+end
+if ~iscell(input),
+    error('Cell-array required.');
+end
+text = '';
+for k=1:length(input),
+    text = sprintf('%s%s%s',text,input{k},separator);
+    if mod(k-1,rowmax) == rowmax-1 && k ~= length(input),
+        text = sprintf('%s\n',text);
+    end
+end
+if ~isempty(text),
+    text = text(1:end-length(separator));
+end
+
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/stringhandling/cellmaxlengthIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/stringhandling/cellmaxlengthIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..316bfbfa7311edb3482c6b69fe114fa5fe3f932e
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/stringhandling/cellmaxlengthIQM.m	
@@ -0,0 +1,19 @@
+function [maxlength] = cellmaxlengthIQM(input)
+% cellmaxlengthIQM: for a cell-array with only string entries the function
+% determines the maxlength of these strings.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+if ~iscell(input),
+    error('Input is not a cell-array.');
+end
+
+maxlength = 0;
+for k=1:length(input),
+    if ~ischar(input{k}),
+        error('Elements of cell-array need to be strings.');
+    end
+    if length(input{k}) > maxlength,
+        maxlength = length(input{k});
+    end
+end
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/stringhandling/explodePCIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/stringhandling/explodePCIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..2f001bba0053b5b0ca7917c8c2623ad7143f05d8
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/stringhandling/explodePCIQM.m	
@@ -0,0 +1,85 @@
+function [elements] = explodePCIQM(text,varargin)
+% explodePCIQM: This function does not(!!!) lead to an explosion of your
+% Personal Computer. It is an auxiliary function allowing to decompose a
+% string expression into its comma separated elements. Commas within
+% parentheses expressions are not considered. This is a useful function to
+% obtain the arguments of a function call, where some arguments might have
+% expressions involving commas but have parentheses around them.
+% Alternatively, a separator character, other then a comma, can be
+% specified by the user.
+%
+% USAGE:
+% ======
+% [elements] = explodePCIQM(text)
+% [elements] = explodePCIQM(text,separatorCharacter)
+% [elements] = explodePCIQM(text,separatorCharacter,groupCharacterStart,groupCharacterEnd)
+%
+% text: text to decompose into its comma separated elements
+% separatorCharacter: one character that should be used for the explosion
+% of the string.
+%
+% DEFAULT VALUES:
+% ===============
+% separatorCharacter: ',' (comma)
+% groupCharacterStart: '(' can also be a cell-array with several
+%                      parenthesis types
+% groupCharacterEnd: ')'  can also be a cell-array with several
+%                      parenthesis types
+%
+% Output Arguments:
+% =================
+% elements: cell-array containing string elements, previously separated by
+% the separator character.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+separatorCharacter = ',';
+groupCharacterStart = {'('};
+groupCharacterEnd = {')'};
+if nargin == 1,
+elseif nargin == 2,
+    separatorCharacter = varargin{1};
+elseif nargin == 4,
+    separatorCharacter = varargin{1};
+    groupCharacterStart = varargin{2};
+    groupCharacterEnd = varargin{3};
+else
+    error('Incorrect number of input arguments.');
+end
+
+if ischar(groupCharacterStart),
+    groupCharacterStart = {groupCharacterStart};
+end
+if ischar(groupCharacterEnd),
+    groupCharacterEnd = {groupCharacterEnd};
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DO THE EXPLOSION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+elements = {};
+openParenthesis = 0;
+lastIndex = 1;
+elementIndex = 1;
+doubletext = double(text);
+doublegroupCharacterStart = double(([groupCharacterStart{:}]));
+doublegroupCharacterEnd = double(([groupCharacterEnd{:}]));
+doubleseparatorCharacter = double(separatorCharacter);
+for k2 = 1:length(text),
+    if sum(doubletext(k2) == doublegroupCharacterStart),
+        openParenthesis = openParenthesis + 1;
+    elseif sum(doubletext(k2) == doublegroupCharacterEnd),
+        openParenthesis = openParenthesis - 1;
+    elseif (doubletext(k2) == doubleseparatorCharacter) && (openParenthesis == 0),
+        elements{elementIndex} = strtrim(text(lastIndex:k2-1));
+        elementIndex = elementIndex + 1;
+        lastIndex = k2+1;
+    end
+end
+elements{elementIndex} = strtrim(text(lastIndex:end));
+return
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/stringhandling/extractPIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/stringhandling/extractPIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..366c041814dadf6ab7e5a7213dba3ab2630b0071
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/stringhandling/extractPIQM.m	
@@ -0,0 +1,27 @@
+function [output] = extractPIQM(text)
+% extractPIQM: This function looks for the top level parentheses in the
+% given text string and returns the substring that is located between these
+% parentheses.
+%
+% USAGE:
+% ======
+% [output] = extractPIQM(text)
+%
+% text: text to look for parentheses
+%
+% Output Arguments:
+% =================
+% output: string between the toplevel parantheses. ('' if no parentheses
+% present.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+
+output = '';
+openParentheses = strfind(text,'(');
+closeParentheses = strfind(text,')');
+if length(openParentheses) == length(closeParentheses) && ~isempty(openParentheses),
+    output = text(min(openParentheses)+1:max(closeParentheses)-1);
+end
+return
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/stringhandling/postFillCharIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/stringhandling/postFillCharIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..a4183739ebb3dd3644e85b078da42189113487af
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/stringhandling/postFillCharIQM.m	
@@ -0,0 +1,10 @@
+function [result] = postFillCharIQM(value2prefill,lengthString,fillChar)
+% [result] = postFillCharIQM(value2prefill,lengthString,fillChar)
+
+if isnumeric(value2prefill),
+    result = [num2str(value2prefill) char(double(fillChar)*ones(1,lengthString-length(num2str(value2prefill))))];
+elseif ischar(value2prefill),
+    result = [value2prefill char(double(fillChar)*ones(1,lengthString-length(value2prefill)))];
+else
+    error('Unknown type to prefill.');
+end
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/stringhandling/preFillCharIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/stringhandling/preFillCharIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..9d5497c3d4190b0f43663864fa40e414afcc1a44
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/stringhandling/preFillCharIQM.m	
@@ -0,0 +1,10 @@
+function [result] = preFillCharIQM(value2prefill,lengthString,fillChar)
+% [result] = preFillCharIQM(value2prefill,lengthString,fillChar)
+
+if isnumeric(value2prefill),
+    result = [char(double(fillChar)*ones(1,lengthString-length(num2str(value2prefill)))) num2str(value2prefill)];
+elseif ischar(value2prefill),
+    result = [char(double(fillChar)*ones(1,lengthString-length(value2prefill))) value2prefill];
+else
+    error('Unknown type to prefill.');
+end
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/survival/IQMcoxExt.m b/IQMtools V1.2.2.2/IQMlite/tools/survival/IQMcoxExt.m
new file mode 100644
index 0000000000000000000000000000000000000000..b7b77c491cd9302c405362f0b813cfa2e2fa53a0
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/survival/IQMcoxExt.m	
@@ -0,0 +1,202 @@
+function [stats,st] = IQMcoxExt(sID_ext,X_ext,d_ext,t_ext,e)
+% [stats,st] = IQMcoxExt(sID_ext,X_ext,d_ext,t_ext,e)
+%
+% Parameter estimation for the extended Cox model. This function uses as
+% input the output of IQMxext but with X_ext having new time-dependent 
+% columns added by the user (eg. the product of a column of X_ext with
+% t_ext. Survival time ties are handled using Efron's method. 
+%
+% Input
+% sID_ext: Extended subjects' IDs (nx1).
+% X_ext: Extended design matrix (nxp).
+% d_ext: Extended censorship status vector (nx1).
+% t_ext: Extended survival time vector (nx1).
+% e: Convergence epsilon (gradient's norm). Default 10^-3;
+%
+% Output
+% stats.Bhat: Estimated vector of the population regression parameters.
+% stats.CovBhat: Estimated covariance matrix of the population regression 
+% parameters.
+% stats.llh: Values of the maximum log-likelihood across the optimization 
+% process.
+% st: Termination state (1 for convergence and 0 otherwise).
+%
+% $Revision: 1.1.1.1 $  $Date: 2013/27/03 11:25:52 $
+% Original Author: Jorge Luis Bernal Rusiel 
+% CVS Revision Info:
+%    $Author: jbernal$
+%    $Date: 2013/27/03 11:25:52 $
+%    $Revision: 1.1 $
+% References: Kleinbaum, D.G., Klein, M., 2005. Survival analysis. A self-
+% learning approach, second edition. New York: Springer..
+%   
+if nargin < 4
+    error('Too few inputs');
+elseif nargin < 5
+    e = 0.001;
+end;
+tic;
+[n,p] = size(X_ext);
+if (length(sID_ext)~=n) || (length(d_ext)~=n) || (length(t_ext)~=n)
+    error(['The design matrix X_ext, censorship status vector d_ext, time'...
+        ' vector t_ext and subject ID vector sID_ext must all have the same'...
+        ' number of rows.']);
+end;
+%indices of unique failure times in ft_ix (last index when ties happen)
+st_ix = find(d_ext==1);
+[~,ft_ix] = unique(t_ext(st_ix),'last');
+ft_ix = st_ix(ft_ix);
+%Starting values
+Bhat = zeros(p,1);
+
+%% Iterations
+nit = 50;
+gnorm = e+1;
+it = 1;
+display('Starting Newton-Raphson iterations');
+while (gnorm>e) && (it<=nit)    
+    gr = SStat_Gradient(X_ext,t_ext,Bhat,ft_ix);
+    He = SStat_Hessian(X_ext,t_ext,Bhat,ft_ix);
+    if (cond(He) < 1e+10)
+        invHe = He\eye(p);
+    else
+        [Vtemp,Dtemp] = eig(He);
+        invHe = Vtemp*diag(1./max(diag(Dtemp),1e-5))*Vtemp';
+    end
+    Bhat = Bhat - invHe*gr;
+    %log-likelihood
+    llh = SStat_Likelihood(X_ext,t_ext,Bhat,ft_ix);
+    display(['Likelihood at iteration ' num2str(it) ' : ' num2str(llh)]);
+    gnorm = norm(gr);
+    display(['Gradient norm: ' num2str(gnorm)]);     
+    it = it+1;
+end;  
+%% Termination
+z_sc = Bhat./sqrt(diag(-invHe));
+pval = 2*(1-normcdf(abs(z_sc),0,1));
+stats = struct('Bhat',Bhat,'zscore',z_sc,'pval',pval,'CovBhat',-invHe,'llh',llh);
+if (gnorm<=e)
+    st = 1;
+else
+    st = 0;
+    display(['Algorithm does not converge after ' num2str(nit)...
+        ' iterations!!!']);
+end;
+et = toc;
+display(['Total elapsed time is ' num2str(et) ' seconds']);
+end
+
+
+
+
+
+
+%% Likelihood, Gradient and Hessian
+
+function llk = SStat_Likelihood(X_ext,t_ext,Bhat,ft_ix)
+% 
+% Log-likelihood value.
+%
+% Input
+% X_ext: Extended design matrix.
+% t_ext: Extended survival time vector.
+% Bhat: Estimated vector of the population regression parameters.
+% ft_ix: Failure time indices in X_ext (last index if any tie).
+%
+% Output
+% llk: Log-likelihood value.
+%
+llk = 0;
+nft = length(ft_ix);
+for j=1:nft
+    term = 0;
+    ties = ft_ix(t_ext(ft_ix(j))==t_ext(ft_ix));
+    nties = length(ties)-1;
+    lpr = X_ext(ties,:)*Bhat;
+    aux1 = sum(exp(lpr));
+    aux2 = sum(exp(X_ext(t_ext(ft_ix(j))==t_ext,:)*Bhat));
+    for l=0:nties
+        term = term + log(aux2-l*aux1/(nties+1));
+    end;
+    llk = llk + sum(lpr) - term;
+end;
+end
+
+
+function gr = SStat_Gradient(X_ext,t_ext,Bhat,ft_ix)
+% 
+% Gradient vector for the log-likelihood.
+%
+% Input
+% X_ext: Extended design matrix.
+% t_ext: Extended survival time vector.
+% Bhat: Estimated vector of the population regression parameters.
+% ft_ix: Failure time indices in X_ext (last index if any tie).
+%
+% Output
+% gr: Gradient vector.
+%
+p = size(X_ext,2);
+gr = zeros(p,1);
+nft = length(ft_ix);
+for j=1:nft
+    ties = ft_ix(t_ext(ft_ix(j))==t_ext(ft_ix));
+    nties = length(ties)-1;
+    riskset = t_ext(ft_ix(j))==t_ext;
+    term1 = sum(X_ext(ties,:),1);
+    term2 = exp(X_ext(riskset,:)*Bhat);
+    term3 = exp(X_ext(ties,:)*Bhat);
+    term4 = term2'*X_ext(riskset,:);
+    term5 = term3'*X_ext(ties,:);
+    term = 0;  
+    for l=0:nties
+        term = term + (term4-l*term5/(nties+1))/(sum(term2)-l*sum(term3)/(nties+1));
+    end;
+    gr = gr + (term1 - term)';
+end;
+end
+
+
+function He = SStat_Hessian(X_ext,t_ext,Bhat,ft_ix)
+% 
+% Hessian matrix for the log-likelihood.
+%
+% Input
+% X_ext: Extended design matrix.
+% t_ext: Extended survival time vector.
+% Bhat: Estimated vector of the population regression parameters.
+% ft_ix: Failure time indices in X_ext (last index if any tie).
+%
+% Output
+% He: Hessian matrix.
+%
+p = size(X_ext,2);
+He = zeros(p,p);
+nft = length(ft_ix);
+for j=1:nft
+    ties = ft_ix(t_ext(ft_ix(j))==t_ext(ft_ix));
+    nties = length(ties)-1;
+    rsk_ix = find(t_ext(ft_ix(j))==t_ext);  
+    m = length(rsk_ix);
+    term1 = 0;
+    for i=1:m
+        term1 = term1 + exp(X_ext(rsk_ix(i),:)*Bhat)*X_ext(rsk_ix(i),:)'*X_ext(rsk_ix(i),:);
+    end;
+    term2 = 0; 
+    for i=1:nties
+        term2 = term2 + exp(X_ext(ties(i),:)*Bhat)*X_ext(ties(i),:)'*X_ext(ties(i),:);
+    end;
+    term3 = sum(exp(X_ext(rsk_ix,:)*Bhat));
+    term4 = sum(exp(X_ext(ties,:)*Bhat));
+    term5 = exp(X_ext(rsk_ix,:)*Bhat)'*X_ext(rsk_ix,:);
+    term6 = exp(X_ext(ties,:)*Bhat)'*X_ext(ties,:);
+    term = 0;  
+    for l=0:nties
+        Z = term5 - l*term6/(nties+1);
+        phi = term3 - l*term4/(nties+1);
+        term = term + (term1-l*term2/(nties+1))/phi - Z'*Z/(phi*phi);                   
+    end;
+    He = He - term;
+end;
+end
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/survival/IQMcoxPH.m b/IQMtools V1.2.2.2/IQMlite/tools/survival/IQMcoxPH.m
new file mode 100644
index 0000000000000000000000000000000000000000..84cd86923744232a0917ceedd5b43cc1bc3f5913
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/survival/IQMcoxPH.m	
@@ -0,0 +1,241 @@
+function [stats,st] = IQMcoxPH(X,d,t,e)
+% [stats,st] = IQMcoxPH(X,d,t,e)
+%
+% Parameter estimation for the Cox proportional hazards model. Survival 
+% time ties are handled using Efron's method.
+%
+% Input
+% X: Design Matrix with the time-independent covariates. (mxp, m # of
+% subjects, p # of covariates). 
+% d: Logical vector (mx1) indicating censorship status (1 if the subject got 
+% the failure event or 0 otherwise).
+% t: Vector (mx1) whose entries are the survival and censored times (ordered 
+% according to X).
+% e: Convergence epsilon (gradient's norm). Default 10^-3;
+%
+% Output
+% stats.Bhat: Estimated vector of the population regression parameters.
+% stats.CovBhat: Estimated covariance matrix of the population regression 
+% parameters.
+% stats.llh: Values of the maximum log-likelihood across the optimization 
+% process.
+% st: Termination state (1 for convergence and 0 otherwise).
+%
+% $Revision: 1.1.1.1 $  $Date: 2013/27/03 11:25:52 $
+% Original Author: Jorge Luis Bernal Rusiel 
+% CVS Revision Info:
+%    $Author: jbernal$
+%    $Date: 2013/27/03 11:25:52 $
+%    $Revision: 1.1 $
+% References: Kleinbaum, D.G., Klein, M., 2005. Survival analysis. A self-
+% learning approach, second edition. New York: Springer..
+%   
+if nargin < 3
+    error('Too few inputs');
+elseif nargin < 4
+    e = 0.001;
+end;
+tic;
+[m,p] = size(X);
+if (length(d)~=m) || (length(t)~=m)
+    error(['All, the design matrix X, censorship status vector d and'...
+        ' time vector t must have the same number of rows.']);
+end;
+%Sort the data by time. If there is a tie between a failure time and a
+%censored time then the failure time goes first.
+st_ix = find(d==1);
+t1 = t(st_ix);
+[t1,t1_ix] = sort(t1);
+X1 = X(st_ix(t1_ix),:);
+cs_ix = find(d==0);
+if ~isempty(cs_ix)
+    t2 = t(cs_ix);
+    [t2,t2_ix] = sort(t2);
+    X2 = X(cs_ix(t2_ix),:);
+    count1 = 1; count2 = 1; i = 0;
+    while (count1 <= length(t1)) && (count2 <= length(t2))
+        i = i + 1;
+        if t1(count1) <= t2(count2)
+            X(i,:) = X1(count1,:);
+            d(i) = 1;
+            t(i) = t1(count1);
+            count1 = count1 + 1;
+        else 
+            X(i,:) = X2(count2,:);
+            d(i) = 0;
+            t(i) = t2(count2);
+            count2 = count2 + 1;
+        end;
+    end;
+    if (count1 > length(t1))
+        X(i+1:end,:) = X2(count2:end,:);
+        d(i+1:end) = 0;
+        t(i+1:end) = t2(count2:end);
+    else
+        X(i+1:end,:) = X1(count1:end,:);
+        d(i+1:end) = 1;
+        t(i+1:end) = t1(count1:end);
+    end;
+else
+    X = X1;
+    t = t1;
+end;
+%indices of unique failure times in ft_ix (last index when ties happen)
+st_ix = find(d==1);
+[ft,ft_ix] = unique(t(st_ix),'last');
+ft_ix = st_ix(ft_ix);
+nft = length(ft);
+%handling ties in failure times
+nties = zeros(1,nft);
+for j=1:nft
+    i = 1;
+    while (ft_ix(j)-i>0) && (ft(j)==t(ft_ix(j)-i))
+        i = i + 1;
+    end;
+    nties(j) = i-1;
+end;
+%Starting values
+Bhat = zeros(p,1);
+
+%% Iterations
+nit = 50;
+gnorm = e+1;
+it = 1;
+display('Starting Newton-Raphson iterations');
+while (gnorm>e) && (it<=nit)    
+    gr = SStat_Gradient(X,Bhat,ft_ix,nties);
+    He = SStat_Hessian(X,Bhat,ft_ix,nties);
+    if (cond(He) < 1e+10)
+        invHe = He\eye(p);
+    else
+        [Vtemp,Dtemp] = eig(He);
+        invHe = Vtemp*diag(1./max(diag(Dtemp),1e-5))*Vtemp';
+    end
+    Bhat = Bhat - invHe*gr;
+    %log-likelihood
+    llh = SStat_Likelihood(X,Bhat,ft_ix,nties);
+    display(['Likelihood at iteration ' num2str(it) ' : ' num2str(llh)]);
+    gnorm = norm(gr);
+    display(['Gradient norm: ' num2str(gnorm)]);     
+    it = it+1;
+end;  
+%% Termination
+z_sc = Bhat./sqrt(diag(-invHe));
+pval = 2*(1-normcdf(abs(z_sc),0,1));
+stats = struct('Bhat',Bhat,'zscore',z_sc,'pval',pval,'CovBhat',-invHe,'llh',llh);
+if (gnorm<=e)
+    st = 1;
+else
+    st = 0;
+    display(['Algorithm does not converge after ' num2str(nit)...
+        ' iterations!!!']);
+end;
+et = toc;
+display(['Total elapsed time is ' num2str(et) ' seconds']);
+end
+
+
+
+
+
+
+%% Likelihood, Gradient and Hessian
+
+function llk = SStat_Likelihood(X,Bhat,ft_ix,nties)
+% 
+% Log-likelihood value.
+%
+% Input
+% X: Ordered design Matrix (according to survival time).
+% Bhat: Estimated vector of the population regression parameters.
+% ft_ix: Failure time indices in X (last index if any tie).
+% nties: Number of ties for each survival time.
+%
+% Output
+% llk: Log-likelihood value.
+%
+llk = 0;
+nft = length(ft_ix);
+for j=1:nft
+    term = 0;
+    lpr = X(ft_ix(j)-nties(j):ft_ix(j),:)*Bhat;
+    aux1 = sum(exp(lpr));
+    aux2 = sum(exp(X(ft_ix(j)-nties(j):end,:)*Bhat));
+    for l=0:nties(j)
+        term = term + log(aux2-l*aux1/(nties(j)+1));
+    end;
+    llk = llk + sum(lpr) - term;
+end;
+end
+
+
+function gr = SStat_Gradient(X,Bhat,ft_ix,nties)
+% 
+% Gradient vector for the log-likelihood.
+%
+% Input
+% X: Ordered design Matrix (according to survival time).
+% Bhat: Estimated vector of the population regression parameters.
+% ft_ix: Failure time indices in X (last index if any tie).
+% nties: Number of ties for each survival time.
+%
+% Output
+% gr: Gradient vector.
+%
+p = size(X,2);
+gr = zeros(p,1);
+nft = length(ft_ix);
+for j=1:nft
+    term1 = sum(X(ft_ix(j)-nties(j):ft_ix(j),:),1);
+    term2 = exp(X(ft_ix(j)-nties(j):end,:)*Bhat);
+    term3 = exp(X(ft_ix(j)-nties(j):ft_ix(j),:)*Bhat);
+    term4 = term2'*X(ft_ix(j)-nties(j):end,:);
+    term5 = term3'*X(ft_ix(j)-nties(j):ft_ix(j),:);
+    term = 0;  
+    for l=0:nties(j)
+        term = term + (term4-l*term5/(nties(j)+1))/(sum(term2)-l*sum(term3)/(nties(j)+1));
+    end;
+    gr = gr + (term1 - term)';
+end;
+end
+
+
+function He = SStat_Hessian(X,Bhat,ft_ix,nties)
+% 
+% Hessian matrix for the log-likelihood.
+%
+% Input
+% X: Ordered design Matrix (according to survival time).
+% Bhat: Estimated vector of the population regression parameters.
+% ft_ix: Failure time indices in X (last index if any tie).
+% nties: Number of ties for each survival time.
+%
+% Output
+% He: Hessian matrix.
+%
+[m,p] = size(X);
+He = zeros(p,p);
+nft = length(ft_ix);
+for j=1:nft
+    term1 = 0; 
+    for i=ft_ix(j)-nties(j):m
+        term1 = term1 + exp(X(i,:)*Bhat)*X(i,:)'*X(i,:);
+    end;
+    term2 = 0; 
+    for i=ft_ix(j)-nties(j):ft_ix(j)
+        term2 = term2 + exp(X(i,:)*Bhat)*X(i,:)'*X(i,:);
+    end;
+    term3 = sum(exp(X(ft_ix(j)-nties(j):end,:)*Bhat));
+    term4 = sum(exp(X(ft_ix(j)-nties(j):ft_ix(j),:)*Bhat));
+    term5 = exp(X(ft_ix(j)-nties(j):m,:)*Bhat)'*X(ft_ix(j)-nties(j):m,:);
+    term6 = exp(X(ft_ix(j)-nties(j):ft_ix(j),:)*Bhat)'*X(ft_ix(j)-nties(j):ft_ix(j),:);
+    term = 0;  
+    for l=0:nties(j)
+        Z = term5 - l*term6/(nties(j)+1);
+        phi = term3 - l*term4/(nties(j)+1);
+        term = term + (term1-l*term2/(nties(j)+1))/phi - Z'*Z/(phi*phi);                   
+    end;
+    He = He - term;
+end;
+end
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/survival/IQMcoxStratPH.m b/IQMtools V1.2.2.2/IQMlite/tools/survival/IQMcoxStratPH.m
new file mode 100644
index 0000000000000000000000000000000000000000..c63902d42e0f9ff3d612441e65ff075e8bbe8dd3
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/survival/IQMcoxStratPH.m	
@@ -0,0 +1,265 @@
+function [stats,st] = IQMcoxStratPH(X,z,d,t,e)
+% [stats,st] = IQMcoxPH(X,z,d,t,e)
+%
+% Parameter estimation for the Stratified Cox proportional hazards model.  
+% Survival time ties are handled using Efron's method.
+%
+% Input
+% X: Design Matrix with the time-independent covariates. (mxp, m # of
+% subjects, p # of covariates). 
+% z: Vector (mx1) with the strata for the rows of X;
+% d: Logical vector (mx1) indicating censorship status (1 if the subject got 
+% the failure event or 0 otherwise).
+% t: Vector (mx1) whose entries are the survival and censored times (ordered 
+% according to X).
+% e: Convergence epsilon (gradient's norm). Default 10^-3;
+%
+% Output
+% stats.Bhat: Estimated vector of the population regression parameters.
+% stats.CovBhat: Estimated covariance matrix of the population regression 
+% parameters.
+% stats.llh: Values of the maximum log-likelihood across the optimization 
+% process.
+% st: Termination state (1 for convergence and 0 otherwise).
+%
+% $Revision: 1.1.1.1 $  $Date: 2013/27/03 11:25:52 $
+% Original Author: Jorge Luis Bernal Rusiel 
+% CVS Revision Info:
+%    $Author: jbernal$
+%    $Date: 2013/27/03 11:25:52 $
+%    $Revision: 1.1 $
+% References: Kleinbaum, D.G., Klein, M., 2005. Survival analysis. A self-
+% learning approach, second edition. New York: Springer..
+%   
+if nargin < 4
+    error('Too few inputs');
+elseif nargin < 5
+    e = 0.001;
+end;
+tic;
+[m,p] = size(X);
+if (length(z)~=m) || (length(d)~=m) || (length(t)~=m) 
+    error(['The design matrix X, strata vector z, censorship status vector d'...
+        ' and time vector t must all have the same number of rows.']);
+end;
+%Sort the data by time. If there is a tie between a failure time and a
+%censored time then the failure time goes first.
+st_ix = find(d==1);
+t1 = t(st_ix);
+[t1,t1_ix] = sort(t1);
+X1 = X(st_ix(t1_ix),:);
+z1 = z(st_ix(t1_ix));
+cs_ix = find(d==0);
+if ~isempty(cs_ix)
+    t2 = t(cs_ix);
+    [t2,t2_ix] = sort(t2);
+    X2 = X(cs_ix(t2_ix),:);
+    z2 = z(cs_ix(t2_ix));
+    count1 = 1; count2 = 1; i = 0;
+    while (count1 <= length(t1)) && (count2 <= length(t2))
+        i = i + 1;
+        if t1(count1) <= t2(count2)
+            X(i,:) = X1(count1,:);
+            z(i) = z1(count1);
+            d(i) = 1;
+            t(i) = t1(count1);
+            count1 = count1 + 1;
+        else 
+            X(i,:) = X2(count2,:);
+            z(i) = z2(count2);
+            d(i) = 0;
+            t(i) = t2(count2);
+            count2 = count2 + 1;
+        end;
+    end;
+    if (count1 > length(t1))
+        X(i+1:end,:) = X2(count2:end,:);
+        z(i+1:end) = z2(count2:end);
+        d(i+1:end) = 0;
+        t(i+1:end) = t2(count2:end);
+    else
+        X(i+1:end,:) = X1(count1:end,:);
+        z(i+1:end) = z1(count1:end);
+        d(i+1:end) = 1;
+        t(i+1:end) = t1(count1:end);
+    end;
+else
+    X = X1;
+    t = t1;
+    z = z1;
+end;
+uz = unique(z);
+nst = length(uz);
+%indices of unique failure times for each stratum in ft_ix (last index when ties happen)
+ft_ix = zeros(nst,sum(d));
+ft = ft_ix;
+nft = zeros(nst,1);
+nties = ft;
+for k=1:nst
+    t_strat = t(z==uz(k));
+    st_ix = find(d(z==uz(k))==1);
+    [ft_aux,ft_ix_aux] = unique(t_strat(st_ix),'last');
+    nft(k) = length(ft_aux);
+    ft_ix(k,1:nft(k)) = st_ix(ft_ix_aux);
+    ft(k,1:nft(k)) = ft_aux;
+    %handling ties in failure times
+    for j=1:nft(k)
+        i = 1;
+        while (ft_ix(k,j)-i>0) && (ft(k,j)==t(ft_ix(k,j)-i))
+            i = i + 1;
+        end;
+        nties(k,j) = i-1;
+    end;
+end;
+%Starting values
+Bhat = zeros(p,1);
+
+%% Iterations
+nit = 50;
+gnorm = e+1;
+it = 1;
+display('Starting Newton-Raphson iterations');
+while (gnorm>e) && (it<=nit)
+    gr = zeros(p,1);
+    He = zeros(p,p);
+    for k=1:length(uz)
+        gr = gr + SStat_Gradient(X(z==uz(k),:),Bhat,ft_ix(k,1:nft(k)),nties(k,1:nft(k)));
+        He = He + SStat_Hessian(X(z==uz(k),:),Bhat,ft_ix(k,1:nft(k)),nties(k,1:nft(k)));
+    end;
+    if (cond(He) < 1e+10)
+        invHe = He\eye(p);
+    else
+        [Vtemp,Dtemp] = eig(He);
+        invHe = Vtemp*diag(1./max(diag(Dtemp),1e-5))*Vtemp';
+    end
+    Bhat = Bhat - invHe*gr;
+    %log-likelihood
+    llh = 0;
+    for k=1:length(uz)
+        llh = llh + SStat_Likelihood(X(z==uz(k),:),Bhat,ft_ix(k,1:nft(k)),nties(k,1:nft(k)));
+    end; 
+    display(['Likelihood at iteration ' num2str(it) ' : ' num2str(llh)]);
+    gnorm = norm(gr);
+    display(['Gradient norm: ' num2str(gnorm)]);     
+    it = it+1;
+end;  
+%% Termination
+z_sc = Bhat./sqrt(diag(-invHe));
+pval = 2*(1-normcdf(abs(z_sc),0,1));
+stats = struct('Bhat',Bhat,'zscore',z_sc,'pval',pval,'CovBhat',-invHe,'llh',llh);
+if (gnorm<=e)
+    st = 1;
+else
+    st = 0;
+    display(['Algorithm does not converge after ' num2str(nit)...
+        ' iterations!!!']);
+end;
+et = toc;
+display(['Total elapsed time is ' num2str(et) ' seconds']);
+end
+
+
+
+
+
+
+%% Likelihood, Gradient and Hessian
+
+function llk = SStat_Likelihood(X,Bhat,ft_ix,nties)
+% 
+% Log-likelihood value.
+%
+% Input
+% X: Ordered design Matrix (according to survival time).
+% Bhat: Estimated vector of the population regression parameters.
+% ft_ix: Failure time indices in X (last index if any tie).
+% nties: Number of ties for each survival time.
+%
+% Output
+% llk: Log-likelihood value.
+%
+llk = 0;
+nft = length(ft_ix);
+for j=1:nft
+    term = 0;
+    lpr = X(ft_ix(j)-nties(j):ft_ix(j),:)*Bhat;
+    aux1 = sum(exp(lpr));
+    aux2 = sum(exp(X(ft_ix(j)-nties(j):end,:)*Bhat));
+    for l=0:nties(j)
+        term = term + log(aux2-l*aux1/(nties(j)+1));
+    end;
+    llk = llk + sum(lpr) - term;
+end;
+end
+
+
+function gr = SStat_Gradient(X,Bhat,ft_ix,nties)
+% 
+% Gradient vector for the log-likelihood.
+%
+% Input
+% X: Ordered design Matrix (according to survival time).
+% Bhat: Estimated vector of the population regression parameters.
+% ft_ix: Failure time indices in X (last index if any tie).
+% nties: Number of ties for each survival time.
+%
+% Output
+% gr: Gradient vector.
+%
+p = size(X,2);
+gr = zeros(p,1);
+nft = length(ft_ix);
+for j=1:nft
+    term1 = sum(X(ft_ix(j)-nties(j):ft_ix(j),:),1);
+    term2 = exp(X(ft_ix(j)-nties(j):end,:)*Bhat);
+    term3 = exp(X(ft_ix(j)-nties(j):ft_ix(j),:)*Bhat);
+    term4 = term2'*X(ft_ix(j)-nties(j):end,:);
+    term5 = term3'*X(ft_ix(j)-nties(j):ft_ix(j),:);
+    term = 0;  
+    for l=0:nties(j)
+        term = term + (term4-l*term5/(nties(j)+1))/(sum(term2)-l*sum(term3)/(nties(j)+1));
+    end;
+    gr = gr + (term1 - term)';
+end;
+end
+
+
+function He = SStat_Hessian(X,Bhat,ft_ix,nties)
+% 
+% Hessian matrix for the log-likelihood.
+%
+% Input
+% X: Ordered design Matrix (according to survival time).
+% Bhat: Estimated vector of the population regression parameters.
+% ft_ix: Failure time indices in X (last index if any tie).
+% nties: Number of ties for each survival time.
+%
+% Output
+% He: Hessian matrix.
+%
+[m,p] = size(X);
+He = zeros(p,p);
+nft = length(ft_ix);
+for j=1:nft
+    term1 = 0; 
+    for i=ft_ix(j)-nties(j):m
+        term1 = term1 + exp(X(i,:)*Bhat)*X(i,:)'*X(i,:);
+    end;
+    term2 = 0; 
+    for i=ft_ix(j)-nties(j):ft_ix(j)
+        term2 = term2 + exp(X(i,:)*Bhat)*X(i,:)'*X(i,:);
+    end;
+    term3 = sum(exp(X(ft_ix(j)-nties(j):end,:)*Bhat));
+    term4 = sum(exp(X(ft_ix(j)-nties(j):ft_ix(j),:)*Bhat));
+    term5 = exp(X(ft_ix(j)-nties(j):m,:)*Bhat)'*X(ft_ix(j)-nties(j):m,:);
+    term6 = exp(X(ft_ix(j)-nties(j):ft_ix(j),:)*Bhat)'*X(ft_ix(j)-nties(j):ft_ix(j),:);
+    term = 0;  
+    for l=0:nties(j)
+        Z = term5 - l*term6/(nties(j)+1);
+        phi = term3 - l*term4/(nties(j)+1);
+        term = term + (term1-l*term2/(nties(j)+1))/phi - Z'*Z/(phi*phi);                   
+    end;
+    He = He - term;
+end;
+end
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/survival/IQMhr.m b/IQMtools V1.2.2.2/IQMlite/tools/survival/IQMhr.m
new file mode 100644
index 0000000000000000000000000000000000000000..018d5d30adf7fd2496fba198dceb471566e8dadc
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/survival/IQMhr.m	
@@ -0,0 +1,41 @@
+function [hr,pval,CI] = IQMhr(x1,x2,stats)
+% [hr,pval,CI] = IQMhr(x1,x2,stats)
+%
+% Hazard ratio estimate for Cox models.
+%
+% Input
+%
+% x1: Row vector with the covariate values for the first group.
+% x2: Row vector with the covariate values for the second group.
+% stats: Structure containing statistiscs obtained with any of IQMcoxPH,
+% IQMcoxStratPH and IQMcoxExt.
+%
+% Output
+% hr: Hazard ratio value.
+% pval: P-value for the hr value.
+% CI: 95% confidence interval for the hazard ratio estimate.
+%
+% $Revision: 1.1.1.1 $  $Date: 2013/27/03 11:25:52 $
+% Original Author: Jorge Luis Bernal Rusiel 
+% CVS Revision Info:
+%    $Author: jbernal$
+%    $Date: 2013/27/03 11:25:52 $
+%    $Revision: 1.1 $
+% References: Kleinbaum, D.G., Klein, M., 2005. Survival analysis. A self-
+% learning approach, second edition. New York: Springer..
+%   
+if nargin < 3
+    error('Too few inputs');
+end;
+p = length(stats.Bhat);
+if (length(x1)~=p) || (length(x2)~=p)
+    error(['Vectors x1, x2 and stats.Bhat must have the same length.']);
+end;
+d = x1-x2;
+lrp = d*stats.Bhat;
+hr = exp(lrp);
+lrp_std = (d'*d).*stats.CovBhat;
+lrp_std = sqrt(sum(lrp_std(:)));
+CI.low = exp(lrp-1.96*lrp_std);
+CI.high = exp(lrp+1.96*lrp_std);
+pval = 2*(1-normcdf(abs(lrp/lrp_std),0,1));
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/survival/IQMkm.m b/IQMtools V1.2.2.2/IQMlite/tools/survival/IQMkm.m
new file mode 100644
index 0000000000000000000000000000000000000000..9a0e5b80121ab56a02e316a6b6adc4144f103c9c
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/survival/IQMkm.m	
@@ -0,0 +1,59 @@
+function [km] = IQMkm(z,d,t,ptype)
+% [km] = IQMkm(z,d,t,ptype)
+%
+% Kaplan-Meier curves estimation and plot.
+%
+% Input
+% z: Discrete covariate (mx1, m # of subjects) with the strata categories.
+% d: Logical vector (mx1) indicating censorship status (1 if the subject got 
+% the failure event or 0 otherwise).
+% t: Vector (mx1) whose entries are the survival and censored times (ordered 
+% according to X).
+% ptype: Plot type string. It can only be either 'km' to plot the KM curves
+% or 'll' to plot the -log(-log(KM)) curves.
+%
+% Output
+% km: Structure array with the Kaplan-Meier estimates for each category of
+% z.
+%
+% $Revision: 1.1.1.1 $  $Date: 2013/27/03 11:25:52 $
+% Original Author: Jorge Luis Bernal Rusiel 
+% CVS Revision Info:
+%    $Author: jbernal$
+%    $Date: 2013/27/03 11:25:52 $
+%    $Revision: 1.1 $
+% References: Kleinbaum, D.G., Klein, M., 2005. Survival analysis. A self-
+% learning approach, second edition. New York: Springer.
+%   
+if nargin < 3
+    error('Too few inputs');
+elseif nargin < 4
+    ptype = 'km';
+end;
+uz = unique(z);
+nuz = length(uz);
+km(1:nuz) = struct('f',[],'t',[]);
+if strcmpi(ptype,'km')
+    figure('Name','KM plot');
+elseif strcmpi(ptype,'ll')
+    figure('Name','-log(-log(KM)) plot');
+else
+    error('The only posible values for ptype are ''km'' or ''ll''.');
+end;
+hold on
+colors = {'b','k','g','c','m','r','y'};
+for i=1:length(uz)
+    t_strat = t(z==uz(i));
+    d_strat = d(z==uz(i));
+    [km(i).f,km(i).t] = ecdf(t_strat,'censoring',~d_strat);
+    km(i).f = 1 - km(i).f;
+    if strcmpi(ptype,'km')
+        stairs(km(i).t,km(i).f,colors{mod(i,7)+1},'LineWidth',2);
+    else
+        stairs(km(i).t,-log(-log(km(i).f)),colors{mod(i,7)+1},'LineWidth',2);
+    end;
+end;
+legend(num2str(uz));
+hold off
+
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/survival/IQMphTest.m b/IQMtools V1.2.2.2/IQMlite/tools/survival/IQMphTest.m
new file mode 100644
index 0000000000000000000000000000000000000000..2c427c49f975347b3368e4266274a5e3df2fb3e3
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/survival/IQMphTest.m	
@@ -0,0 +1,131 @@
+function [pval,rho] = IQMphTest(X,d,t,stats_PH)
+% [pval,rho] = IQMphTest(X,d,t,stats_PH)
+%
+% Schoenfeld residuals test for the proportional hazards assumption.
+%
+% Input
+% X: Design Matrix with the time-independent covariates. (mxp, m # of
+% subjects, p # of covariates). 
+% d: Logical vector (mx1) indicating censorship status (1 if the subject got 
+% the failure event or 0 otherwise).
+% t: Vector (mx1) whose entries are the survival and censored times (ordered 
+% according to X).
+% stats_PH: Structure obtained from IQMcoxPH
+%
+% Output
+% pval: P-values indicating the probability of the PH assumption for each 
+% covariate.
+% rho: Correlations between Schoenfeld residuals and ranked failure times.
+%
+% $Revision: 1.1.1.1 $  $Date: 2013/27/03 11:25:52 $
+% Original Author: Jorge Luis Bernal Rusiel 
+% CVS Revision Info:
+%    $Author: jbernal$
+%    $Date: 2013/27/03 11:25:52 $
+%    $Revision: 1.1 $
+% References: Kleinbaum, D.G., Klein, M., 2005. Survival analysis. A self-
+% learning approach, second edition. New York: Springer..
+%   
+if nargin < 4
+    error('Too few inputs');
+end;
+[m,p] = size(X);
+if (length(d)~=m) || (length(t)~=m)
+    error(['All, the design matrix X, censorship status vector d and'...
+        ' time vector t must have the same number of rows.']);
+end;
+if length(stats_PH.Bhat)~=p
+    error(['The vector stats.Bhat must have the same length as the number'...
+        ' of colums of X.']);
+end;
+%Sort the data by time. If there is a tie between a failure time and a
+%censored time then the failure time goes first.
+st_ix = find(d==1);
+t1 = t(st_ix);
+[t1,t1_ix] = sort(t1);
+X1 = X(st_ix(t1_ix),:);
+cs_ix = find(d==0);
+if ~isempty(cs_ix)
+    t2 = t(cs_ix);
+    [t2,t2_ix] = sort(t2);
+    X2 = X(cs_ix(t2_ix),:);
+    count1 = 1; count2 = 1; i = 0;
+    while (count1 <= length(t1)) && (count2 <= length(t2))
+        i = i + 1;
+        if t1(count1) <= t2(count2)
+            X(i,:) = X1(count1,:);
+            d(i) = 1;
+            t(i) = t1(count1);
+            count1 = count1 + 1;
+        else 
+            X(i,:) = X2(count2,:);
+            d(i) = 0;
+            t(i) = t2(count2);
+            count2 = count2 + 1;
+        end;
+    end;
+    if (count1 > length(t1))
+        X(i+1:end,:) = X2(count2:end,:);
+        d(i+1:end) = 0;
+        t(i+1:end) = t2(count2:end);
+    else
+        X(i+1:end,:) = X1(count1:end,:);
+        d(i+1:end) = 1;
+        t(i+1:end) = t1(count1:end);
+    end;
+else
+    X = X1;
+    t = t1;
+end;
+%indices of unique failure times in ft_ix (last index when ties happen)
+st_ix = find(d==1);
+[ft,ft_ix] = unique(t(st_ix),'last');
+ft_ix = st_ix(ft_ix);
+nft = length(ft);
+%handling ties in failure times by substracting a very small random number
+rand('state',sum(100*clock));
+for j=1:nft
+    i = 1;
+    while (ft_ix(j)-i>0) && (ft(j)==t(ft_ix(j)-i))
+        i = i + 1;
+    end;
+    nties = i-1;
+    tt = t(ft_ix(j)-nties:ft_ix(j)) - 1e-5*(1 + rand(nties+1,1));
+    tX = X(ft_ix(j)-nties:ft_ix(j),:);
+    [stt,stt_ix] = sort(tt);
+    t(ft_ix(j)-nties:ft_ix(j)) = stt;
+    X(ft_ix(j)-nties:ft_ix(j),:) = tX(stt_ix,:);
+end;
+nft = length(st_ix);
+r = zeros(nft,p);
+for i=1:nft
+    lprv = exp(X(st_ix(i):end,:)*stats_PH.Bhat);
+    r(i,:) = X(st_ix(i),:) - (lprv'*X(st_ix(i):end,:))./sum(lprv);
+end;
+[rho,pval] = corr(r,[1:nft]');
+
+% Plot Schoenfeld residuals over Ranked failure times for eye inspection.
+figure;
+nall = size(r,2);
+ncol = ceil(sqrt(nall));
+nrow = ceil(nall/ncol);
+for k=1:nall,
+    subplot(nrow,ncol,k);
+    plot([1:nft],r(:,k),'o');
+    ylabel('Schoenfeld residuals');
+    xlabel('Ranked failure times');
+    title(sprintf('beta_%d',k),'Interpreter','none');
+    grid on
+    set(gca,'XLim',[1 nft])
+    % Add loess line
+    hold on
+    rsmooth = smoothIQM([1:nft],r(:,k),0.5,'loess');
+    plot([1:nft],rsmooth,'k-','LineWidth',2);
+    % Plot zero line
+    plot(get(gca,'XLim'),[0 0],'k--');
+    % Add legend
+    h = legend(['Residuals over time ' sprintf('\n(corr=%1.2g, p=%1.2g)',rho(k),pval(k))],'Loess smoother','Zero line','Location','best');
+    set(h,'Interpreter','none')
+    axis square
+end
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/survival/IQMxext.m b/IQMtools V1.2.2.2/IQMlite/tools/survival/IQMxext.m
new file mode 100644
index 0000000000000000000000000000000000000000..ae3fa25311d2160cd87b5b5a02d5ba26461e2e9a
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/survival/IQMxext.m	
@@ -0,0 +1,114 @@
+function [sID_ext,X_ext,d_ext,t_ext] = IQMxext(sID,X,d,t)
+% [sID_ext,X_ext,d_ext,t_ext] = IQMxext(sID,X,d,t)
+%
+% Extension (by adding new rows) of a design matrix comprising only time-
+% independent covariates to a design matrix for which time-dependent 
+% covariates can be easily added.
+%
+% Input
+% sID: Subjects' IDs (for each row of X).
+% X: Design Matrix with the time-independent covariates. (mxp, m # of
+% subjects, p # of covariates). 
+% d: Logical vector (mx1) indicating censorship status (1 if the subject got 
+% the failure event or 0 otherwise).
+% t: Vector (mx1) whose entries are the survival and censored times (ordered 
+% according to X).
+%
+% Output
+% sID_ext: Extended subjects' IDs.
+% X_ext: Extended design matrix.
+% d_ext: Extended censorship status vector.
+% t_ext: Extended survival time vector.
+%
+% $Revision: 1.1.1.1 $  $Date: 2013/27/03 11:25:52 $
+% Original Author: Jorge Luis Bernal Rusiel 
+% CVS Revision Info:
+%    $Author: jbernal$
+%    $Date: 2013/27/03 11:25:52 $
+%    $Revision: 1.1 $
+% References: Kleinbaum, D.G., Klein, M., 2005. Survival analysis. A self-
+% learning approach, second edition. New York: Springer..
+%   
+if nargin < 4
+    error('Too few inputs');
+end;
+[m,p] = size(X);
+if (length(sID)~=m) || (length(d)~=m) || (length(t)~=m)
+    error(['All, the design matrix X, censorship status vector d, '...
+        'time vector t and subject ID vector must have the same number of rows.']);
+end;
+%Sort the data by time. If there is a tie between a failure time and a
+%censored time then the failure time goes first.
+st_ix = find(d==1);
+t1 = t(st_ix);
+[t1,t1_ix] = sort(t1);
+X1 = X(st_ix(t1_ix),:);
+sID1 = sID(st_ix(t1_ix));
+cs_ix = find(d==0);
+if ~isempty(cs_ix)
+    t2 = t(cs_ix);
+    [t2,t2_ix] = sort(t2);
+    X2 = X(cs_ix(t2_ix),:);
+    sID2 = sID(cs_ix(t2_ix));
+    count1 = 1; count2 = 1; i = 0;
+    while (count1 <= length(t1)) && (count2 <= length(t2))
+        i = i + 1;
+        if t1(count1) <= t2(count2)
+            sID(i) = sID1(count1);
+            X(i,:) = X1(count1,:);
+            d(i) = 1;
+            t(i) = t1(count1);
+            count1 = count1 + 1;
+        else 
+            sID(i) = sID2(count2);
+            X(i,:) = X2(count2,:);
+            d(i) = 0;
+            t(i) = t2(count2);
+            count2 = count2 + 1;
+        end;
+    end;
+    if (count1 > length(t1))
+        sID(i+1:end) = sID2(count2:end);
+        X(i+1:end,:) = X2(count2:end,:);
+        d(i+1:end) = 0;
+        t(i+1:end) = t2(count2:end);
+    else
+        sID(i+1:end) = sID1(count1:end);
+        X(i+1:end,:) = X1(count1:end,:);
+        d(i+1:end) = 1;
+        t(i+1:end) = t1(count1:end);
+    end;
+else
+    sID = sID1;
+    X = X1;
+    t = t1;
+end;
+%indices of unique failure times in ft_ix (last index when ties happen)
+st_ix = find(d==1);
+[ft,ft_ix] = unique(t(st_ix),'last');
+ft_ix = st_ix(ft_ix);
+nft = length(ft);
+n = 0;
+for j=1:nft
+    n = n + sum(t>t(ft_ix(j)));
+end;
+n = n + m;
+X_ext = zeros(n,p);
+d_ext = zeros(n,1);
+t_ext = zeros(n,1);
+count = 1;
+for i=1:m
+    ni = sum(t(ft_ix) < t(i));
+    X_ext(count:count+ni,:) = kron(ones(ni+1,1),X(i,:));
+    sID_ext(count:count+ni) = sID(i);
+    d_ext(count:count+ni-1) = 0;
+    d_ext(count+ni) = d(i);
+    t_ext(count:count+ni-1) = t(ft_ix(t(ft_ix)<t(i)));
+    t_ext(count+ni) = t(i);
+    count = count + ni + 1;
+end;
+
+
+
+
+
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/symbolic/IQMsymjacobian.m b/IQMtools V1.2.2.2/IQMlite/tools/symbolic/IQMsymjacobian.m
new file mode 100644
index 0000000000000000000000000000000000000000..3de44b34f87ba10cec24a86ff7bcb3df7843154c
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/symbolic/IQMsymjacobian.m	
@@ -0,0 +1,137 @@
+function [output] = IQMsymjacobian(model,varargin)
+% IQMsymjacobian: Determines a symbolic Jacobian and the derivative of the
+% ODE right hand side with respect to given parameters. For the latter to
+% be computed, parameters need to be specified. The general computation for
+% all parameters in a model would be often to time costly.
+%
+% USAGE:
+% ======
+% output = IQMsymjacobian(model)
+% output = IQMsymjacobian(model, simpleflag)
+% output = IQMsymjacobian(model, parameternames)
+% output = IQMsymjacobian(model, parameternames, simpleflag)
+%
+% model: IQMmodel
+% simpleflag: =0 => do not try to simplify (default), =1 => try to simplify (slower)
+% parameternames: cellarray with parameters to compute the derivative of
+% the ODE right hand side for. 
+%
+% Output Arguments:
+% =================
+% output: structure containing all output information:
+%   output.states: cellarray with all statenames in the model   
+%   output.jacobian: cell-matrix containing the symbolic expressions for the jacobian
+% If parameters are given the output contains additionally:   
+%   output.parameters: cellarray of considered parameters
+%   outputs.dfdp: cell-matrix containing the symbolic expressions for dfdp 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK SYMBOLIC TOOLBOX
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isSymbolicpresentIQM(),
+    error('Symbolic toolboc needed, but not available.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK TYPE OF MODEL
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~strcmp(class(model),'IQMmodel'),
+    error('Incorrect model input argument.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% SIMPLE FLAG & PARAMETERS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+simpleflag = 0;
+parameternames = {};
+if nargin == 2,
+    if iscell(varargin{1}) || ischar(varargin{1}),
+        parameternames = varargin{1};
+    else
+        simpleflag = varargin{1};
+    end
+elseif nargin == 3,
+    parameternames = varargin{1};
+    simpleflag = varargin{2};
+end
+if ischar(parameternames),
+    parameternames = {parameternames};
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET ALL FORMULAS AND ODES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[statenames,ODEs] = IQMstates(model);
+[variablenames, variableformulas] = IQMvariables(model);
+[reactionnames, reactionformulas] = IQMreactions(model);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EXPAND VARIABLES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for k = 1:length(variablenames),
+    for k2 = k+1:length(variablenames),
+        variableformulas{k2} = char(subs(variableformulas{k2}, variablenames{k}, variableformulas{k}));
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INSERT VARIABLES TO REACTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for k = 1:length(reactionnames),
+    for k2 = 1:length(variablenames),
+        reactionformulas{k} = char(subs(reactionformulas{k}, variablenames{k2}, variableformulas{k2}));
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INSERT VARIABLES AND REACTIONS INTO ODES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for k = 1:length(ODEs),
+    for k2 = 1:length(variablenames),
+        ODEs{k} = char(subs(ODEs{k}, variablenames{k2}, variableformulas{k2}));
+    end
+    for k2 = 1:length(reactionnames),
+        ODEs{k} = char(subs(ODEs{k}, reactionnames{k2}, reactionformulas{k2}));
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DETERMINE JACOBIAN
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+jacobian = cell(length(statenames));
+for k = 1:length(statenames),
+    for k2 = 1:length(statenames),
+        jacobian{k,k2} = char(diff(ODEs{k},statenames{k2}));
+        if simpleflag == 1,
+            jacobian{k,k2} = char(simple(sym(jacobian{k,k2})));
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DETERMINE DFDP
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+dfdp = {};
+if ~isempty(parameternames),
+    for k = 1:length(statenames),
+        for k2 = 1:length(parameternames),
+            dfdp{k,k2} = char(diff(ODEs{k},parameternames{k2}));
+            if simpleflag == 1,
+                dfdp{k,k2} = char(simple(sym(dfdp{k,k2})));
+            end
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CONSTRUCT OUTPUT ARGUMENT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+output = [];
+output.states = statenames;
+output.jacobian = jacobian;
+if ~isempty(dfdp),
+    output.parameters = parameternames;
+    output.dfdp = dfdp;
+end
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/symbolic/formula2vecIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/symbolic/formula2vecIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..bfe85632a920d629c9d9f3fd35b68b2ce8153f08
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/symbolic/formula2vecIQM.m	
@@ -0,0 +1,12 @@
+function [formula] = formula2vecIQM(formula)
+% formula2vecIQM: Converts a formula given as a string into a formula that
+% can be evaluated with variables given as vectors. (Adding '.' in front of
+% '*', '/', '^'
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+formula = regexprep(formula,'\*','.*');
+formula = regexprep(formula,'\/','./');
+formula = regexprep(formula,'\^','.^');
+
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/symbolic/maplearrayIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/symbolic/maplearrayIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..7520be8e934c44dcd58338aeff4b5693c8d8a668
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/symbolic/maplearrayIQM.m	
@@ -0,0 +1,15 @@
+function [output] = maplearrayIQM(input)
+% maplearrayIQM: Creates a symbolic expression of the form: '{a,b,c,d}' 
+% where a, b,c ,d are strings coming from a cellarray input argument.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+for kindex=1:length(input)
+    if kindex==1
+        output = sprintf('{%s', input{kindex});
+    else
+        output = sprintf('%s,%s', output, input{kindex});
+    end
+end
+output = sym(strcat(output,'}'));
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/symbolic/substitutevarsIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/symbolic/substitutevarsIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..58a133896c980c807e56d29b5c02ea5f04d8e7d6
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/symbolic/substitutevarsIQM.m	
@@ -0,0 +1,38 @@
+function [model] = substitutevarsIQM(model)
+% substitutevarsIQM: For each of the selected reactions substitutes variables
+% into the reaction rate expression, thereby creating a expression
+% consisting solely of parameters and states. 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% check if symbolic toolbox is present
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isSymbolicpresentIQM,
+    error('The model reduction feature requires the presence of the symbolic toolbox.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% substitution
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[variablenames, variableformulas] = IQMvariables(model);
+iqms = struct(model);
+% For all reactions
+for k = 1:length(iqms.reactions)
+    % reaction rate formula
+    formula = iqms.reactions(k).formula;
+    % determines all variables and parameters in expression
+    match = regexp(formula,'\w+','match');
+    members = find(ismember(variablenames, match)');
+    while ~eq(sum(members), 0)
+        % Substitutes relevant variable expressions into reaction
+        formula = char(subs(formula, variablenames(members), variableformulas(members)));
+        % updates list of variables found in reaction rate expression
+        match = regexp(formula,'\w+','match');
+        members = find(ismember(variablenames, match)', 1);
+    end
+    % sets new reactionformula
+    iqms.reactions(k).formula = formula;
+end
+model = IQMmodel(iqms);
+model = cleanmodelIQM(model,1);
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/templates/IQMnewscript.m b/IQMtools V1.2.2.2/IQMlite/tools/templates/IQMnewscript.m
new file mode 100644
index 0000000000000000000000000000000000000000..4180a02e0227c79afd9bb8a03383c4a606ec45a6
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/templates/IQMnewscript.m	
@@ -0,0 +1,37 @@
+function [] = newscriptIQM(varargin)
+% newscriptIQM: Creates a new script with a short guide on how to
+% initialize IQM Tools.
+%
+% USAGE:
+% ======
+%   newscriptIQM
+%   newscriptIQM('scriptname')
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+file = which('scriptTemplateIQM.m');
+if nargin == 0,
+    copyfile(file,[pwd '/newscript.m']);
+elseif nargin == 1,
+    if ~ischar(varargin{1}),
+        copyfile(file,[pwd '/newscript.m']);
+    else
+        filename = varargin{1};
+        content  = fileread(file);
+        content  = strrep(content,'TEMPLATE_SCRIPT_NAME',filename);
+        
+        % Get IQM Tools folder
+        iqmfolder = [fileparts(which('installIQMlite.m')) '/..'];
+        oldpath = pwd();
+        cd(iqmfolder);
+        content  = strrep(content,'D:\IQM Tools Suite',pwd);
+        cd(oldpath);
+        
+        fid      = fopen([pwd '/' filename '.m'],'w');
+        fwrite(fid,content);
+        fclose(fid);
+    end
+else
+    error('Incorrect number of input arguments.');
+end
+    
diff --git a/IQMtools V1.2.2.2/IQMlite/tools/templates/scriptTemplateIQM.m b/IQMtools V1.2.2.2/IQMlite/tools/templates/scriptTemplateIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..eedba36c5bce258c5779a6f805f7744f3935ec7d
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMlite/tools/templates/scriptTemplateIQM.m	
@@ -0,0 +1,45 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% SCRIPT_NAME
+%
+% [PURPOSE]
+% 
+% 
+% [AUTHOR]
+%
+%
+% [DATE]
+% 
+%
+% [DEPENDENCIES]
+% 
+%
+% [INPUT]
+% 
+%   
+%
+% [OUTPUT]
+%
+% [OTHER]
+%
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Clear all - install needed scripts
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+clc;
+clear all;
+close all;
+fclose all;
+restoredefaultpath;
+
+% In the next line, please enter the path to your IQM Tools folder. It can
+% be a relative or an absolute path.
+PATH_IQM            = 'D:\IQM Tools Suite'; 
+oldpath             = pwd(); cd(PATH_IQM); installIQMtools; cd(oldpath);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Intialize compliance mode
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+IQMinitializeCompliance('SCRIPT_NAME.m');
+
diff --git a/IQMtools V1.2.2.2/IQMpro/Contents.m b/IQMtools V1.2.2.2/IQMpro/Contents.m
new file mode 100644
index 0000000000000000000000000000000000000000..c013ffb8abc60584abdb25a88e12e1e7e64699c4
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/Contents.m	
@@ -0,0 +1,218 @@
+% IQM Tools Pro
+% Version 1.2.2 (R2015B) 02.01.2017
+% 
+% IQMpro
+% =======
+% 	Contents                                               - This help text
+% 	SETUP_PATHS_TOOLS_IQMPRO                               - Setup script for IQMpro - please customize according to your needs
+% 	installIQMpro                                          - This script installs the IQMpro package of the IQM Suite of modeling tools
+% 
+% Project ceation and handling (Sysbio/syspharm)
+% ==============================================
+% 	IQMprojectSB                                           - Creates a project object containing models, experiments, measurements, and information needed for parameterestimation
+% 	IQMexportproject                                       - Exports a given project to a projectfolder
+% 	IQMsaveproject                                         - Save an IQMprojectSB object as a binary MATLAB MAT fil with .iqmp as extension
+% 
+% projectSBhandling
+% 	IQManalyzeresiduals                                    - Determines and analyzes the residuals for a given project
+% 	IQMcomparemeasurements                                 - Simulates the experiments in the project for the models in the project and compares the simulated results to the  measurements
+% 	IQMcreaterunestimationscript                           - Creates a run estimation script for the  given project and eventually given modelindex
+% 	IQMexportestimation                                    - Exports the selected estimation settings in an IQMprojectSB into a flat text file
+% 	IQMgetexperiment                                       - Get experiment(s) from the given project
+% 	IQMgetmeasurement                                      - Get measurement(s) from the given project and  experiment
+% 	IQMgetmodel                                            - Get model(s) from the given project
+% 	IQMidentifiability                                     - Performs parameter identifiability analysis for a  given project
+% 	IQMinfo                                                - Quick dump of contents of an IQMprojectSB
+% 	IQMinsilicoexpproj                                     - Runs an in-silico experiment directly on a model and  experiment within a IQMprojectSB
+% 	IQMplotmeasurements                                    - Plots all measurements in the given IQMprojectSB using IQMplot
+% 	IQMreducerateexpressionsProject                        - Function allowing the interactive and iterative reduction of complex kinetic rate expressions
+% 	IQMupdateexperiment                                    - Update or add a experiment in a project
+% 	IQMupdatemeasurement                                   - Update or add a measurement in an experiment of a project
+% 	IQMupdatemodel                                         - Update or add a model in a project
+% 	isIQMprojectSB                                         - Checks if provided input argument is an IQMprojectSB
+% 
+% High performace simulation, using MEX models
+% ============================================
+% 	IQMPsimulate                                           - Function allowing to simulate IQMmodels and MEX simulation functions
+% 	IQMsensitivity                                         - Determine the sensitivities of states and variables with respect to initial conditions and parameters, using a finite difference approach.
+% 	
+%   IQMmakeMEXmodel                                        - Converts an IQMmodel to an executable C-code MEX model
+% 	IQMmakeTempMEXmodel                                    - Used to create a temporary MEX simulation function
+% 
+% Systems Modeling Tools
+% ======================
+% 	IQMparametercorrelation                                - Function for determining parameter correlations based on parametric sensitivities
+% 	IQMmanualtuning                                        - Allows to compare simulated experiments data to measurements and perform manual parameter tuning
+% 	IQMmodeltuning                                         - Allows to compare and tune a model to one or more sets of data
+% 	IQMparamestGUI                                         - Graphical user-interface for running parameter estimation tasks
+% 
+% 	plotIQMP                                               - Allows to compare simulated experiments data to measurements
+% 
+%   IQMparameterestimation                                 - This function performs parameter estimation for  a given IQM project
+% 	defaultcostparameterestimationIQM                      - Default cost function used for parameter estimation. Can be customized and passed to IQMparameterestimation
+% 
+% 	IQMfaboxplot                                           - Plots a box-and-whisker diagram for the estimation data
+% 	IQMfaclustering                                        - Performs hierarchical clustering based on Euclidean distance of the estimated parameter sets
+% 	IQMfacorr                                              - Determines the correlation matrix for the parameter sets determined with the IQMparameterfitanalysis function
+% 	IQMfahist                                              - Plots histograms for the parameter values that have been estimated using the IQMparameterfitanalysis function
+% 	IQMfasigncorr                                          - A matrix of p-values for testing the hypothesis of no significant correlation is computed 
+% 	IQMparameterfitanalysis                                - Parameter estimation for the given project is repeated several times from randomly perturbed starting conditions
+% 
+% 	IQMfadetcorr                                           - Plots detailed pairwise correlations between parameters
+%     
+% Clinical Data Tools
+% ===================
+% IQM Tools use a standard format for clinical data. This format is documented in the function IQMcheckGeneralDataFormat.
+% 
+% GeneralDataFormat
+% 	IQMaddNLMEinfo2data                                    - Adds some analysis and NLME tool relevant information into the provided dataset
+% 	IQMcheckGeneralDataFormat                              - Check the format of a dataset against the requirements of the IQM Tools General Dataset format for clinical data
+% 	IQMcheckGeneralDataFormatHeader                        - Similar to IQMcheckGeneralDataFormat but check only the header names but not internal consistency
+% 	IQMcreateGeneralDataset                                - Create an empty general dataset
+% 	IQMdataAddTimeDependentCovariate                       - Adds user defined time dependent continuous and  categorical covariates to a dataset in the general data format.
+% 	IQMdataAddTimeIndependentCovariate                     - Adds user defined time independent continuous and  categorical covariates to a dataset in the general data format.
+% 	IQMgenerateVALUEfromVALUE_TEXT                         - Generate numerical values in VALUE for VALUETXT definitions
+% 	isGeneralDatasetIQM                                    - Checks if the dataset "data" is in the general dataset format
+% 
+% ProcessData
+% 	IQMdataGetBaselineValues                               - Calculate the baseline values of specified  readouts
+% 	IQMdataGetValues                                       - Extract values for each individual for event NAME from the dataset 
+% 	IQMselectDataEvents                                    - Allows to select events to retain in the dataset
+% 	IQMsubsetData                                          - Allows to subset individual subjects in clinical datasets
+% 
+% TaskDataset
+% 	IQMcheckTaskDataset                                    - Check if dataset in task specific dataset format
+% 	IQMcheckTaskDatasetHeader                              - Similar to IQMcheckTaskDataset but check only the header names but not internal consistency
+% 	IQMconvertGeneral2TaskDataset                          - Augments a dataset in the general data format, used in IQM Tools, with information needed for analysis
+% 	isTaskDatasetIQM                                       - Checks if the dataset "data" is in the general task dataset format
+% 
+% DataExploration
+% 	IQMdataInfoValues                                      - Function to get information about the link between VALUETXT and VALUE
+% 	IQMexploreBLLOQdata                                    - Displays a table with information about the number of BLOQ data per NAME
+% 	IQMexploreCovariateCorrelations                        - Graphical exploration of covariates 
+% 	IQMexploreDataContents                                 - Produces a table, showing the study numbers, the study description, the contained treatment groups in the studies, etc.
+% 	IQMexploreDataMedian                                   - Plot data with respect to the medians of selected readouts
+% 	IQMexploreDataMedianCovariates                         - Plot data with respect to the medians of selected readouts with covariate information
+% 	IQMexploreDataVariability                              - Explore varibility of readouts in the data
+% 	IQMexploreDistribution                                 - Explore distribution of readouts in the data
+% 	IQMexploreDistributionCorrelation                      - Explore distribution of readouts in the data with covariate information
+% 	IQMexploreIndivData                                    - Plot individual data for on readout from the task specific dataset used in IQM Tools
+% 	IQMexploreIndivDataRelation                            - Plot individual data for multiple readouts from the task specific dataset used in IQM Tools
+% 	IQMexploreMissingEventRate                             - Rate of missing events over NT by group
+% 	IQMexploreMissingObservationGraphics                   - Missing observations in the dataset
+% 	IQMexploreNTvsTIME                                     - NT vs TIME
+% 	IQMexplorePDdataWrapper                                - Function generating typical plots for PD data - bot continuous and categorical
+% 	IQMexplorePKdataWrapper                                - Function generating typical standard plots for dose and PK data
+% 	IQMexploreSummaryStats                                 - Produces summary statistics for the provided dataset
+% 
+% NLME Dataset Preparation
+% ========================
+% DataCleaning
+% 	IQMcleanImputeCovariates                               - Imputation of missing covariates
+% 	IQMcleanRemoveIGNOREDrecords                           - Removes all records from the dataset that have non empty (or NaN) entries in the IGNORE column
+% 	IQMcleanRemovePlaceboSubjects                          - Removes all subjects which only received 0 doses or  no doses at all
+% 	IQMcleanRemoveRecordsSUBJECTs                          - Removes defined subjects (by USUBJID) and records (by index of  the row in which the record is located)
+% 	IQMcleanRemoveSubjectsNoObservations                   - Removes all subjects which do not have any  observations (defined by EVID=0 and MDV=0)
+% 	IQMcleanRemoveZeroDoses                                - Removes all dose records with 0 amount
+% 
+% BLOQhandling
+% 	IQMhandleBLOQdata                                      - Allows handling of M1,3,4,5,6,7 methods for BLOQ
+% 
+% DataNLMEConversion
+% 	IQMaddIndivRegressionParamFromNLMEproject              - Allows to add columns to dataset to be used as regression parameters in the model
+% 	IQMcheckNLMEdatasetHeader                              - Checks if the minimal required elements are present in an NLME dataset that is going to be used for fitting
+% 	IQMconvertTask2NLMEdataset                             - Converts a task specific general dataset into a dataset that is suitable for NLME analysis in NONMEM and MONOLIX
+% 	IQMgetNLMEdataHeader                                   - Generates information about the dataset header needed for NLME model creation
+% 	IQMgetRegressionParameters                             - Returns information about regression parameters in an IQMmodel
+% 
+% DataNLMEInfo
+% 	IQMinfoNLMEdata                                        - Provides information mapping ADM and doses, YTYPE and readouts
+% 
+%     
+% NLME Parameter Estimation Tools Interfaces
+% ==========================================
+% MONOLIX
+% 	IQMcreateMLXTRANfile                                   - Creates an MLXTRAN structural model file based on the IQMmodel and the dosing information
+% 	IQMcreateMONOLIXproject                                - Creates a Monolix/MLXTRAN project from an IQMmodel and an IQMdosing scheme
+% 	IQMrunMONOLIXproject                                   - Runs a specified Monolix project
+% 	IQMrunMONOLIXprojectFolder                             - Runs all the Monolix projects in the specified folder
+% 	IQMsampleMONOLIXparam                                  - Samples parameters from both uncertainty and variability distributions from a Monolix fit
+% 	isMONOLIXprojectIQM                                    - Checks if given project path is a Monolix project
+% 
+% NONMEM
+% 	IQMcreateNONMEMproject                                 - Creates a NONMEM project from an IQMmodel and an IQMdosing scheme
+% 	IQMcreateNONMEMresultsTable                            - Parses the results of a NONMEM run and reports them in a similar manner as in the MONOLIX pop_parameters.txt file
+% 	IQMplotConvergenceNONMEM                               - Plots the convergence plots for NONMEM 
+% 	IQMrunNONMEMproject                                    - Runs a specified NONMEM project
+% 	IQMrunNONMEMprojectFolder                              - Runs all the NONMEM projects in the specified folder
+% 	IQMsampleNONMEMparam                                   - Samples parameters from both uncertainty and variability distributions from a NONMEM fit
+% 	isNONMEMprojectIQM                                     - Checks if given project path is a NONMEM project
+% 
+% NLME Modeling Tools
+% ===================
+% NMLEprojectHandling
+% 	IQMcreateNLMEmodelGENcode                              - Generates code that can be used to generate a NONMEM or MONOLIX NLME  project
+% 	IQMcreateNLMEproject                                   - Creates a NONMEM or MONOLIX roject from an IQMmodel and an IQMdosing scheme
+%   IQMcreateGeneralLinearNLMEproject                      - This function allows to generate a general linear model using NONMEM or MONOLIX
+% 	IQMgetNLMEfitIndivPopMeanParam                         - Returns the individual population mean parameters for all subjects in the NLME fit
+% 	IQMgetNLMEfitIndivparam                                - Returns the individual parameters from an NLME fit (NONMEM or MONOLIX)
+% 	IQMgetNLMEparameterResults                             - Parses an NLME project folder and returns the parameter estimates and additional information
+% 	IQMrunNLMEproject                                      - Runs a specified NLME project (NONMEM or MONOLIX)
+% 	IQMrunNLMEprojectFolder                                - Runs all NLME projects (NONMEM and MONOLIX) in the specified folder
+% 	IQMsampleNLMEfitParam                                  - Samples parameters from both uncertainty and variability distributions from a NLME fit
+% 	isNLMEprojectIQM                                       - Checks if given project path is an NMLE project folder (NONMEM or MONOLIX)
+% 
+% NLMEfitAnalysis
+% 	IQMfitanalysisETAvsCOV                                 - Plot the individual variations over covariates and categorical covariates
+% 	IQMfitanalysisGOFplots                                 - Produces several plots that can be used for checking the goodness of fit
+% 	IQMfitanalysisGeneralPlots                             - Wrapper for different fit analysis functions that plot things that are independent of a specific output of the model
+% 	IQMfitanalysisIndividualFits                           - Plots individual fits and population prediction against observed data over time
+% 	IQMfitanalysisOutlierDetection                         - Searches for outliers and displays info about them
+% 	IQMfitanalysisOutputPlots                              - Wrapper for different fit analysis functions that plot things that are dependent of a specific output of the model
+% 	IQMfitanalysisRandomEffects                            - Plots information about the random effects 
+% 
+% NLMEfitSummary
+% 	IQMfitsummaryAll                                       - Wrapper for IQMfitsummaryMetrics, IQMfitsummaryParameters, IQMfitsummaryCovariances, IQMfitsummaryCovariates 
+% 	IQMfitsummaryCovariances                               - Generates information about covariance estimates of all projects in the same folder
+% 	IQMfitsummaryCovariates                                - Generates information about covariate estimates of all projects in the same folder
+% 	IQMfitsummaryMetrics                                   - Generates information about model metrics of all projects in the same folder
+% 	IQMfitsummaryParameters                                - Generates information about parameter estimates of all projects in the same folder
+% 	IQMfitsummaryTable                                     - Creates a typical report-type NLME model parameter table
+% 
+% NLMEtools
+% 	IQMassessInformationContent                            - Allows to predict the information content in data of future studies, given the planned dosing and observation schedule
+% 	IQMbootstrap                                           - Runs a bootstrap analysis on the provided NLME project folder
+% 	IQMcompareModels                                       - Allows to compare the structural models for different estimation results from NLME models
+% 	IQMcovariateAssessmentUncertainty                      - Assesses the changes that a covariates introduces on the model parameters, relative to a reference individual
+% 	IQMcreateVPC                                           - Generates a VPC for a given NLMEproject
+% 	IQMcreateVPCplot                                       - Plots a VPC without the need to re-run the simulations
+% 	IQMcreateVPCstratified                                 - Generates a stratified VPC for a given NLMEproject
+% 	IQMduplicateNLMEmodel                                  - Duplicates a NLME model, specified by the path to its project folder (modelSource) to a new path (modelDestination)
+% 	IQMscm                                                 - Stepwise covariate search, using forward inclusion / backward  elimination
+% 	IQMtrialGroupSimulation                                - Performs a trial simulation for a single treatment arm
+% 
+% IQM Tools Workflow Tools
+% ========================
+% PopPKmodel
+% 	IQMbuildPopPKModelSpace                                - Assess a user defined popPK model subspace
+% 	IQMcleanPopPKdataWrapper                               - Wrapper for different cleaning functions for standard popPK datasets
+% 	IQMcomparePopPKmodels                                  - Allows to compare different popPK models created with the popPK workflow in IQM Tools
+% 	IQMcreatePopPKstratifiedVPC                            - Creates a stratified VPC for a given model on a given dataset
+% 	IQMscmPopPK                                            - Stepwise covariate search, using forward inclusion / backward  elimination
+% 	IQMsimulatePopPKmodel                                  - Allows to simulate PK models for user defined dosing schemes
+% 
+% Simplified PopPK workflow
+%   IQMsimplifiedPopPKinit 								   - Initialize simplified popPK workflow
+% 	IQMsimplifiedPopPKcheckData 						   - Check dataset format and do some preparations
+%   IQMsimplifiedPopPKexploreData 						   - Explore data 
+%   IQMsimplifiedPopPKgetNLMEdata 						   - Get NLME dataset and header info
+%   IQMsimplifiedPopPKmodel 							   - Build popPK model functions
+%
+% PopPDmodel
+% 	IQMcleanPopPDdataWrapper                               - Wrapper for different cleaning functions for standard popPD datasets
+% 
+% Auxiliary
+% =========
+% 	lookforIQMP                                            - Allows to search IQM Pro folders recursively for a given text
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
diff --git a/IQMtools V1.2.2.2/IQMpro/LICENSE.txt b/IQMtools V1.2.2.2/IQMpro/LICENSE.txt
new file mode 100644
index 0000000000000000000000000000000000000000..b32b29f619008e4ab46d2e734cdc831bb2ef0557
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/LICENSE.txt	
@@ -0,0 +1,29 @@
+                BSD 3-clause "New" or "Revised" License
+
+Copyright (c) 2016 IntiQuan GmbH
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+  this list of conditions and the following disclaimer in the documentation
+  and/or other materials provided with the distribution.
+
+* Neither the name of IQM Tools nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/IQMtools V1.2.2.2/IQMpro/SETUP_PATHS_TOOLS_IQMPRO.m b/IQMtools V1.2.2.2/IQMpro/SETUP_PATHS_TOOLS_IQMPRO.m
new file mode 100644
index 0000000000000000000000000000000000000000..4fed82542cdade9bb73a9ac08fe1fbbb4c919d7b
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/SETUP_PATHS_TOOLS_IQMPRO.m	
@@ -0,0 +1,50 @@
+% In this file you need to provide the names and potentially the paths to
+% the executables for tools, such as NONMEM and MONOLIX.
+% 
+% If executables in the system path, then only the names of the executables are needed.
+%
+% It is possible to define paths for Windows and Unix (use Unix for Mac) independently,
+% allowing to use the package on different systems without the need to
+% re-edit the paths. If a tool is not available on a system, then just
+% leave the path empty.
+
+% In the case that a queuing system is used (only under unix),
+% then please provide here the command that reads out the queue. It is 
+% assumed that the command that runs a NONMEM or MONOLIX job via the queue
+% returns the jobID as a number. It is also assumed that this number
+% appears when the queue status command is called:
+PATH_SYSTEM_QUEUE_STATUS_UNIX               = '';
+% If no queuing system used then keep this variable empty ('')
+
+% NONMEM (currently tested version: 7.2 and 7.3)
+PATH_SYSTEM_NONMEM_WINDOWS                  = 'nmfe73';
+PATH_SYSTEM_NONMEM_UNIX                     = 'nmfe73';                            
+
+% NONMEM PARALLEL
+PATH_SYSTEM_NONMEM_PARALLEL_WINDOWS         = 'nmfe73par';
+PATH_SYSTEM_NONMEM_PARALLEL_UNIX            = 'nmfe73par';                         
+
+% nmfe73par is assumed to be a shell script with the following calling
+% syntax:   "nmfe73par NRNODES controlfile outputfile". If you do not have
+% one available, please ask your sysadmin to generate on for you
+
+% MONOLIX STANDALONE (ONLY VERSION 4.3.2 and 4.3.3 supported at the moment)
+PATH_SYSTEM_MONOLIX_WINDOWS                 = 'C:\INSTALL\Monolix\Monolix432s\bin\Monolix.bat';
+PATH_SYSTEM_MONOLIX_UNIX                    = '.../bin/Monolix.sh';                % Define UNIX path for Mac
+% MONOLIX 4.3.3 on Mac typically installs in the following folder. If you have got a Mac,
+% and have Monolix 4.3.3 installed, uncomment the following line:
+% PATH_SYSTEM_MONOLIX_UNIX = '/Applications/Monolix-4.3.3s.app/Contents/MacOS/run_monolix.sh';
+
+% MONOLIX STANDALONE PARALLEL (version >= 4.3.2)
+PATH_SYSTEM_MONOLIX_PARALLEL_WINDOWS        = '';
+PATH_SYSTEM_MONOLIX_PARALLEL_UNIX           = '';               				% Define UNIX path for Mac
+
+% Name of MATLAB parallel toolbox profile
+MATLABPOOL_PROFILE                          = 'local';
+
+% Preferred ordering criterion for tables of NLME estimates
+% Only impacts dislay (ordering) in output tables)
+NLME_ORDER_CRITERION                        = 'BIC'; % Alternative: 'AIC', 'BIC', or 'OBJ'
+
+% Define default number of processors to use in case that parallel toolbox available
+N_PROCESSORS_PAR                            = 4;
diff --git a/IQMtools V1.2.2.2/IQMpro/auxiliary/data/checkDataColumnsIQM.m b/IQMtools V1.2.2.2/IQMpro/auxiliary/data/checkDataColumnsIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..71b739ac696bb4c98a095b32749ba7f62981eef0
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/auxiliary/data/checkDataColumnsIQM.m	
@@ -0,0 +1,46 @@
+function [] = checkDataColumnsIQM(data,COLNAMES)
+% This function checks if the COLNAMES are present as columns in the table
+% data. If not or not all then an error is shown.
+%
+% [SYNTAX]
+% [] = checkDataColumnsIQM(data,COLNAMES)
+%
+% [INPUT]
+% data:             Dataset in MATLAB table format
+% COLNAMES:         String of cell-array of strings to test if these names
+%                   exist as column names in the table
+%
+% [OUTPUT]
+% Error is shown if one or more of the COLNAMES do not exist as columns in
+% the data table
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% If COLNAMES empty then return
+if isempty(COLNAMES),
+    return
+end
+
+% Check input arguments
+if ~istable(data),
+    error('Input argument is not a MATLAB table.');
+end
+if ischar(COLNAMES),
+    COLNAMES = {COLNAMES};
+end
+
+% Check COLNAMES
+colnamestable = data.Properties.VariableNames;
+errorText = '';
+for k=1:length(COLNAMES),
+    if ~isempty(COLNAMES{k}),
+        if isempty(strmatchIQM(COLNAMES{k},colnamestable,'exact')),
+            errorText = sprintf('%sThe dataset does not contain the column "%s".\n',errorText,COLNAMES{k});
+        end
+    end
+end
+
+% Handle error if needed
+if ~isempty(errorText),
+    error(errorText);
+end
diff --git a/IQMtools V1.2.2.2/IQMpro/auxiliary/data/createCarryForwardValuesIQM.m b/IQMtools V1.2.2.2/IQMpro/auxiliary/data/createCarryForwardValuesIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..1d4f357de797e6300ecf9775ec0108e18111cfc5
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/auxiliary/data/createCarryForwardValuesIQM.m	
@@ -0,0 +1,38 @@
+function [CFvector] = createCarryForwardValuesIQM(vector,FLAG)
+% This function takes the vector containing numeric values and NaN values
+% and produces a full vector by carry-forward.
+%
+% [SYNTAX]
+% [CFvector] = createCarryForwardValuesIQM(vector)
+% [CFvector] = createCarryForwardValuesIQM(vector,FLAG)
+%
+% [INPUT]
+% vector:           Numeric vector with entries numeric and NaN
+% FLAG:             =1: first non-NaN value will be used for leading NaN
+%                   values.
+%                   =0: leading NaN values will be kept (default).
+%
+% [OUTPUT]
+% CFvector:         Transformed vector with carried forward values
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle variable input arguments
+if nargin<2,
+    FLAG = 0;
+end
+
+CFvector = NaN(size(vector));
+ixNumber = find(~isnan(vector));
+for k2=1:length(ixNumber),
+    CFvector(ixNumber(k2):end) = vector(ixNumber(k2));
+end
+
+% Handle leading NaN values if desired ... by setting to first non-NaN
+% value
+if FLAG,
+    ix = find(~isnan(CFvector));
+    if ~isempty(ix) && ix(1)>1,
+        CFvector(1:ix(1)-1) = CFvector(ix(1));
+    end
+end
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/auxiliary/data/echangeSpacesDataIQM.m b/IQMtools V1.2.2.2/IQMpro/auxiliary/data/echangeSpacesDataIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..52c7b7087bd1ba23568ad5e34776f2925e08d286
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/auxiliary/data/echangeSpacesDataIQM.m	
@@ -0,0 +1,40 @@
+function [dataNew] = echangeSpacesDataIQM(data)
+% This function removes all spaces in string elements in a matlab table
+% and exchanges them agains ":::". This is sometimes needed when
+% outdated software (like NONMEM) is unable to handle spaces in strings. I
+% know this is a feature and not bug in the view of NONMEM users - I
+% personally think this is not acceptable.
+%
+% The function restoreSpacesDataIQM() will reverse this change.
+%
+% [SYNTAX]
+% [dataNew] = echangeSpacesDataIQM(data)
+%
+% [INPUT]
+% data:             Dataset in MATLAB table format or string 
+%
+% [OUTPUT]
+% dataNew:          Dataset in MATLAB table format or string with all spaces (' ')
+%                   exchanged with ':::' 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Check input arguments
+if istable(data),
+    % Exchange all spaces in string variables with ':::' in dataset
+    varNames = data.Properties.VariableNames;
+    for k=1:length(varNames),
+        if ~isnumeric(data.(varNames{k})),
+            data.(varNames{k}) = strrep(data.(varNames{k}),' ',':::');
+        end
+    end
+    % Assign output variable
+    dataNew = data;
+elseif ischar(data),
+    dataNew = strrep(data,' ',':::');    
+else
+    error('Input argument is not a MATLAB table or a string.');
+end
+
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/auxiliary/data/findNonEmptyCellsIQM.m b/IQMtools V1.2.2.2/IQMpro/auxiliary/data/findNonEmptyCellsIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..1dc39fdb76bf5012af5355498b4cc693af93d889
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/auxiliary/data/findNonEmptyCellsIQM.m	
@@ -0,0 +1,34 @@
+function [ix] = findNonEmptyElementsIQM(data,COLUMN)
+% This function searches column COLUMN in dataset data for non-empty
+% entries and returns the indices of these columns. Not so interesting for
+% numeric columns as this can be done without this function easy but for
+% cell-array string columns this is a good function.
+%
+% [SYNTAX]
+% [ix] = findNonEmptyElementsIQM(data,COLUMN)
+%
+% [INPUT]
+% data:             Dataset in MATLAB table format
+% COLUMN:           Column name of column to search for non emtpy entries
+%
+% [OUTPUT]
+% ix:               Indices of rows in dataset with non empty COLUMN.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Check input arguments
+if ischar(data),
+    data = IQMloadCSVdataset(data);
+end
+
+if ~istable(data),
+    error('Input argument is not a MATLAB table.');
+end
+
+% Get ix
+if isnumeric(data.(COLUMN)),
+    ix = find(~isnan(data.(COLUMN)));
+else
+    ix = setdiff(1:height(data),strmatchIQM('',data.(COLUMN),'exact'));
+end
+
diff --git a/IQMtools V1.2.2.2/IQMpro/auxiliary/data/restoreSpacesDataIQM.m b/IQMtools V1.2.2.2/IQMpro/auxiliary/data/restoreSpacesDataIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..26bbb62fd00dd41847326c51b433e67a98e2c459
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/auxiliary/data/restoreSpacesDataIQM.m	
@@ -0,0 +1,40 @@
+function [dataNew] = restoreSpacesDataIQM(data)
+% This function removes ":::" in string elements in a matlab table
+% and exchanges them against " ". This is sometimes needed when
+% outdated software (like NONMEM) is unable to handle spaces in strings. I
+% know this is a feature and not bug in the view of NONMEM users - I
+% personally think this is not acceptable.
+%
+% The function echangeSpacesDataIQM() is doing the opposite.
+%
+% [SYNTAX]
+% [dataNew] = restoreSpacesDataIQM(data)
+%
+% [INPUT]
+% data:             Dataset in MATLAB table format or string 
+%
+% [OUTPUT]
+% dataNew:          Dataset in MATLAB table format or string with all ':::'
+%                   exchanged with ' ' 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Check input arguments
+if istable(data),
+    % Exchange all spaces in string variables with ':::' in dataset
+    varNames = data.Properties.VariableNames;
+    for k=1:length(varNames),
+        if ~isnumeric(data.(varNames{k})),
+            data.(varNames{k}) = strrep(data.(varNames{k}),':::',' ');
+        end
+    end
+    % Assign output variable
+    dataNew = data;
+elseif ischar(data),
+    dataNew = strrep(data,':::',' ');
+else
+    error('Input argument is not a MATLAB table or a string.');
+end
+
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/auxiliary/getMONOLIXversionIQM.m b/IQMtools V1.2.2.2/IQMpro/auxiliary/getMONOLIXversionIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..13d88760ea2ec02e5a89db60b2d85ee719645001
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/auxiliary/getMONOLIXversionIQM.m	
@@ -0,0 +1,37 @@
+function [MLXversion] = getMONOLIXversionIQM()
+% Function tries to determine the MONOLIX version that is used with IQM
+% Tools. Since Lixoft does not understand the need of some users to access
+% the version number by a script we try to infer the version from the path
+% in which MONOLIX is installed.
+%
+% MLXversion: output argument with the following possibilities
+%       '432': Version 4.3.2
+%       '433': Version 4.3.3
+%       'unknown': Not identified
+
+% Get the MONOLIX path
+PATH_MONOLIX = getNLMEtoolInfoIQM();
+
+% Remove special signs
+test = regexprep(PATH_MONOLIX,'\W','');
+
+% Check 4.3.2
+ix432 = strfind(test,'432');
+
+% Check 4.3.3
+ix433 = strfind(test,'433');
+
+% Assign output argument
+if isempty(ix432) && isempty(ix433),
+    MLXversion = 'unknown';
+end
+
+if ~isempty(ix432) && isempty(ix433),
+    MLXversion = '432';
+end
+ 
+if isempty(ix432) && ~isempty(ix433),
+    MLXversion = '433';
+end
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/auxiliary/getNLMEtoolInfoIQM.m b/IQMtools V1.2.2.2/IQMpro/auxiliary/getNLMEtoolInfoIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..1e4818bd378dfa137a2807e3df681e81e52584b3
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/auxiliary/getNLMEtoolInfoIQM.m	
@@ -0,0 +1,18 @@
+function [PATH_MONOLIX,PATH_MONOLIX_PAR,PATH_NONMEM,PATH_NONMEM_PAR] = getNLMEtoolInfoIQM()
+% Function loads and returns the paths to MONOLIX and NONMEM executables, set-up in the 
+% SETUP_PATHS_TOOLS_IQMPRO file
+
+% Run the SETUP_NLME_TOOLS script
+SETUP_PATHS_TOOLS_IQMPRO
+
+if isunix,
+    PATH_MONOLIX        = PATH_SYSTEM_MONOLIX_UNIX;
+    PATH_MONOLIX_PAR    = PATH_SYSTEM_MONOLIX_PARALLEL_UNIX;
+    PATH_NONMEM         = PATH_SYSTEM_NONMEM_UNIX;
+    PATH_NONMEM_PAR     = PATH_SYSTEM_NONMEM_PARALLEL_UNIX;
+else
+    PATH_MONOLIX        = PATH_SYSTEM_MONOLIX_WINDOWS;
+    PATH_MONOLIX_PAR    = PATH_SYSTEM_MONOLIX_PARALLEL_WINDOWS;
+    PATH_NONMEM         = PATH_SYSTEM_NONMEM_WINDOWS;
+    PATH_NONMEM_PAR     = PATH_SYSTEM_NONMEM_PARALLEL_WINDOWS;
+end
diff --git a/IQMtools V1.2.2.2/IQMpro/auxiliary/lookforIQMP.m b/IQMtools V1.2.2.2/IQMpro/auxiliary/lookforIQMP.m
new file mode 100644
index 0000000000000000000000000000000000000000..719bc006efcc61ede4ea02c4910f63146fd37807
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/auxiliary/lookforIQMP.m	
@@ -0,0 +1,37 @@
+function [] = lookforIQMP(text)
+% lookforIQM: searches all m-files in the IQM Pro folder tree for the 
+% text given as argument. It displays the filenames in which the text
+% appears and additionally opens the files in the editor.
+
+old = pwd;
+cd([fileparts(which('installIQMpro')) '/..']);
+try, recurseFolder('IQMpro',text); catch end
+cd(old);
+return
+
+function recurseFolder(folder,text)
+% change folder
+cd(folder);
+% check all m files in folder for the text
+mfiles = dir('*.m');
+for k = 1:length(mfiles),
+    % read file
+    content = fileread(strcat(mfiles(k).name));
+    if strfind(content,text),
+        disp(mfiles(k).name);
+        edit(mfiles(k).name);
+    else
+%        edit(mfiles(k).name);
+    end
+end
+% recurse in all subfolders
+allfiles = dir;
+for k = 1:length(allfiles),
+    if ~strcmp(allfiles(k).name,'..') && ~strcmp(allfiles(k).name,'.') && allfiles(k).isdir == 1,
+        recurseFolder(allfiles(k).name,text);
+    end
+end
+% up we go
+cd ..
+return
+
diff --git a/IQMtools V1.2.2.2/IQMpro/auxiliary/moddosparsing/basicmodelparsingIQM.m b/IQMtools V1.2.2.2/IQMpro/auxiliary/moddosparsing/basicmodelparsingIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..b27f2fe2cf272b6e4bdf6553dd23a4abb3cf1123
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/auxiliary/moddosparsing/basicmodelparsingIQM.m	
@@ -0,0 +1,363 @@
+function [modelinfo] = basicmodelparsingIQM(model)
+% basicmodelparsingIQM: Basic parsing of the model as preparation for 
+% export of population modeling formats (e.g. MONOLIX/NONMEM). The
+% function returns the following structure:
+%
+% modelinfo.model:             the model
+% modelinfo.inputs.name:       input name
+% modelinfo.inputs.factors:    cell-array with input factors
+% modelinfo.inputs.terms:      cell-array with complete input string (for
+%                              simpler removing)
+% modelinfo.inputs.stateindex: vector with stateindices to which the same
+%                              input is applied
+% modelinfo.inputs.parindex:   index of the INPUT* parameter definition in
+%                              the IQMmodel (used to remove it when
+%                              parameters are written to (e.g.) an MLXTRAN
+%                              file).   
+% modelinfo.outputs.name:      output name
+% modelinfo.outputs.formula:   output formula
+% modelinfo.outputs.notes:     output notes
+% modelinfo.outputs.varindex:  index of output in model variables
+% modelinfo.param_est.name:    name of parameter to estimate 
+% modelinfo.param_est.notes:   estimated parameter notes
+% modelinfo.param_est.value0:  initial guess for parameter
+% modelinfo.param_est.parindex: index of parameter in parameters
+% modelinfo.param_reg.name:    name of regression parameter
+% modelinfo.param_reg.notes:   regression parameter notes
+% modelinfo.param_reg.parindex: index of reg param in parameters
+% modelinfo.param_reg.varindex: index of reg param in variables
+% modelinfo.param_pk.name:     name of parameter to define in PK section
+%                              (this is MLXTRAN specific but might be
+%                              useful for other applications to).
+% modelinfo.param_pk.value:    value of parameter
+% modelinfo.param_pk.parindex: index or parameter in model
+% modelinfo.param_pk.notes:    notes of the parameters
+%
+% Only very basic error handling is done. More intensive error checking is
+% done later, dependent on the tool that is going to be used for
+% pop-modelling (different features might be allowed).
+%
+% USAGE:
+% ======
+% [modelinfo] = basicmodelparsingIQM(model) 
+%
+% model: IQMmodel
+%
+% Output Arguments:
+% =================
+% modelinfo: see structure definition above
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check input
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isIQMmodel(model),
+    error('First input argument is not an IQMmodel.');
+end
+ms = struct(model);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK MODEL: INPUTS ONLY ON STATES?
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~inputsonlyonstatesIQM(model),
+    error('The model contains ''INPUT*'' identifiers on other elements than ODEs.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INITIALIZE OUTPUT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+inputsStruct = struct('name',{},'stateindex',{},'parindex',{},'factors',{},'terms',{});
+outputsStruct = struct('name',{},'formula',{},'notes',{});
+param_estStruct = struct('name',{},'notes',{},'value0',{},'parindex',{});
+param_regStruct = struct('name',{},'notes',{},'parindex',{},'varindex',{});
+param_pkStruct = struct('name',{},'notes',{},'value',{},'parindex',{});
+modelinfo = struct('model',model,'inputs',inputsStruct,'outputs',outputsStruct,'param_est',param_estStruct,'param_reg',param_regStruct,'param_pk',param_pkStruct);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DETERMINE PARAMETERS TO BE ESTIMATED
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for k=1:length(ms.parameters),
+    if ~isempty(strfind(ms.parameters(k).notes,'<estimate>')),
+        modelinfo.param_est(end+1).name = ms.parameters(k).name;
+        modelinfo.param_est(end).value0 = ms.parameters(k).value;
+        modelinfo.param_est(end).notes = ms.parameters(k).notes;
+        modelinfo.param_est(end).parindex = k;
+    end
+end
+% if no parameters to be estimated => error!
+if isempty(modelinfo.param_est),
+    error('No parameters in model selected for estimation.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DETERMINE REGRESSION PARAMETERS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Regression parameters can be defined as parameters or as variables in the
+% IQMmodel. The latter allows to implement lookup-tables in the model (if
+% the use of experiment descriptions is not considered).
+for k=1:length(ms.parameters),
+    if ~isempty(strfind(ms.parameters(k).notes,'<regression>')),
+        modelinfo.param_reg(end+1).name = ms.parameters(k).name;
+        modelinfo.param_reg(end).notes = strrep(ms.parameters(k).notes,'<regression>','');
+        modelinfo.param_reg(end).parindex = k;
+        modelinfo.param_reg(end).varindex = [];
+    end
+end        
+for k=1:length(ms.variables),
+    if ~isempty(strfind(ms.variables(k).notes,'<regression>')),
+        modelinfo.param_reg(end+1).name = ms.variables(k).name;
+        modelinfo.param_reg(end).notes = strrep(ms.variables(k).notes,'<regression>','');
+        modelinfo.param_reg(end).parindex = [];
+        modelinfo.param_reg(end).varindex = k;
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET MODEL INPUT INFORMATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[statenames,ODEs] = IQMstates(model);
+% get model input names (unique)
+inputnames = {};
+inputodeindex = [];
+for k=1:length(ODEs),
+    y = regexp(ODEs{k},'(INPUT\w*)','tokens');
+    for k2=1:length(y),
+        x = y{k2};
+        inputnames{end+1} = x{1};
+        inputodeindex(end+1) = k;
+    end
+end    
+% add the current into to the structure and do basic error checking (same
+% input is not allowed to appear twice in same ODE)
+for k=1:length(inputnames),
+    inputindex = strmatchIQM(inputnames{k},{modelinfo.inputs.name},'exact');
+    if isempty(inputindex),
+        modelinfo.inputs(end+1).name = inputnames{k};
+        modelinfo.inputs(end).stateindex = inputodeindex(k);
+    else
+        modelinfo.inputs(inputindex).stateindex = [modelinfo.inputs(inputindex).stateindex inputodeindex(k)];
+    end
+end
+for k=1:length(modelinfo.inputs),
+    if length(modelinfo.inputs(k).stateindex) ~= length(unique(modelinfo.inputs(k).stateindex)),
+        error('Input ''%s'' appears more than once in the same ODE.',modelinfo.inputs(k).name);
+    end
+end
+% determine the input factors
+for k=1:length(modelinfo.inputs),
+    stateindex = modelinfo.inputs(k).stateindex;
+    for k2=1:length(stateindex),
+        [factor, term] = getInputFactorFromODE(ODEs{stateindex(k2)},modelinfo.inputs(k).name);
+        modelinfo.inputs(k).factors{end+1} = factor;
+        modelinfo.inputs(k).terms{end+1} = term;
+    end
+end
+% determine the indices of the IQMmodel parameters that define the nominal
+% input parameters
+for k=1:length(modelinfo.inputs),
+    index = strmatchIQM(modelinfo.inputs(k).name,{ms.parameters.name},'exact');
+    if isempty(index),
+        error('Input ''%s'' is used in the model but undefined as a parameter.',modelinfo.inputs(k).name);
+    end
+    modelinfo.inputs(k).parindex = index;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET MODEL OUTPUT INFORMATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Outputs are defined be OUTPUT1 = ..., OUTPUT2 = ...
+% The ordering is done by the number after OUTPUT.
+searchOutput = 1;
+indexOutput = 1;
+allvarnames = {ms.variables.name};
+while (searchOutput == 1),
+    searchOutputName = sprintf('OUTPUT%d',indexOutput);
+    index = strmatchIQM(searchOutputName,allvarnames,'exact');
+    if ~isempty(index),
+        modelinfo.outputs(end+1).name = searchOutputName;
+        modelinfo.outputs(end).formula = ms.variables(index).formula;
+        modelinfo.outputs(end).notes = ms.variables(index).notes;
+        modelinfo.outputs(end).varindex = index;
+        % search for next output
+        indexOutput = indexOutput + 1;
+    else
+        % No output with given index found => stop the search
+        searchOutput = 0;
+    end
+end
+% Error if no outputs are detected
+if isempty(modelinfo.outputs),
+    error('No outputs have been defined in the model using the "OUTPUT*" identifier.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE PARAMETERS etc. FOR INPUT FACTORS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Parameters used in the prefactors of inputs are either estimated, 
+% defined as regression variables, or defined in the PK section of an 
+% MLXTRAN file (and not in the ODE section). For that we need to determine 
+% the parameters that are to be put
+% into the PK section. This is MLXTRAN specific but the information
+% collected might come handy also for other export formats(?).
+% The information is stored in the following part of the structure:
+%
+% modelinfo.param_pk.name:     name of parameter to define in PK section
+%                              (this is MLXTRAN specific but might be
+%                              useful for other applications to).
+% modelinfo.param_pk.value:    value of parameter
+% modelinfo.param_pk.parindex: index or parameter in model
+% modelinfo.param_pk.notes:    notes of the parameters
+% 
+% All input pre-factors are only allowed to contain parameters No states,
+% no other parameters, no variables. => error if
+% 1) get all pre-factors
+allfactors = {};
+for k=1:length(modelinfo.inputs),
+    temp = modelinfo.inputs(k).factors;
+    allfactors = {allfactors{:} temp{:}};
+end
+% 2) get all parameters ... remove the ones to be estimated
+pn = IQMparameters(model);               % all 
+pnest = {modelinfo.param_est.name};     % to be estimated
+pnreg = {};
+for k=1:length(modelinfo.param_reg),
+    if ~isempty(modelinfo.param_reg(k).parindex),
+        pnreg{end+1} = modelinfo.param_reg(k).name;
+    end
+end
+pnnotest = setdiff(pn,{pnest{:} pnreg{:}});           % not to be estimated
+% 3) Check if parameter that are not estimated appear in the factors and
+% add them to the param_pk field of the modelinfo structure
+for k=1:length(allfactors),
+    test = ['#' allfactors{k} '#'];
+    for k2=1:length(pnnotest),
+        index = regexp(test,['\W' pnnotest{k2} '\W'], 'once' );
+        if ~isempty(index),
+            % the parameter is not estimated an appears in the input factor
+            % check if it is already added to the param_pk field and if not
+            % => add it 
+            if isempty(strmatchIQM(pnnotest{k2},{modelinfo.param_pk.name},'exact')),
+                parindex = strmatchIQM(pnnotest{k2},pn,'exact');
+                modelinfo.param_pk(end+1).name = ms.parameters(parindex).name;
+                modelinfo.param_pk(end).value = ms.parameters(parindex).value;
+                modelinfo.param_pk(end).parindex = parindex;
+                modelinfo.param_pk(end).notes = ms.parameters(parindex).notes;
+            end
+        end
+    end
+end
+% 4) Check state, variable, reaction appearance in factors (if yes => error)
+sn = IQMstates(model);
+vn = IQMvariables(model);
+rn = IQMreactions(model);
+allother = {sn{:} vn{:} rn{:}};
+for k=1:length(allfactors),
+    test = ['#' allfactors{k} '#'];
+    for k2=1:length(allother),
+        index = regexp(test,['\W' allother{k2} '\W'], 'once' );
+        if ~isempty(index),
+            disp('===============================================================================================');
+            disp(sprintf('The model component ''%s'' appears in an input pre-factor ''%s''.\nPlease note that no states, variables, or reactions are allowed to\nappear in these pre-factors. Only parameters!',allother{k2},allfactors{k}));
+            disp(' ');
+            disp('You might need to rearrange manually some equations from the ODE section in MLXTRAN to the PK section.');
+            disp('===============================================================================================');
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% ITS DONE ... RETURN
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+return
+
+
+        
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EXTRACT INPUT TERMS and check for validity
+% Only prefixes/prefactors to inputs allowed - otherwise error
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [factor,term] = getInputFactorFromODE(ODE,name)
+% find the start-index for the input name
+si = strfind(ODE,name);
+% get ODE text before input
+ODEpre = strtrim(ODE(1:si-1));
+ODEpost = strtrim(ODE(si+length(name):end));
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DO SOME CHECKS FIRST: 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% 1) the INPUT* identifier needs to be the last element in the input term.
+% => ODEpost needs to start by "+" or "-" and contain as many opening
+% parentheses than closing ones. Because otherwise INPUT* would be in at
+% least one parenthesis. => Not allowed. 
+if ~isempty(ODEpost),
+    if ODEpost(1) ~= '+' && ODEpost(1) ~= '-',
+        error('The ''%s'' identifier must be the last element in the input term.',name);
+    end
+end
+npo = length(strfind(ODEpost,'(')); 
+npc = length(strfind(ODEpost,')'));
+if npo ~= npc,
+    error('The ''%s'' identifier is not allowed to be inside a parenthesis.',name);
+end
+% 2) The last character in the ODEpre string needs to be a '+' or a '*'. So
+% that in the latter case the part in front of the INPUT* identifier can be
+% understood as a factor. 
+if ~isempty(ODEpre),
+    if ODEpre(end) ~= '+' && ODEpre(end) ~= '*',
+        error('The ''%s'' term requires the following syntax: ''...+%s'' or ''...+(expression)*%s''.',name,name,name);
+    end
+end
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET THE FACTORS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% 3) If ODEpre is empty or ODEpre(end) = '+' then the factor is simply: 1
+if isempty(ODEpre),
+    factor = '1';
+    term = name;
+    return
+elseif ODEpre(end) == '+',
+    factor = '1';
+    term = ['+' name];
+    return
+end
+% 4) Parse the multiplicative input factor: We search for a '+' or '-'
+% outside of parentheses from right to left in ODEpre. If '-' then error.
+% If no + found then it is assumed that INPUT statement first in ODE.
+po = 0;
+plusFound = 0;
+for k=length(ODEpre):-1:1,
+    if ODEpre(k) == '(',
+        % count opening parenthesis
+        po = po+1;
+    end
+    if ODEpre(k) == ')',
+        % count closing parenthesis
+        po = po-1;
+    end
+    if ODEpre(k) == '+' && po == 0,
+        % start of factor found
+        plusFound = 1;
+        break;
+    end
+    if ODEpre(k) == '-' && po == 0,
+        % start of factor found but '-' not allowed
+        error('An input term for ''%s'' is substracted from an ODE (addition only allowed).',name); 
+        break;
+    end
+end
+% 5) extract the factor and return (ITS DONE :))
+if plusFound,
+    factor = ODEpre(k+1:end-1);
+else
+    factor = ODEpre(k:end-1);
+end    
+term = [ODEpre(k:end-1) '*' name];
+return
+
+
+
+
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/auxiliary/moddosparsing/inputsonlyonstatesIQM.m b/IQMtools V1.2.2.2/IQMpro/auxiliary/moddosparsing/inputsonlyonstatesIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..6687b69231b96be567ade819cc6a3d442d101fc9
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/auxiliary/moddosparsing/inputsonlyonstatesIQM.m	
@@ -0,0 +1,49 @@
+function [output] = inputsonlyonstatesIQM(model)
+% inputsonlyonstatesIQM: Function checks if dosing inputs defined by
+% "INPUTS*" are only added to ODEs.
+%
+% USAGE:
+% ======
+% [output] = inputsonlyonstatesIQM(model) 
+%
+% model: IQMmodel
+%
+% Output Arguments:
+% =================
+% output: =0: inputs not only on states (ODEs)
+%         =1: inputs only on states (ODEs) (or if no INPUT* definition
+%         exists in the model
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check input
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isIQMmodel(model),
+    error('First input argument is not an IQMmodel.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INITIALIZE OUTPUT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+output = 1;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK RHSs
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[statenames,ODEs] = IQMstates(model);
+[varnames,varformulas] = IQMvariables(model);
+[reacnames,reacformulas] = IQMreactions(model);
+
+% 1) Check if "INPUT" defined in varformulas or reacformulas => error
+for k=1:length(varformulas),
+    if ~isempty(strfind(varformulas{k},'INPUT')),
+        output = 0; 
+    end
+end    
+for k=1:length(reacformulas),
+    if ~isempty(strfind(reacformulas{k},'INPUT')),
+        output = 0;
+    end
+end    
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/auxiliary/moddosparsing/mergemoddosstructsIQM.m b/IQMtools V1.2.2.2/IQMpro/auxiliary/moddosparsing/mergemoddosstructsIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..d30dfe3fb1233f3b37978d4af23134985f07f696
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/auxiliary/moddosparsing/mergemoddosstructsIQM.m	
@@ -0,0 +1,188 @@
+function [moddosinfo] = mergemoddosstructsIQM(modelinfo,dosing)
+% mergemoddosstructsIQM: Merge a modelinfo struct (returned by
+% basicmodelparsingIQM) with an IQMdosing object into a structure that
+% contains necessary information for both MONOLIX and NONMEM conversion and simulation
+% of the dosing scheme. 
+%
+% moddosinfo.model:             the model
+% moddosinfo.inputs.name:       input name
+% moddosinfo.inputs.factors:    cell-array with input factors
+% moddosinfo.inputs.terms:      cell-array with complete input string (for
+%                               simpler removing)
+% moddosinfo.inputs.stateindex: vector with stateindices to which the same
+%                               input is applied
+% moddosinfo.inputs.parindex:   index of the INPUT* parameter definition in
+%                               the IQMmodel (used to remove it when
+%                               parameters are written to (e.g.) an MLXTRAN
+%                               file).   
+% moddosinfo.inputs.type:       type of the input
+% moddosinfo.inputs.time:       time point of the input (unused for
+%                               MLXTRAN conversion but for simulation)
+% moddosinfo.inputs.Tlag:       []: no lag, numeric: lag present with
+%                               given value. (=0: lag present with 0 as
+%                               initial value ... in case of
+%                               optimization)
+% moddosinfo.inputs.D:          dose information (unused for MLXTRAN
+%                               conversion but for simulation)
+% moddosinfo.inputs.parameters: additional parameters (input-type
+%                               dependent (Tinf, Tk0, ka) ... already
+%                               changed parameter names for after merging!
+% moddosinfo.inputs.notes:      input notes (unsused, except for
+%                               documentation)
+% moddosinfo.outputs.name:      output name
+% moddosinfo.outputs.formula:   output formula
+% moddosinfo.outputs.notes:     output notes
+% moddosinfo.outputs.varindex:  index of output in model variables
+% moddosinfo.param_est.name:    name of parameter to estimate (defined by
+%                               the identifier "<estimate>" in the
+%                               IQMmodel)
+% moddosinfo.param_est.notes:   estimated parameter notes
+% moddosinfo.param_est.value0:  initial guess for parameter
+% moddosinfo.param_est.parindex: index of parameter in parameters
+% moddosinfo.param_reg.name:    name of regression parameter (defined by
+%                               the identifier "<regression>" in the
+%                               IQMmodel) 
+% moddosinfo.param_reg.notes:   regression parameter notes
+% moddosinfo.param_reg.parindex: index of reg param in parameters
+% moddosinfo.param_reg.varindex: index of reg param in variables
+% moddosinfo.param_pk.name:     name of parameter to define in PK section
+%                               (this is MLXTRAN specific but might be
+%                               useful for other applications to).
+% moddosinfo.param_pk.value:    value of parameter
+% moddosinfo.param_pk.parindex: index or parameter in model
+% moddosinfo.param_pk.notes:    notes of the parameters
+%
+% Only very basic error handling is done. More intensive error checking is
+% done later, dependent on the tool that is going to be used for
+% pop-modelling (different features might be allowed).
+%
+% USAGE:
+% ======
+% [moddosinfo] = mergemoddosstructsIQM(modelinfo,dosing)
+%
+% modelinfo: modelinfo struct (returned by basicmodelparsingIQM)
+% dosing: IQMdosing object
+%
+% Output Arguments:
+% =================
+% moddosinfo: see structure definition above
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS LITE>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check inputs
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isIQMdosing(dosing),
+    error('Second input argument is not an IQMdosing object.');
+end
+ds = struct(dosing);
+moddosinfo  = modelinfo; % assign output with modelinfo, then add input info
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% RUN THROUGH ALL MODEL INPUTS AND ADD INPUT RELATED INFORMATION TO moddosinfo
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for k=1:length(moddosinfo.inputs),
+    % find model input in dosing scheme (by comparing names)
+    index = strmatchIQM(moddosinfo.inputs(k).name, {ds.inputs.name},'exact');
+    % if input name not found => error
+    % We keep this error for the moment. Technically it is not necessary
+    % ... but forces the modeler to be more consistent. If too restrictive
+    % then we can take the error away and just remove this input from the
+    % moddosinfo structure.
+    if isempty(index),
+        error('Input ''%s'' defined in the model but undefined in the IQMdosing scheme.',moddosinfo.inputs(k).name);
+    end
+    % add the dosing input definition from the IQMdosing object to the
+    % moddosinfo structure
+    moddosinfo.inputs(k).type = ds.inputs(index).type;
+    moddosinfo.inputs(k).time = ds.inputs(index).time;
+    moddosinfo.inputs(k).Tlag = ds.inputs(index).Tlag;
+    moddosinfo.inputs(k).D = ds.inputs(index).D;
+    moddosinfo.inputs(k).parameters = ds.inputs(index).parameters;
+    moddosinfo.inputs(k).TlagNotes = ds.inputs(index).TlagNotes;
+    moddosinfo.inputs(k).TlagName = ['Tlag' '' lower(ds.inputs(index).name)];
+    moddosinfo.inputs(k).notes = ds.inputs(index).notes;
+    % update parameter name
+    if ~isempty(moddosinfo.inputs(k).parameters),
+        moddosinfo.inputs(k).parameters.name = [moddosinfo.inputs(k).parameters.name '' lower(ds.inputs(index).name)];
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% RUN THROUGH ALL dosing parameters (ka, Tinf, Rate, Tk0) and check
+% if they are to be estimated or obtained from regression => add to
+% respective field in moddosinfo. 
+% If not estimate and not regression, then add to PK parameters, since to
+% be defined in the $PK section in MLXTRAN ... and also in NONMEM.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for k=1:length(moddosinfo.inputs),
+    nameinput = lower(moddosinfo.inputs(k).name);
+    if ~isempty(moddosinfo.inputs(k).parameters),
+        nameparam = [moddosinfo.inputs(k).parameters.name]; 
+        notesparam = moddosinfo.inputs(k).parameters.notes;
+        valueparam = moddosinfo.inputs(k).parameters.value;
+        % Check if to be estimated
+        if ~isempty(strfind(notesparam,'<estimate>')),
+            % Add to param_est
+            notesparam = strrep(notesparam,'<estimate>','');
+            moddosinfo.param_est(end+1).name = nameparam;
+            moddosinfo.param_est(end).notes = notesparam;
+            moddosinfo.param_est(end).value0 = valueparam;
+            moddosinfo.param_est(end).parindex = [];  % keep it empty, because yet unknown
+        elseif ~isempty(strfind(notesparam,'<regression>'))
+            % Add to param_reg
+            notesparam = strrep(notesparam,'<regression>','');
+            moddosinfo.param_reg(end+1).name = nameparam;
+            moddosinfo.param_reg(end).notes = notesparam;
+            moddosinfo.param_reg(end).parindex = [];  % keep it empty, because yet unknown            
+            moddosinfo.param_reg(end).varindex = [];  % keep it empty, because always empty
+        else
+            % Add to param_pk
+            moddosinfo.param_pk(end+1).name = nameparam;
+            moddosinfo.param_pk(end).notes = notesparam;
+            moddosinfo.param_pk(end).value = valueparam;             
+            moddosinfo.param_pk(end).parindex = [];  % keep it empty, because yet unknown 
+        end            
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% RUN THROUGH ALL Tlag parameters and check
+% if they are to be estimated or obtained from regression => add to
+% respective field in moddosinfo.
+% If not estimate and not regression, then add to PK parameters, since to
+% be defined in the $PK section in MLXTRAN ... and also in NONMEM.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for k=1:length(moddosinfo.inputs),
+    nameinput = lower(moddosinfo.inputs(k).name);
+    if ~isempty(moddosinfo.inputs(k).Tlag),
+        nameparam = moddosinfo.inputs(k).TlagName; 
+        notesparam = moddosinfo.inputs(k).TlagNotes;
+        valueparam = moddosinfo.inputs(k).Tlag;
+        % Check if to be estimated
+        if ~isempty(strfind(notesparam,'<estimate>')),
+            % Add to param_est
+            notesparam = strrep(notesparam,'<estimate>','');
+            moddosinfo.param_est(end+1).name = nameparam;
+            moddosinfo.param_est(end).notes = notesparam;
+            moddosinfo.param_est(end).value0 = valueparam;
+            moddosinfo.param_est(end).parindex = [];  % keep it empty, because yet unknown
+        elseif ~isempty(strfind(notesparam,'<regression>'))
+            % Add to param_reg
+            notesparam = strrep(notesparam,'<regression>','');
+            moddosinfo.param_reg(end+1).name = nameparam;
+            moddosinfo.param_reg(end).notes = notesparam;
+            moddosinfo.param_reg(end).parindex = [];  % keep it empty, because yet unknown            
+            moddosinfo.param_reg(end).varindex = [];  % keep it empty, because always empty
+        else
+            % Add to param_pk
+            moddosinfo.param_pk(end+1).name = nameparam;
+            moddosinfo.param_pk(end).notes = notesparam;
+            moddosinfo.param_pk(end).value = valueparam;             
+            moddosinfo.param_pk(end).parindex = [];  % keep it empty, because yet unknown 
+        end            
+    end
+end
+
+
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/auxiliary/parallel/getN_PROCESSORS_PARIQM.m b/IQMtools V1.2.2.2/IQMpro/auxiliary/parallel/getN_PROCESSORS_PARIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..d448d26323708e3daa8b127c08844b82bad067fd
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/auxiliary/parallel/getN_PROCESSORS_PARIQM.m	
@@ -0,0 +1,15 @@
+function [N_PROCESSORS_PAR] = getN_PROCESSORS_PARIQM()
+% This function returns the number of processors to use by default if
+% computation using the parallel MATLAB toolbox is desired.
+%
+% [SYNTAX]
+% [poolsize] = sizeParallelIQM()
+%
+% [INPUT]
+%
+% [OUTPUT]
+% poolsize:     Number of parallel processors available
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+SETUP_PATHS_TOOLS_IQMPRO
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/auxiliary/variablename/makeVariableNameIQM.m b/IQMtools V1.2.2.2/IQMpro/auxiliary/variablename/makeVariableNameIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..7215eda7853bb47441e95ee3a71aeb85714c008b
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/auxiliary/variablename/makeVariableNameIQM.m	
@@ -0,0 +1,20 @@
+function [name] = makeVariableNameIQM(string)
+% This function takes a string as input and removes from it the characters
+% that are not suitable in variable names.
+%
+% The underlying function is the following:
+%
+%  name = regexprep(string,'\W','')
+%
+% [SYNTAX]
+% [name] = makeVariableNameIQM(string)
+%
+% [INPUT]
+% string:           String 
+%
+% [OUTPUT]
+% name:             String made fit as variable name
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+name = regexprep(string,'\W','');
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/classes/@IQMprojectSB/IQMexportproject.m b/IQMtools V1.2.2.2/IQMpro/classes/@IQMprojectSB/IQMexportproject.m
new file mode 100644
index 0000000000000000000000000000000000000000..c7d451f7320e7e07f52bbaae773fa2eabda0ccdc
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/classes/@IQMprojectSB/IQMexportproject.m	
@@ -0,0 +1,151 @@
+function [] = IQMexportproject(project,varargin)
+% IQMexportproject: exports a given project to a projectfolder
+%
+% USAGE:
+% ======
+% [] = IQMexportproject(project)        
+% [] = IQMexportproject(project,foldername)        
+%
+% project:  IQMprojectSB object
+% foldername: foldername
+%
+% DEFAULT VALUES:
+% ===============
+% foldername: foldername derived from project name
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+oldfolder = pwd();
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin == 1,
+    foldername = regexprep(project.name,'\W','');
+elseif nargin == 2,
+    foldername = regexprep(varargin{1},'\W','');
+else
+    error('Wrong number of input arguments.');
+end
+    
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK FOLDERNAME
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% check if foldername already exists
+% if exist(foldername),
+%     error('Folder ''%s'' already exists. Please specify a different name.',foldername);
+% end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CREATE FOLDERS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+mkdir(foldername);
+cd(foldername);
+mkdir('models');
+mkdir('experiments');
+mkdir('estimations');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CREATE NOTES.TXT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fid = fopen('notes.txt','w');
+notes = fwrite(fid,project.notes)';
+fclose(fid);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EXPORT THE MODELS (only .txt FORMAT)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+cd('models');
+modelnames = {};
+for k=1:length(project.models),
+    if isempty(project.modeltypes),
+        modeltype = 0;
+    else
+        modeltype = project.modeltypes(k);
+    end
+    modelstruct = IQMstruct(project.models{k});
+    nrequalnames = length(strmatchIQM(modelstruct.name,modelnames,'exact'));
+    if nrequalnames > 0,
+        if modeltype == 0,
+            IQMcreateTEXTfile(project.models{k},sprintf('%s_%d',modelstruct.name,nrequalnames+1));
+        else
+            IQMcreateTEXTBCfile(project.models{k},sprintf('%s_%d',modelstruct.name,nrequalnames+1));
+        end
+    else
+        if modeltype == 0,
+            IQMcreateTEXTfile(project.models{k},modelstruct.name);
+        else
+            IQMcreateTEXTBCfile(project.models{k},modelstruct.name);
+        end
+    end
+    modelnames{end+1} = modelstruct.name;
+end
+cd('..');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EXPORT THE EXPERIMENTS AND MEASUREMENTS (only .txt FORMAT)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+cd('experiments');
+experimentnames = {};
+for k=1:length(project.experiments),
+    % check for multiple equal experiment names
+    nrequalnames = length(strmatchIQM(project.experiments(k).name,experimentnames,'exact'));
+    if nrequalnames > 0,
+        expfoldername = sprintf('%s_%d',project.experiments(k).name,nrequalnames+1);
+    else
+        expfoldername = project.experiments(k).name;
+    end
+    experimentnames{end+1} = project.experiments(k).name;
+    % create folder for current experiment
+    if isempty(expfoldername),
+        expfoldername = ['Experiment ' num2str(k)];
+    end
+    
+    mkdir(expfoldername);
+    cd(expfoldername);
+    % create notes.txt file
+    fid = fopen('notes.txt','w');
+    notes = fwrite(fid,project.experiments(k).notes);
+    fclose(fid);    
+    % export experiment
+    IQMcreateEXPfile(project.experiments(k).experiment);
+    % create measurement files (only .csv files)
+    measurementnames = {};
+    for k2=1:length(project.experiments(k).measurements),
+        measstruct = IQMstruct(project.experiments(k).measurements{k2});
+        nrequalnames = length(strmatchIQM(measstruct.name,measurementnames,'exact'));
+        if nrequalnames > 0,
+            measname = sprintf('%s_%d',measstruct.name,nrequalnames+1);
+        else
+            measname = measstruct.name;
+        end
+        measurementnames{end+1} = measstruct.name;
+        % export measurement
+        IQMexportCSVmeasurement(project.experiments(k).measurements{k2},measname);
+    end
+    cd('..');
+end
+cd('..');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EXPORT THE ESTIMATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+cd('estimations');
+for k=1:length(project.estimations),
+    % convert estimation to text
+    text = sprintf('%% Estimation Settings\n\nestimation = [];');
+    text = getdatatextstructIQM(project.estimations{k},'estimation',text);
+    % filename
+    ext = num2str(k);
+    ext = char([48*ones(1,3-length(ext)) double(ext)]);
+    filename = sprintf('Estimation_%s.est',ext);
+    % write to file
+    fid = fopen(filename,'w');
+    fwrite(fid,text);
+    fclose(fid);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% BACK TO STARTING FOLDER
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+cd(oldfolder);
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/classes/@IQMprojectSB/IQMprojectSB.m b/IQMtools V1.2.2.2/IQMpro/classes/@IQMprojectSB/IQMprojectSB.m
new file mode 100644
index 0000000000000000000000000000000000000000..38a635dbf70799c13d0e93e1b9307438dea0807d
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/classes/@IQMprojectSB/IQMprojectSB.m	
@@ -0,0 +1,92 @@
+function [project] = IQMprojectSB(varargin)
+% IQMprojectSB: creates a project object containing models, experiments,
+% measurements, and information needed for parameterestimation
+%
+% USAGE:
+% ======
+% [project] = IQMprojectSB()               creates an empty IQMprojectSB 
+% [project] = IQMprojectSB(structure)      creates an IQMprojectSB from a MATLAB
+%                                         structure in the internal project format
+% [project] = IQMprojectSB(projectin)      construction from a given IQMprojectSB (projectin)
+% [project] = IQMprojectSB('file.iqmp')     loading a binary IQMprojectSB
+%                                         stored in a MATLAB MAT file with .iqmp as extension
+% [project] = IQMprojectSB('foldername')   converting a IQM project folder structure to an IQMprojectSB.
+%
+% Output Arguments:
+% =================
+% project: IQMprojectSB object 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK THE TYPE OF THE INPUT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin==0,
+    inputType = 'empty';
+elseif nargin == 1,
+    input = varargin{1};
+    if isIQMprojectSB(input),
+        inputType = 'IQMprojectSB';
+    elseif isstruct(input),
+        inputType = 'structure';
+    elseif ischar(input),
+        if ~isempty(strfind(input,'.iqmp')),
+            inputType = 'IQMPfile';
+        else 
+            inputType = 'projectfolder';
+        end
+    else 
+        error('Input argument of unknown type');
+    end
+else
+    error('Wrong number of input arguments.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CONSTRUCT THE IQMPROJECT OBJECT 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if strcmp('empty',inputType),
+    % experiments substructure
+    experimentsStruct = struct('name',{},'notes',{},'experiment',{},'measurements',{});
+    % Create structure
+    structure = struct('name','unnamed project','notes','','models','','modeltypes','','experiments',experimentsStruct,'estimations','');
+    % construct the project object
+    project = class(structure,'IQMprojectSB');
+elseif strcmp('IQMprojectSB',inputType),
+    % copy the project object
+    project = input;
+elseif strcmp('structure',inputType),
+    % check if the given structure is a IQMprojectSB structure (only check the
+    % top-level fields)
+    checkFields = {'name','notes','models','experiments','estimations'};
+    for k = 1:length(checkFields),
+        if ~isfield(input,checkFields{k}),
+            errorMsg = sprintf('Given structure is not a valid internal IQMprojectSB structure.');
+            error(errorMsg);
+        end
+    end
+    % construct the project object
+    project = class(input,'IQMprojectSB');
+elseif strcmp('IQMPfile',inputType),
+    % check if a file with given filename exists
+    [path,name,ext] = fileparts(input);
+    filename = fullfile(path, [name '.iqmp']); 
+    if ~exist(filename),
+        errorMsg = sprintf('IQMprojectSB file, "%s", does not exist.', filename);
+        error(errorMsg);
+    end
+    % If file exists then import it
+    load(filename,'-MAT');
+    eval(sprintf('project = %s;',name));
+elseif strcmp('projectfolder',inputType),
+%     % Import a project folder to an IQMprojectSB
+%     % first check if the input variable corresponds to a folder in the
+%     % current directory
+%     if exist([pwd '/' input]) ~= 7,
+%         error('Projectfolder ''%s'' does not exist in the current directory.',input);
+%     end
+    project = importprojectfolderIQM(input);
+else
+    error('Wrong input arguments.');
+end
+return
diff --git a/IQMtools V1.2.2.2/IQMpro/classes/@IQMprojectSB/IQMsaveproject.m b/IQMtools V1.2.2.2/IQMpro/classes/@IQMprojectSB/IQMsaveproject.m
new file mode 100644
index 0000000000000000000000000000000000000000..2087350235acf7d5b5c566af5e7a85781802e1be
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/classes/@IQMprojectSB/IQMsaveproject.m	
@@ -0,0 +1,35 @@
+function [] = IQMsaveproject(project,varargin)
+% IQMsaveproject: save a IQMprojectSB object as a binary MATLAB MAT file
+% with .iqmp as extension. The name of the project object variable is the same 
+% as the name of the file.
+%
+% USAGE:
+% ======
+% [] = IQMsaveproject(project)        
+% [] = IQMsaveproject(project,filename)        
+%
+% project:  IQMprojectSB object
+% filename: filename (.iqmp is optional)
+%
+% DEFAULT VALUES:
+% ===============
+% filename: filename derived from project name
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin == 1,
+    filename = regexprep(project.name,'\W','');
+elseif nargin == 2,
+    filename = regexprep(regexprep(varargin{1},'.iqmp',''),'\W','');
+else
+    error('Wrong number of input arguments.');
+end
+    
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% SAVE THE PROJECT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+eval(sprintf('%s = project;',filename));
+eval(sprintf('save %s.iqmp %s -MAT',filename,filename));
diff --git a/IQMtools V1.2.2.2/IQMpro/classes/@IQMprojectSB/IQMstruct.m b/IQMtools V1.2.2.2/IQMpro/classes/@IQMprojectSB/IQMstruct.m
new file mode 100644
index 0000000000000000000000000000000000000000..674f0039e4e6b1d9ff329d997256e0f31fba2339
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/classes/@IQMprojectSB/IQMstruct.m	
@@ -0,0 +1,20 @@
+function [structure] = IQMstruct(project)
+% IQMstruct: This function returns the internal data structure
+% of an IQMprojectSB
+%
+% USAGE:
+% ======
+% [structure] = IQMstruct(IQMprojectSB) 
+%
+% IQMprojectSB: IQMprojectSB 
+%
+% Output Arguments:
+% =================
+% structure: internal data structure of the IQMprojectSB
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% VERY SIMPLE FUNCTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+structure = struct(project);
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/classes/@IQMprojectSB/display.m b/IQMtools V1.2.2.2/IQMpro/classes/@IQMprojectSB/display.m
new file mode 100644
index 0000000000000000000000000000000000000000..85605241614a30977a769b017c8e39f87dbd895d
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/classes/@IQMprojectSB/display.m	
@@ -0,0 +1,25 @@
+function [] = display(project)
+% display: Displays information about IQMprojectSB. This function is 
+% called by MATLAB whenever an object is the result of a statement that
+% is not terminated by a semicolon. 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% COLLECT INFORMATION ABOUT THE PROJECT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+numberModels = length(project.models);
+numberExperiments = length(project.experiments);
+numberMeasurements = length([project.experiments(1:end).measurements]);
+numberEstimations = length(project.estimations);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DISPLAY INFORMATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+text = sprintf('\tIQMprojectSB\n\t============\n');
+text = sprintf('%s\tName: %s\n',text,project.name);
+text = sprintf('%s\tNumber Models:\t\t\t%d\n',text,numberModels);
+text = sprintf('%s\tNumber Experiments:\t\t%d\n',text,numberExperiments);
+text = sprintf('%s\tNumber Measurements:\t%d\n',text,numberMeasurements);
+text = sprintf('%s\tNumber Estimations:\t\t%d\n',text,numberEstimations);
+disp(text);
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/classes/@IQMprojectSB/private/importprojectfolderIQM.m b/IQMtools V1.2.2.2/IQMpro/classes/@IQMprojectSB/private/importprojectfolderIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..6c3e017fc61132545bf9beaa8a74cfe487523414
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/classes/@IQMprojectSB/private/importprojectfolderIQM.m	
@@ -0,0 +1,181 @@
+function [project] = importprojectfolderIQM(folder)
+% importprojectfolderIQM: imports a project folder to a IQM project
+% object.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+global useIQMguiFlag
+if useIQMguiFlag ~= 1,
+    useIQMguiFlag = 0;
+end
+
+oldfolder = pwd(); % save starting folder
+cd(folder); % change into the project folder
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INITIALIZE EMPTY IQMPROJECT OBJECT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+project = IQMprojectSB();
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% ASSIGN NAME
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+project.name = folder;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% READ NOTES.TXT AND ASSIGN THEM
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try
+    notes = fileread([pwd,'/','notes.txt']);     
+catch
+    notes = '';
+end
+project.notes = notes;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHANGE INTO THE MODELS FOLDER AND LOAD MODELS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if exist([pwd,'/','models']) ~= 7,
+    cd(oldfolder);
+    error('No ''models'' folder is defined.');
+end
+cd('models');
+models = {};
+modeltypes = [];
+files = dir();
+% get files in model folder
+for k=1:length(files),
+    if ~files(k).isdir,
+        filename = files(k).name;
+        % check correct extensions (.txt, .txtbc, .xml)
+        [a,b,EXT] = fileparts(filename);
+        if strcmp(EXT,'.txt') || strcmp(EXT,'.txtbc') || strcmp(EXT,'.xml'),
+            try
+                % import models
+                models{end+1} = IQMmodel(filename);
+                if strcmp(EXT,'.txt'),
+                    modeltypes(end+1) = 0;  % txt
+                else
+                    modeltypes(end+1) = 1;  % txtbc or SBML
+                end
+            catch
+                disp(sprintf('Warning: Error during model import: %s',lasterr));
+            end
+        end
+    end
+end
+if length(models) == 0,
+    disp(sprintf('Warning: No models defined in the project.'));
+end
+% add models to project
+project.models = models;
+project.modeltypes = modeltypes;
+% exit the models folder
+cd('..');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHANGE INTO THE EXPERIMENTS FOLDER AND LOAD EXPERIMENTS AND MEASUREMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if exist([pwd,'/','experiments']) ~= 7,
+    cd(oldfolder);
+    error('No ''experiments'' folder is defined.');
+end
+cd('experiments');
+files = dir();
+nrexperiments = 0;
+% get files in experiments folder and search for experiment folders
+if useIQMguiFlag,
+    h = waitbar(0,'Importing project. Please wait...');
+end
+for k=1:length(files),
+    if useIQMguiFlag,
+        waitbar(k/length(files),h)
+    end
+    if files(k).isdir,
+        % . and .. not useful
+        if ~strcmp(files(k).name(1),'.') && ~strcmp(files(k).name,'..'),        
+%        if ~strcmp(files(k).name,'.') && ~strcmp(files(k).name,'..'),
+            % change into the current folder
+            cd(files(k).name);
+            % load notes.txt file for the current experiment
+            try
+                notes = fileread([pwd,'/','notes.txt']);
+            catch
+                notes = '';
+            end
+            % load experiment file for the current experiment (required
+            % to be there and error if more than one present)
+            expfiles = dir('*.exp');
+            if length(expfiles) > 1,
+                cd(oldfolder);
+                error('Experiment folder ''%s'' contains more than one experiment description.',files(k).name);
+            end
+            if length(expfiles) == 0,
+                cd(oldfolder);
+                error('Experiment folder ''%s'' contains no experiment description.',files(k).name);
+            end
+            experiment = IQMexperiment(expfiles(1).name);
+            % add experiment to project structure
+            nrexperiments = nrexperiments + 1;
+            project.experiments(nrexperiments).name = files(k).name;
+            project.experiments(nrexperiments).notes = notes;
+            project.experiments(nrexperiments).experiment = experiment;
+            % now check for measurements (they are not required to be there)
+            measurements = {};
+            allfiles = dir();
+            for k=1:length(allfiles),
+                if ~allfiles(k).isdir,
+                    filename = allfiles(k).name;
+                    % check correct extensions (.xls, .csv) (.xls only when not unix)
+                    [a,b,EXT] = fileparts(filename);
+                    if strcmp(EXT,'.csv') || (strcmp(EXT,'.xls') && ~isunix),
+                        try
+                            % import measurements
+                            meas = IQMmeasurement(filename);
+                            if iscell(meas),
+                                measurements = {measurements{:} meas{:}};
+                            else
+                                measurements{end+1} = meas;
+                            end
+                        catch
+                            disp(sprintf('Warning: Error during measurement import: %s',lasterr));
+                        end
+                    end
+                end
+            end
+            project.experiments(nrexperiments).measurements = measurements;
+            % change out of the current folder
+            cd('..');
+        end
+    end
+end
+if useIQMguiFlag,
+    close(h);
+end
+cd('..');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHANGE INTO THE ESTIMATIONS FOLDER AND LOAD ESTIMATIONS (OPTIONAL)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+estimations = {};
+if exist([pwd,'/','estimations']) == 7,
+    cd('estimations');
+    files = dir('*.est');
+    for k=1:length(files),
+        content = fileread(files(k).name);
+        try
+            eval(content)
+            estimations{end+1} = estimation;
+        catch
+            disp(sprintf('Syntax error in estimation ''%s''. Neglected from import.',files(k).name));
+        end
+    end
+end
+project.estimations = estimations;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% RETURN TO STARTING FOLDER
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+cd(oldfolder);
+            
+            
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/IQManalyzeresiduals.m b/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/IQManalyzeresiduals.m
new file mode 100644
index 0000000000000000000000000000000000000000..d9fbff365a11764a86dd0d2c5e96d87cec81cfe6
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/IQManalyzeresiduals.m	
@@ -0,0 +1,303 @@
+function [varargout] = IQManalyzeresiduals(project,varargin)
+% IQManalyzeresiduals: Determines and analyzes the residuals for a 
+% given project. The function either returns the residuals and 
+% corresponding analysis information or plots the results.
+%
+% The residuals are statistically tested with the Null Hypothesis 
+% that they are normal with unspecified mean and variance. Currently, the
+% means are not tested agains the hypothesis that they have all the
+% properties of white noise. Furthermore, the autocorrelations of the
+% (mean-free) residuals are calculated. 
+%
+% USAGE:
+% ======
+% IQManalyzeresiduals(project)
+% IQManalyzeresiduals(project,modelindex)
+% IQManalyzeresiduals(project,estimation)
+% IQManalyzeresiduals(project,modelindex,alpha)
+% IQManalyzeresiduals(project,estimation,alpha)
+% [output] = IQManalyzeresiduals(project)
+% [output] = IQManalyzeresiduals(project,modelindex)
+% [output] = IQManalyzeresiduals(project,estimation)
+% [output] = IQManalyzeresiduals(project,modelindex,alpha)
+% [output] = IQManalyzeresiduals(project,estimation,alpha)
+%
+% project: IQMprojectSB to determine the residuals for.
+% modelindex: The index of the model in the project to use for residual
+%   determination. 
+% estimation: Same structure as used for parameter estimation
+%   (IQMparameterestimation), defining the experiments to
+%   take into account. Additionally, if defined the timescalingFlag is
+%   taken into account.
+% alpha: The significance level for the test of the individual residuals
+%   against the Null Hypothesis that they are normally distributed.
+%
+% DEFAULT VALUES:
+% ===============
+% modelindex: 1
+% estimation: all experiments and measurements are taken into account
+% alpha = 0.05
+%
+% Output Arguments:
+% =================
+% If no output argument is specified, the residuals and
+% additional analysis information is plotted using the IQMplot GUI, allowing
+% to also consider the FFT and the autocorrelation of the residuals.
+% Otherwise, the results are returned as a structure with the following
+% fields: 
+%
+% output(e).name: Name of the e-th experiment 
+% output(e).measurement: Results for the measurements in the e-th experiment
+% 
+% output(e).measurement(m).name: Name of the m-th measurement in the e-th experiment
+% output(e).measurement(m).components: Names of the measured components for
+%   which the residuals have been determined.
+% output(e).measurement(m).time: Timevector for the measurement
+% output(e).measurement(m).timescalingFlag: Value of the timescalingFlag
+%   used for the analysis. This flag can be defined via the estimation
+%   input argument. Hint: Keep it either on the same value as for parameter
+%   estimation or set it to zero.
+% output(e).measurement(m).residuals: Matrix with residuals (weighted
+%   according to the timescalingFlag setting). Rows correspond to
+%   time-points and columns to the measured components (same order as 
+%   in output(e).measurement(m).components).
+% output(e).measurement(m).pValue: are the p-values corresponding to each
+%   component residual. A pvalue is the probability of observing the given
+%   result (residuals) by chance given that the null hypothesis (residuals
+%   normally distributed) is true. Small values of  pValue cast doubt on
+%   the validity of the null hypothesis. 
+% output(e).measurement(m).alpha: The significance level for the test of
+%   the individual residuals against the Null Hypothesis that they are
+%   normally distributed. (Same value as input argument "alpha" or default
+%   setting).
+% output(e).measurement(m).H: Result of the hypothesis test for each
+%   component residuals. H=0 (alpha<pValue) => Null Hypothesis accepted,
+%   H=1 (alpha>=pValue) => Null Hypothesis rejected.
+% output(e).measurement(m).autocorrelation_Rxx: Normalized autocorrelations
+%   of the (mean-free) residuals. One column per residual.
+% output(e).measurement(m).autocorrelation_lag: The lags are useful for
+%   plotting the Rxx results.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Force IQMplot not to remove the zero frequency component for the fourier
+% analysis of the residuals
+global doRemoveZeroComponentFlag
+doRemoveZeroComponentFlag = 0;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% BASIC CHECK OF THE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isIQMprojectSB(project),
+    error('Input argument ''project'' is not an IQMprojectSB.');
+end
+projectstruct = IQMstruct(project);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+modelindex = 1;
+experimentindices = 1:length(projectstruct.experiments);
+alpha = 0.05;
+displayFlag = 0;        % not changed
+scalingFlag = 0;        % not changed
+timescalingFlag = 0;    % this is used if defined
+if nargin < 1 || nargin > 3,
+    error('Incorrect number of input arguments.');
+end
+if nargin >= 2,
+    if isstruct(varargin{1}),
+        estimation = varargin{1};
+        try modelindex = estimation.modelindex; catch, end
+        try experimentindices = estimation.experiments.indices; catch, end
+        try timescalingFlag = estimation.timescalingFlag; catch, end
+    else
+        modelindex = varargin{1};
+    end
+end
+if nargin >= 3,
+    alpha = varargin{2};
+end
+
+% try to get the integrator options from the estimation structure.
+% otherwise use default options
+try OPTIONS = estimation.integrator.options; catch, OPTIONS = []; end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS EXPERIMENT AND MEASUREMENT INFORMATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+model = projectstruct.models{modelindex};
+% HANDLE NON-NUMERIC INITIAL CONDITIONS just by replacing them
+% + warning ... as user feedback
+if ~hasonlynumericICsIQM(model),
+    model = IQMconvertNonNum2NumIC(model);
+    disp('Warning: The model contains non-numeric initial conditions. For this analysis these are replaced');
+    disp('by numeric initial conditions, determined from the non-numeric ones.');
+end
+experiments = projectstruct.experiments(experimentindices);
+work = getexpmeasinfoIQM(model,modelindex,experiments,experimentindices,displayFlag,scalingFlag,timescalingFlag);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Simulate all experiments and add results to work structure
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for exp=1:length(work),
+    mexmodel = work(exp).model;
+    timevector = work(exp).timevector;
+    simdata = IQMPsimulate(mexmodel, timevector,[],[],[],OPTIONS);
+    work(exp).statevalues = simdata.statevalues;
+    work(exp).variablevalues = simdata.variablevalues;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Determine the residuals for each experiment and each measurement
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+residuals = [];
+for exp=1:length(work),
+    experiment = work(exp);
+    residuals(exp).name = ['Residuals for: ' experiment.experimentname];
+    AllRxx = [];
+    for meas=1:length(experiment.measurement),
+        measurement = experiment.measurement(meas);
+        timevectorindices = measurement.timevectorindices;
+        timevector = experiment.timevector(timevectorindices);
+        timescaling = measurement.timescaling(:);
+        % states
+        stateindices = measurement.stateindices;
+        if ~isempty(stateindices),
+            simstates = experiment.statevalues(timevectorindices,stateindices);
+            stateresiduals = measurement.statereferences - simstates;
+            statenames = measurement.statenames;
+        else
+            stateresiduals = [];
+            statenames = {};
+        end
+        % variables
+        variableindices = measurement.variableindices;
+        if ~isempty(variableindices),
+            simvariables = experiment.variablevalues(timevectorindices,variableindices);
+            variableresiduals = measurement.variablereferences - simvariables;
+            variablenames = measurement.variablenames;
+        else
+            variableresiduals = [];
+            variablenames = {};
+        end
+        values = [stateresiduals variableresiduals];
+        % apply the time scaling  
+        values = values.*timescaling(:,ones(1,size(values,2)));
+        % determine autocorrelations of residuals
+        allRxx = [];
+        allLag = [];
+        indexNaNlater = [];
+        for k=1:size(values,2),
+            % get values to resample and analyze
+            x1 = values(:,k);
+            t1 = timevector;
+            % remove NaNs
+            nanindex = find(isnan(x1));
+            x1(nanindex) = [];
+            t1(nanindex) = [];
+            % determine the sampling time (half the min size for finer resolution)
+            deltaT = min(t1(2:end)-t1(1:end-1))/2;
+            if ~isempty(x1),
+                [x2,t2] = resampleIQM(t1,x1,deltaT,'linear');
+                x2 = x2-mean(x2); % make mean free
+                [Rxx,lag] = xcorrIQM(x2,x2,length(x2)-1,'coeff');
+            else
+                lag = [];
+                Rxx = [];
+                indexNaNlater = [indexNaNlater k];
+            end
+            allLag = [allLag lag(:)];
+            allRxx = [allRxx Rxx(:)];
+        end
+        % handle indexNaNlater (insert columns of NaN values)
+        ncoltot = size(allRxx,2) + length(indexNaNlater);
+        distribindices = setdiff([1:ncoltot],indexNaNlater);
+        AllLag = allLag(:,1);
+        AllRxx(:,distribindices) = allRxx;
+        AllRxx(:,indexNaNlater) = NaN*ones(size(AllLag,1),length(indexNaNlater));
+        % add to residuals
+        residuals(exp).measurement(meas).name = ['Residuals for: ' measurement.name];
+        residuals(exp).measurement(meas).components = {statenames{:} variablenames{:}};
+        residuals(exp).measurement(meas).time = timevector;        
+        residuals(exp).measurement(meas).timescalingFlag = timescalingFlag;
+        residuals(exp).measurement(meas).residuals = values;
+        % do a statistical test to check if residuals are white
+        H = []; pValue = [];
+        for k=1:size(values,2),
+            vector = values(:,k);
+            vector(find(isnan(vector))) = [];
+            if length(vector) >= 3,
+                [H(k), pValue(k)] = swtestIQM(vector,alpha,0);
+            else
+                H(k) = NaN;
+                pValue(k) = NaN;
+            end
+        end
+        residuals(exp).measurement(meas).pValue = pValue;
+        residuals(exp).measurement(meas).alpha = alpha;
+        residuals(exp).measurement(meas).H = H;
+        % add also the autocorrelation results
+        residuals(exp).measurement(meas).autocorrelation_Rxx = AllRxx;
+        residuals(exp).measurement(meas).autocorrelation_lag = AllLag;
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle the output
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargout == 0,
+    % Plot the results
+
+    % Prepare the data structures
+    datastructs = {};
+    for exp=1:length(residuals),
+        for meas=1:length(residuals(exp).measurement),
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+            % Time series of residuals
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+            nameexp = residuals(exp).name;
+            namemeas = residuals(exp).measurement(meas).name;
+            names = residuals(exp).measurement(meas).components;
+            time = residuals(exp).measurement(meas).time(:);
+            values = residuals(exp).measurement(meas).residuals;
+            name = sprintf('Residuals for EXPERIMENT: %s, MEASUREMENT: %s',strrep(nameexp,'_',' '),strrep(namemeas,'_',' '));
+            % construct legend using the H values
+            H = residuals(exp).measurement(meas).H;
+            pValue = residuals(exp).measurement(meas).pValue;
+            legend = {};
+            for k=1:length(names),
+                if ~isnan(H(k)),
+                    if H(k) == 0,
+                        legend{k} = sprintf('%s (pV: %1.2g, H0 accepted with significance %g)',names{k},pValue(k),alpha);
+                    else
+                        legend{k} = sprintf('%s (pV: %1.2g, H0 rejected with significance %g)',names{k},pValue(k),alpha);
+                    end
+                else
+                    legend{k} = sprintf('%s (no data)',names{k});
+                end
+            end
+            datastructs{end+1} = createdatastructIQMplotIQM(time,values,names,legend,'o-',name);
+        end
+    end
+    % Do the plotting
+    text = '';
+    for k=1:length(datastructs),
+        text = sprintf('%sdatastructs{%d}, ',text,k);
+    end
+    text = text(1:end-2);
+    eval(sprintf('IQMplot(%s)',text))
+else
+    varargout{1} = residuals;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DELETE MEX MODELS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+global compiledExpModelsIQMparamestGUI % if not empty then models are precompiled and should not be deleted
+if isempty(compiledExpModelsIQMparamestGUI),
+    clear mex
+    for e=1:length(work),
+        delete(work(e).mexfullpath);
+    end
+end
diff --git a/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/IQMcomparemeasurements.m b/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/IQMcomparemeasurements.m
new file mode 100644
index 0000000000000000000000000000000000000000..321a72c79db2b01c557ddfd37532205cd7f46aa7
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/IQMcomparemeasurements.m	
@@ -0,0 +1,216 @@
+function [varargout] = IQMcomparemeasurements(project,varargin)
+% IQMcomparemeasurements: Simulates the experiments in the project for the
+% models in the project and compares the simulated results to the
+% measurements. 
+%
+% USAGE:
+% ======
+% [] = IQMcomparemeasurements(project)        
+% [plotdata] = IQMcomparemeasurements(project,modelindices)        
+% [plotdata] = IQMcomparemeasurements(project,modelindices,experimentindices)        
+% [plotdata] = IQMcomparemeasurements(project,modelindices,experimentindices,OPTIONS)        
+%
+% project:  IQMprojectSB object
+% modelindices: indices of the models in the project to use for comparison
+%   (scalar or vector)
+% experimentindices: vector with indices of the experiments to do the
+%   comparison for
+% OPTIONS: structure with integrator options.
+%        OPTIONS.abstol: abs tolerance
+%        OPTIONS.reltol: rel tolerance
+%        OPTIONS.minstep: min step-size of integrator
+%        OPTIONS.maxstep: max step-size of integrator
+%        OPTIONS.maxnumsteps: maximum number of steps to be
+%          taken by the solver in its attempt to reach the next
+%          output time 
+%   
+% DEFAULT VALUES:
+% ===============
+% modelindices: comparison carried out for all models in the project if
+%               modelindices is not given
+% experimentindices: all experiments in the project
+% OPTIONS.abstol: 1e-6
+% OPTIONS.reltol: 1e-6
+% OPTIONS.minstep: 0
+% OPTIONS.maxstep: inf
+% OPTIONS.maxnumsteps: 500
+%
+% Output Arguments:
+% =================
+% If no output argument is given, the function plots the data using
+% plotIQMP. Otherwise a datastructure (plotdata) is given back that can be
+% used as input argument for plotIQMP.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check input argument
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isIQMprojectSB(project),
+    error('Input argument is not an IQMprojectSB.');
+end
+projectstruct = IQMstruct(project);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handling variable input arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin == 1,
+    modelindex = [1:length(projectstruct.models)];
+    experimentindices = [1:length(projectstruct.experiments)];
+    OPTIONS = [];
+elseif nargin == 2,
+    modelindex = varargin{1};
+    experimentindices = [1:length(projectstruct.experiments)];
+    OPTIONS = [];
+elseif nargin == 3,
+    modelindex = varargin{1};
+    experimentindices = varargin{2};
+    OPTIONS = [];
+elseif nargin == 4,
+    modelindex = varargin{1};
+    experimentindices = varargin{2};
+    OPTIONS = varargin{3};
+else
+    error('Incorrect number of input arguments.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK WHICH EXPERIMENTS DO NOT HAVE MEASUREMENT DATA ASSIGNED TO
+% THESE ARE SKIPPED FROM THE CONSIDERATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+text = '';
+useexperimentindices = [];
+
+for e=1:length(experimentindices),
+    if isempty(projectstruct.experiments(experimentindices(e)).measurements),
+        text = sprintf('%sExperiment %d has no measurements assigned to ... not considered here.\n',text,experimentindices(e));
+    else
+        useexperimentindices = [useexperimentindices experimentindices(e)];
+    end
+end
+if ~isempty(text),
+    disp(text);
+end
+if isempty(useexperimentindices),
+    error('No measurements in the selected experiments. No comparison possible.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET ALL MEASUREMENT INFORMATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+infostruct = [];
+for k=1:length(projectstruct.models(modelindex)),
+    model = projectstruct.models{modelindex(k)};
+    experiments = projectstruct.experiments(useexperimentindices);
+    displayFlag = 0;
+    expmeasinfo = getexpmeasinfoIQM(model,modelindex(k),experiments,useexperimentindices,displayFlag);
+    infostruct(k).modelstruct = IQMstruct(projectstruct.models{modelindex(k)});
+    infostruct(k).modelindex = modelindex(k);
+    infostruct(k).expinfostruct = expmeasinfo;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% ADD SIMULATION DATA TO THE STRUCTURE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 
+plotdata = [];
+plotdata.project = projectstruct.name;
+plotdata.notes = projectstruct.notes;
+plotdata.model = [];
+% run through all models
+for m=1:length(projectstruct.models(modelindex)),
+    % model data
+    modelstruct = infostruct(m).modelstruct;
+    plotdata.model(m).name = modelstruct.name;      
+    plotdata.model(m).notes = modelstruct.notes;
+    for e=1:length(infostruct(m).expinfostruct),
+        % experiment data
+        plotdata.model(m).experiment(e).name = infostruct(m).expinfostruct(e).experimentname;
+        timevector = infostruct(m).expinfostruct(e).timevector;
+        timestart = timevector(1);
+        timeend = timevector(end);
+        timevectorsim = [timestart:(timeend-timestart)/1000:timeend];
+        plotdata.model(m).experiment(e).timevector = timevectorsim;
+        expstatenames = infostruct(m).expinfostruct(e).statenames;          
+        expvariablenames = infostruct(m).expinfostruct(e).variablenames; 
+        plotdata.model(m).experiment(e).componentnames = {expstatenames{:} expvariablenames{:}};  
+        % simulate to get the state and variable values
+        mexmodel = infostruct(m).expinfostruct(e).model;
+        ic = infostruct(m).expinfostruct(e).initialconditions;
+        try 
+            simdata = feval(mexmodel,timevectorsim,ic,[],OPTIONS);
+            % collect all states and variables that are measured
+            stateindices = infostruct(m).expinfostruct(e).stateindices;
+            statevalues = simdata.statevalues(:,stateindices);
+            variableindices = infostruct(m).expinfostruct(e).variableindices;
+            variablevalues = simdata.variablevalues(:,variableindices);
+        catch
+            disp(lasterr)
+            statevalues = NaN(length(timevectorsim),length(expstatenames));
+            variablevalues = NaN(length(timevectorsim),length(expvariablenames));
+        end
+        % add simulated state trajectories
+        plotdata.model(m).experiment(e).componentvalues = [statevalues variablevalues];
+        for meas=1:length(infostruct(m).expinfostruct(e).measurement),
+            % measurement data
+            plotdata.model(m).experiment(e).measurement(meas).name = infostruct(m).expinfostruct(e).measurement(meas).name;
+            timevectormeas = timevector(infostruct(m).expinfostruct(e).measurement(meas).timevectorindices);
+            plotdata.model(m).experiment(e).measurement(meas).timevector = timevectormeas;
+            % reorder the measurements
+            measstatenames = infostruct(m).expinfostruct(e).measurement(meas).statenames;
+            measvariablenames = infostruct(m).expinfostruct(e).measurement(meas).variablenames;
+            % states 
+            for k=1:length(expstatenames),
+                index = strmatchIQM(expstatenames{k},measstatenames,'exact');
+                if ~isempty(index),
+                    plotdata.model(m).experiment(e).measurement(meas).componentnames{k} = measstatenames{index};
+                    plotdata.model(m).experiment(e).measurement(meas).componentvalues(:,k) = infostruct(m).expinfostruct(e).measurement(meas).statereferences(:,index);
+                    plotdata.model(m).experiment(e).measurement(meas).maxvalues(:,k) = infostruct(m).expinfostruct(e).measurement(meas).statemaxvalues(:,index);
+                    plotdata.model(m).experiment(e).measurement(meas).minvalues(:,k) = infostruct(m).expinfostruct(e).measurement(meas).stateminvalues(:,index);
+                else
+                    plotdata.model(m).experiment(e).measurement(meas).componentnames{k} = 'not available';
+                    plotdata.model(m).experiment(e).measurement(meas).componentvalues(:,k) = NaN(length(timevectormeas),1);
+                    plotdata.model(m).experiment(e).measurement(meas).maxvalues(:,k) = NaN(length(timevectormeas),1);
+                    plotdata.model(m).experiment(e).measurement(meas).minvalues(:,k) = NaN(length(timevectormeas),1);
+                end                    
+            end
+            offset = length(expstatenames);
+            % variables
+            for k=1:length(expvariablenames),
+                index = strmatchIQM(expvariablenames{k},measvariablenames,'exact');
+                if ~isempty(index),
+                    plotdata.model(m).experiment(e).measurement(meas).componentnames{offset+k} = measvariablenames{index};
+                    plotdata.model(m).experiment(e).measurement(meas).componentvalues(:,offset+k) = infostruct(m).expinfostruct(e).measurement(meas).variablereferences(:,index);
+                    plotdata.model(m).experiment(e).measurement(meas).maxvalues(:,offset+k) = infostruct(m).expinfostruct(e).measurement(meas).variablemaxvalues(:,index);
+                    plotdata.model(m).experiment(e).measurement(meas).minvalues(:,offset+k) = infostruct(m).expinfostruct(e).measurement(meas).variableminvalues(:,index);
+                else
+                    plotdata.model(m).experiment(e).measurement(meas).componentnames{offset+k} = 'not available';
+                    plotdata.model(m).experiment(e).measurement(meas).componentvalues(:,offset+k) = NaN(length(timevectormeas),1);
+                    plotdata.model(m).experiment(e).measurement(meas).maxvalues(:,offset+k) = NaN(length(timevectormeas),1);
+                    plotdata.model(m).experiment(e).measurement(meas).minvalues(:,offset+k) = NaN(length(timevectormeas),1);
+                end                    
+            end
+        end
+    end
+end        
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% OUTPUT ARGUMENT OR PLOTTING
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargout == 0,
+    plotIQMP(plotdata);
+else
+    varargout{1} = plotdata;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DELETE MEX MODELS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+global compiledExpModelsIQMparamestGUI % if not empty then models are precompiled and should not be deleted
+if isempty(compiledExpModelsIQMparamestGUI),
+    clear mex
+    for m=1:length(infostruct),
+        for e=1:length(infostruct(m).expinfostruct),
+            delete(infostruct(m).expinfostruct(e).mexfullpath);
+        end
+    end
+end
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/IQMcreaterunestimationscript.m b/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/IQMcreaterunestimationscript.m
new file mode 100644
index 0000000000000000000000000000000000000000..9dbbc5127e4c22dbd8e2ede4c54ad49735783207
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/IQMcreaterunestimationscript.m	
@@ -0,0 +1,169 @@
+function IQMcreaterunestimationscript(project,varargin)
+% IQMcreaterunestimationscript: Creates a run estimation script for the
+% given project and eventually given modelindex. This script can
+% be seen as a template for parameter estimation and fit analysis tasks. 
+%
+% USAGE:
+% ======
+% IQMcreaterunestimationscript(project)
+% IQMcreaterunestimationscript(project,modelindex)
+% IQMcreaterunestimationscript(project,modelindex,filename)
+% IQMcreaterunestimationscript(project,modelindex,filename,OPTIONS)
+%
+% project: IQMprojectSB
+% modelindex: index of the model in the project to use
+% filename: name of the run estimation file (*.m)
+% OPTIONS: a structure with additional informations
+%   OPTIONS.lowerbounds: scalar factor, determining the lower bound for a
+%       parameter by: factor*"original parameter value".
+%   OPTIONS.highbounds: scalar factor, determining the upper bound for a
+%       parameter by: factor*"original parameter value".
+% 
+% DEFAULT VALUES:
+% ===============
+% modelindex: 1
+% filename: 'runEstimation.m'
+% OPTIONS.lowbounds: 0.1
+% OPTIONS.highbounds: 10
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLING VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+modelindex = 1;
+filename = 'runEstimation.m';
+lowbounds = 0.1;
+highbounds = 10;
+handles = [];
+if nargin >= 2,
+    modelindex = varargin{1};
+end
+if nargin >= 3,
+    filename = varargin{2};
+end
+if nargin == 4,
+    OPTIONS = varargin{3};
+end
+if nargin < 1 || nargin > 4,
+    error('Incorrect number of input arguments.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% BASIC CHECK OF THE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isIQMprojectSB(project),
+    error('Input argument ''project'' is not an IQMprojectSB.');
+end
+if ~ischar(filename),
+    error('Input argument ''filename'' is not a string.');
+end
+ps = IQMstruct(project);
+[dummy,filename] = fileparts(filename);
+try lowbounds = OPTIONS.lowbounds; catch, end
+try highbounds = OPTIONS.highbounds; catch, end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET PROJECT INFORMATION AND CHECK AGAIN
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+name = ps.name;
+nrmodels = length(ps.models);
+nrexperiments = length(ps.experiments);
+nrestimations = length(ps.estimations);
+if modelindex < 1 || modelindex > nrmodels,
+    error('''modelindex'' is out of bounds.');
+end
+OPTIONS = [];
+OPTIONS.lowbounds = lowbounds;
+OPTIONS.highbounds = highbounds;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% WRITE OUT THE SCRIPT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fid = fopen([filename '.m'],'w');
+fprintf(fid,'%%%% Below you find a template script, allowing to run parameter estimation\n');
+fprintf(fid,'%% using command-line arguments. It is constructed in such a way that you can\n');
+fprintf(fid,'%% use the "cell-mode" of the MATLAB editor, increasing the ease of use.\n');
+fprintf(fid,'%% The cell-model can be enabled by choosing in the menu "Cell->Enable Cell Mode".\n');
+fprintf(fid,'%% Once enabled, you can execute the yellow cells in this script (assuming you\n');
+fprintf(fid,'%% opened it in the MATLAB editor) by selecting them and pressing "Ctrl-Enter".\n');
+fprintf(fid,'clc; clear all;close all\n');
+fprintf(fid,'\n');
+fprintf(fid,'%%%% LOAD THE PROJECT (SELECT ONE OF BOTH POSSIBILITIES)\n');
+fprintf(fid,'%% Only us one of the following two commands! Uncomment the other that you don''t need.\n');
+fprintf(fid,'iqmp = IQMprojectSB(''projectfilename.iqmp'');  %% Enter the name of the project file (*.iqmp) to load\n',filename);
+fprintf(fid,'iqmp = IQMprojectSB(''projectfoldername'');  %% Enter the name of the project folder to import\n',filename);
+fprintf(fid,'\n'); 
+fprintf(fid,'%%%% DISPLAY INFORMATION ABOUT THE PROJECT\n');
+fprintf(fid,'IQMinfo(iqmp);\n');
+fprintf(fid,'\n');
+fprintf(fid,'%%%% KEEP THE ORIGINAL PROJECT UNCHANGED\n');
+fprintf(fid,'iqmpopt = iqmp;\n');
+fprintf(fid,'\n'); 
+fprintf(fid,'%%%% COMPARE MEASUREMENTS WITH MODEL\n');
+fprintf(fid,'IQMcomparemeasurements(iqmp)\n');
+fprintf(fid,'\n');
+[output] = getparamictextIQM(project,modelindex,OPTIONS);
+fprintf(fid,'%s',output.completeText);
+fprintf(fid,'\n'); 
+fprintf(fid,'%%%% DEFINE THE ESTIMATION INFORMATION (STRUCTURE)\n');
+fprintf(fid,'estimation = [];\n'); 
+fprintf(fid,'\n');
+fprintf(fid,'%% Model and experiment settings\n');
+fprintf(fid,'estimation.modelindex = 1;\n');
+e = IQMgetexperiment(project);
+text = sprintf('%d, ',[1:length(e)]);
+fprintf(fid,'estimation.experiments.indices = [%s];\n',text(1:end-2));
+text = sprintf('%d, ',ones(1,length(e)));
+fprintf(fid,'estimation.experiments.weight = [%s];\n',text(1:end-2));
+fprintf(fid,'\n');
+fprintf(fid,'%% Optimization settings\n');
+fprintf(fid,'estimation.optimization.method = ''simplexIQM'';\n');   
+fprintf(fid,'estimation.optimization.options.maxfunevals = 2000;\n');  
+fprintf(fid,'\n');
+fprintf(fid,'%% Integrator settings\n');
+fprintf(fid,'estimation.integrator.options.abstol = 1e-006;\n');
+fprintf(fid,'estimation.integrator.options.reltol = 1e-006;\n');
+fprintf(fid,'estimation.integrator.options.minstep = 0;\n');
+fprintf(fid,'estimation.integrator.options.maxstep = Inf;\n');
+fprintf(fid,'estimation.integrator.options.maxnumsteps = 1000;\n');
+fprintf(fid,'\n');
+fprintf(fid,'%% Flags\n');
+fprintf(fid,'estimation.displayFlag = 2; %% show iterations and final message\n');   
+fprintf(fid,'estimation.scalingFlag = 2; %% scale by mean values\n');  
+fprintf(fid,'estimation.timescalingFlag = 0; %% do not apply time-scaling\n');  
+fprintf(fid,'estimation.initialconditionsFlag = 1; %% do use initial conditions from measurement data (if available)\n');  
+fprintf(fid,'\n');
+fprintf(fid,'%% Always needed (do not change ... unless you know what you do)\n');
+fprintf(fid,'estimation.parameters = paramdata;\n');
+fprintf(fid,'estimation.parameterslocal = paramdatalocal;\n');
+fprintf(fid,'estimation.initialconditions = icdata;\n');
+fprintf(fid,'\n');
+fprintf(fid,'%% Run estimation\n');
+fprintf(fid,'output = IQMparameterestimation(iqmpopt,estimation)\n');
+fprintf(fid,'%% Get optimized project\n');
+fprintf(fid,'iqmpopt = output.projectopt;\n');
+fprintf(fid,'\n');
+fprintf(fid,'%%%% COMPARE OPTIMIZED PROJECT WITH MEASUREMENTS\n');
+fprintf(fid,'IQMcomparemeasurements(iqmpopt,estimation.modelindex);\n');
+fprintf(fid,'\n');
+fprintf(fid,'%%%% ANALYSIS OF RESIDUALS\n');
+fprintf(fid,'IQManalyzeresiduals(iqmpopt,estimation)\n');
+fprintf(fid,'\n'); 
+fprintf(fid,'%%%% RUN A-POSTERIORI IDENTIFIABILITY ANALYSIS (only considering global variables)\n');
+fprintf(fid,'IQMidentifiability(iqmpopt,paramdata(:,1))\n');
+fprintf(fid,'\n');
+fprintf(fid,'%%%% RUN SOME FIT ANALYSIS\n');
+fprintf(fid,'%% (after completion click in lower figure to remove outliers, corresponding\n');
+fprintf(fid,'%%  to local minima. Finish with "Enter")\n');
+fprintf(fid,'output = IQMparameterfitanalysis(iqmpopt,estimation)\n');
+fprintf(fid,'\n');
+fprintf(fid,'%%%% FITANALYSIS EVALUATION\n');
+fprintf(fid,'IQMfaboxplot(output)\n');
+fprintf(fid,'IQMfahist(output)\n');
+fprintf(fid,'IQMfacorr(output)\n');
+fprintf(fid,'IQMfaclustering(output)\n');
+fprintf(fid,'IQMfadetcorr(output)\n');
+fprintf(fid,'IQMfasigncorr(output)\n');
+fprintf(fid,'\n');
+fclose(fid);
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/IQMexportestimation.m b/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/IQMexportestimation.m
new file mode 100644
index 0000000000000000000000000000000000000000..b8cf1d0daab10174f65ae452cfe511431b030a67
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/IQMexportestimation.m	
@@ -0,0 +1,41 @@
+function IQMexportestimation(project,estimationindex,filename)
+% IQMexportestimation: Exports the selected estimation settings in an
+% IQMprojectSB into a flat text file.
+%
+% USAGE:
+% ======
+% IQMexportestimation(project,estimationindex,filename)
+%
+% project: IQMprojectSB
+% estimationindex: the index of the estimation to export
+% filename: name of the file to write the estimation to (*.est)
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% BASIC CHECK OF THE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isIQMprojectSB(project),
+    error('Input argument ''project'' is not an IQMprojectSB.');
+end
+if ~ischar(filename),
+    error('Input argument ''filename'' is not a string.');
+end
+projectstruct = IQMstruct(project);
+[dummy,filename] = fileparts(filename);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% BASIC CHECK OF THE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if estimationindex > length(projectstruct.estimations) || estimationindex < 1,
+    error('Estimation index out of bounds.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DO THE EXPORT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% convert estimation to text
+text = sprintf('%% Estimation Settings\n\nestimation = [];');
+text = getdatatextstructIQM(projectstruct.estimations{estimationindex},'estimation',text);
+% write to file
+IQMwriteText2File(text,[filename '.est']);
diff --git a/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/IQMgetexperiment.m b/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/IQMgetexperiment.m
new file mode 100644
index 0000000000000000000000000000000000000000..1b54742a0ce07469caa1065bd9662f4da9786691
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/IQMgetexperiment.m	
@@ -0,0 +1,55 @@
+function [experiments] = IQMgetexperiment(project,varargin)
+% IQMgetexperiment: get experiment(s) from the given project
+%
+% USAGE:
+% ======
+% [experiments] = IQMgetexperiment(project)        
+% [experiments] = IQMgetexperiment(project,experimentindices)        
+%
+% project:  IQMprojectSB object
+% experimentindices: index/indices of the experiment in project to return
+%                    (scalar index or vector of indices)
+%
+% Output Arguments:
+% =================
+% experiments: if no experimentindices are specified, all the experiments are
+%         returned. If more than one experiment is present in the project a
+%         cell-array of experiments is returned. If an experimentindices 
+%         (scalar index of vector of indices) argument is specified the
+%         corresponding experiment(s) will be returned. 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check input argument
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isIQMprojectSB(project),
+    error('Input argument is not an IQMprojectSB.');
+end
+project = IQMstruct(project);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Variable input arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin == 1,
+    if length(project.experiments) == 1,
+        experiments = project.experiments(1).experiment;
+    else
+        experiments = {project.experiments.experiment};
+    end
+elseif nargin == 2,
+    if ~isnumeric(varargin{1}),
+        error('Wrong input argument ''experimentindices''.');
+    end
+    if ~isempty(find(varargin{1}>length(project.experiments))) || ~isempty(find(varargin{1} < 1)),
+        error('''experimentindices'' input argument is out of bounds.');
+    end
+    if length(varargin{1}) == 1,
+        experiments = project.experiments(varargin{1}).experiment;
+    else 
+        experiments = {project.experiments(varargin{1}).experiment};
+    end
+else
+    error('Incorrect number of input arguments.');
+end
+return
diff --git a/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/IQMgetmeasurement.m b/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/IQMgetmeasurement.m
new file mode 100644
index 0000000000000000000000000000000000000000..11e572788d41340468092bff1be99e5d9c92ddbc
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/IQMgetmeasurement.m	
@@ -0,0 +1,66 @@
+function [measurements] = IQMgetmeasurement(project,varargin)
+% IQMgetmeasurement: get measurement(s) from the given project and
+% experiment.
+%
+% USAGE:
+% ======
+% [measurements] = IQMgetmeasurement(project,experimentindex)        
+% [measurements] = IQMgetmeasurement(project,experimentindex,measurementindices)        
+%
+% project:  IQMprojectSB object
+% experimentindex:    index of the experiment in the project for which to return
+%                     the measurements
+% measurementindices: index/indices of the measurement(s) in the specified
+%                     experiment return (scalar or vector of indices)
+%
+% Output Arguments:
+% =================
+% measurements: if no measurementindices are specified, all the measurements
+%         are returned. If more than one measurement is present in the
+%         projects experiment a cell-array of measurements is returned. If a
+%         measurementindices argument is specified the corresponding
+%         measurement(s) will be returned. 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check input argument
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isIQMprojectSB(project),
+    error('Input argument is not an IQMprojectSB.');
+end
+project = IQMstruct(project);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Variable input arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin ~= 2 && nargin ~= 3,
+    error('Incorrect number of input arguments.');
+end
+if ~isnumeric(varargin{1}) || length(varargin{1}) ~= 1,
+    error('Incorrect ''experimentindex'' input argument.');
+end
+if varargin{1} > length(project.experiments) || varargin{1} < 1,
+    error('''experimentindex'' input argument is out of bounds.');
+end
+
+if nargin == 2,
+    measurements = project.experiments(varargin{1}).measurements;
+    if length(measurements) == 1,
+        measurements = measurements{1};
+    end
+elseif nargin == 3,
+    if ~isnumeric(varargin{2}),
+        error('Wrong input argument ''measurementindices''.');
+    end
+    if ~isempty(find(varargin{2}>length(project.experiments(varargin{1}).measurements))) || ~isempty(find(varargin{2} < 1)),
+        error('''measurementindices'' input argument is out of bounds.');
+    end
+    if length(varargin{2}) == 1,
+        measurements = project.experiments(varargin{1}).measurements{varargin{2}};
+    else 
+        measurements = {project.experiments(varargin{1}).measurements{varargin{2}}};
+    end
+else
+end
+return
diff --git a/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/IQMgetmodel.m b/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/IQMgetmodel.m
new file mode 100644
index 0000000000000000000000000000000000000000..bd78c150c2402edd9f189b208e6958a10436c3e4
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/IQMgetmodel.m	
@@ -0,0 +1,57 @@
+function [models] = IQMgetmodel(project,varargin)
+% IQMgetmodel: get model(s) from the given project
+%
+% USAGE:
+% ======
+% [models] = IQMgetmodel(project)        
+% [models] = IQMgetmodel(project,modelindices)        
+%
+% project:  IQMprojectSB object
+% modelindices: indices of the model in project to return (scalar
+%               or vector of indices)
+%
+% Output Arguments:
+% =================
+% models: if no modelindices are specified, all the models are returned. If
+%         more than one model is present in the project a cell-array of
+%         models is returned. If a modelindices argument is specified the
+%         corresponding model(s) will be returned.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check input argument
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isIQMprojectSB(project),
+    error('Input argument is not an IQMprojectSB.');
+end
+project = IQMstruct(project);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Variable input arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin == 1,
+    if length(project.models) == 1,
+        models = project.models{1};
+    else
+        models = project.models;
+    end
+elseif nargin == 2,
+    if ~isnumeric(varargin{1}),
+        error('Wrong input argument ''modelindices''.');
+    end
+    if ~isempty(find(varargin{1}>length(project.models))) || ~isempty(find(varargin{1} < 1)),
+        error('''modelindices'' input argument is out of bounds.');
+    end
+    if length(varargin{1}) == 1,
+        models = project.models{varargin{1}};
+    else 
+        models = {project.models{varargin{1}}};
+    end
+else
+    error('Incorrect number of input arguments.');
+end
+
+
+
+return
diff --git a/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/IQMidentifiability.m b/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/IQMidentifiability.m
new file mode 100644
index 0000000000000000000000000000000000000000..d2264ba27da810df906782293a7011b0f47f94e6
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/IQMidentifiability.m	
@@ -0,0 +1,242 @@
+function [varargout] = IQMidentifiability(project,parameters,varargin)
+% IQMidentifiability: Performs parameter identifiability analysis for a
+% given project, based on IQMsensitivity and IQMparametercorrelation.
+% The model and the experiments to consider can be chosen. 
+% Time points to take into account are determined from the measurement
+% data that are available in the project. More information can be found in
+% the help text to the IQMparametercorrelation function.
+%
+% USAGE:
+% ======
+% output = IQMidentifiability(project, parameters)
+% output = IQMidentifiability(project, parameters, options)
+%
+% project: IQMprojectSB to analyze
+% parameters: Cell-array of parameternames for which to determine the
+%       identifiability
+% options: structure with the following fields:
+%       options.pValueFlag: =0: plot correlations, =1: plot p-values
+%       options.pValueCutOff: pValue for which to make a decision if
+%            correlated or not. (For plotting purposes the pValues below
+%            the threshold are set to zero)
+%       options.modelindex: Index of the model in the project to consider
+%       options.experimentindices: Vector of indices indicating the experiments to
+%                                  consider
+%       options.integratoroptions.abstol: abs tolerance
+%       options.integratoroptions.reltol: rel tolerance
+%       options.integratoroptions.minstep: min step-size of integrator
+%       options.integratoroptions.maxstep: max step-size of integrator
+%       options.integratoroptions.maxnumsteps: maximum number of steps to be
+%         taken by the solver in its attempt to reach the next
+%         output time 
+
+% DEFAULT VALUES:
+% ===============
+% options.pValueFlag:           0 (plot correlations)
+% options.pValueCutOff:         0.05 
+% options.modelindex:           1 (first model)
+% options.experimentindices:    1:n (all experiments)
+% options.integratoroptions.abstol: 1e-6
+% options.integratoroptions.reltol: 1e-6
+% options.integratoroptions.minstep: 0
+% options.integratoroptions.maxstep: inf
+% options.integratoroptions.maxnumsteps: 500
+%
+% Output Arguments:
+% =================
+% When called without an output argument the parameter correlation
+% information is graphically represented. Both the correlations and the 
+% P-values are plotted.
+% To be more consistent with the coloring not the P-values but (1-Pvalues)
+% are plotted. The lighter the color, the higher the correlation between
+% the corresponding parameters. 
+% 
+% If an output argument is given, the results are returned as a
+% MATLAB structure as follows:
+%      output.parameters: cell-array with parameter names
+%      output.correlationMatrix: parameter correlation matrix
+%      output.pValues: a matrix of p-values for testing
+%           the hypothesis of no correlation.  Each p-value is the probability
+%           of getting a correlation as large as the observed value by random
+%           chance, when the true correlation is zero.  If pValues(i,j) is small, say
+%           less than 0.05, then the correlation correlationMatrix(i,j) is
+%           significant.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+global useIQMguiFlag
+if useIQMguiFlag ~= 1,
+    useIQMguiFlag = 0;
+end
+
+projectstruct = IQMstruct(project);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE INPUT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% default values
+modelindex = 1;
+experimentindices = [1:length(projectstruct.experiments)];
+pValueCutOff = 0.05;
+pValueFlag = 0;
+% varargins
+if nargin < 2 || nargin > 3,
+    error('Incorrect number of input arguments.');
+end
+if nargin == 3,
+    options = varargin{1};
+    if isfield(options,'modelindex'),
+        modelindex = options.modelindex;
+    end
+    if isfield(options,'experimentindices'),
+        experimentindices = options.experimentindices;
+    end
+    if isfield(options,'pValueCutOff'),
+        pValueCutOff = options.pValueCutOff;
+        if isempty(pValueCutOff),
+            pValueCutOff = 0;
+        end
+    end
+    if isfield(options,'pValueFlag'),
+        pValueFlag = options.pValueFlag;
+        if isempty(pValueFlag),
+            pValueFlag = 0;
+        end
+    end
+end
+if modelindex < 0 || modelindex > length(projectstruct.models),
+    error('''modelindex'' out of bounds.');
+end
+if min(experimentindices) < 1 || max(experimentindices) > length(projectstruct.experiments),
+    error('''experimentindices'' out of bounds.');
+end
+% get integratoroptions
+try integratoroptions = options.integratoroptions; catch, integratoroptions = []; end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% MERGE MODEL WITH EXPERIMENTS, CHECK, AND PERFORM SENSITIVITY SIMULATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+modelexp = {};
+senssimdata = [];        % senssimdata for each experiment
+measuredcomponents = [];     % measured components for each experiment
+measuredcomponents.states = {};
+measuredcomponents.variables = {};
+
+if useIQMguiFlag,
+    h = waitbar(0,'Calculating. Please wait...');
+end
+
+for e=1:length(experimentindices),
+    if useIQMguiFlag,
+        waitbar(e/length(experimentindices),h)
+    end
+    modelexp{e} = IQMmergemodexp(projectstruct.models{modelindex},projectstruct.experiments(experimentindices(e)).experiment);
+    % check if all parameters in the modelexp ... if not then error
+    getparamindicesIQM(modelexp{e},parameters);
+    % construct the simulation time vector
+    timevector = [];
+    componentnames = {};
+    for m=1:length(projectstruct.experiments(experimentindices(e)).measurements),
+        [timevectormeas, componentnamesmeas] = IQMmeasurementdata(projectstruct.experiments(experimentindices(e)).measurements{m});
+        timevector = [timevector(:); timevectormeas];
+        componentnames = {componentnames{:} componentnamesmeas{:}};
+    end
+    timevector = sort(unique(timevector));
+    componentnames = unique(componentnames);
+    % perform sensitivity simulation for chosen parameters
+    senssimdata{e} = IQMsensitivity(modelexp{e},timevector, parameters,[],integratoroptions);
+    % save measured states and variables for each experiment
+    allmodelstates = IQMstates(modelexp{e});
+    allmodelvariables = IQMvariables(modelexp{e});
+    indexs = 1;
+    indexv = 1;
+    for k=1:length(componentnames),
+        if ~isempty(strmatchIQM(componentnames{k},allmodelstates,'exact')),
+            measuredcomponents(e).states{indexs} = componentnames{k};
+            indexs = indexs+1;
+        end
+        if ~isempty(strmatchIQM(componentnames{k},allmodelvariables,'exact')),
+            measuredcomponents(e).variables{indexv} = componentnames{k};
+            indexv = indexv+1;
+        end
+    end
+end
+if useIQMguiFlag,
+    close(h);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PERFORM PARAMETER CORRELATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+paramcorrdata = IQMparametercorrelation(senssimdata,parameters,measuredcomponents);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CONSTRUCT OUTPUT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargout ~= 0,
+    output = [];
+    output.parameters = paramcorrdata.parameters;
+    output.correlationMatrix = paramcorrdata.correlationMatrix;
+    output.pValues = paramcorrdata.pValues;
+    output.corrcoefLB = paramcorrdata.corrcoefLB;
+    output.corrcoefUB = paramcorrdata.corrcoefUB;
+    varargout{1} = output;
+else
+    if pValueFlag == 0,
+        % Plot the correlation matrix (absolute values)
+        plotData = paramcorrdata.correlationMatrix;
+        titleText = 'Parameter Correlation Matrix (absolute values)';
+        % Plot the correlation matrix (absolute values)
+        % Prepare plot matrix
+        plotMatrix = [plotData zeros(size(plotData,1),1); -ones(1,size(plotData,2)+1)];
+        plotMatrix = abs(plotMatrix);
+        % Plot the result
+        figH = figure; clf;
+        axesH = gca(figH);
+        pcolor(plotMatrix);
+        axis square;
+        colorbar('EastOutside','YTick',[-1,-0.8,-0.6,-0.4,-0.2,0,0.2,0.4,0.6,0.8,1]);
+        set(axesH,'XTick',[1.5:size(plotData,1)+0.5]);
+        set(axesH,'XTickLabel',paramcorrdata.parameters);
+        try
+            set(gca,'XTickLabelRotation',90);
+        catch
+        end
+        set(axesH,'YTick',[1.5:size(plotData,1)+0.5]);
+        set(axesH,'YTickLabel',paramcorrdata.parameters);
+        colormap('Bone');
+        hlhlx = title(titleText);
+        set(hlhlx,'Interpreter','none');
+    else
+        % Plot the P-Value matrix
+        plotData = paramcorrdata.pValues;
+        if ~isempty(pValueCutOff),
+            plotData(find(plotData<pValueCutOff)) = 0;
+            titleText = sprintf('(1-P)-values. Cut-off threshold: 1-%g',pValueCutOff);
+        else
+            titleText = '(1-P)-values.';
+        end
+        plotData = 1-plotData;
+        plotData = plotData + eye(size(plotData));
+        % Prepare plot matrix
+        plotMatrix = [plotData zeros(size(plotData,1),1); -ones(1,size(plotData,2)+1)];
+        plotMatrix = abs(plotMatrix);
+        % Plot the result
+        figH = figure; clf;
+        axesH = gca(figH);
+        pcolor(plotMatrix);
+        axis square;
+        colorbar('EastOutside','YTick',[-1,-0.8,-0.6,-0.4,-0.2,0,0.2,0.4,0.6,0.8,1]);
+        set(axesH,'XTick',[1.5:size(plotData,1)+0.5]);
+        set(axesH,'XTickLabel',paramcorrdata.parameters);
+        try
+            set(gca,'XTickLabelRotation',90);
+        catch
+        end
+        set(axesH,'YTick',[1.5:size(plotData,1)+0.5]);
+        set(axesH,'YTickLabel',paramcorrdata.parameters);
+        colormap('Bone');
+        hlhlx = title(titleText);
+        set(hlhlx,'Interpreter','none');
+    end
+end
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/IQMinfo.m b/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/IQMinfo.m
new file mode 100644
index 0000000000000000000000000000000000000000..3456173953cb36c1d1213b3d3cb7489f3300fa66
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/IQMinfo.m	
@@ -0,0 +1,57 @@
+function [] = IQMinfo(project)
+% IQMinfo: quick dump of contents of an IQMprojectSB. Mainly used to check
+% if everything is correct and to determine the model, experiment, and
+% measurement indices.
+%
+% USAGE:
+% ======
+% [] = IQMinfo(project)        
+%
+% project:  IQMprojectSB object
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check input argument
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isIQMprojectSB(project),
+    error('Input argument is not an IQMprojectSB.');
+end
+project = IQMstruct(project);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Collect information
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+name = project.name;
+notes = project.notes;
+models = project.models;
+experiments = project.experiments;
+estimations = project.estimations;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Display information
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+disp(' ');
+disp('===PROJECT INFO===============================================');
+disp(sprintf('Project name: %s',name));
+disp('---NOTES------------------------------------------------------');
+notes = double(notes); notes(find(notes==13)) = []; notes = char(notes);
+disp(sprintf('Project notes: %s',notes));
+disp('---MODELS-----------------------------------------------------');
+for k=1:length(models),
+    ms = IQMstruct(models{k});
+    disp(sprintf('Model %d: %s',k,ms.name));
+end
+disp('---EXPERIMENTS------------------------------------------------');
+for k=1:length(experiments),
+    es = IQMstruct(experiments(k).experiment);
+    disp(sprintf('Experiment %d: %s',k,es.name));
+    for k2=1:length(experiments(k).measurements),
+        ms = IQMstruct(experiments(k).measurements{k2});
+        disp(sprintf('\tMeasurement %d: %s',k2,ms.name));
+    end
+end
+disp('---ESTIMATIONS------------------------------------------------');
+disp(sprintf('%d estimations present',length(estimations)));
+disp('==============================================================');
+disp(' ');
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/IQMinsilicoexpproj.m b/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/IQMinsilicoexpproj.m
new file mode 100644
index 0000000000000000000000000000000000000000..42b2fec6cae9b76c0e3d8d6d132520eb7c10a4ce
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/IQMinsilicoexpproj.m	
@@ -0,0 +1,140 @@
+function [varargout] = IQMinsilicoexpproj(project,modelindex,experimentindex,timevector,varargin)
+% IQMinsilicoexpproj runs an in-silico experiment directly on a model and
+% experiment within a IQMprojectSB. Simulated data can be returned in the 
+% IQMmeasurement format, plotted, or written in a CSV
+% or Excel measurement file (the latter only under Windows).
+%
+% Note: In contrast to IQMinsilicoexp, this function per default exports
+% the insilico generated data to a CSV measurement file.
+%
+% USAGE:
+% ======
+% [] = IQMinsilicoexpproj(project,modelindex,experimentindex,timevector [,OPTIONS])         
+% [] = IQMinsilicoexpproj(project,modelindex,experimentindex,timevector,measurements [,OPTIONS])         
+% [] = IQMinsilicoexpproj(project,modelindex,experimentindex,timevector,measurements,filetypeFlag [,OPTIONS])         
+% [] = IQMinsilicoexpproj(project,modelindex,experimentindex,timevector,measurements,filetypeFlag,filename [,OPTIONS])         
+% [output] = IQMinsilicoexpproj(project,modelindex,experimentindex,timevector [,OPTIONS])         
+% [output] = IQMinsilicoexpproj(project,modelindex,experimentindex,timevector,measurements [,OPTIONS])         
+%
+% project:           IQMprojectSB to perform the experiment on
+% modelindex:        Index of the model in the project to be used
+% experimentindex:   Index of the experiment to be used (scalar only)
+% timevector:        Timevector to be used for simulation
+% measurements:      cell-array with the names of the components to measure
+%                    (states, variables, reactions)
+% filetypeFlag:      0=plot results, 1=CSV measurement file, 2=Excel measurement
+%                    file
+% filename:          Name of the measurement file (or of the measurement) to generate
+% OPTIONS: structure with integrator options.
+%        OPTIONS.abstol: abs tolerance
+%        OPTIONS.reltol: rel tolerance
+%        OPTIONS.minstep: min step-size of integrator
+%        OPTIONS.maxstep: max step-size of integrator
+%        OPTIONS.maxnumsteps: maximum number of steps to be
+%          taken by the solver in its attempt to reach the next
+%          output time 
+%
+% DEFAULT VALUES:
+% ===============
+% measurements: all states are measured
+% filetypeFlag: 1 (export to CSV file). If output argument is specified, the 
+%               setting of the filetype flag is ignored
+% filename: combination of model and experiment name
+% OPTIONS.abstol: 1e-6
+% OPTIONS.reltol: 1e-6
+% OPTIONS.minstep: 0
+% OPTIONS.maxstep: inf
+% OPTIONS.maxnumsteps: 500
+%
+% Output Arguments:
+% =================
+% output: An IQMmeasurement object with the resulting data
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK INPUTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isIQMprojectSB(project),
+    error('The first input argument needs to be an IQMprojectSB.');
+end
+projectstruct = IQMstruct(project);
+if modelindex < 0 || modelindex > length(projectstruct.models),
+    error('''modelindex'' out of bounds.');
+end
+if experimentindex < 1 || experimentindex > length(projectstruct.experiments),
+    error('''experimentindex'' out of bounds.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Convert to IQMinsilicoexp
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+model = projectstruct.models{modelindex};
+experiment = projectstruct.experiments(experimentindex).experiment;
+modelstruct = struct(model);
+experimentstruct = struct(experiment);
+filetypeFlag = 1; % per default: export as CSV file
+filename = [modelstruct.name '_' experimentstruct.name];
+measurements = IQMstates(model);
+OPTIONS = [];
+optionsgiven = 0;
+if nargin == 5,
+    if isstruct(varargin{1}) || (isempty(varargin{1}) && isnumeric(varargin{1})),
+        OPTIONS = varargin{1};
+        optionsgiven = 1;        
+    else
+        measurements = varargin{1};
+    end
+elseif nargin == 6,
+    measurements = varargin{1};
+    if isstruct(varargin{2}) || (isempty(varargin{2}) && isnumeric(varargin{2})),
+        OPTIONS = varargin{2};
+        optionsgiven = 1;        
+    else
+        filetypeFlag = varargin{2};
+    end
+elseif nargin == 7,
+    measurements = varargin{1};
+    filetypeFlag = varargin{2};
+    if isstruct(varargin{3}) || (isempty(varargin{3}) && isnumeric(varargin{3})),
+        OPTIONS = varargin{3};
+        optionsgiven = 1;        
+    else
+        filename = varargin{3};
+    end    
+elseif nargin == 8.
+    measurements = varargin{1};
+    filetypeFlag = varargin{2};
+    filename = varargin{3};
+    OPTIONS = varargin{4};
+    optionsgiven = 1;        
+end
+if isempty(measurements),
+    measurements = IQMstates(model);
+end
+
+mynargin = nargin;
+if optionsgiven == 1,
+    mynargin = mynargin - 1; % adapting to w/o options ...
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% RUN IQMinsilicoexp
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargout == 0,
+    if mynargin >= 4 || mynargin <= 6,
+        IQMinsilicoexp(model,experiment,timevector,measurements,filetypeFlag,OPTIONS);
+    elseif mynargin == 7,
+        IQMinsilicoexp(model,experiment,timevector,measurements,filetypeFlag,filename,OPTIONS);
+    else
+        error('Incorrect number of input arguments');
+    end
+else
+    if mynargin >= 4 || mynargin <= 6,
+        varargout{1} = IQMinsilicoexp(model,experiment,timevector,measurements,filetypeFlag,OPTIONS);
+    elseif mynargin == 7,
+        varargout{1} = IQMinsilicoexp(model,experiment,timevector,measurements,filetypeFlag,filename,OPTIONS);
+    else
+        error('Incorrect number of input arguments');
+    end
+end
diff --git a/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/IQMplotmeasurements.m b/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/IQMplotmeasurements.m
new file mode 100644
index 0000000000000000000000000000000000000000..7158fe83d040883b94e8b40e99b65da6471a83e5
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/IQMplotmeasurements.m	
@@ -0,0 +1,68 @@
+function [] = IQMplotmeasurements(project,varargin)
+% IQMplotmeasurements: Plots all measurements in the given IQMprojectSB
+% using IQMplot. Very useful to get a quick overview over measurement
+% results. The function opens a simple GUI where you in the upper left
+% corner can select the experiment and measurement to display. If error
+% bound information is available in the measurement data this is displayed.
+%
+% USAGE:
+% ======
+% [] = IQMplotmeasurements(project)        
+% [] = IQMplotmeasurements(project,experimentindices)        
+%
+% project:  IQMprojectSB object
+% experimentindices: vector with indices of the experiments for which to
+%   plot the measurement data. Per default the measurement data of all
+%   experiments is plotted.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check input argument
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isIQMprojectSB(project),
+    error('Input argument is not an IQMprojectSB.');
+end
+project = IQMstruct(project);
+experiments = project.experiments;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle variable input arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+experimentindices = [1:length(experiments)];
+if nargin == 2,
+    experimentindices = varargin{1};
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get all measurements from all experiments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+datastructures = {};
+for k=1:length(experimentindices),
+    es = IQMstruct(experiments(experimentindices(k)).experiment);
+    for k2=1:length(experiments(experimentindices(k)).measurements),
+        % get IQMplot datastructure for measurement
+        ds = IQMvisualizemeasurement(experiments(experimentindices(k)).measurements{k2});
+        % update name of measurement in plotstructure
+        ds.name = sprintf('E%d: %s, M%d: %s',experimentindices(k),experiments(experimentindices(k)).name,k2,ds.name);
+        datastructures{end+1} = ds;
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Error if empty
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(datastructures),
+    error('The project does not contain any measurements.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Display using IQMplot
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% construct call for IQMplot
+plotcall = 'IQMplot(';
+for k=1:length(datastructures),
+    plotcall = sprintf('%sdatastructures{%d},',plotcall,k);
+end
+plotcall = [plotcall(1:end-1) ');'];
+eval(plotcall);
diff --git a/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/IQMreducerateexpressionsProject.m b/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/IQMreducerateexpressionsProject.m
new file mode 100644
index 0000000000000000000000000000000000000000..f58adfbc6b77014ea0d78a7787a698d3f49ee181
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/IQMreducerateexpressionsProject.m	
@@ -0,0 +1,145 @@
+function [projectout] = IQMreducerateexpressionsProject(project,modelindex,varargin)
+% IQMreducerateexpressionsProject: Function allowing the interactive and iterative
+% reduction of complex kinetic rate expressions. The function is directly
+% applicable to projects and will reduce a selected model of the project
+% using all or selected experiments from the project.
+% 
+% USAGE:
+% ======
+% [modelred] = IQMreducerateexpressionsProject(project)
+% [modelred] = IQMreducerateexpressionsProject(project, modelindex)
+% [modelred] = IQMreducerateexpressionsProject(project, modelindex, experimentindices)
+% [modelred] = IQMreducerateexpressionsProject(project, modelindex, experimentindices, options)
+%
+% project:              IQMprojectSB to consider for reduction
+% modelindex:           Index of the model to reduce
+% experimentindices:    Vector of indices of the experiments to consider
+%                       (time-points will be taken from the available
+%                       measurements. In case no measurements are available, 
+%                       they can be generated using the IQMinsilicoexp function) 
+% options: structure containing options for the reduction algorithm:
+%        options.tol: tolerance for singularity detection (smallest SV)
+%        options.keeporigparameters: =0: do not keep original parameters
+%                                    =2: do always keep original parameters
+%                                    =1: keep original parameters only if
+%                                        it leads to fewer parameters
+%        options.numeratorweighting: =1: weight numerator terms and denumerator terms 
+%                                    such that numerators are kept
+%                                    =0: dont do any weighting
+%
+% DEFAULT VALUES:
+% ===============
+% options.tol:                  1e-5
+% options.keeporigparameters:   0
+% options.numeratorweighting:   0
+%
+% Output Arguments:
+% =================
+% project: new project in which the reduced model has been appended.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+disp('Please note that the reduction functionality is still a bit limited.');
+disp('Many special cases of models are not treated yet and thus a lot of errors might appear.');
+disp('It certainly does not work for models with varying compartment sizes, piecewise expressions');
+disp('in the rate expressions, etc. Just try it out and if it does not work correctly please');
+disp('contact me: henning@sbtoolbox2.org');
+disp(' ');
+disp('Press a key to start');
+pause;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% BASIC CHECK OF THE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isIQMprojectSB(project),
+    error('Input argument ''project'' is not an IQMprojectSB.');
+end
+projectstruct = IQMstruct(project);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+modelindex = 1;
+experimentindices = [1:length(projectstruct.experiments)];
+options = [];
+options.tol = 1e-5;
+options.keeporigparameters = 0;
+options.numeratorweighting = 0;
+if nargin == 1,
+    % do nothing
+elseif nargin == 2,
+    modelindex = varargin{1};
+elseif nargin == 3,
+    modelindex = varargin{1};
+    experimentindices = varargin{2};
+elseif nargin == 3,
+    modelindex = varargin{1};
+    experimentindices = varargin{2};
+    checkoptions = varargin{3};
+    if isfield(checkoptions,'tol'),
+        options.tol = checkoptions.tol;
+    end
+    if isfield(checkoptions,'keeporigparameters'),
+        options.keeporigparameters = checkoptions.keeporigparameters;
+    end
+    if isfield(checkoptions,'numeratorweighting'),
+        options.numeratorweighting = checkoptions.numeratorweighting;
+    end    
+else
+    error('Incorrect number of input arguments.');
+end
+if modelindex < 0 || modelindex > length(projectstruct.models),
+    error('''modelindex'' out of bounds.');
+end
+if min(experimentindices) < 1 || max(experimentindices) > length(projectstruct.experiments),
+    error('''experimentindices'' out of bounds.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PREPARE THE CALLING OF THE REDUCE FUNCTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+model = projectstruct.models{modelindex};
+experiments = {projectstruct.experiments(experimentindices).experiment};
+% get the timevectors for the experiments from the available measurement
+% data (if none available then error).
+timevectors = {};
+for e=1:length(projectstruct.experiments),
+    timevector = [];
+    for m=1:length(projectstruct.experiments(e).measurements),
+        tv = IQMmeasurementdata(projectstruct.experiments(e).measurements{m});
+        timevector = [timevector; tv];
+    end
+    timevector = sort(unique(timevector));
+    if isempty(timevector),
+        % no measurements present
+        error('No measurement data present for experiment ''%d''. Could not determine timevector.\nUse IQMinsilicoexpproj to generate insilico data with realistic timevector.',e);
+    end
+    timevectors{e} = timevector;
+end
+% Just no extravariables
+extravariables = {};
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CONVERT RATE FUNCTIONS TO RATE FORMULAS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+modelstruct = IQMstruct(model);
+for k=1:length(modelstruct.reactions),
+    modelstruct.reactions(k).formula = getkinformulaIQM(modelstruct.reactions(k).formula);
+end
+model = IQMmodel(modelstruct);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PERFORM THE REDUCTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+disp('Starting reduction ...');
+modelred = IQMredallreac(model,experiments,timevectors,options,extravariables);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% ADD REDUCED MODEL TO THE PROJECT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+disp('Adding reduced model to the project ...');
+mrs = struct(modelred);
+mrs.name = [mrs.name '_reduced'];
+modelred = IQMmodel(mrs);
+projectout = IQMupdatemodel(project,modelred);
+
diff --git a/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/IQMupdateexperiment.m b/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/IQMupdateexperiment.m
new file mode 100644
index 0000000000000000000000000000000000000000..ad2525ea311560ee776aef36776aba385fe86c16
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/IQMupdateexperiment.m	
@@ -0,0 +1,56 @@
+function [project] = IQMupdateexperiment(project,experiment,varargin)
+% IQMupdateexperiment: update or add a experiment in a project.  
+%
+% USAGE:
+% ======
+% [project] = IQMupdateexperiment(project,experiment)
+% [project] = IQMupdateexperiment(project,experiment,experimentindex)        
+%
+% project:         IQMprojectSB object
+% experiment:      IQMexperiment which to update or add
+% experimentindex: index of the experiment to be updated. If omitted the experiment is
+%                  added to the project as last experiment.
+%
+% Output Arguments:
+% =================
+% project: updated project
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check input argument
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isIQMprojectSB(project),
+    error('First input argument is not an IQMprojectSB.');
+end
+if ~isIQMexperiment(experiment),
+    error('Second input argument is not an IQMexperiment.');
+end
+projectstruct = IQMstruct(project);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Variable input arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin == 2,
+    experimentindex = length(projectstruct.experiments)+1;
+elseif nargin == 3,
+    experimentindex = varargin{1};
+    if experimentindex < 1 || experimentindex > length(projectstruct.experiments),
+        error('''experimentindex'' out of bounds.');
+    end
+else
+    error('Incorrect number of input arguments.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Adding/Updating the project
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+projectstruct.experiments(experimentindex).experiment = experiment;
+if isempty(projectstruct.experiments(experimentindex).name),
+    % use experiments name as name for the experiment in the project
+    % (otherwise empty if added experiments)
+    x = struct(experiment);
+    projectstruct.experiments(experimentindex).name = x.name;
+end
+project = IQMprojectSB(projectstruct);
+return
diff --git a/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/IQMupdatemeasurement.m b/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/IQMupdatemeasurement.m
new file mode 100644
index 0000000000000000000000000000000000000000..c5b37b24201b049f5cadfd673419816211acb7d1
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/IQMupdatemeasurement.m	
@@ -0,0 +1,54 @@
+function [project] = IQMupdatemeasurement(project,experimentindex,measurement,varargin)
+% IQMupdatemeasurement: update or add a measurement in an experiment of a project.  
+%
+% USAGE:
+% ======
+% [project] = IQMupdatemeasurement(project,experimentindex,measurement)
+% [project] = IQMupdatemeasurement(project,experimentindex,measurement,measurementindex)
+%
+% project:          IQMprojectSB object
+% experimentindex:  index of the experiment to add the measurement to
+% measurement:      IQMmeasurement which to update or add
+% measurementindex: index of the measurement to be updated. If omitted the measurment is
+%                   added to the experiment as last measurement.
+%
+% Output Arguments:
+% =================
+% project: updated project
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check input argument
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isIQMprojectSB(project),
+    error('First input argument is not an IQMprojectSB.');
+end
+if ~isnumeric(experimentindex),
+    error('Second input argument is not an experiment index.');
+end
+if ~isIQMmeasurement(measurement),
+    error('Third input argument is not an IQMmeasurement.');
+end
+projectstruct = IQMstruct(project);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Variable input arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin == 3,
+    measurementindex = length(projectstruct.experiments(experimentindex).measurements)+1;
+elseif nargin == 4,
+    measurementindex = varargin{1};
+    if measurementindex < 1 || measurementindex > length(projectstruct.experiments(experimentindex).measurements),
+        error('''measurementindex'' out of bounds.');
+    end
+else
+    error('Incorrect number of input arguments.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Adding/Updating the project
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+projectstruct.experiments(experimentindex).measurements{measurementindex} = measurement;
+project = IQMprojectSB(projectstruct);
+return
diff --git a/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/IQMupdatemodel.m b/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/IQMupdatemodel.m
new file mode 100644
index 0000000000000000000000000000000000000000..ae98c74ffc903ad8aa67c0fca36aff4bc4f8f4bb
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/IQMupdatemodel.m	
@@ -0,0 +1,50 @@
+function [project] = IQMupdatemodel(project,model,varargin)
+% IQMupdatemodel: update or add a model in a project.  
+%
+% USAGE:
+% ======
+% [project] = IQMupdatemodel(project,model)        
+% [project] = IQMupdatemodel(project,model,modelindex)        
+%
+% project:  IQMprojectSB object
+% model:    IQMmodel which to update or add
+% modelindex: index of the model to be updates. If omitted the model is
+%           added to the project as last model.
+%
+% Output Arguments:
+% =================
+% project: updated project
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check input argument
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isIQMprojectSB(project),
+    error('First input argument is not an IQMprojectSB.');
+end
+if ~isIQMmodel(model),
+    error('Second input argument is not an IQMmodel.');
+end
+projectstruct = IQMstruct(project);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Variable input arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin == 2,
+    modelindex = length(projectstruct.models)+1;
+elseif nargin == 3,
+    modelindex = varargin{1};
+    if modelindex < 1 || modelindex > length(projectstruct.models),
+        error('''modelindex'' out of bounds.');
+    end
+else
+    error('Incorrect number of input arguments.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Adding/Updating the project
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+projectstruct.models{modelindex} = model;
+project = IQMprojectSB(projectstruct);
+return
diff --git a/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/auxiliary/getdatatextstructIQM.m b/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/auxiliary/getdatatextstructIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..7417f26a75e28d23189395a0b566bbc42dce3bab
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/auxiliary/getdatatextstructIQM.m	
@@ -0,0 +1,41 @@
+function text = getdatatextstructIQM(root,roottext,text)
+% getdatatextstructIQM: converts a structure to a flat file
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% converting given root level of a structure into text
+fn = fieldnames(root);
+for k=1:length(fn),
+    fv = getfield(root,fn{k});
+    if isstruct(fv),
+        text = getdatatextstructIQM(fv,[roottext '.' fn{k}],text);
+    else
+        if isnumeric(fv),
+            if length(fv) == 1,
+                help = num2str(fv);
+                text = sprintf('%s\n%s.%s = %s;',text,roottext,fn{k},help);
+            else
+                help = sprintf('%g, ',fv);
+                text = sprintf('%s\n%s.%s = [%s];',text,roottext,fn{k},help(1:end-2));
+            end
+        end
+        if ischar(fv),
+            text = sprintf('%s\n%s.%s = ''%s'';',text,roottext,fn{k},fv);
+        end
+        if iscell(fv),
+            help = '';
+            for k2 = 1:length(fv),
+                if ischar(fv{k2}),
+                    help2 = ['''' fv{k2} ''''];
+                elseif isnumeric(fv{k2}),
+                    help2 = num2str(fv{k2});
+                else
+                    help2 = '';
+                end
+                help = sprintf('%s%s, ',help,help2);
+            end
+            text = sprintf('%s\n%s.%s = {%s};',text,roottext,fn{k},help(1:end-2));
+        end
+    end
+end
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/auxiliary/getexpmeasinfoIQM.m b/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/auxiliary/getexpmeasinfoIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..2a3aef7c48f40b1db6eeec71db159bcd9b135287
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/auxiliary/getexpmeasinfoIQM.m	
@@ -0,0 +1,488 @@
+function [modexpmeasinfostruct] = getexpmeasinfoIQM(model,modelindex,experiments,experimentindices,varargin)
+% getexpmeasinfoIQM: creates a datastructure containing all information 
+% about experiments and measurements. This structure is, e.g., used in the
+% IQMparameterestimation function. It generates temporary MEX models and
+% adds their names to the output structure. 
+%
+% USAGE:
+% ======
+% [output] = getexpmeasinfoIQM(model,modelindex,experiments)        
+% [output] = getexpmeasinfoIQM(model,modelindex,experiments,displayFlag,scalingFlag,timescalingFlag,initialconditionsFlag,weight)        
+%
+% model:        IQMmodel 
+% modelindex:   index of the model in the project (only used if run from IQMparamestGUI)
+% experiments:  'experiments' structure as in the IQMprojectSB structure
+%               (name and notes fields can be skipped)
+% experimentindices: index of the experiments in the project to be considered (only used if run from IQMparamestGUI)
+% displayFlag:  0-2: silent, 3: display information about the different
+%               steps
+% scalingFlag:  Allows to choose which type of scaling is to be used (main
+%               use: for parameter estimation. Possible settings for this flag are
+%               explained in the help text of the IQMparameterestimation function.
+% timescalingFlag:  0=no time scaling, 1...N=time scaling. For equidistantly
+%               sampled data this flag has no significance. For
+%               nonequidistantly sampled data the time scaling allows to
+%               give ranges of measurement data with scarce sampling more
+%               weight. With increasing N the time weighting is made
+%               smaller. N=1 results in maximum time weighting.
+% initialconditionsFlag: 0=use initial conditions stored in the model or
+%               experiments. 1=determine initialconditions from the
+%               measurement data (mean values of first time points). Note
+%               that the function takes into account if not there are
+%               differences in the components that have been measured.
+%               States for which no measurements exist are initialized
+%               using the values from the model or experiment.
+% weight:       cell array with vectors containing weights
+%               for the different measurements in the different experiments
+%
+% DEFAULT VALUES:
+% ===============
+% displayFlag: 0=silent
+% scalingFlag: scaling using mean values of the measured data
+% initialconditionsFlag: 1=initial conditions based on measurements
+% weight: {}
+%
+% Output Arguments:
+% =================
+% modexpmeasinfostruct: structure with following content
+%       .IQMmodel                         IQMmodel (model merged with experiment)
+%       .model                           compiled mex model (merged with experiment)
+%       .mexfullpath                     full path to mex model (useful for deleting if after use) 
+%       .experimentname                  name of the experiment
+%
+%       .measurement.name                name of the measurement
+%       .measurement.statenames          names of measured states  
+%       .measurement.stateindices        indices of measured states in model
+%       .measurement.statereferences     measurements of states
+%       .measurement.statemaxvalues      max errorbounds for measurement
+%       .measurement.stateminvalues      min errorbounds for measurement
+%       .measurement.statescaling        scaling for measured states
+%       .measurement.variablenames       names of measured variables  
+%       .measurement.variableindices     indices of measured variables in model
+%       .measurement.variablereferences  measurements of variables
+%       .measurement.variablemaxvalues   max errorbounds for measurement
+%       .measurement.variableminvalues   min errorbounds for measurement
+%       .measurement.variablescaling     scaling for measured variables
+%       .measurement.timescaling         vector for scaling over time
+%       .measurement.timevectorindices   indices in timevector to which the measurements belong
+%       .measurement.weight              weight to address different importances of measurements for the costfunction
+%
+%       .statenames                      names of all states that are measured in at least one measurement
+%       .stateindices                    indices of all states that are measured 
+%       .initialconditions               initial conditions for experiment simulation
+%       .variablenames                   names of all variables that are measured in at least one measurement
+%       .variableindices                 indices of all variables that are measured 
+%
+%       .timevector                      global timevector for experiment simulation
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GLOBAL VARIABLES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+global scalingFlag timescalingFlag displayFlag initialconditionsFlag
+
+global compiledExpModelsIQMparamestGUI % if not empty then models are precompiled
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE NON-NUMERIC INITIAL CONDITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% just by replacing them
+% + warning ... as user feedback
+if ~hasonlynumericICsIQM(model),
+    model = IQMconvertNonNum2NumIC(model);
+    disp('Warning: The model contains non-numeric initial conditions. For this analysis these are replaced');
+    disp('by numeric initial conditions, determined from the non-numeric ones.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+displayFlag = 0;
+scalingFlag = 0;
+timescalingFlag = 0;
+initialconditionsFlag = 1;
+weight = {};
+if nargin < 2 || nargin > 9,
+    error('Incorrect number of input arguments.');
+elseif nargin == 5,
+    displayFlag = varargin{1};
+elseif nargin == 6,
+    displayFlag = varargin{1};
+    scalingFlag = varargin{2};
+elseif nargin == 7,
+    displayFlag = varargin{1};
+    scalingFlag = varargin{2};
+    timescalingFlag = varargin{3};
+elseif nargin == 8,
+    displayFlag = varargin{1};
+    scalingFlag = varargin{2};
+    timescalingFlag = varargin{3};
+    initialconditionsFlag = varargin{4};
+elseif nargin == 9,
+    displayFlag = varargin{1};
+    scalingFlag = varargin{2};
+    timescalingFlag = varargin{3};
+    initialconditionsFlag = varargin{4};
+    weight = varargin{5};
+end    
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% MERGING MODELS AND EXPERIMENTS + MEX FILE GENERATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(compiledExpModelsIQMparamestGUI),
+    % not precompiled ...
+    [modelexperiments,mexmodelexperiments,mexmodelfullpaths] = mergemodelwithexperiments(model,experiments);
+else
+    % precompiled by IQMparamestGUI
+    [modelexperiments,mexmodelexperiments,mexmodelfullpaths] = getmodelwithexperiments(compiledExpModelsIQMparamestGUI,modelindex,experimentindices);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESSING ALL INTO A STRUCTURE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+modexpmeasinfostruct = getexpmeasinfostruct(modelexperiments,mexmodelexperiments,mexmodelfullpaths,experiments,weight);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% MERGING MODELS AND EXPERIMENTS + MEX FILE GENERATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [modelexperiments,mexmodelexperiments,mexmodelfullpaths] = mergemodelwithexperiments(model,experiments)
+global useIQMguiFlag
+if useIQMguiFlag ~= 1,
+    useIQMguiFlag = 0;
+end
+modelexperiments = {};
+mexmodelexperiments = {};
+mexmodelfullpaths = {};
+if useIQMguiFlag,
+    h = waitbar(0,'Compiling Models. Please wait...');
+end
+for k=1:length(experiments),
+    if useIQMguiFlag,
+        waitbar(k/length(experiments),h)
+    end    
+    % merging
+    modelexperiments{k} = IQMmergemodexp(model,experiments(k).experiment);
+    % compiling
+    [MEXmodel, MEXmodelfullpath] = IQMmakeTempMEXmodel(modelexperiments{k});
+    mexmodelexperiments{k} = MEXmodel;
+    mexmodelfullpaths{k} = MEXmodelfullpath;
+end
+if useIQMguiFlag,
+    close(h);
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PRECOMPILED FROM IQMparamestGUI ... get the info
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [modelexperiments,mexmodelexperiments,mexmodelfullpaths] = getmodelwithexperiments(compiledExpModelsIQMparamestGUI,modelindex,experimentindices)
+modelexperiments = {};
+mexmodelexperiments = {};
+mexmodelfullpaths = {};
+for k=1:length(experimentindices),
+    modelexperiments{k} = compiledExpModelsIQMparamestGUI(modelindex).experiment(experimentindices(k)).modexp;
+    mexmodelexperiments{k} = compiledExpModelsIQMparamestGUI(modelindex).experiment(experimentindices(k)).MEXmodel;
+    mexmodelfullpaths{k} = compiledExpModelsIQMparamestGUI(modelindex).experiment(experimentindices(k)).MEXmodelfullpath;
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESSING ALL INTO A STRUCTURE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [modexpmeasinfostruct] = getexpmeasinfostruct(modelexperiments,mexmodelexperiments,mexmodelfullpaths,experiments,weight)
+global displayFlag
+if displayFlag == 3,
+    disp('Building data structure with experiment and measurement information ...');
+    infomergmodexp()
+end
+% initialize structure
+modexpmeasinfostruct = [];      
+% fill stucture with data
+for k=1:length(experiments),
+    % MEXmodel
+    modexpmeasinfostruct(k).IQMmodel = modelexperiments{k}; % IQMmodel running the experiment
+    modexpmeasinfostruct(k).model = mexmodelexperiments{k}; % mex model running the experiment
+    modexpmeasinfostruct(k).mexfullpath = mexmodelfullpaths{k}; % mex model running the experiment
+    expstruct = IQMstruct(experiments(k).experiment);
+    modexpmeasinfostruct(k).experimentname = expstruct.name;
+    % get all the states and variables in the current model+experiment
+    allmodelstates = IQMstates(modelexperiments{k});
+    allmodelvariables = IQMvariables(modelexperiments{k});
+    % 1) Getting the overall timevector to simulate for experiment
+    %    It is given by all measured timepoints in all measurements for that experiment
+    % 2) Check if the measured components are present in the
+    %    model (at the moment only states are allowed to be measured)
+    % 3) Get the stateindices and statereferences
+    % 4) Get the scaling for each measurment
+    % 5) Get the timevector for each measurement
+    % 6) Get the timescaling for each measurement
+    % 7) Get the indices of all states that have unknown initial conditions (not measured and not set in the experiment)
+    timevector = [];
+    allmeasstates = {};
+    allmeasvariables = {};
+    for k2=1:length(experiments(k).measurements),
+        % get the structure of the current measurement
+        measstruct = IQMstruct(experiments(k).measurements{k2});
+        % name of measurement 
+        modexpmeasinfostruct(k).measurement(k2).name = measstruct.name;
+        % add measurement timepoints to timevector
+        timevectormeasurement = measstruct.time;
+        timevector = unique([timevector(:)' timevectormeasurement(:)']);
+        % process states in measurements
+        [statenames,stateindices,statereferences,statemaxvalues,stateminvalues] = processStateMeasurements(modelexperiments{k},measstruct);
+        % process variables in measurements
+        [variablenames,variableindices,variablereferences,variablemaxvalues,variableminvalues] = processVariableMeasurements(modelexperiments{k},measstruct);
+        % save statenames and variablenames appearing in all measurements
+        allmeasstates = unique({allmeasstates{:} statenames{:}});
+        allmeasvariables = unique({allmeasvariables{:} variablenames{:}});
+        % add state info to the structure
+        modexpmeasinfostruct(k).measurement(k2).statenames = statenames;
+        modexpmeasinfostruct(k).measurement(k2).stateindices = stateindices; 
+        modexpmeasinfostruct(k).measurement(k2).statereferences = statereferences;
+        modexpmeasinfostruct(k).measurement(k2).statemaxvalues = statemaxvalues;
+        modexpmeasinfostruct(k).measurement(k2).stateminvalues = stateminvalues;
+        modexpmeasinfostruct(k).measurement(k2).statescaling = getScaling(statereferences,statemaxvalues,stateminvalues);
+        % add variable info to the structure
+        modexpmeasinfostruct(k).measurement(k2).variablenames = variablenames;
+        modexpmeasinfostruct(k).measurement(k2).variableindices = variableindices; 
+        modexpmeasinfostruct(k).measurement(k2).variablereferences = variablereferences;
+        modexpmeasinfostruct(k).measurement(k2).variablemaxvalues = variablemaxvalues;
+        modexpmeasinfostruct(k).measurement(k2).variableminvalues = variableminvalues;
+        modexpmeasinfostruct(k).measurement(k2).variablescaling = getScaling(variablereferences,variablemaxvalues,variableminvalues);
+        if isempty(weight),
+            % set to 1 if weight not defined
+            modexpmeasinfostruct(k).measurement(k2).weight = 1;
+        else
+            % set the defined value
+            modexpmeasinfostruct(k).measurement(k2).weight = weight{k}(k2);
+        end
+    end
+    % add the sorted simulation timevector to the structure
+    modexpmeasinfostruct(k).timevector = sort(timevector);
+    % now we can determine the timevectorindices for each measurement and the timescaling
+    for k2=1:length(experiments(k).measurements),
+        % get the structure of the current measurement
+        measstruct = IQMstruct(experiments(k).measurements{k2});
+        timevectormeasurement = measstruct.time;
+        [timevectormeas,timevectorindices] = intersect(modexpmeasinfostruct(k).timevector,timevectormeasurement);
+        modexpmeasinfostruct(k).measurement(k2).timevectorindices = timevectorindices;
+        timescaling = gettimescaling(timevectormeas);
+        modexpmeasinfostruct(k).measurement(k2).timescaling = timescaling;
+    end
+    % add names of all measured states to the structure
+    modexpmeasinfostruct(k).statenames = allmeasstates;
+    % determine the stateindices of the measured components in all the
+    % measurements of this experiment        
+    allstateindices = [];
+    for k2=1:length(allmeasstates),
+        index = strmatchIQM(allmeasstates{k2},allmodelstates,'exact');
+        allstateindices = [allstateindices index];
+    end
+    modexpmeasinfostruct(k).stateindices = allstateindices;
+    % determine the initial conditions (take care of the fact that in
+    % different measurements different states might be measured)
+    % also take care of the initialconditionsFlag
+    modexpmeasinfostruct(k).initialconditions = processInitialconditions(modelexperiments{k},modexpmeasinfostruct(k));
+    % add names of all measured variables to the structure
+    modexpmeasinfostruct(k).variablenames = allmeasvariables;
+    % determine the variableindices of the measured components in all the
+    % measurements of this experiment        
+    allvariableindices = [];
+    for k2=1:length(allmeasvariables),
+        index = strmatchIQM(allmeasvariables{k2},allmodelvariables,'exact');
+        allvariableindices = [allvariableindices index];
+    end
+    modexpmeasinfostruct(k).variableindices = allvariableindices;
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INFO MERGED MODEL EXP
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [] = infomergmodexp()
+global scalingFlag timescalingFlag initialconditionsFlag
+% intialconditions
+if initialconditionsFlag == 0,
+    disp(sprintf('\t ... nominal initialconditions from model and experiment'));
+elseif initialconditionsFlag == 1,
+    disp(sprintf('\t ... initialconditions taken from the measurements if present'));
+end
+% scaling
+if scalingFlag == 0,
+    disp(sprintf('\t ... no scaling of data'));
+elseif scalingFlag == 1,
+    disp(sprintf('\t ... scaling of data by max(abs(measurement))'));
+elseif scalingFlag == 2,
+    disp(sprintf('\t ... scaling of data by mean(measurement)'));
+elseif scalingFlag == 3,
+    disp(sprintf('\t ... scaling of data by the difference between max and min values'));
+end
+% timescaling
+if timescalingFlag == 0,
+    disp(sprintf('\t ... no time scaling'));
+elseif timescalingFlag == 1,
+    disp(sprintf('\t ... time scaling on'));
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DETERMINE THE SCALING OF EACH MEASUREMENT IN EACH EXPERIMENT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [scaling] = getScaling(references,maxref,minref)
+global scalingFlag 
+if scalingFlag == 0,
+    % no scaling
+    scaling = ones(size(references));
+elseif scalingFlag == 1,
+    % scale by maxabs value of references
+    scaling = max(abs(references));
+    % expand to matrix with same column entries
+    scaling = scaling(ones(1,size(references,1)),:);
+elseif scalingFlag == 2,
+    % scale by mean value of references 
+    % take care of possible NaN (missing data) values
+    scaling = [];
+    for k=1:size(references,2),
+        data = references(:,k);
+        data(find(isnan(data))) = [];
+        if ~isempty(data),
+            scaling(k) = mean(data);
+        else
+            scaling(k) = 1;
+        end
+    end
+    % expand to matrix with same column entries
+    scaling = scaling(ones(1,size(references,1)),:);
+elseif scalingFlag == 3,
+    % scaling by the difference between max and min values
+    scaling = maxref-minref;
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DETERMINE THE TIMESCALING OF EACH MEASUREMENT IN EACH EXPERIMENT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [timescaling] = gettimescaling(timevectormeas)
+global timescalingFlag
+if timescalingFlag == 0,
+    % no timescaling
+    timescaling = ones(length(timevectormeas),1);
+else
+    % augment timevector with two elements
+    timevectormeas = timevectormeas(:);
+    timehelp = [timevectormeas(1)-timevectormeas(2); timevectormeas; timevectormeas(end)+timevectormeas(end-1)];
+    % get the raw scaling
+    timescaleraw = (timehelp(3:end)-timehelp(1:end-2))/2;
+    timescaleraw = timescaleraw/min(timescaleraw);
+    timescaling = timescaleraw.^(1/timescalingFlag);
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DETERMINE THE INITIAL CONDITIONS FOR EACH EXPERIMENT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [initialconditions] = processInitialconditions(modelexperiment,experiment)
+global initialconditionsFlag
+initialconditions = IQMinitialconditions(modelexperiment);
+if initialconditionsFlag == 0,
+    % if flag==0 then just use the initialconditions defined by model and
+    % experiment description
+    return
+end
+% construct intialconditions from measured data at the first time point
+% do not use data if NaN!
+datapresent = zeros(1,length(IQMstates(modelexperiment)));
+suminitialconditions = zeros(1,length(IQMstates(modelexperiment)));
+for k=1:length(experiment.measurement),
+    stateindices = experiment.measurement(k).stateindices;
+    if ~isempty(stateindices),
+        measuredics = experiment.measurement(k).statereferences(1,:);
+        suminitialconditions(stateindices) = suminitialconditions(stateindices) + measuredics;
+        datapresent(stateindices) = datapresent(stateindices)+1;
+    end
+end
+% add ones to avoid division by zero
+divisionvector = datapresent;
+divisionvector(find(divisionvector==0)) = 1;
+definedinitialconditions = suminitialconditions./divisionvector;
+% handle NaN initial conditions (if measured but first time point
+% undefined) by just exchanging for the model/experiment definition.
+nanindices = find(isnan(definedinitialconditions));
+definedinitialconditions(nanindices) = initialconditions(nanindices);
+% insert the determined initial conditions into the initialconditions vector
+initialconditions(find(datapresent~=0)) = definedinitialconditions(find(datapresent~=0));
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECKING AND PROCESSING THE MEASUREMENTS (STATES)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [statenames,stateindices,statereferences,statemaxvalues,stateminvalues] = processStateMeasurements(modelexperiment, measstruct);
+global scalingFlag
+% get all states in the model with experiment    
+allmodelstates = IQMstates(modelexperiment);
+measuredcomponentnames = {measstruct.data.name};
+% initialize
+statenames = {};
+stateindices = [];
+statereferences = [];
+statemaxvalues = [];
+stateminvalues = [];
+% get all the states from the measured components
+for k=1:length(measuredcomponentnames),
+    index = strmatchIQM(measuredcomponentnames{k},allmodelstates,'exact');
+    if ~isempty(index),
+        % measured component is a state ... so get the data
+        statenames{end+1} = measuredcomponentnames{k};
+        stateindices = [stateindices index];
+        statereferences(:,end+1) = measstruct.data(k).values;
+        statemaxvalues(:,end+1) = measstruct.data(k).maxvalues;
+        stateminvalues(:,end+1) = measstruct.data(k).minvalues;
+        % check if NaN appears in min or max values ... if yes then the
+        % min/max scaling can not be used.
+        if sum(isnan(measstruct.data(k).maxvalues)) > 0 && scalingFlag == 3,
+            warning('Max values are not defined for all measurements. Min/max scaling (scalingFlag=3) might not be the right choice!');
+        end
+        if sum(isnan(measstruct.data(k).minvalues)) < 0 && scalingFlag == 3,
+            warning('Min values are not defined for all measurements. Min/max scaling (scalingFlag=3) might not be the right choice!');
+        end        
+    end
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECKING AND PROCESSING THE MEASUREMENTS (VARIABLES)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [variablenames,variableindices,variablereferences,variablemaxvalues,variableminvalues] = processVariableMeasurements(modelexperiment, measstruct);
+global scalingFlag
+% get all states in the model with experiment    
+allmodelvariables = IQMvariables(modelexperiment);
+measuredcomponentnames = {measstruct.data.name};
+% initialize
+variablenames = {};
+variableindices = [];
+variablereferences = [];
+variablemaxvalues = [];
+variableminvalues = [];
+% get all the variables from the measured components
+for k=1:length(measuredcomponentnames),
+    index = strmatchIQM(measuredcomponentnames{k},allmodelvariables,'exact');
+    if ~isempty(index),
+        % measured component is a variable ... so get the data
+        variablenames{end+1} = measuredcomponentnames{k};
+        variableindices = [variableindices index];
+        variablereferences(:,end+1) = measstruct.data(k).values;
+        variablemaxvalues(:,end+1) = measstruct.data(k).maxvalues;
+        variableminvalues(:,end+1) = measstruct.data(k).minvalues;
+        % check if NaN appears in min or max values ... if yes then the
+        % min/max scaling can not be used.
+        if sum(isnan(measstruct.data(k).maxvalues)) > 0 && scalingFlag == 3,
+            warning('Max values are not defined for all measurements. Min/max scaling (scalingFlag=3) might not be the right choice!');
+        end
+        if sum(isnan(measstruct.data(k).minvalues)) < 0 && scalingFlag == 3,
+            warning('Min values are not defined for all measurements. Min/max scaling (scalingFlag=3) might not be the right choice!');
+        end        
+    end
+end
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/isIQMprojectSB.m b/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/isIQMprojectSB.m
new file mode 100644
index 0000000000000000000000000000000000000000..dc10279bc54b3d2f8a824186c159272214f32956
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/classeshandling/projectSBhandling/isIQMprojectSB.m	
@@ -0,0 +1,6 @@
+function [output] = isIQMprojectSB(project)
+% isIQMprojectSB: check if input argument is an IQMprojectSB
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+output = strcmp(class(project),'IQMprojectSB');
diff --git a/IQMtools V1.2.2.2/IQMpro/installIQMpro.m b/IQMtools V1.2.2.2/IQMpro/installIQMpro.m
new file mode 100644
index 0000000000000000000000000000000000000000..7aa7730ac8779270a1180c92f1a30fdbc8943366
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/installIQMpro.m	
@@ -0,0 +1,75 @@
+function [] = installIQMpro()
+% installIQMpro
+% This script installs the PRO version of the IQM Suite of modeling tools.
+%
+%       installIQMpro
+%
+% The function will check for an installation of IQM Tools Lite. If not 
+% present, and error will be shown. It also will check for a previous
+% installation of IQM Tools Pro and in this case issue an error as well.
+% The reasons for this are: IQM Tools Lite needs to be present for the
+% functions in the PRO part. MATLAB allows simultaneous installations of
+% the same toolboxes, which might lead to issues with different versions.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Check correct starting folder
+currentDir = pwd;
+installIQMproDir = fileparts(which('installIQMpro.m'));
+if ~strcmp(currentDir,installIQMproDir),
+    error('Run the ''installIQMpro'' script from the folder where it is located.');
+end
+
+% Check that IQM Tools Lite is installed
+IGMLiteVer = ver('IQMlite');
+if isempty(IGMLiteVer),
+    error('Please install the "IQM Tools Lite" first.');
+end
+
+% Check that correct local path (network paths are not allowed)
+if strcmp(currentDir(1:2),'\\'),
+    error(sprintf('The installation can not be run from a network path (\\\\...).\nPlease run the installation from a local path.'));
+end
+
+% Check if IQM Pro already installed
+IGMProVer = ver('IQMpro');
+if length(IGMProVer) >= 1,
+    error('"IQM Tools Pro" already installed. Please use "restoredefaultpath" before installing a different version.');
+end
+
+% Add IQM Tools Pro to the path 
+addpath(genpath(pwd));
+
+% Compile and install the needed packages 
+PATH_IQMPRO = pwd();
+if ~ispc,
+    cd(fileparts(which('buildCVODElibunix.m')));
+    buildCVODElibunix
+    cd(PATH_IQMPRO);
+else
+    cd(fileparts(which('buildCVODElib.m')));
+    buildCVODElib
+    cd(PATH_IQMPRO);
+end
+
+% Message
+disp(' ');
+disp('IQM Tools Pro');
+disp('	- Developer: IntiQuan GmbH (info@intiquan.com)');
+disp('	- Installation completed');
+disp(' ');
+disp(' ');
+disp('License IQM Tools Pro:');
+disp(' ');
+disp(regexprep(fileread('license.txt'),'\r',''));
+
+
+
+
+try
+    % Check version number (>=R2013B required)
+    if verLessThan('matlab','8.2.0'),
+        warning('All Pharmacometrics related functionality in IQM Tools Pro require >=MATLAB R2013B.');
+    end
+end
+
diff --git a/IQMtools V1.2.2.2/IQMpro/installation.txt b/IQMtools V1.2.2.2/IQMpro/installation.txt
new file mode 100644
index 0000000000000000000000000000000000000000..9b5bea3cf3aad610c0d49385bb7c73b36208103d
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/installation.txt	
@@ -0,0 +1,22 @@
+Installation of IQM Tools Pro
+=============================
+
+When you are reading this document, you already have successfully obtained IQM Tools Pro from somewhere.
+Please perform the following steps to install it:
+
+- Move the IQMpro folder to the same folder in which IQMlite is located
+- Start MATLAB
+- Install first IQMlite
+- Change into the IQMpro folder
+- Open the file "SETUP_PATHS_TOOLS_IQMPRO.m" in the editor, read its documentation and modify setup accordingly (if needed). Then save and close the file
+- Run "installIQMpro.m" script
+- If you have the parallel toolbox for MATLAB, please do the following setting
+    - Home->parallel->parallel preferences deselect the checkbox "Automatically create a parallel pool" 
+
+Note: The installation of IQM Tools Pro does not save the MATLAB path. This means that everytime you start MATLAB you will need to 
+      execute the "installIQMpro" script. This procedure has been chosen on purpose, for compliance and reproducibility reasons.
+
+Requirements:
+- MATLAB >=R2013b is required. 
+- MATLAB >=R2015b is suggested.
+If using MATLAB R2014b or R2015a, the export of figures to files is VERY slow. Please avoid using these versions.
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/release.txt b/IQMtools V1.2.2.2/IQMpro/release.txt
new file mode 100644
index 0000000000000000000000000000000000000000..7ab71b93e7796aa74aba9450f0a7ae6221b65a30
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/release.txt	
@@ -0,0 +1,51 @@
+Release Notes IQM Tools Pro
+===========================
+
+Version 1.2.2 (02.01.2017)
+--------------------------
+- Minor big fixes
+- Improved graphical output
+
+Version 1.2.1 (30.04.2016)
+--------------------------
+- Minor bug fixes
+- Error message when MONOLIX 2006R1 is used - will be handled in V1.3
+- Use of the IGNORE column for data cleaning (without removal of records from the dataset)
+- Allow an NLME tool not to be present and still run IQMrunNLMEprojectFolder without error (not running the tool obviously)
+
+Version 1.2 (13.04.2016)
+------------------------
+- Minor bug fixes
+- Added handling of sequential 0th/1st order absorption 
+- Added handling of non-numeric lag time definitions and their handling in IQMdosing schemes
+- Support to convert NRDOSES and INTERVAL to ADDL and II in NLME dataset
+- $SIZES in NONMEM control files is now set automatically
+- Added support for automatic generation of general linear models in both NONMEM (ADVAN5/7) and MONOLIX
+- Update to also be compatible with MONOLIX 4.3.3
+- Added support for handling of time dependent categorical covariates (limited for now to NONMEM and analytic models in the popPK workflow)
+- Added loess smoothing to some GOF plots
+
+Version 1.1 (10.02.2016)
+------------------------
+- Minor bug fixes
+- Allow covariate centering in popPK workflowAdded
+- Allow zero order absorption time to be estimated
+- Included possibility for zero and mixed order absorption into the popPK workflow
+- Added simplified popPK workflow
+
+Version 1.0 (09.11.2015)
+------------------------
+- First full release of IQM Pro - the follow-up of SBPOP and SBTOOLBOX2
+- Many improvements with respect to SBPOP (stability, usability, documentation, functionality)
+- Where SBPOP used the "dataset" type, IQM Tools uses the "table" type
+- IQM Tools does not require the presence of the stats toolbox 
+- Parallel computation is used in several functions if the parallel toolbox is available
+- Recommended use of MATLAB >= R2015b (>=R2013B is required)
+- Implemented "compliance mode" for time and information stamps on figures, tables, text
+- Pre Monolix 4.3.2 not supported anymore
+- Support for NONMEM >= 7.2
+- Improved support for pharmacometric work with a new general dataset format
+- Many new tutorials available from the www.intiquan.com website, documenting the
+  use of IQM Tools Pro for pharmacometric work
+
+  
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/include/CVODEmex25.h b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/include/CVODEmex25.h
new file mode 100644
index 0000000000000000000000000000000000000000..c1c93de83ef9019427a1db8135680c409cdd6e26
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/include/CVODEmex25.h	
@@ -0,0 +1,32 @@
+/*
+ * CVODEmex25.h: MEX/CVODES Interface for Sundials CVODES version 2.5
+ *
+ * Information:
+ * ============
+ * IQM Tools Pro
+ */
+
+/* CVODE related flags */
+#define DOFLAG_DDT 0
+#define DOFLAG_VARREAC 1
+#define DOFLAG_EVENTS 2
+#define DOFLAG_EVENTASSIGN 3
+#define DOFLAG_CALCICS 4
+
+/* ParamData (contains pointer to parameter values passed to integrator) */
+typedef struct {
+    double *parametervector;
+} ParamData;
+
+/* Variables defined outside the library */
+extern double defaultICs_num[], defaultParam[];
+extern char  *defaultICs_nonnum[];
+extern char  *stateNames[], *parameterNames[], *variableNames[], *variableFormulas[], *reactionNames[], *eventNames[]; 
+extern const int NRSTATES, NRPARAMETERS, NRVARIABLES, NRREACTIONS, NREVENTS;
+extern const int hasOnlyNumericICs;
+extern int   *interpcseIQM_check; /* needed for spline function in mexsplineaddon.h */
+extern int   *interpcseSlopeIQM_check; /* needed for spline function in mexsplineaddon.h */
+
+/* Functions containing the model equations */
+extern void model(double time, double *stateVector, double *DDTvector, ParamData *paramdataPtr, int DOflag, double *variableVector, double *reactionVector, double *gout, int *eventVector);
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/include/kineticformulas.h b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/include/kineticformulas.h
new file mode 100644
index 0000000000000000000000000000000000000000..7b9dec99d643572d1e697f537e2a398fe36d9825
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/include/kineticformulas.h	
@@ -0,0 +1,193 @@
+/*
+ * kineticformulas.h: Include file for specification of useful kinetic formulas
+ *
+ * Information:
+ * ============
+ * IQM Tools Pro
+ */
+
+double kin_mass_action_irr(double k, double substrate)
+{
+    return k*substrate;    
+}
+
+double kin_mass_action_rev(double k1, double substrate, double k2, double product)
+{
+    return k1*substrate - k2*product;    
+}
+
+double kin_degradation(double kdeg, double substrate)
+{
+    return kdeg*substrate;    
+}
+
+double kin_michaelis_menten_irr(double V, double substrate, double Km)
+{
+    return V*substrate / ( Km + substrate );    
+}
+
+double kin_hill_cooperativity_irr(double V, double substrate, double h, double Shalve)
+{
+    return V*pow(substrate,h) / (pow(Shalve,h) + pow(substrate,h));    
+}
+
+double kin_mixed_inihib_irr(double V, double substrate, double Km, double inhibitor, double Kis, double Kic)
+{
+    return V*substrate / ( Km*(1+inhibitor/Kis) + substrate*(1+inhibitor/Kic) );    
+}
+
+double kin_noncomp_inihib_irr(double V, double substrate, double Km, double inhibitor, double Ki)
+{
+    return V*substrate / ( (Km+substrate)*(1+inhibitor/Ki) );
+}
+
+double kin_uncomp_inihib_irr(double V, double substrate, double Km, double inhibitor, double Ki)
+{
+    return V*substrate / ( Km + substrate*(1+inhibitor/Ki) );
+}
+
+double kin_comp_inihib_irr(double V, double substrate, double Km, double inhibitor, double Ki)
+{
+    return V*substrate / ( Km*(1+inhibitor/Ki) + substrate );
+}
+
+double kin_substrate_inihib_irr(double V, double substrate, double Km, double Ki)
+{
+    return V*substrate / ( Km + substrate + Km*pow((substrate/Ki),2.0) );
+}
+
+double kin_allosteric_inihib_mwc_irr(double V, double substrate, double Ks, double n, double L, double inhibitor, double Ki)
+{
+    return V*substrate*pow((Ks+substrate),(n-1.0)) / ( L*pow((Ks*(1+inhibitor/Ki)),n) + pow((Ks+substrate),n) );
+}
+
+double kin_allosteric_inihib_empirical_rev(double Vf, double substrate, double Kms, double Vr, double product, double Kmp, double inhibitor, double Ki, double n)
+{
+    return (Vf*substrate/Kms - Vr*product/Kmp) / (1 + substrate/Kms + product/Kmp + pow((inhibitor/Ki),n));
+}
+
+double kin_catalytic_activation_irr(double V, double substrate, double activator, double Kms, double Ka)
+{
+    return V*substrate*activator / ( (Kms + substrate)*(Ka+activator) );
+}
+
+double kin_catalytic_activation_rev(double Vf, double substrate, double Kms, double Vr, double product, double Kmp, double activator, double Ka)
+{
+    return ( Vf*substrate/Kms - Vr*product/Kmp )*activator / ( (1+substrate/Kms+product/Kmp)*(Ka+activator) );
+}
+
+double kin_comp_inihib_rev(double Vf, double substrate, double Kms, double Vr, double product, double Kmp, double inhibitor, double Ki)
+{
+    return (Vf*substrate/Kms - Vr*product/Kmp) / ( 1+substrate/Kms+product/Kmp+inhibitor/Ki );
+}
+
+double kin_constantflux(double v)
+{
+    return v;
+}
+
+double kin_hyperbolic_modifier_irr(double V,double substrate,double b,double modifier,double a,double Kd,double Km)
+{
+    return V*substrate*(1+b*modifier/(a*Kd)) / ( Km*(1+modifier/Kd) + substrate*(1+modifier/(a*Kd)) );
+}
+
+double kin_hyperbolic_modifier_rev(double Vf,double substrate,double Kms,double Vr,double product,double Kmp,double b,double modifier,double a,double Kd)
+{
+    return (Vf*substrate/Kms - Vr*product/Kmp)*(1+b*modifier/(a*Kd)) / ( 1+modifier/Kd+(substrate/Kms+product/Kmp)*(1+modifier/(a*Kd)) );
+}
+
+double kin_hill_rev(double Vf,double substrate,double Shalve,double product,double Keq,double Phalve,double h)
+{
+    return Vf*substrate/Shalve*(1-product/(substrate*Keq))*pow((substrate/Shalve+product/Phalve),(h-1.0)) / ( 1+pow((substrate/Shalve + product/Phalve),h) );
+}
+
+double kin_iso_uni_uni_rev(double Vf,double substrate,double product,double Keq,double Kii,double Kms,double Kmp)
+{
+    return Vf*(substrate-product/Keq) / ( substrate*(1+product/Kii) + Kms*(1+product/Kmp) );
+}
+
+double kin_mixed_activation_irr(double V,double substrate,double activator,double Kms,double Kas,double Kac)
+{
+    return V*substrate*activator / ( Kms*(Kas+activator) + substrate*(Kac+activator) );
+}
+
+double kin_mixed_activation_rev(double Vf,double substrate,double Kms,double Vr,double product,double Kmp,double activator,double Kas,double Kac)
+{
+    return (Vf*substrate/Kms - Vr*product/Kmp)*activator / ( Kas+activator+(substrate/Kms+product/Kmp)*(Kac+activator) );
+}
+
+double kin_mixed_inihib_rev(double Vf,double substrate,double Kms,double Vr,double product,double Kmp,double inhibitor,double Kis,double Kic)
+{
+    return (Vf*substrate/Kms - Vr*product/Kmp) / ( 1+inhibitor/Kis+(substrate/Kms+product/Kmp)*(1+inhibitor/Kic) );
+}
+
+double kin_noncomp_inihib_rev(double Vf,double substrate,double Kms,double Vr,double product,double Kmp,double inhibitor,double Ki)
+{
+    return (Vf*substrate/Kms-Vr*product/Kmp) / ( (1+substrate/Kms+product/Kmp)*(1+inhibitor/Ki) );
+}
+
+double kin_ordered_bi_bi_rev(double Vf,double substratea,double substrateb,double productp,double productq,double Keq,double Kip,double Kma,double Kmb,double Kia,double Vr,double Kmq,double Kmp,double Kib)
+{
+    return Vf*(substratea*substrateb-productp*productq/Keq) / (substratea*substrateb*(1+productp/Kip) + Kma*substrateb + Kmb*(substratea+Kia)+Vf/(Vr*Keq)*(Kmq*productp*(1+substratea/Kia) + productq*(Kmp*(1+Kia*substrateb/(Kma*Kmb))+productp*(1+substrateb/Kib))) );
+}
+
+double kin_ordered_bi_uni_rev(double Vf,double substratea,double substrateb,double product,double Keq,double Kma,double Kmb,double Vr,double Kmp,double Kia)
+{
+    return Vf*(substratea*substrateb-product/Keq) / ( substratea*substrateb+Kma*substrateb+Kmb*substratea+Vf/(Vr*Keq)*(Kmp+product*(1+substratea/Kia)) );
+}
+
+double kin_ordered_uni_bi_rev(double Vf,double substrate,double productp,double productq,double Keq,double Kms,double Kip,double Vr,double Kmq,double Kmp)
+{
+    return Vf*(substrate-productp*productq/Keq) / ( Kms+substrate*(1+productp/Kip)+Vf/(Vr*Keq)*(Kmq*productp+Kmp*productq+productp*productq) );
+}
+
+double kin_michaelis_menten_rev(double Vf,double substrate,double Kms,double Vr,double product,double Kmp)
+{
+    return (Vf*substrate/Kms+Vr*product/Kmp) / ( 1+substrate/Kms+product/Kmp );
+}
+
+double kin_substrate_inihib_rev(double Vf,double substrate,double Kms,double Vr,double product,double Kmp,double Ki)
+{
+    return (Vf*substrate/Kms-Vr*product/Kmp) / ( 1+substrate/Kms+product/Kmp+pow((substrate/Ki),2.0) );
+}
+
+double kin_uncomp_inihib_rev(double Vf,double substrate,double Kms,double Vr,double product,double Kmp,double inhibitor,double Ki)
+{
+    return ( Vf*substrate/Kms-Vr*product/Kmp ) / ( 1+(substrate/Kms+product/Kmp)*(1+inhibitor/Ki) );
+}
+
+double kin_uni_uni_rev(double Vf,double substrate,double product,double Keq,double Kms,double Kmp)
+{
+    return Vf*( substrate-product/Keq ) / ( substrate+Kms*(1+product/Kmp) );
+}
+
+double kin_specific_activation_irr(double V,double substrate,double activator,double Kms,double Ka)
+{
+    return V*substrate*activator/( Kms*Ka+(Kms+substrate)*activator );
+}
+
+double kin_specific_activation_rev(double Vf,double substrate,double Kms,double Vr,double product,double Kmp,double activator,double Ka)
+{
+    return ( Vf*substrate/Kms-Vr*product/Kmp )*activator / ( Ka+(1+substrate/Kms+product/Kmp)*activator );
+}
+
+double kin_substrate_activation_irr(double V,double substrate,double Ksa,double Ksc)
+{
+    return V*pow((substrate/Ksa),2.0) / ( 1+substrate/Ksc+substrate/Ksa+pow((substrate/Ksa),2.0) );
+}
+
+double kin_ping_pong_bi_bi_rev(double Vf,double substratea,double substrateb,double productp,double productq,double Keq,double Kiq,double Kma,double Kmb,double Vr,double Kmq,double Kia,double Kmp)
+{
+    return Vf*( substratea*substrateb-productp*productq/Keq ) / (substratea*substrateb*(1+productq/Kiq)+Kma*substrateb+Kmb*substratea+Vf/(Vr*Keq)*(Kmq*productp*(1+substratea/Kia)+productq*(Kmp+productp)));
+}
+
+double kin_hill_1_modifier_rev(double Vf,double substrate,double Shalve,double product,double Keq,double Phalve,double h,double modifier,double Mhalve,double alpha)
+{
+    return Vf*substrate/Shalve*(1-product/(substrate*Keq))*pow((substrate/Shalve+product/Phalve),(h-1.0)) / ( (1+pow((modifier/Mhalve),h))/(1+alpha*pow((modifier/Mhalve),h))+pow((substrate/Shalve + product/Phalve),h) );
+}
+
+double kin_hill_2_modifiers_rev(double Vf,double substrate,double Shalve,double product,double Keq,double Phalve,double h,double modifierA,double MAhalve,double modifierB,double MBhalve,double alphaA,double alphaB,double alphaAB)
+{
+    return Vf*substrate/Shalve*(1-product/(substrate*Keq))*pow((substrate/Shalve+product/Phalve),(h-1.0)) / ( (1+pow((modifierA/MAhalve),h) + 1+pow((modifierB/MBhalve),h)) / ( 1+alphaA*pow((modifierA/MAhalve),h)+alphaB*pow((modifierB/MBhalve),h)+alphaA*alphaB*alphaAB*pow((modifierA/MAhalve),h)*pow((modifierB/MBhalve),h) ) + pow((substrate/Shalve + product/Phalve),h) );
+}
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/include/mexmathaddon.h b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/include/mexmathaddon.h
new file mode 100644
index 0000000000000000000000000000000000000000..1dac56a0515a41fe0b1e5db45dc5046d86326415
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/include/mexmathaddon.h	
@@ -0,0 +1,263 @@
+/*
+ * mexmathaddon.h: Include file for automatically generated MEX model files.
+ *
+ * Information:
+ * ============
+ * IQM Tools Pro 
+ */
+
+#define pi 3.141592653589793
+
+#ifdef __LCC__
+double max(double a, double b)
+{
+    if (a<b) return b;
+    else return a;
+}
+
+double min(double a, double b)
+{
+    if (a>b) return b;
+    else return a;
+}
+#endif
+
+#ifdef __GNUC__
+double max(double a, double b)
+{
+    return fmax(a,b);
+}
+
+double min(double a, double b)
+{
+    return fmin(a,b);
+}
+#endif
+
+
+
+double minIQM(int nargs, ...)
+{
+    int k;
+    double minimum;
+    double checkmin;
+    va_list vararg;
+    va_start(vararg, nargs);
+    minimum = va_arg(vararg, double);
+    for (k=1; k<nargs; k++ ) {
+        checkmin = va_arg(vararg, double);
+        if (checkmin < minimum) {
+            minimum = checkmin;
+        }
+    }
+    va_end (vararg);
+    return minimum;
+}
+
+double maxIQM(int nargs, ...)
+{
+    int k;
+    double maximum;
+    double checkmax;
+    va_list vararg;
+    va_start(vararg, nargs);
+    maximum = va_arg(vararg, double);
+    for (k=1; k<nargs; k++ ) {
+        checkmax = va_arg(vararg, double);
+        if (checkmax > maximum) {
+            maximum = checkmax;
+        }
+    }
+    va_end (vararg);
+    return maximum;
+}
+
+double indexmaxIQM(int nargs, ...)
+{
+    int k;
+    double maximum;
+    double indexmaximum;
+    double checkmax;
+    va_list vararg;
+    va_start(vararg, nargs);
+    maximum = va_arg(vararg, double);
+    indexmaximum = 1;
+    for (k=1; k<nargs; k++ ) {
+        checkmax = va_arg(vararg, double);
+        if (checkmax > maximum) {
+            maximum = checkmax;
+            indexmaximum = (double)k+1;
+        }
+    }
+    va_end (vararg);
+    return indexmaximum;
+}
+
+double sign(double a)
+{
+    if (a<0) return -1;
+    else if (a==0) return 0;
+    else if (a>0) return 1;
+    else return a;
+}
+
+double absIQM(double a)
+{
+    if (a < 0) return -a;
+    else return a;
+}
+
+double mod(double a, double b)
+{
+    if (b == 0) return a;
+    else if (a == b) return 0;
+    return sign(b)*absIQM(a-floor(a/b)*b);
+}
+
+double nthrootIQM(double a, double n)
+{
+    return pow(a,1.0/n);
+}
+
+double andIQM(int nargs, ...)
+{
+    int k;
+    va_list vararg;
+    va_start(vararg, nargs);
+    for (k=0; k<nargs; k++ ) {
+        if (va_arg(vararg, double) == 0) {
+            va_end (vararg);
+            return 0;
+        }
+    }
+    va_end (vararg);
+    return 1;
+}
+
+double orIQM(int nargs, ...)
+{
+    int k;
+    va_list vararg;
+    va_start(vararg, nargs);
+    for (k=0; k<nargs; k++ ) {
+        if (va_arg(vararg, double) != 0) {
+            va_end (vararg);
+            return 1;
+        }
+    }
+    va_end (vararg);
+    return 0;
+}
+
+double piecewiseIQM(int nargs, ...)
+{
+    int k, oddnumber;
+    double *data;
+    double returnvalue;
+    va_list vararg;
+    va_start(vararg, nargs);
+    /* Read in all variable input arguments in double array */
+    data = (double *)mxCalloc(nargs,sizeof(double));
+    for (k=0; k<nargs; k++ ) {
+        data[k] = va_arg(vararg, double);
+    }
+    /* 
+       Determine result
+       Check if odd or even number of input arguments
+     */
+    oddnumber = nargs % 2;
+    for (k=0;k<nargs-oddnumber;k+=2) {
+        if (data[k+1] != 0) {
+            returnvalue = data[k];
+            mxFree(data); /* free temporary array */
+            return returnvalue;
+        }
+    }
+    if (oddnumber != 0) {
+            returnvalue = data[nargs-1];
+            mxFree(data); /* free temporary array */
+            return returnvalue;
+    }
+    else {
+        mexErrMsgTxt("A piecewise statement is wrongly defined - missing (but needed) default value.");
+        mxFree(data); /* free temporary array */
+        return 0; /* statement never reached */
+    }
+}
+
+double piecewiseT0IQM(int nargs, ...) /* does the same as the piecewiseIQM function but does not lead to added events in the simulation model */
+{
+    int k, oddnumber;
+    double *data;
+    double returnvalue;
+    va_list vararg;
+    va_start(vararg, nargs);
+    /* Read in all variable input arguments in double array */
+    data = (double *)mxCalloc(nargs,sizeof(double));
+    for (k=0; k<nargs; k++ ) {
+        data[k] = va_arg(vararg, double);
+    }
+    /* 
+       Determine result
+       Check if odd or even number of input arguments
+     */
+    oddnumber = nargs % 2;
+    for (k=0;k<nargs-oddnumber;k+=2) {
+        if (data[k+1] != 0) {
+            returnvalue = data[k];
+            mxFree(data); /* free temporary array */
+            return returnvalue;
+        }
+    }
+    if (oddnumber != 0) {
+            returnvalue = data[nargs-1];
+            mxFree(data); /* free temporary array */
+            return returnvalue;
+    }
+    else {
+        mexErrMsgTxt("A piecewise statement is wrongly defined - missing (but needed) default value.");
+        mxFree(data); /* free temporary array */
+        return 0; /* statement never reached */
+    }
+}
+
+
+double piecewiseSmoothIQM(double t,double y0,double y1,double alpha) 
+{
+
+return (y0+y1*exp(alpha*t))/(1+exp(alpha*t));
+
+}
+        
+
+double gt(double a, double b)
+{
+    if (a > b) return 1;
+    else return 0;
+}
+
+double ge(double a, double b)
+{
+    if (a >= b) return 1;
+    else return 0;
+}
+
+double lt(double a, double b)
+{
+    if (a < b) return 1;
+    else return 0;
+}
+
+double le(double a, double b)
+{
+    if (a <= b) return 1;
+    else return 0;
+}
+
+double eq(double a, double b)
+{
+    if (a*b < 0) return 0;
+    else if ( absIQM(a-b) < 10.0*mxGetEps() ) return 1;
+    else return 0;
+}
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/include/mexsplineaddon.h b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/include/mexsplineaddon.h
new file mode 100644
index 0000000000000000000000000000000000000000..eb8d9b6e0dfbf98b143569abcf7018d4e6abc067
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/include/mexsplineaddon.h	
@@ -0,0 +1,1895 @@
+/*
+ * mexsplineaddon.h: contains the function interpcseIQM, interpcsexIQM and '
+ *      the function interpcsIQM
+ *      Cubic spline interpolation with (and without) endpoints for use 
+ *      by the CVODE integrator in the SBPD package
+ *
+ * The interpcsIQM is a function for cubic spline interpolation, but without the 
+ * possibility of defining slopes at the endpoints.
+ * 
+ * The interpcseIQM function allows to define slopes at the endpoints. The 
+ * spline coefficients are only calculated once and then only evaluated (faster)
+ * 
+ * the interpcsexIQM function determines the spline coefficients each time, allowing to 
+ * implement time dependent spline functions (slower).
+ *
+ */
+
+/* interpcseIQM and interpcsexIQM FUNCTIONS:
+ * Original C-code for spline interpolation taken from:
+ *   http://www.mech.uq.edu.au/staff/jacobs/nm_lib/cmathsrc/spline.c
+ *
+ * The syntax of this MEX function (to be used via CVODE interface) is as follows:
+ *
+ * yy = interpcseIQM(nargs,n,x1,x2,...,xn,y1,y2,...,yn,xx)
+ * yy = interpcseIQM(nargs,n,e1,e2,x1,x2,...,xn,y1,y2,...,yn,xx)
+ *
+ * nargs:  number of arguments
+ * n:      number of points in the x and y vectors
+ * xi:     x-values 
+ * yi:     y-values
+ * xx:     x-value at which to evaluate the spline function (do NOT allow multiple)
+ * e1,e2:  endpoint derivatives (if specified, both need to be given)
+ * yy:     interpolated value
+ */
+
+/*
+ *========================================================================
+ * Initialization of the spline related functions
+ *========================================================================
+ */
+void spline (int n, int e1, int e2, double s1, double s2, double x[], double y[], double b[], double c[], double d[], int *flag);
+double seval (int n, double xx, double x[], double y[], double b[], double c[], double d[], int *last);
+double deriv (int n, double xx, double x[], double b[], double c[], double d[], int *last);
+
+/*
+ *========================================================================
+ * Declare variables for the interpcseIQM function
+ *========================================================================
+ */
+#define MAX_INTERPCSEIQM 10000    /* defined maximum number of interpcseIQM functions in the model */
+int*    interpcseIQM_check = NULL; /* is initialized each new integration start to NULL ... required */
+double* xvec[MAX_INTERPCSEIQM];
+double* yvec[MAX_INTERPCSEIQM];
+double* bvec[MAX_INTERPCSEIQM];
+double* cvec[MAX_INTERPCSEIQM];
+double* dvec[MAX_INTERPCSEIQM];
+
+int*    interpcseSlopeIQM_check = NULL; /* is initialized each new integration start to NULL ... required */
+double* xvecslope[MAX_INTERPCSEIQM];
+double* yvecslope[MAX_INTERPCSEIQM];
+double* bvecslope[MAX_INTERPCSEIQM];
+double* cvecslope[MAX_INTERPCSEIQM];
+double* dvecslope[MAX_INTERPCSEIQM];
+
+/*
+ *========================================================================
+ * INTERFACE FUNCTION for interpcseIQM ... 
+ *========================================================================
+ */
+double interpcseIQM(int nargs, ...)
+{
+    /*************************************************************/
+    /* Define the variables needed for the spline function calls */
+    /*************************************************************/
+    int    index_pw; /* index of the interpcseIQM function */
+    int    n;
+    double *x;
+    double *y;
+    double xx;
+    double s1,s2;
+    int    e1,e2;
+    double *b;
+    double *c;
+    double *d;
+    int    flag;
+    int    last;
+    int    k;
+    double yy;
+    int    newCall;
+    double b2,c2,d2,x0,x1,y0,y1;
+    
+    /***************************************/
+    /* Handle the variable input arguments */
+    /***************************************/
+    /* Initialize the va_list */
+    va_list vararg;
+    va_start(vararg, nargs);
+    /* Get the index of the current interpcseIQM function */
+    index_pw = (int) va_arg(vararg, double);
+    /* Get the number of the x and y axis nodes for interpolation */
+    n = (int) va_arg(vararg, double);
+    /* Get the xx value at which to interpolate */
+    xx = va_arg(vararg, double);
+    
+    /* Check if too many interpcseIQM functions in the model (unlikely) */
+    if (index_pw >= MAX_INTERPCSEIQM) {
+        mexErrMsgTxt("interpcseIQM_CVODE: To many calls to interpcseIQM in the model.");
+    }
+    
+    /* Check if memory already obtained for handling the different calls */
+    if (interpcseIQM_check == NULL) interpcseIQM_check = (int *) mxCalloc(MAX_INTERPCSEIQM, sizeof(int));
+    
+    /* Check if new call or subsequent call */
+    if (interpcseIQM_check[index_pw] == 69) {
+        newCall = 0;
+    } else {
+        newCall = 1;
+        interpcseIQM_check[index_pw] = 69;
+    }
+
+    if (newCall == 1 || n == 2) {
+        /* First call to this function ... get the information */
+        /* Check if the number of input argument is plausible and define slopes */
+        if (nargs == 3+2*n) {
+            /* Plausible, but no slopes defined */
+            e1 = 0; s1 = 0; /* set s1 to 0 but it is not used */
+            e2 = 0; s2 = 0; /* set s2 to 0 but it is not used */
+        } else if (nargs == 3+2*n+2) {
+            /* Plausible, slopes are defined */
+            e1 = 1; s1 = va_arg(vararg, double);
+            e2 = 1; s2 = va_arg(vararg, double);
+        } else {
+            mexErrMsgTxt("interpcseIQM_CVODE: Incorrect number of input arguments (increase MAX_INTERPCSEIQM in mexsplineaddon.h).");
+        }
+        
+        /***********/
+        /* If n==2 */
+        /***********/
+        if (n == 2) {
+            if (e1 == 0 || e2 == 0) mexErrMsgTxt("interpcseIQM: n=2 requires the definition of slopes.");
+            x0 = va_arg(vararg, double);
+            x1 = va_arg(vararg, double);
+            y0 = va_arg(vararg, double);
+            y1 = va_arg(vararg, double);
+            /* End the variable input handling */
+            va_end (vararg);
+            b2 = s1;
+            c2 = -(-3.0*y1+3.0*y0+(s2+2.0*s1)*x1+(-s2-2.0*s1)*x0)/(pow(x1, 2.0)-2.0*x0*x1+pow(x0, 2.0));
+            d2 = (-2.0*y1+2.0*y0+(s2+s1)*x1+(-s2-s1)*x0)/(pow(x1, 3.0)-3.0*x0*pow(x1, 2.0)+3.0*pow(x0, 2.0)*x1-pow(x0, 3.0));
+            yy = y0 + b2*(xx-x0) + c2*pow(xx-x0, 2.0) + d2*pow(xx-x0, 3.0);   
+        } else {
+            /***********/
+            /* If n!=2 */
+            /***********/
+            /* Allocate memory for x and y */
+            x  = (double *) mxCalloc(n, sizeof(double));
+            y  = (double *) mxCalloc(n, sizeof(double));
+            /* Parse input arguments into x and y */
+            for (k=0;k<n;k++) x[k] = va_arg(vararg, double);
+            for (k=0;k<n;k++) y[k] = va_arg(vararg, double);
+            /* End the variable input handling */
+            va_end (vararg);
+        
+            /*****************************/
+            /* Allocate memory for b,c,d */
+            /*****************************/
+            b  = (double *) mxCalloc(n, sizeof(double));
+            c  = (double *) mxCalloc(n, sizeof(double));
+            d  = (double *) mxCalloc(n, sizeof(double));
+            
+            /****************************/
+            /* Call the spline function */
+            /****************************/
+            spline(n, e1, e2, s1, s2, x, y, b, c, d, &flag);
+            
+            /*********************************/
+            /* Save b,c,d,x,y for next calls */
+            /*********************************/
+            xvec[index_pw] = x;
+            yvec[index_pw] = y;
+            bvec[index_pw] = b;
+            cvec[index_pw] = c;
+            dvec[index_pw] = d;
+            
+            /***************************************/
+            /* Call the spline evaluation function */
+            /***************************************/
+            yy = seval (n, xx, x, y, b, c, d, &last);            
+        }
+    } else {
+        /* get x,y,b,c,d pointers */
+        x = xvec[index_pw];
+        y = yvec[index_pw];
+        b = bvec[index_pw];
+        c = cvec[index_pw];
+        d = dvec[index_pw];
+        /***************************************/
+        /* Call the spline evaluation function */
+        /***************************************/
+        yy = seval(n, xx, x, y, b, c, d, &last);
+    }
+    
+    /*********************************/
+    /* Return the interpolated value */
+    /*********************************/
+    return yy;
+}
+
+
+/*
+ *========================================================================
+ * INTERFACE FUNCTION for interpcseIQM ... 
+ *========================================================================
+ */
+double interpcseSlopeIQM(int nargs, ...)
+{
+    /*************************************************************/
+    /* Define the variables needed for the spline function calls */
+    /*************************************************************/
+    int    index_pw; /* index of the interpcseSlopeIQM function */
+    int    n;
+    double *x;
+    double *y;
+    double xx;
+    double s1,s2;
+    int    e1,e2;
+    double *b;
+    double *c;
+    double *d;
+    int    flag;
+    int    last;
+    int    k;
+    double yy;
+    int    newCall;
+    double b2,c2,d2,x0,x1,y0,y1;
+    
+    /***************************************/
+    /* Handle the variable input arguments */
+    /***************************************/
+    /* Initialize the va_list */
+    va_list vararg;
+    va_start(vararg, nargs);
+    /* Get the index of the current interpcseSlopeIQM function */
+    index_pw = (int) va_arg(vararg, double);
+    /* Get the number of the x and y axis nodes for interpolation */
+    n = (int) va_arg(vararg, double);
+    /* Get the xx value at which to interpolate */
+    xx = va_arg(vararg, double);
+    
+    /* Check if too many interpcseSlopeIQM functions in the model (unlikely) */
+    if (index_pw >= MAX_INTERPCSEIQM) {
+        mexErrMsgTxt("interpcseSlopeIQM_CVODE: To many calls to interpcseIQM in the model.");
+    }
+    
+    /* Check if memory already obtained for handling the different calls */
+    if (interpcseSlopeIQM_check == NULL) interpcseSlopeIQM_check = (int *) mxCalloc(MAX_INTERPCSEIQM, sizeof(int));
+    
+    /* Check if new call or subsequent call */
+    if (interpcseSlopeIQM_check[index_pw] == 69) {
+        newCall = 0;
+    } else {
+        newCall = 1;
+        interpcseSlopeIQM_check[index_pw] = 69;
+    }
+
+    if (newCall == 1 || n == 2) {
+        /* First call to this function ... get the information */
+        /* Check if the number of input argument is plausible and define slopes */
+        if (nargs == 3+2*n) {
+            /* Plausible, but no slopes defined */
+            e1 = 0; s1 = 0; /* set s1 to 0 but it is not used */
+            e2 = 0; s2 = 0; /* set s2 to 0 but it is not used */
+        } else if (nargs == 3+2*n+2) {
+            /* Plausible, slopes are defined */
+            e1 = 1; s1 = va_arg(vararg, double);
+            e2 = 1; s2 = va_arg(vararg, double);
+        } else {
+            mexErrMsgTxt("interpcseSlopeIQM_CVODE: Incorrect number of input arguments (increase MAX_INTERPCSEIQM in mexsplineaddon.h).");
+        }
+        
+        /***********/
+        /* If n==2 */
+        /***********/
+        if (n == 2) {
+            if (e1 == 0 || e2 == 0) mexErrMsgTxt("interpcseSlopeIQM_CVODE: n=2 requires the definition of slopes.");
+            x0 = va_arg(vararg, double);
+            x1 = va_arg(vararg, double);
+            y0 = va_arg(vararg, double);
+            y1 = va_arg(vararg, double);
+            /* End the variable input handling */
+            va_end (vararg);
+            b2 = s1;
+            c2 = -(-3.0*y1+3.0*y0+(s2+2.0*s1)*x1+(-s2-2.0*s1)*x0)/(pow(x1, 2.0)-2.0*x0*x1+pow(x0, 2.0));
+            d2 = (-2.0*y1+2.0*y0+(s2+s1)*x1+(-s2-s1)*x0)/(pow(x1, 3.0)-3.0*x0*pow(x1, 2.0)+3.0*pow(x0, 2.0)*x1-pow(x0, 3.0));
+            yy = b2 + 2.0*c2*(xx-x0) + 3.0*d2*pow(xx-x0, 2.0);   
+        } else {
+            /***********/
+            /* If n!=2 */
+            /***********/
+            /* Allocate memory for x and y */
+            x  = (double *) mxCalloc(n, sizeof(double));
+            y  = (double *) mxCalloc(n, sizeof(double));
+            /* Parse input arguments into x and y */
+            for (k=0;k<n;k++) x[k] = va_arg(vararg, double);
+            for (k=0;k<n;k++) y[k] = va_arg(vararg, double);
+            /* End the variable input handling */
+            va_end (vararg);
+        
+            /*****************************/
+            /* Allocate memory for b,c,d */
+            /*****************************/
+            b  = (double *) mxCalloc(n, sizeof(double));
+            c  = (double *) mxCalloc(n, sizeof(double));
+            d  = (double *) mxCalloc(n, sizeof(double));
+            
+            /****************************/
+            /* Call the spline function */
+            /****************************/
+            spline(n, e1, e2, s1, s2, x, y, b, c, d, &flag);
+            
+            /*********************************/
+            /* Save b,c,d,x,y for next calls */
+            /*********************************/
+            xvecslope[index_pw] = x;
+            yvecslope[index_pw] = y;
+            bvecslope[index_pw] = b;
+            cvecslope[index_pw] = c;
+            dvecslope[index_pw] = d;
+            
+            /***************************************/
+            /* Call the spline evaluation function */
+            /***************************************/
+            yy = deriv(n, xx, x, b, c, d, &last);            
+        }
+    } else {
+        /* get x,y,b,c,d pointers */
+        x = xvecslope[index_pw];
+        y = yvecslope[index_pw];
+        b = bvecslope[index_pw];
+        c = cvecslope[index_pw];
+        d = dvecslope[index_pw];
+        /***************************************/
+        /* Call the spline evaluation function */
+        /***************************************/
+        yy = deriv(n, xx, x, b, c, d, &last);
+    }
+    
+    /*********************************/
+    /* Return the interpolated value */
+    /*********************************/
+    return yy;
+}
+
+/*
+ *========================================================================
+ * INTERFACE FUNCTION for interpcsexIQM ... 
+ *========================================================================
+ */
+double interpcsexIQM(int nargs, ...)
+{
+    /*************************************************************/
+    /* Define the variables needed for the spline function calls */
+    /*************************************************************/
+    int    n;
+    double *x;
+    double *y;
+    double xx;
+    double s1,s2;
+    int    e1,e2;
+    double *b;
+    double *c;
+    double *d;
+    int    flag;
+    int    last;
+    int    k;
+    double yy;
+    double b2, c2, d2;
+    double x0,x1,y0,y1;
+    
+    /***************************************/
+    /* Handle the variable input arguments */
+    /***************************************/
+    /* Initialize the va_list */
+    va_list vararg;
+    va_start(vararg, nargs);
+    /* Get the number of the x and y axis nodes for interpolation */
+    n = (int) va_arg(vararg, double);
+    /* Check if the number of input argument is plausible and define slopes */
+    if (nargs == 1+2*n+1) {
+        /* Plausible, but no slopes defined */
+        e1 = 0; s1 = 0; /* set s1 to 0 but it is not used */
+        e2 = 0; s2 = 0; /* set s2 to 0 but it is not used */
+    } else if (nargs == 1+2*n+1+2) {
+        /* Plausible, slopes are defined */
+        e1 = 1; s1 = va_arg(vararg, double);
+        e2 = 1; s2 = va_arg(vararg, double);
+    } else {
+        mexErrMsgTxt("interpcseIQM_CVODE: Incorrect number of input arguments.");
+    }
+    
+    /***********/
+    /* If n==2 */
+    /***********/
+    if (n==2) {        
+        if (e1 == 0 || e2 == 0) mexErrMsgTxt("interpcseIQM: n=2 requires the definition of slopes.");
+        x0 = va_arg(vararg, double);
+        x1 = va_arg(vararg, double);
+        y0 = va_arg(vararg, double);
+        y1 = va_arg(vararg, double);
+
+        /* Get the xx value at which to interpolate */
+        xx = va_arg(vararg, double);
+        /* End the variable input handling */
+        va_end(vararg);
+
+        b2 = s1;
+        c2 = -(-3.0*y1+3.0*y0+(s2+2.0*s1)*x1+(-s2-2.0*s1)*x0)/(pow(x1,2.0)-2.0*x0*x1+pow(x0,2.0));
+        d2 = (-2.0*y1+2.0*y0+(s2+s1)*x1+(-s2-s1)*x0)/(pow(x1,3.0)-3.0*x0*pow(x1,2.0)+3.0*pow(x0,2.0)*x1-pow(x0,3.0));
+        yy = y0 + b2*(xx-x0) + c2*pow(xx-x0,2.0) + d2*pow(xx-x0,3.0);
+    } else {
+        /***********/
+        /* If n!=2 */
+        /***********/
+        /* Allocate memory for x and y */
+        x  = (double *) mxCalloc(n, sizeof(double));
+        y  = (double *) mxCalloc(n, sizeof(double));
+        /* Parse input arguments into x and y */
+        for (k=0;k<n;k++) x[k] = va_arg(vararg, double);
+        for (k=0;k<n;k++) y[k] = va_arg(vararg, double);
+        
+        /* Get the xx value at which to interpolate */
+        xx = va_arg(vararg, double);
+        /* End the variable input handling */
+        va_end(vararg);
+        
+        /*****************************/
+        /* Allocate memory for b,c,d */
+        /*****************************/
+        b  = (double *) mxCalloc(n, sizeof(double));
+        c  = (double *) mxCalloc(n, sizeof(double));
+        d  = (double *) mxCalloc(n, sizeof(double));
+        
+        /****************************/
+        /* Call the spline function */
+        /****************************/
+        spline(n, e1, e2, s1, s2, x, y, b, c, d, &flag);
+        
+        /***************************************/
+        /* Call the spline evaluation function */
+        /***************************************/
+        yy = seval(n, xx, x, y, b, c, d, &last);
+        
+        /***************/
+        /* Free memory */
+        /***************/
+        mxFree(x);
+        mxFree(y);
+        mxFree(b);
+        mxFree(c);
+        mxFree(d);
+    }
+    
+    /*********************************/
+    /* Return the interpolated value */
+    /*********************************/
+    return yy;
+}
+
+
+/*
+ *========================================================================
+ * INTERFACE FUNCTION for interpcsexSlopeIQM ... 
+ *========================================================================
+ */
+double interpcsexSlopeIQM(int nargs, ...)
+{
+    /*************************************************************/
+    /* Define the variables needed for the spline function calls */
+    /*************************************************************/
+    int    n;
+    double *x;
+    double *y;
+    double xx;
+    double s1,s2;
+    int    e1,e2;
+    double *b;
+    double *c;
+    double *d;
+    int    flag;
+    int    last;
+    int    k;
+    double yy;
+    double b2, c2, d2;
+    double x0,x1,y0,y1;
+    
+    /***************************************/
+    /* Handle the variable input arguments */
+    /***************************************/
+    /* Initialize the va_list */
+    va_list vararg;
+    va_start(vararg, nargs);
+    /* Get the number of the x and y axis nodes for interpolation */
+    n = (int) va_arg(vararg, double);
+    /* Check if the number of input argument is plausible and define slopes */
+    if (nargs == 1+2*n+1) {
+        /* Plausible, but no slopes defined */
+        e1 = 0; s1 = 0; /* set s1 to 0 but it is not used */
+        e2 = 0; s2 = 0; /* set s2 to 0 but it is not used */
+    } else if (nargs == 1+2*n+1+2) {
+        /* Plausible, slopes are defined */
+        e1 = 1; s1 = va_arg(vararg, double);
+        e2 = 1; s2 = va_arg(vararg, double);
+    } else {
+        mexErrMsgTxt("interpcsexSlopeIQM_CVODE: Incorrect number of input arguments.");
+    }
+    
+    /***********/
+    /* If n==2 */
+    /***********/
+    if (n==2) {        
+        if (e1 == 0 || e2 == 0) mexErrMsgTxt("interpcsexSlopeIQM: n=2 requires the definition of slopes.");
+        x0 = va_arg(vararg, double);
+        x1 = va_arg(vararg, double);
+        y0 = va_arg(vararg, double);
+        y1 = va_arg(vararg, double);
+
+        /* Get the xx value at which to interpolate */
+        xx = va_arg(vararg, double);
+        /* End the variable input handling */
+        va_end(vararg);
+
+        b2 = s1;
+        c2 = -(-3.0*y1+3.0*y0+(s2+2.0*s1)*x1+(-s2-2.0*s1)*x0)/(pow(x1,2.0)-2.0*x0*x1+pow(x0,2.0));
+        d2 = (-2.0*y1+2.0*y0+(s2+s1)*x1+(-s2-s1)*x0)/(pow(x1,3.0)-3.0*x0*pow(x1,2.0)+3.0*pow(x0,2.0)*x1-pow(x0,3.0));
+        yy = b2 + 2.0*c2*(xx-x0) + 3.0*d2*pow(xx-x0,2.0);
+    } else {
+        /***********/
+        /* If n!=2 */
+        /***********/
+        /* Allocate memory for x and y */
+        x  = (double *) mxCalloc(n, sizeof(double));
+        y  = (double *) mxCalloc(n, sizeof(double));
+        /* Parse input arguments into x and y */
+        for (k=0;k<n;k++) x[k] = va_arg(vararg, double);
+        for (k=0;k<n;k++) y[k] = va_arg(vararg, double);
+        
+        /* Get the xx value at which to interpolate */
+        xx = va_arg(vararg, double);
+        /* End the variable input handling */
+        va_end(vararg);
+        
+        /*****************************/
+        /* Allocate memory for b,c,d */
+        /*****************************/
+        b  = (double *) mxCalloc(n, sizeof(double));
+        c  = (double *) mxCalloc(n, sizeof(double));
+        d  = (double *) mxCalloc(n, sizeof(double));
+        
+        /****************************/
+        /* Call the spline function */
+        /****************************/
+        spline(n, e1, e2, s1, s2, x, y, b, c, d, &flag);
+        
+        /***************************************/
+        /* Call the spline evaluation function */
+        /***************************************/
+        yy = deriv(n, xx, x, b, c, d, &last);
+        
+        /***************/
+        /* Free memory */
+        /***************/
+        mxFree(x);
+        mxFree(y);
+        mxFree(b);
+        mxFree(c);
+        mxFree(d);
+    }
+    
+    /*********************************/
+    /* Return the interpolated value */
+    /*********************************/
+    return yy;
+}
+
+/*=========================================================================
+   Cubic spline coefficients
+   -------------------------
+   Evaluate the coefficients b[i], c[i], d[i], i = 0, 1, .. n-1 for
+   a cubic interpolating spline
+
+   S(xx) = Y[i] + b[i] * w + c[i] * w**2 + d[i] * w**3
+   where w = xx - x[i]
+   and   x[i] <= xx <= x[i+1]
+
+   The n supplied data points are x[i], y[i], i = 0 ... n-1.
+
+   Input :
+   -------
+   n       : The number of data points or knots (n >= 2)
+   end1,
+   end2    : = 1 to specify the slopes at the end points
+             = 0 to obtain the default conditions
+   slope1,
+   slope2  : the slopes at the end points x[0] and x[n-1]
+             respectively
+   x[]     : the abscissas of the knots in strictly
+             increasing order
+   y[]     : the ordinates of the knots
+
+   Output :
+   --------
+   b, c, d : arrays of spline coefficients as defined above
+             (See note 2 for a definition.)
+   iflag   : status flag
+            = 0 normal return
+            = 1 less than two data points; cannot interpolate
+            = 2 x[] are not in ascending order
+
+   This C code written by ...  Peter & Nigel,
+   ----------------------      Design Software,
+                               42 Gubberley St,
+                               Kenmore, 4069,
+                               Australia.
+
+   Version ... 1.1, 30 September 1987
+   -------     2.0, 6 April 1989    (start with zero subscript)
+                                     remove ndim from parameter list
+               2.1, 28 April 1989   (check on x[])
+               2.2, 10 Oct   1989   change number order of matrix
+
+   Notes ...
+   -----
+   (1) The accompanying function seval() may be used to evaluate the
+       spline while deriv will provide the first derivative.
+   (2) Using p to denote differentiation
+       y[i] = S(X[i])
+       b[i] = Sp(X[i])
+       c[i] = Spp(X[i])/2
+       d[i] = Sppp(X[i])/6  ( Derivative from the right )
+   (3) Since the zero elements of the arrays ARE NOW used here,
+       all arrays to be passed from the main program should be
+       dimensioned at least [n].  These routines will use elements
+       [0 .. n-1].
+   (4) Adapted from the text
+       Forsythe, G.E., Malcolm, M.A. and Moler, C.B. (1977)
+       "Computer Methods for Mathematical Computations"
+       Prentice Hall
+   (5) Note that although there are only n-1 polynomial segments,
+       n elements are requird in b, c, d.  The elements b[n-1],
+       c[n-1] and d[n-1] are set to continue the last segment
+       past x[n-1].
+=========================================================================*/
+void spline (int n, int end1, int end2,
+            double slope1, double slope2,
+            double x[], double y[],
+            double b[], double c[], double d[],
+            int *iflag)
+{  /* begin procedure spline() */
+
+int    nm1, ib, i;
+double t;
+int    ascend;
+
+nm1    = n - 1;
+*iflag = 0;
+
+if (n < 2)
+  {  /* no possible interpolation */
+  *iflag = 1;
+  return;
+  }
+
+ascend = 1;
+for (i = 1; i < n; ++i) if (x[i] <= x[i-1]) ascend = 0;
+if (!ascend)
+   {
+   *iflag = 2;
+   return;
+   }
+
+if (n >= 3)
+   {    /* ---- At least quadratic ---- */
+
+   /* ---- Set up the symmetric tri-diagonal system
+           b = diagonal
+           d = offdiagonal
+           c = right-hand-side  */
+   d[0] = x[1] - x[0];
+   c[1] = (y[1] - y[0]) / d[0];
+   for (i = 1; i < nm1; ++i)
+      {
+      d[i]   = x[i+1] - x[i];
+      b[i]   = 2.0 * (d[i-1] + d[i]);
+      c[i+1] = (y[i+1] - y[i]) / d[i];
+      c[i]   = c[i+1] - c[i];
+      }
+
+   /* ---- Default End conditions
+           Third derivatives at x[0] and x[n-1] obtained
+           from divided differences  */
+   b[0]   = -d[0];
+   b[nm1] = -d[n-2];
+   c[0]   = 0.0;
+   c[nm1] = 0.0;
+   if (n != 3)
+      {
+      c[0]   = c[2] / (x[3] - x[1]) - c[1] / (x[2] - x[0]);
+      c[nm1] = c[n-2] / (x[nm1] - x[n-3]) - c[n-3] / (x[n-2] - x[n-4]);
+      c[0]   = c[0] * d[0] * d[0] / (x[3] - x[0]);
+      c[nm1] = -c[nm1] * d[n-2] * d[n-2] / (x[nm1] - x[n-4]);
+      }
+
+   /* Alternative end conditions -- known slopes */
+   if (end1 == 1)
+      {
+      b[0] = 2.0 * (x[1] - x[0]);
+      c[0] = (y[1] - y[0]) / (x[1] - x[0]) - slope1;
+      }
+   if (end2 == 1)
+      {
+      b[nm1] = 2.0 * (x[nm1] - x[n-2]);
+      c[nm1] = slope2 - (y[nm1] - y[n-2]) / (x[nm1] - x[n-2]);
+      }
+
+   /* Forward elimination */
+   for (i = 1; i < n; ++i)
+     {
+     t    = d[i-1] / b[i-1];
+     b[i] = b[i] - t * d[i-1];
+     c[i] = c[i] - t * c[i-1];
+     }
+
+   /* Back substitution */
+   c[nm1] = c[nm1] / b[nm1];
+   for (ib = 0; ib < nm1; ++ib)
+      {
+      i    = n - ib - 2;
+      c[i] = (c[i] - d[i] * c[i+1]) / b[i];
+      }
+
+   /* c[i] is now the sigma[i] of the text */
+
+   /* Compute the polynomial coefficients */
+   b[nm1] = (y[nm1] - y[n-2]) / d[n-2] + d[n-2] * (c[n-2] + 2.0 * c[nm1]);
+   for (i = 0; i < nm1; ++i)
+      {
+      b[i] = (y[i+1] - y[i]) / d[i] - d[i] * (c[i+1] + 2.0 * c[i]);
+      d[i] = (c[i+1] - c[i]) / d[i];
+      c[i] = 3.0 * c[i];
+      }
+   c[nm1] = 3.0 * c[nm1];
+   d[nm1] = d[n-2];
+
+   }  /* at least quadratic */
+
+else  /* if n >= 3 */
+   {  /* linear segment only  */
+   b[0] = (y[1] - y[0]) / (x[1] - x[0]);
+   c[0] = 0.0;
+   d[0] = 0.0;
+   b[1] = b[0];
+   c[1] = 0.0;
+   d[1] = 0.0;
+   }
+}  /* end of spline() */
+
+
+/*-------------------------------------------------------------------*/
+/*-----------------------------------------------------------------*/
+/*-----------------------------------------------------------------*/
+double seval (int n, double u,
+              double x[], double y[],
+              double b[], double c[], double d[],
+              int *last)
+/*-----------------------------------------------------------------*/
+/*Purpose ...
+  -------
+  Evaluate the cubic spline function
+
+  S(xx) = y[i] + b[i] * w + c[i] * w**2 + d[i] * w**3
+  where w = u - x[i]
+  and   x[i] <= u <= x[i+1]
+  Note that Horner's rule is used.
+  If u < x[0]   then i = 0 is used.
+  If u > x[n-1] then i = n-1 is used.
+
+  Input :
+  -------
+  n       : The number of data points or knots (n >= 2)
+  u       : the abscissa at which the spline is to be evaluated
+  Last    : the segment that was last used to evaluate U
+  x[]     : the abscissas of the knots in strictly increasing order
+  y[]     : the ordinates of the knots
+  b, c, d : arrays of spline coefficients computed by spline().
+
+  Output :
+  --------
+  seval   : the value of the spline function at u
+  Last    : the segment in which u lies
+
+  Notes ...
+  -----
+  (1) If u is not in the same interval as the previous call then a
+      binary search is performed to determine the proper interval.
+
+*/
+/*-------------------------------------------------------------------*/
+{  /* begin function seval() */
+
+int    i, j, k;
+double w;
+
+i = *last;
+if (i >= n-1) i = 0;
+if (i < 0)  i = 0;
+
+if ((x[i] > u) || (x[i+1] < u))
+  {  /* ---- perform a binary search ---- */
+  i = 0;
+  j = n;
+  do
+    {
+    k = (i + j) / 2;         /* split the domain to search */
+    if (u < x[k])  j = k;    /* move the upper bound */
+    if (u >= x[k]) i = k;    /* move the lower bound */
+    }                        /* there are no more segments to search */
+  while (j > i+1);
+  }
+*last = i;
+
+/* ---- Evaluate the spline ---- */
+w = u - x[i];
+w = y[i] + w * (b[i] + w * (c[i] + w * d[i]));
+return (w);
+}
+/*-------------------------------------------------------------------*/
+
+/*-------------------------------------------------------------------*/
+/*-----------------------------------------------------------------*/
+/*-----------------------------------------------------------------*/
+double deriv (int n, double u,
+              double x[],
+              double b[], double c[], double d[],
+              int *last)
+/*-----------------------------------------------------------------*/
+/* Purpose ...
+   -------
+   Evaluate the derivative of the cubic spline function
+
+   S(x) = B[i] + 2.0 * C[i] * w + 3.0 * D[i] * w**2
+   where w = u - X[i]
+   and   X[i] <= u <= X[i+1]
+   Note that Horner's rule is used.
+   If U < X[0] then i = 0 is used.
+   If U > X[n-1] then i = n-1 is used.
+
+   Input :
+   -------
+   n       : The number of data points or knots (n >= 2)
+   u       : the abscissa at which the derivative is to be evaluated
+   last    : the segment that was last used
+   x       : the abscissas of the knots in strictly increasing order
+   b, c, d : arrays of spline coefficients computed by spline()
+
+   Output :
+   --------
+   deriv : the value of the derivative of the spline
+           function at u
+   last  : the segment in which u lies
+
+   Notes ...
+   -----
+   (1) If u is not in the same interval as the previous call then a
+       binary search is performed to determine the proper interval.
+
+*/
+/*-------------------------------------------------------------------*/
+{  /* begin function deriv() */
+
+int    i, j, k;
+double w;
+
+i = *last;
+if (i >= n-1) i = 0;
+if (i < 0) i = 0;
+
+if ((x[i] > u) || (x[i+1] < u))
+  {  /* ---- perform a binary search ---- */
+  i = 0;
+  j = n;
+  do
+    {
+    k = (i + j) / 2;          /* split the domain to search */
+    if (u < x[k])  j = k;     /* move the upper bound */
+    if (u >= x[k]) i = k;     /* move the lower bound */
+    }                         /* there are no more segments to search */
+  while (j > i+1);
+  }
+*last = i;
+
+/* ---- Evaluate the derivative ---- */
+w = u - x[i];
+w = b[i] + w * (2.0 * c[i] + w * 3.0 * d[i]);
+return (w);
+
+} /* end of deriv() */
+/*-------------------------------------------------------------------*/
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*************************************************************/
+/*************************************************************/
+/*************************************************************/
+/*************************************************************/
+/*************************************************************/
+/* interpcsIQM function ... MEX version for CVODE use  */
+/*************************************************************/
+
+void spline_pchip_set( int n, double x[], double f[], double d[] );
+void spline_pchip_val( int n, double x[], double f[], double d[],  int ne, double xe, double *feptr );
+int i4_max( int i1, int i2 );
+int chfev( double x1, double x2, double f1, double f2, double d1, double d2, int ne, double xe, double *feptr, int next[] );
+double r8_min( double x, double y );
+double r8_max( double x, double y );
+double pchst( double arg1, double arg2 );
+
+
+/****************************************************************************/
+
+double interpcsIQM(int nargs, int n, double xe, ...)
+
+/****************************************************************************
+
+  Purpose:
+
+    interpcsIQM is the calling function to evaluate a piecewise cubic spline 
+    function and calculte the Hermite interpolant.
+
+
+  Modified:
+
+    1 October 2007
+
+  Author:
+
+    Basti Bergdahl,
+    Department of Applied Microbiology,
+    Lund Insitute of Technology.
+
+  Calling syntax:
+
+    interpcsIQM(NARGS, N, XE, X1,...,XN,F1,...,FN)
+
+  Parameters:
+
+    Input, int NARGS, the total number of input arguments (not counting NARGS itself).
+    The number should be even, otherwise an error will occure.
+
+    Input, int N, the number of data points (rows in the table).  N must be at least 2.
+
+    Input, double XE, point at which the function is to be evaluated.
+
+    Input, double X1,...,XN, the strictly increasing independent variable values.
+
+    Input, double F1,...,FN, dependent variable values to be interpolated.  This
+    routine is designed for monotonic data, but it will work for any F-array.
+    It will force extrema at points where monotonicity switches direction.
+
+    Output, double FE, the value of the cubic Hermite function at XE.
+*/
+{
+    va_list vararg;
+    int k, oddnumber;
+    int ne = 1;
+    double *data, *x, *f, *d, *feptr;
+    double fe;
+
+    /* Check if table data has been given */
+    if (nargs == 2)
+    {
+        mexErrMsgTxt("interpcsIQM error: Input incorrect. No data for the table has been supplied.");
+        return 0;
+    }
+
+    /* Check if odd or even number of input arguments */
+    oddnumber = nargs % 2;
+    if (oddnumber != 0)
+    {
+        mexErrMsgTxt("interpcsIQM error: Input incorrect. The number of inputs should be even.");
+        return 0;
+    }
+
+    /* If number of input arguments in odd, check if
+     * the X and Y vectors are of the same size */
+    if ((nargs-2)/2 != n)
+    {
+        mexErrMsgTxt("interpcsIQM error: Input incorrect. The X and Y vectors are either of different lengths or");
+        mexErrMsgTxt("an incorrect number for the data points has been given.");
+        return 0;
+    }
+
+    /* Read in all variable input arguments in double array */    
+    va_start(vararg, xe);
+    data = (double *)mxCalloc((n*2),sizeof(double));
+    for (k=0; k<nargs-2; k++ )
+    {
+        data[k] = va_arg(vararg, double);
+    }
+
+    /* Create the X and Y arrays making up the table */
+    x = (double *)mxCalloc(n,sizeof(double));
+    f = (double *)mxCalloc(n,sizeof(double));
+    for (k=0; k<n; k++)
+    {
+        x[k] = data[k];
+        f[k] = data[k+n];
+    }
+    mxFree(data); /* free temporary array */
+
+    /* handle off limit values */
+    if (xe < x[0]) return(f[0]);
+    if (xe > x[n-1]) return(f[n-1]);
+    
+    /* Calculate the derivatives for the piecewise cubic Hermite interpolant */
+    d = (double *)mxCalloc(n,sizeof(double));
+    spline_pchip_set(n, x, f, d);
+
+    /* Evaluate the cubic Hermite function at x */    
+    feptr = &fe;
+    spline_pchip_val(n, x, f, d, ne, xe, feptr);
+
+    return(fe);
+}
+
+
+
+/****************************************************************************/
+
+void spline_pchip_set( int n, double x[], double f[], double d[] )
+
+/****************************************************************************
+
+  Purpose:
+
+    SPLINE_PCHIP_SET sets derivatives for a piecewise cubic Hermite interpolant.
+
+  Discussion:
+
+    This routine computes what would normally be called a Hermite
+    interpolant.  However, the user is only required to supply function
+    values, not derivative values as well.  This routine computes
+    "suitable" derivative values, so that the resulting Hermite interpolant
+    has desirable shape and monotonicity properties.
+
+    The interpolant will have an extremum at each point where
+    monotonicity switches direction.
+
+    The resulting piecewise cubic Hermite function may be evaluated
+    by SPLINE_PCHIP_VAL..
+
+    This routine was originally called "PCHIM".
+
+  Modified:
+
+    14 August 2005
+
+  Author:
+
+    Fred Fritsch,
+    Mathematics and Statistics Division,
+    Lawrence Livermore National Laboratory.
+
+    C++ translation by John Burkardt.
+
+  Reference:
+
+    Fred Fritsch, Ralph Carlson,
+    Monotone Piecewise Cubic Interpolation,
+    SIAM Journal on Numerical Analysis,
+    Volume 17, Number 2, April 1980, pages 238-246.
+
+    Fred Fritsch, Judy Butland,
+    A Method for Constructing Local Monotone Piecewise
+    Cubic Interpolants,
+    SIAM Journal on Scientific and Statistical Computing,
+    Volume 5, Number 2, 1984, pages 300-304.
+
+  Parameters:
+
+    Input, int N, the number of data points.  N must be at least 2.
+
+    Input, double X[N], the strictly increasing independent
+    variable values.
+
+    Input, double F[N], dependent variable values to be interpolated.  This
+    routine is designed for monotonic data, but it will work for any F-array.
+    It will force extrema at points where monotonicity switches direction.
+
+    Output, double D[N], the derivative values at the
+    data points.  If the data are monotonic, these values will determine
+    a monotone cubic Hermite function.
+*/
+{
+  double del1;
+  double del2;
+  double dmax;
+  double dmin;
+  double drat1;
+  double drat2;
+  double dsave;
+  double h1;
+  double h2;
+  double hsum;
+  double hsumt3;
+  int i;
+  int ierr;
+  int nless1;
+  double temp;
+  double w1;
+  double w2;
+
+  /*  Check the arguments. */
+
+  if ( n < 2 )
+  {
+    ierr = -1;
+    mexErrMsgTxt("\n");
+    mexErrMsgTxt("SPLINE_PCHIP_SET - Fatal error!\n");
+    mexErrMsgTxt("  Number of data points less than 2.\n");
+    exit ( ierr );
+  }
+
+  for ( i = 1; i < n; i++ )
+  {
+    if ( x[i] <= x[i-1] )
+    {
+      ierr = -3;
+      mexErrMsgTxt("\n");
+      mexErrMsgTxt("SPLINE_PCHIP_SET - Fatal error!\n");
+      mexErrMsgTxt("  X array not strictly increasing.\n");
+      exit ( ierr );
+    }
+  }
+
+  ierr = 0;
+  nless1 = n - 1;
+  h1 = x[1] - x[0];
+  del1 = ( f[1] - f[0] ) / h1;
+  dsave = del1;
+
+/*  Special case N=2, use linear interpolation. */
+
+  if ( n == 2 )
+  {
+    d[0] = del1;
+    d[n-1] = del1;
+    return;
+  }
+
+/*  Normal case, 3 <= N. */
+
+  h2 = x[2] - x[1];
+  del2 = ( f[2] - f[1] ) / h2;
+
+/*  Set D(1) via non-centered three point formula, adjusted to be
+    shape preserving. */
+
+  hsum = h1 + h2;
+  w1 = ( h1 + hsum ) / hsum;
+  w2 = -h1 / hsum;
+  d[0] = w1 * del1 + w2 * del2;
+
+  if ( pchst ( d[0], del1 ) <= 0.0 )
+  {
+    d[0] = 0.0;
+  }
+
+/*  Need do this check only if monotonicity switches. */
+
+  else if ( pchst ( del1, del2 ) < 0.0 )
+  {
+     dmax = 3.0 * del1;
+
+     if ( fabs ( dmax ) < fabs ( d[0] ) )
+     {
+       d[0] = dmax;
+     }
+
+  }
+
+/*  Loop through interior points. */
+
+  for ( i = 2; i <= nless1; i++ )
+  {
+    if ( 2 < i )
+    {
+      h1 = h2;
+      h2 = x[i] - x[i-1];
+      hsum = h1 + h2;
+      del1 = del2;
+      del2 = ( f[i] - f[i-1] ) / h2;
+    }
+
+/*  Set D(I)=0 unless data are strictly monotonic. */
+
+    d[i-1] = 0.0;
+
+    temp = pchst ( del1, del2 );
+
+    if ( temp < 0.0 )
+    {
+      ierr = ierr + 1;
+      dsave = del2;
+    }
+
+/*  Count number of changes in direction of monotonicity. */
+
+    else if ( temp == 0.0 )
+    {
+      if ( del2 != 0.0 )
+      {
+        if ( pchst ( dsave, del2 ) < 0.0 )
+        {
+          ierr = ierr + 1;
+        }
+        dsave = del2;
+      }
+    }
+
+/*  Use Brodlie modification of Butland formula. */
+
+    else
+    {
+      hsumt3 = 3.0 * hsum;
+      w1 = ( hsum + h1 ) / hsumt3;
+      w2 = ( hsum + h2 ) / hsumt3;
+      dmax = r8_max ( fabs ( del1 ), fabs ( del2 ) );
+      dmin = r8_min ( fabs ( del1 ), fabs ( del2 ) );
+      drat1 = del1 / dmax;
+      drat2 = del2 / dmax;
+      d[i-1] = dmin / ( w1 * drat1 + w2 * drat2 );
+    }
+  }
+
+/*  Set D(N) via non-centered three point formula, adjusted to be
+    shape preserving. */
+
+  w1 = -h2 / hsum;
+  w2 = ( h2 + hsum ) / hsum;
+  d[n-1] = w1 * del1 + w2 * del2;
+
+  if ( pchst ( d[n-1], del2 ) <= 0.0 )
+  {
+    d[n-1] = 0.0;
+  }
+  else if ( pchst ( del1, del2 ) < 0.0 )
+  {
+
+/*  Need do this check only if monotonicity switches. */
+
+    dmax = 3.0 * del2;
+
+    if ( fabs ( dmax ) < abs ( d[n-1] ) )
+    {
+      d[n-1] = dmax;
+    }
+
+  }
+  return;
+}
+
+/****************************************************************************/
+
+void spline_pchip_val( int n, double x[], double f[], double d[],
+  int ne, double xe, double *feptr )
+
+/****************************************************************************
+
+  Purpose:
+
+    SPLINE_PCHIP_VAL evaluates a piecewise cubic Hermite function.
+
+  Description:
+
+    This routine may be used by itself for Hermite interpolation, or as an
+    evaluator for SPLINE_PCHIP_SET.
+
+    This routine evaluates the cubic Hermite function at the points XE.
+
+    Most of the coding between the call to CHFEV and the end of
+    the IR loop could be eliminated if it were permissible to
+    assume that XE is ordered relative to X.
+
+    CHFEV does not assume that X1 is less than X2.  Thus, it would
+    be possible to write a version of SPLINE_PCHIP_VAL that assumes a strictly
+    decreasing X array by simply running the IR loop backwards
+    and reversing the order of appropriate tests.
+
+    The present code has a minor bug, which I have decided is not
+    worth the effort that would be required to fix it.
+    If XE contains points in [X(N-1),X(N)], followed by points less than
+    X(N-1), followed by points greater than X(N), the extrapolation points
+    will be counted (at least) twice in the total returned in IERR.
+
+    The evaluation will be most efficient if the elements of XE are
+    increasing relative to X; that is, for all J <= K,
+      X(I) <= XE(J)
+    implies
+      X(I) <= XE(K).
+
+    If any of the XE are outside the interval [X(1),X(N)],
+    values are extrapolated from the nearest extreme cubic,
+    and a warning error is returned.
+
+    This routine was originally named "PCHFE".
+
+  Modified:
+
+    14 August 2005
+
+  Author:
+
+    Fred Fritsch,
+    Mathematics and Statistics Division,
+    Lawrence Livermore National Laboratory.
+
+    C++ translation by John Burkardt.
+
+  Reference:
+
+    Fred Fritsch, Ralph Carlson,
+    Monotone Piecewise Cubic Interpolation,
+    SIAM Journal on Numerical Analysis,
+    Volume 17, Number 2, April 1980, pages 238-246.
+
+  Parameters:
+
+    Input, int N, the number of data points.  N must be at least 2.
+
+    Input, double X[N], the strictly increasing independent
+    variable values.
+
+    Input, double F[N], the function values.
+
+    Input, double D[N], the derivative values.
+
+    Input, int NE, the number of evaluation points.
+
+    Input, double XE, point at which the function is to
+    be evaluated.
+
+    Output, double FE, the value of the cubic Hermite
+    function at XE.
+*/
+{
+  int i;
+  int ierc;
+  int ierr;
+  int ir;
+  int j;
+  int j_first;
+  int j_new;
+  int j_save;
+  int next[2];
+  int nj;
+
+/*  Check arguments. */
+
+  if ( n < 2 )
+  {
+    ierr = -1;
+    mexErrMsgTxt("\n");
+    mexErrMsgTxt("SPLINE_PCHIP_VAL - Fatal error!\n");
+    mexErrMsgTxt("Number of data points less than 2.\n");
+    exit ( ierr );
+  }
+
+  for ( i = 1; i < n; i++ )
+  {
+    if ( x[i] <= x[i-1] )
+    {
+      ierr = -3;
+      mexErrMsgTxt("\n");
+      mexErrMsgTxt("SPLINE_PCHIP_VAL - Fatal error!\n");
+      mexErrMsgTxt("X array not strictly increasing.\n");
+      exit ( ierr );
+    }
+  }
+
+  if ( ne < 1 )
+  {
+    ierr = -4;
+    mexErrMsgTxt("\n");
+    mexErrMsgTxt("SPLINE_PCHIP_VAL - Fatal error!\n");
+    mexErrMsgTxt("Number of evaluation points less than 1.\n");
+    return;
+  }
+
+  ierr = 0;
+
+/*  Loop over intervals.
+  The interval index is IL = IR-1.
+  The interval is X(IL) <= X < X(IR).
+*/
+  j_first = 1;
+  ir = 2;
+
+  for ( ; ; )
+  {
+/*
+  Skip out of the loop if have processed all evaluation points.
+*/
+    if ( ne < j_first )
+    {
+      break;
+    }
+/*
+  Locate all points in the interval.
+*/
+    j_save = ne + 1;
+
+    for ( j = j_first; j <= ne; j++ )
+    {
+      if ( x[ir-1] <= xe )
+      {
+        j_save = j;
+        if ( ir == n )
+        {
+          j_save = ne + 1;
+        }
+        break;
+      }
+    }
+/*
+  Have located first point beyond interval.
+*/
+    j = j_save;
+
+    nj = j - j_first;
+/*
+  Skip evaluation if no points in interval.
+*/
+    if ( nj != 0 )
+    {
+/*
+  Evaluate cubic at XE(J_FIRST:J-1).
+*/
+      ierc = chfev ( x[ir-2], x[ir-1], f[ir-2], f[ir-1], d[ir-2], d[ir-1],
+        nj, xe, feptr, next );
+
+      if ( ierc < 0 )
+      {
+        ierr = -5;
+        mexErrMsgTxt("\n");
+        mexErrMsgTxt("SPLINE_PCHIP_VAL - Fatal error!\n");
+        mexErrMsgTxt("Error return from CHFEV.\n");
+        exit ( ierr );
+      }
+/*
+  In the current set of XE points, there are NEXT(2) to the right of X(IR).
+*/
+      if ( next[1] != 0 )
+      {
+        if ( ir < n )
+        {
+          ierr = -5;
+          mexErrMsgTxt("\n");
+          mexErrMsgTxt("SPLINE_PCHIP_VAL - Fatal error!\n");
+          mexErrMsgTxt("IR < N.\n");
+          exit ( ierr );
+        }
+/*
+  These are actually extrapolation points.
+*/
+        ierr = ierr + next[1];
+
+      }
+/*
+  In the current set of XE points, there are NEXT(1) to the left of X(IR-1).
+*/
+      if ( next[0] != 0 )
+      {
+/*
+  These are actually extrapolation points.
+*/
+        if ( ir <= 2 )
+        {
+          ierr = ierr + next[0];
+        }
+        else
+        {
+          j_new = -1;
+
+          for ( i = j_first; i <= j-1; i++ )
+          {
+            if ( xe < x[ir-2] )
+            {
+              j_new = i;
+              break;
+            }
+          }
+
+          if ( j_new == -1 )
+          {
+            ierr = -5;
+            mexErrMsgTxt("\n");
+            mexErrMsgTxt("SPLINE_PCHIP_VAL - Fatal error!\n");
+            mexErrMsgTxt("  Could not bracket the data point.\n");
+            exit ( ierr );
+          }
+/*
+  Reset J.  This will be the new J_FIRST.
+*/
+          j = j_new;
+/*
+  Now find out how far to back up in the X array.
+*/
+          for ( i = 1; i <= ir-1; i++ )
+          {
+            if ( xe < x[i-1] )
+            {
+              break;
+            }
+          }
+/*
+  At this point, either XE(J) < X(1) or X(i-1) <= XE(J) < X(I) .
+
+  Reset IR, recognizing that it will be incremented before cycling.
+*/
+          ir = i4_max ( 1, i-1 );
+        }
+      }
+
+      j_first = j;
+    }
+
+    ir = ir + 1;
+
+    if ( n < ir )
+    {
+      break;
+    }
+
+  }
+
+  return;
+}
+
+/****************************************************************************/
+
+int chfev( double x1, double x2, double f1, double f2, double d1, double d2,
+  int ne, double xe, double *feptr, int next[] )
+
+/****************************************************************************
+
+  Purpose:
+
+    CHFEV evaluates a cubic polynomial given in Hermite form.
+
+  Discussion:
+
+    This routine evaluates a cubic polynomial given in Hermite form at an
+    array of points.  While designed for use by SPLINE_PCHIP_VAL, it may
+    be useful directly as an evaluator for a piecewise cubic
+    Hermite function in applications, such as graphing, where
+    the interval is known in advance.
+
+    The cubic polynomial is determined by function values
+    F1, F2 and derivatives D1, D2 on the interval [X1,X2].
+
+  Modified:
+
+    12 August 2005
+
+  Author:
+
+    Fred Fritsch,
+    Mathematics and Statistics Division,
+    Lawrence Livermore National Laboratory.
+
+    C++ translation by John Burkardt.
+
+  Reference:
+
+    Fred Fritsch, Ralph Carlson,
+    Monotone Piecewise Cubic Interpolation,
+    SIAM Journal on Numerical Analysis,
+    Volume 17, Number 2, April 1980, pages 238-246.
+
+    David Kahaner, Cleve Moler, Steven Nash,
+    Numerical Methods and Software,
+    Prentice Hall, 1989,
+    ISBN: 0-13-627258-4,
+    LC: TA345.K34.
+
+  Parameters:
+
+    Input, double X1, X2, the endpoints of the interval of
+    definition of the cubic.  X1 and X2 must be distinct.
+
+    Input, double F1, F2, the values of the function at X1 and
+    X2, respectively.
+
+    Input, double D1, D2, the derivative values at X1 and
+    X2, respectively.
+
+    Input, int NE, the number of evaluation points.
+
+    Input, double XE, the point at which the function is to
+    be evaluated.  If the value of XE is outside the interval
+    [X1,X2], a warning error is returned in NEXT.
+
+    Output, double FE, the value of the cubic function
+    at the point XE.
+
+    Output, int NEXT[2], indicates the number of extrapolation points:
+    NEXT[0] = number of evaluation points to the left of interval.
+    NEXT[1] = number of evaluation points to the right of interval.
+
+    Output, int CHFEV, error flag.
+    0, no errors.
+    -1, NE < 1.
+    -2, X1 == X2.
+*/
+{
+  double c2;
+  double c3;
+  double del1;
+  double del2;
+  double delta;
+  double h;
+  int ierr;
+  double x;
+  double fe;
+  double xma;
+  double xmi;
+
+  if ( ne < 1 )
+  {
+    ierr = -1;
+    mexErrMsgTxt("\n");
+    mexErrMsgTxt("CHFEV - Fatal error!\n");
+    mexErrMsgTxt("  Number of evaluation points is less than 1.\n");
+    printf("  NE = %d\n", ne);
+    return ierr;
+  }
+
+  h = x2 - x1;
+
+  if ( h == 0.0 )
+  {
+    ierr = -2;
+    mexErrMsgTxt("\n");
+    mexErrMsgTxt("CHFEV - Fatal error!\n");
+    mexErrMsgTxt("  The interval [X1,X2] is of zero length.\n");
+    return ierr;
+  }
+/*
+  Initialize.
+*/
+  ierr = 0;
+  next[0] = 0;
+  next[1] = 0;
+  xmi = r8_min ( 0.0, h );
+  xma = r8_max ( 0.0, h );
+/*
+  Compute cubic coefficients expanded about X1.
+*/
+  delta = ( f2 - f1 ) / h;
+  del1 = ( d1 - delta ) / h;
+  del2 = ( d2 - delta ) / h;
+  c2 = -( del1 + del1 + del2 );
+  c3 = ( del1 + del2 ) / h;
+    x = xe - x1;
+    fe = f1 + x * ( d1 + x * ( c2 + x * c3 ) );
+    *feptr = fe;
+/*
+  Count the extrapolation points.
+*/
+    if ( x < xmi )
+    {
+      next[0] = next[0] + 1;
+    }
+
+    if ( xma < x )
+    {
+      next[1] = next[1] + 1;
+    }
+
+
+  return 0;
+}
+
+/****************************************************************************/
+
+double pchst( double arg1, double arg2 )
+
+/****************************************************************************
+
+  Purpose:
+
+    PCHST: PCHIP sign-testing routine.
+
+  Discussion:
+
+    This routine essentially computes the sign of ARG1 * ARG2.
+
+    The object is to do this without multiplying ARG1 * ARG2, to avoid
+    possible over/underflow problems.
+
+  Modified:
+
+    12 August 2005
+
+  Author:
+
+    Fred Fritsch,
+    Mathematics and Statistics Division,
+    Lawrence Livermore National Laboratory.
+
+    C++ translation by John Burkardt.
+
+  Reference:
+
+    Fred Fritsch, Ralph Carlson,
+    Monotone Piecewise Cubic Interpolation,
+    SIAM Journal on Numerical Analysis,
+    Volume 17, Number 2, April 1980, pages 238-246.
+
+  Parameters:
+
+    Input, double ARG1, ARG2, two values to check.
+
+    Output, double PCHST,
+    -1.0, if ARG1 and ARG2 are of opposite sign.
+     0.0, if either argument is zero.
+    +1.0, if ARG1 and ARG2 are of the same sign.
+*/
+{
+  double value;
+
+  if ( arg1 == 0.0 )
+  {
+    value = 0.0;
+  }
+  else if ( arg1 < 0.0 )
+  {
+    if ( arg2 < 0.0 )
+    {
+      value = 1.0;
+    }
+    else if ( arg2 == 0.0 )
+    {
+      value = 0.0;
+    }
+    else if ( 0.0 < arg2 )
+    {
+      value = -1.0;
+    }
+  }
+  else if ( 0.0 < arg1 )
+  {
+    if ( arg2 < 0.0 )
+    {
+      value = -1.0;
+    }
+    else if ( arg2 == 0.0 )
+    {
+      value = 0.0;
+    }
+    else if ( 0.0 < arg2 )
+    {
+      value = 1.0;
+    }
+  }
+
+  return(value);
+}
+
+/****************************************************************************/
+
+double r8_max( double x, double y )
+
+/****************************************************************************
+
+  Purpose:
+
+    R8_MAX returns the maximum of two R8's.
+
+  Modified:
+
+    10 January 2002
+
+  Author:
+
+    John Burkardt
+
+  Parameters:
+
+    Input, double X, Y, the quantities to compare.
+
+    Output, double R8_MAX, the maximum of X and Y.
+*/
+{
+  if ( y < x )
+  {
+    return(x);
+  }
+  else
+  {
+    return(y);
+  }
+}
+/****************************************************************************/
+
+double r8_min( double x, double y )
+
+/****************************************************************************
+
+  Purpose:
+
+    R8_MIN returns the minimum of two R8's.
+
+  Modified:
+
+    09 May 2003
+
+  Author:
+
+    John Burkardt
+
+  Parameters:
+
+    Input, double X, Y, the quantities to compare.
+
+    Output, double R8_MIN, the minimum of X and Y.
+*/
+{
+  if ( y < x )
+  {
+    return(y);
+  }
+  else
+  {
+    return(x);
+  }
+}
+
+
+/****************************************************************************/
+
+int i4_max ( int i1, int i2 )
+
+/****************************************************************************
+
+  Purpose:
+
+    I4_MAX returns the maximum of two I4's.
+
+  Modified:
+
+    13 October 1998
+
+  Author:
+
+    John Burkardt
+
+  Parameters:
+
+    Input, int I1, I2, are two integers to be compared.
+
+    Output, int I4_MAX, the larger of I1 and I2.
+
+*/
+{
+  if ( i2 < i1 )
+  {
+    return(i1);
+  }
+  else
+  {
+    return(i2);
+  }
+
+}
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/lib/CVODEmex25.a b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/lib/CVODEmex25.a
new file mode 100644
index 0000000000000000000000000000000000000000..fd4d2f3c6a2cac80df2cee1ca4437312bc150e7a
Binary files /dev/null and b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/lib/CVODEmex25.a differ
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/lib/CVODEmex25.lib b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/lib/CVODEmex25.lib
new file mode 100644
index 0000000000000000000000000000000000000000..d8bdca8601ea673c50a6f73200bf5d7c7442c003
Binary files /dev/null and b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/lib/CVODEmex25.lib differ
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/CVODEmex25.c b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/CVODEmex25.c
new file mode 100644
index 0000000000000000000000000000000000000000..9e60a86127e176c690d637ec9b5996a8c814bb7c
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/CVODEmex25.c	
@@ -0,0 +1,818 @@
+/*
+ * CVODEmex25.c: MEX/CVODES Interface for Sundials CVODES version 2.5
+ *
+ * Information:
+ * ============
+ * IQM Tools Pro
+ */
+
+#include <mex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <string.h>
+#include <matrix.h>
+#include <math.h>
+
+/* CVODES includes */
+#include <cvodes/cvodes.h>
+#include <nvector/nvector_serial.h>
+#include <sundials/sundials_types.h>
+#include <sundials/sundials_math.h>
+#include "CVODEmex25.h"
+
+/* Definitions for CVODES */
+#define ABSTOL  1.0e-6  
+#define RELTOL  1.0e-6  
+#define MAXNUMSTEPS     100000  /* default in CVODE is 500 but higher is better for general purpose */
+#define MAXERRTESTFAILS 50      /* default is 7 */
+#define Ith(v,i) NV_Ith_S(v,i-1)
+
+/* Initialize functions */
+static void doInitilizationVariables();
+static mxArray* handleInputArguments(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]);
+static mxArray* doXdotCalc();
+static void allocSimMemory();
+static void initCVODE();
+static void integrate();
+static void reportSTATS();
+static mxArray* constructOutput();
+static void addVec2Mat(double *matrix, double *rowvector, int row, int nrows, int ncols);
+static int f(double time, N_Vector u, N_Vector udot, void *f_data);
+static int g(double time, N_Vector y, double *gout, void *g_data);
+static void errorMsg(char *text);
+static void freeMem();
+
+/* Some global variables for the interface */
+int k,k2;   /* some loop variables */
+
+int length2check;
+
+char stringbuffer[256];
+
+mxArray *timesimvectorMX = NULL;
+double *timesimvector = NULL;
+
+mxArray *parametervectorMX = NULL;
+double *parametervector = NULL;
+double *parametervectorCVODES = NULL; 
+
+mxArray *initialconditionsMX = NULL;
+double *initialconditions = NULL;
+
+mxArray *optionsMX = NULL;
+
+mxArray *showIntegratorStatsMX = NULL; 
+int showIntegratorStats = 0;            /* Flag defining if integrator stats shown or not */
+
+
+mxArray *minstepMX = NULL;
+double minstep;
+mxArray *maxstepMX = NULL;
+double maxstep;
+mxArray *maxnumstepsMX = NULL;
+long int maxnumsteps;
+mxArray *reltolMX = NULL;
+double reltol;
+mxArray *abstolMX = NULL;
+double abstol;
+mxArray *maxerrtestfailsMX = NULL;
+int maxerrtestfails;
+mxArray *maxorderMX = NULL;
+int maxorder;
+mxArray *maxconvfailsMX = NULL;
+int maxconvfails;
+mxArray *initstepMX = NULL;
+double initstep;
+mxArray *maxnonlineariterMX = NULL;
+int maxnonlineariter;
+
+
+
+
+mxArray *xdotcalcMX = NULL;
+double xdotcalc;
+
+int numbertimesteps;
+
+mxArray *resultMX = NULL;
+double *result = NULL;
+
+mxArray *statesMX = NULL;
+
+mxArray *statevaluesMX = NULL;
+double *statevalues = NULL;
+
+mxArray *variablesMX = NULL;
+
+mxArray *variablevaluesMX = NULL;
+double *variablevalues = NULL;
+
+mxArray *reactionsMX = NULL;
+
+mxArray *reactionvaluesMX = NULL;
+double *reactionvalues = NULL;
+
+mxArray *eventsMX = NULL;
+
+mxArray *eventtimesMX = NULL;
+double *eventtimes = NULL;
+
+mxArray *eventflagsMX = NULL;
+double *eventflags = NULL;
+
+/* CVODES needed data */
+ParamData modeldata;
+N_Vector u = NULL;
+void *cvode_mem;
+int flag, flagroot;
+double treturn;
+double tendstep;
+
+/* Interface to model RHS */
+double *statevec = NULL;
+double *variablevec = NULL;
+double *reactionvec = NULL;
+int *eventvec = NULL;
+double *eventdataold = NULL;
+int nreventshappend;
+double *eventflagsdata = NULL;
+double eventcorrecttest;
+
+/* Error Flags */
+int timevectorEmpty = 0;
+int timevectorNotVector = 0;
+int timevectorIsScalar = 0;
+
+/* Method (stiff, nonstiff) Variables */
+mxArray *methodMX = NULL;
+int method;
+
+/* Integrator Statistics */
+long int STATS_nsteps;
+long int STATS_nfevals;
+long int STATS_netfails;
+double STATS_hinused;
+double STATS_tolsfac;
+  
+/*
+ *========================================================================
+ * MEX INTERFACE FOR MEX SIMULATION MODELS
+ *========================================================================
+ */
+void CVODEmex25(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
+{
+    /* Initialize variables that are needed externally */
+    interpcseIQM_check = NULL; /* needed for spline function in mexsplineaddon.h */
+    interpcseSlopeIQM_check = NULL; /* needed for spline function in mexsplineaddon.h */
+
+    /* Initialize all other variables that are initialized during their definition
+     * Needs to be redone since not re-defined/initialized if MEX file recalled */
+    doInitilizationVariables();
+    
+    /* Handle variable input arguments */
+    resultMX = handleInputArguments(nlhs, plhs, nrhs, prhs);
+    if (resultMX != NULL) {
+        /* No integration requested */
+        plhs[0] = resultMX;
+        return;
+    }
+    
+    /* Check if timevector defined */
+    if (timevectorEmpty == 1) mexErrMsgTxt("Timevector is empty.");
+        
+    /* check if integration or xdot calculation */
+    if (xdotcalc != 0) {
+        /* return the RHS of the ODEs at given state and parameter values */
+        resultMX = doXdotCalc();
+        plhs[0] = resultMX;
+        return;
+    }
+    
+    /* Do error checks ... timevector needs to be defined if integration is to be done! */
+    if (timevectorNotVector == 1 || timevectorIsScalar == 1) mexErrMsgTxt("'timevector' input argument needs to be a vector if you want to do a simulation.");
+    /* Otherwise do the integration */
+    /* Allocate memory for the simulation */
+    allocSimMemory();
+    /* Initialize CVODES */
+    initCVODE();
+    /* Integrate */
+    integrate();
+    /* Report Statistics of Integration */
+    reportSTATS();
+    /* Construct result */
+    plhs[0] = constructOutput();
+    /* Free allocated memory */
+    freeMem();
+}
+
+/*
+ *========================================================================
+ * Integration statistics report function
+ *========================================================================
+ */
+static void reportSTATS()
+{
+    /* Get the statistics */
+    CVodeGetNumSteps(cvode_mem,&STATS_nsteps);
+    CVodeGetNumRhsEvals(cvode_mem,&STATS_nfevals);
+    CVodeGetNumErrTestFails(cvode_mem,&STATS_netfails);
+    CVodeGetActualInitStep(cvode_mem,&STATS_hinused);
+    CVodeGetTolScaleFactor(cvode_mem,&STATS_tolsfac);
+    /* Report statistics */
+    if (showIntegratorStats != 0) {
+        mexPrintf("\nIntegrator Statistics\n");
+        mexPrintf("=====================\n");
+        mexPrintf("Cumulative number of internal steps:    %ld\n",STATS_nsteps);
+        mexPrintf("No. of calls to r.h.s. function:        %ld\n",STATS_nfevals);
+        mexPrintf("No. of local error test failures:       %ld\n",STATS_netfails);
+        mexPrintf("Actual init step size used:             %g\n",STATS_hinused);
+        mexPrintf("Suggested factor for tolerance scaling: %g\n\n",STATS_tolsfac);
+    }
+}
+
+/*
+ *========================================================================
+ * Help function to add a row vector to a matrix
+ *========================================================================
+ */
+static void addVec2Mat(double *matrix, double *rowvector, int row, int nrrows, int nrcols)
+{
+    int k;
+    for (k=0;k<nrcols;k++) {
+        matrix[row+k*nrrows] = rowvector[k];
+    }
+}
+
+/*
+ *========================================================================
+ * RHS function f(t,u) 
+ *========================================================================
+ */
+static int f(double time, N_Vector u, N_Vector udot, void *f_data)
+{
+    double *statevec, *DDTvector;
+    ParamData *paramdataPtr;
+    /* get pointer to modeldata */
+    paramdataPtr = (ParamData*) f_data;
+    /* connect input and result data */
+    statevec = NV_DATA_S(u);
+    DDTvector = NV_DATA_S(udot);
+    /* run the model */
+    model(time, statevec, DDTvector, paramdataPtr, DOFLAG_DDT, NULL, NULL, NULL, NULL);
+    return(0);
+}
+
+/*
+ *========================================================================
+ * Event function 
+ *========================================================================
+ */
+static int g(double time, N_Vector y, double *gout, void *g_data)
+{
+    double *statevec;
+    ParamData *paramdataPtr;
+    /* get pointer to model data */
+    paramdataPtr = (ParamData*) g_data;
+    /* connect input data */
+    statevec = NV_DATA_S(y);
+    /* run the event function */
+    model(time, statevec, NULL, paramdataPtr, DOFLAG_EVENTS, NULL, NULL, gout, NULL);
+    return(0);
+}
+
+/*
+ *========================================================================
+ * Error function 
+ *========================================================================
+ */
+static void errorMsg(char *text)
+{
+    /* First free the allocated memory */
+    freeMem();
+    /* Then print error message and exit */
+    mexErrMsgTxt(text);
+}
+
+/*
+ *========================================================================
+ * Free the memory 
+ *========================================================================
+ */
+static void freeMem()
+{
+    /* Free all CVODE related memory */
+    N_VDestroy_Serial(u);  /* Free the u vector */
+    CVodeFree(&cvode_mem);  /* Free the integrator memory */
+}
+
+    /*
+     * ==============================================
+     * HANDLE THE VARIABLE INPUT ARGUMENTS
+     * ==============================================
+     */
+static mxArray* handleInputArguments(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
+{
+    mxArray *rhs[1], *lhs[1]; /* for calling matlab function "convertNNCa2NANNCaIQM" */
+
+    /* need to set to NULL some things for checking */
+    parametervectorMX = NULL;
+    initialconditionsMX = NULL;
+    optionsMX = NULL;
+    
+    if (nrhs == 0) {
+        /***************************************************/
+        /* no input arguments => return initial conditions */
+        /***************************************************/
+        
+        /* check if only numeric initial conditions */
+        if (hasOnlyNumericICs) {
+            /* numeric */
+            resultMX = mxCreateDoubleMatrix(NRSTATES, 1, mxREAL);
+            result = mxGetPr(resultMX);
+            for (k=0; k<NRSTATES; k++) result[k] = defaultICs_num[k];
+            return resultMX;
+        } else {
+            /* non-numeric */
+            resultMX = mxCreateCellMatrix(NRSTATES, 1);
+            result = mxGetPr(resultMX);
+            for (k=0; k<NRSTATES; k++) mxSetCell(resultMX,k,mxCreateString(defaultICs_nonnum[k]));
+            /* call matlab function with resultMX as input to convert numeric strings to numbers ... */
+            rhs[0] = resultMX;
+            mexCallMATLAB(1, lhs, 1, rhs, "convertNNCa2NANNCaIQM");
+            return lhs[0];
+        }
+    } else if (nrhs == 1) {
+        /***************************************************/
+        /* handle single input argument                    */
+        /***************************************************/
+        
+        if (mxIsEmpty(prhs[0])) {
+            mexErrMsgTxt("Timevector is empty.");
+        } 
+        if (mxIsChar(prhs[0])) {
+            length2check = (mxGetM(prhs[0]) * mxGetN(prhs[0]));
+            if (length2check == 6) {       
+                resultMX = mxCreateCellMatrix(NRSTATES, 1);
+                for (k=0; k<NRSTATES; k++) mxSetCell(resultMX,k,mxCreateString(stateNames[k]));
+                return resultMX;
+            }
+            else if (length2check == 10) { 
+                resultMX = mxCreateCellMatrix(NRPARAMETERS, 1);
+                for (k=0; k<NRPARAMETERS; k++) mxSetCell(resultMX,k,mxCreateString(parameterNames[k]));
+                return resultMX;
+            }
+            else if (length2check == 13) { 
+                resultMX = mxCreateCellMatrix(NRVARIABLES, 1);
+                for (k=0; k<NRVARIABLES; k++) mxSetCell(resultMX,k,mxCreateString(variableNames[k]));
+                return resultMX;
+            }
+            else if (length2check == 15) { 
+                resultMX = mxCreateDoubleMatrix(NRPARAMETERS, 1, mxREAL);
+                result = mxGetPr(resultMX);
+                for (k=0; k<NRPARAMETERS; k++) result[k] = defaultParam[k];
+                return resultMX;
+            } 
+            else if (length2check == 16) { 
+                resultMX = mxCreateCellMatrix(NRVARIABLES, 1);
+                for (k=0; k<NRVARIABLES; k++) mxSetCell(resultMX,k,mxCreateString(variableFormulas[k]));
+                return resultMX;
+            } else mexErrMsgTxt("Incorrect input argument.");
+        } else {
+            if (!mxIsDouble(prhs[0])) mexErrMsgTxt("Check the 'timevector' (first) input argument.");
+            /* if no error then the first argument is the timevector for simulation */
+            timesimvectorMX = (mxArray *) prhs[0];
+        }
+    } else {
+        /***************************************************/
+        /* handle other numbers of input arguments         */
+        /***************************************************/
+        
+        if (!mxIsDouble(prhs[0])) mexErrMsgTxt("Check 'timevector' (first) input argument.");
+        timesimvectorMX = (mxArray *) prhs[0];
+        if (nrhs >= 2) {
+            if (!mxIsDouble(prhs[1]) && !mxIsEmpty(prhs[1])) mexErrMsgTxt("Check 'initialconditions' (second) input argument.");
+            initialconditionsMX = (mxArray *) prhs[1];
+        }
+        if (nrhs >= 3) {
+            if (!mxIsDouble(prhs[2]) && !mxIsEmpty(prhs[2])) mexErrMsgTxt("Check 'parametervector' (third) input argument.");
+            parametervectorMX = (mxArray *) prhs[2];
+        } 
+        if (nrhs >= 4) {
+            if (!mxIsStruct(prhs[3]) && !mxIsEmpty(prhs[3])) mexErrMsgTxt("Check 'options' (fourth) input argument.");
+            optionsMX = (mxArray *) prhs[3];
+        }
+        if (nrhs >= 5) {
+            mexErrMsgTxt("Incorrect number of input arguments.");
+        }
+    }
+    /***************************************************/
+    /* process input arguments                         */
+    /***************************************************/
+
+    /* process timevector only if not empty */
+    if (!mxIsEmpty(timesimvectorMX)) {
+        timesimvector = mxGetPr(timesimvectorMX);
+        /* Get some flags to check usability of time vector */
+        numbertimesteps = mxGetM(timesimvectorMX)*mxGetN(timesimvectorMX);
+        if (numbertimesteps == 1) timevectorIsScalar = 1; /* needed if xdotcalc */
+        if (mxGetN(timesimvectorMX) > 1 && mxGetM(timesimvectorMX) > 1) timevectorNotVector = 1; /* vector needed for simulation */
+    } else {
+        /* set error flag for simulation case */
+        timevectorEmpty = 1;
+    }
+    /* check parametervector */
+    /* needs to be done before initial conditions in order to be able to handle non-numeric ICs */
+    /* we need to get new memory for the parametervector in order to create an independent copy of
+     * the default parameter vector. Otherwise events on parameters do change the default parameter vector 
+     * which definitely is not desired!!! */
+    parametervector = (double *) mxCalloc(NRPARAMETERS, sizeof(double));
+    /* Copy default parameters into the parametervector */
+    for (k=0; k<NRPARAMETERS; k++) parametervector[k] = defaultParam[k];
+    
+    if (parametervectorMX != NULL) {
+        if (!mxIsEmpty(parametervectorMX)) {
+            if (mxGetN(parametervectorMX)*mxGetM(parametervectorMX) != NRPARAMETERS || (mxGetN(parametervectorMX) > 1 && mxGetM(parametervectorMX) > 1)) mexErrMsgTxt("'parametervector' needs to be a vector of 'number parameters' length.");
+            parametervector = mxGetPr(parametervectorMX);
+        }
+    }
+    /* assign parametervector to modeldata struct */
+    modeldata.parametervector = parametervector;
+    /* process initial conditions */
+    initialconditions = (double *) mxCalloc(NRSTATES,sizeof(double));
+    /* For the initial conditions we need to take care of eventual non-numeric initial conditions */
+    /* These can depend on parameters (both nominal and user-provided ones */
+    /* If the user provides initial conditions, these overwrite all other ones and the non-numeric equations */
+    /* will not be used anymore. */
+    if (hasOnlyNumericICs == 1) {
+        for (k=0;k<NRSTATES;k++) initialconditions[k] = defaultICs_num[k];
+    } else {
+        calc_ic_model(initialconditions, &modeldata);
+    }
+    if (initialconditionsMX != NULL) {
+        if (!mxIsEmpty(initialconditionsMX)) {
+            if (mxGetN(initialconditionsMX)*mxGetM(initialconditionsMX) != NRSTATES || (mxGetN(initialconditionsMX) > 1 && mxGetM(initialconditionsMX) > 1)) mexErrMsgTxt("'initialconditions' needs to be a vector of 'number states' length.");
+            initialconditions = mxGetPr(mxDuplicateArray(initialconditionsMX));
+        }
+    }    
+    /* check options */
+    showIntegratorStats         = 0;
+    minstep                     = 0.0;              /* default value in CVODE */
+    maxstep                     = 0.0;              /* default value in CVODE => infinity */
+    maxnumsteps                 = MAXNUMSTEPS;      /* we set a value different from CVODE default values as default */
+    maxerrtestfails             = MAXERRTESTFAILS;  /* we set a value different from CVODE default values as default */
+    maxorder                    = 5;                /* default value for default method (stiff) */
+    maxconvfails                = 10;               /* default value in CVODE */
+    initstep                    = 0.0;              /* default value in CVODE */
+    maxnonlineariter            = 3;                /* default value in CVODE */
+    method                      = 0;                /* 0 = stiff, 1 = nonstiff, default: 0 */
+    reltol                      = RELTOL;           /* we set a value different from CVODE default values as default */
+    abstol                      = ABSTOL;           /* we set a value different from CVODE default values as default */
+    xdotcalc                    = 0;
+    if (optionsMX != NULL) {
+        if (!mxIsEmpty(optionsMX)) {
+            showIntegratorStatsMX = mxGetField(optionsMX, 0, "showIntegratorStats");
+            if (showIntegratorStatsMX != NULL) 
+                if (mxIsDouble(showIntegratorStatsMX)) 
+                    showIntegratorStats = (int)mxGetScalar(showIntegratorStatsMX); 
+                else 
+                    mexErrMsgTxt("'options.showIntegratorStats' wrongly defined.");
+
+            minstepMX = mxGetField(optionsMX, 0, "minstep");
+            if (minstepMX != NULL) 
+                if (mxIsDouble(minstepMX)) 
+                    minstep = mxGetScalar(minstepMX); 
+                else 
+                    mexErrMsgTxt("'options.minstep' wrongly defined.");
+            maxstepMX = mxGetField(optionsMX, 0, "maxstep");
+            if (maxstepMX != NULL) 
+                if (mxIsDouble(maxstepMX)) 
+                    maxstep = mxGetScalar(maxstepMX); 
+                else 
+                    mexErrMsgTxt("'options.maxstep' wrongly defined.");
+            maxnumstepsMX = mxGetField(optionsMX, 0, "maxnumsteps");
+            if (maxnumstepsMX != NULL) 
+                if (mxIsDouble(maxnumstepsMX)) 
+                    maxnumsteps = (long int)mxGetScalar(maxnumstepsMX); 
+                else 
+                    mexErrMsgTxt("'options.maxnumsteps' wrongly defined.");
+            methodMX = mxGetField(optionsMX, 0, "method");
+            if (methodMX != NULL) {
+                if (mxIsChar(methodMX)) {
+                    if (mxGetM(methodMX) * mxGetN(methodMX) == 8) {
+                        method      = 1;    /* "nonstiff" method ... just check the length of the string */
+                        maxorder    = 12;   /* nonstiff Adams */
+                    } else if (mxGetM(methodMX) * mxGetN(methodMX) == 5) {
+                        method      = 0;    /* "stiff method */
+                        maxorder    = 5;    /* stiff BDF */
+                    } else {
+                        mexErrMsgTxt("'options.method' wrongly defined.");
+                    }
+                } else {
+                    mexErrMsgTxt("'options.method' wrongly defined.");
+                }
+            }
+
+			reltolMX = mxGetField(optionsMX, 0, "reltol");
+            if (reltolMX != NULL) 
+                if (mxIsDouble(reltolMX)) 
+                    reltol = mxGetScalar(reltolMX); 
+                else 
+                    mexErrMsgTxt("'options.reltol' wrongly defined.");
+            abstolMX = mxGetField(optionsMX, 0, "abstol");
+            if (abstolMX != NULL) 
+                if (mxIsDouble(abstolMX)) 
+                    abstol = mxGetScalar(abstolMX); 
+                else 
+                    mexErrMsgTxt("'options.abstol' wrongly defined.");
+            xdotcalcMX = mxGetField(optionsMX, 0, "xdotcalc");
+            if (xdotcalcMX != NULL) 
+                if (mxIsDouble(xdotcalcMX)) 
+                    xdotcalc = mxGetScalar(xdotcalcMX); 
+                else 
+                    mexErrMsgTxt("'options.xdotcalc' wrongly defined.");
+
+            
+            /* Additional Options */
+            maxerrtestfailsMX = mxGetField(optionsMX, 0, "maxerrtestfails");
+            if (maxerrtestfailsMX != NULL) 
+                if (mxIsDouble(maxerrtestfailsMX)) 
+                    maxerrtestfails = (int)mxGetScalar(maxerrtestfailsMX); 
+                else 
+                    mexErrMsgTxt("'options.maxerrtestfails' wrongly defined.");            
+
+            maxorderMX = mxGetField(optionsMX, 0, "maxorder");
+            if (maxorderMX != NULL) 
+                if (mxIsDouble(maxorderMX)) 
+                    maxorder = (int)mxGetScalar(maxorderMX); 
+                else 
+                    mexErrMsgTxt("'options.maxorder' wrongly defined.");            
+
+            maxconvfailsMX = mxGetField(optionsMX, 0, "maxconvfails");
+            if (maxconvfailsMX != NULL) 
+                if (mxIsDouble(maxconvfailsMX)) 
+                    maxconvfails = (int)mxGetScalar(maxconvfailsMX); 
+                else 
+                    mexErrMsgTxt("'options.maxconvfails' wrongly defined.");    
+            
+            initstepMX = mxGetField(optionsMX, 0, "initstep");
+            if (initstepMX != NULL) 
+                if (mxIsDouble(initstepMX)) 
+                    initstep = (double)mxGetScalar(initstepMX); 
+                else 
+                    mexErrMsgTxt("'options.initstep' wrongly defined.");                
+
+            maxnonlineariterMX = mxGetField(optionsMX, 0, "maxnonlineariter");
+            if (maxnonlineariterMX != NULL) 
+                if (mxIsDouble(maxnonlineariterMX)) 
+                    maxnonlineariter = (double)mxGetScalar(maxnonlineariterMX); 
+                else 
+                    mexErrMsgTxt("'options.maxnonlineariter' wrongly defined.");                
+        }
+    }
+    return NULL;
+}
+
+    /*
+     * ==============================================
+     * GET RHS OF ODEs (fir time = 0)
+     * ==============================================
+     */
+static mxArray* doXdotCalc()
+{
+    /* Check if timevector is a scalar */
+    if (timevectorIsScalar != 1) mexErrMsgTxt("'timevector' input argument needs to be a scalar if you want to calculate the RHS.");
+    resultMX = mxCreateDoubleMatrix(NRSTATES, 1, mxREAL);
+    result = mxGetPr(resultMX);
+    model(timesimvector[0], initialconditions, result, &modeldata, DOFLAG_DDT, NULL, NULL, NULL, NULL);
+    return resultMX;
+}
+
+    /*
+     * ==============================================
+     * ALLOCATE MEMORY 
+     * ==============================================
+     */
+static void allocSimMemory()
+{
+    statevaluesMX = mxCreateDoubleMatrix(numbertimesteps, NRSTATES, mxREAL);
+    statevalues = mxGetPr(statevaluesMX);
+    if (NRVARIABLES > 0) {
+        variablevec = (double *) mxCalloc(NRVARIABLES, sizeof(double));
+        variablevaluesMX = mxCreateDoubleMatrix(numbertimesteps, NRVARIABLES, mxREAL);
+        variablevalues = mxGetPr(variablevaluesMX);
+    }
+    if (NRREACTIONS > 0) {
+        reactionvec = (double *) mxCalloc(NRREACTIONS, sizeof(double));
+        reactionvaluesMX = mxCreateDoubleMatrix(numbertimesteps, NRREACTIONS, mxREAL);
+        reactionvalues = mxGetPr(reactionvaluesMX);
+    }
+    if (NREVENTS > 0) {
+        eventvec = (int *) mxCalloc(NREVENTS, sizeof(int));
+        eventdataold = (double *) mxCalloc(NREVENTS, sizeof(double));
+    }
+}
+    
+    /*
+     * ==============================================
+     * INITIALIZE INTEGRATOR
+     * ==============================================
+     */
+static void initCVODE()
+{
+    u = N_VMake_Serial(NRSTATES,initialconditions);
+    /* Set integration method (stiff or non-stiff) */
+    if (method == 0) {
+        cvode_mem = CVodeCreate(CV_BDF, CV_NEWTON);    /* default (stiff) */
+    }
+    else cvode_mem = CVodeCreate(CV_ADAMS, CV_FUNCTIONAL);          /* nonstiff */
+    CVodeMalloc(cvode_mem, f, timesimvector[0], u, CV_SS, reltol, &abstol);
+    if (NREVENTS > 0) {
+        CVodeRootInit(cvode_mem, NREVENTS, g, &modeldata);
+    }
+    CVodeSetFdata(cvode_mem, &modeldata);
+    if (minstep > 0) CVodeSetMinStep(cvode_mem, minstep);
+    if (maxstep > 0) CVodeSetMaxStep(cvode_mem, maxstep);
+    if (maxnumsteps > 0) CVodeSetMaxNumSteps(cvode_mem, maxnumsteps);
+    CVodeSetMaxErrTestFails(cvode_mem, maxerrtestfails);
+    CVodeSetMaxOrd(cvode_mem, maxorder);
+    CVodeSetMaxConvFails(cvode_mem, maxconvfails);
+    CVodeSetInitStep(cvode_mem, initstep);
+    CVodeSetMaxNonlinIters(cvode_mem, maxnonlineariter);
+    CVDense(cvode_mem,NRSTATES);
+}
+
+    /*
+     * ==============================================
+     * DO THE INTEGRATION
+     * ==============================================
+     */
+static void integrate()
+{
+    addVec2Mat(statevalues,initialconditions,0,numbertimesteps,NRSTATES);
+    model(timesimvector[0], initialconditions, NULL, &modeldata, DOFLAG_VARREAC, variablevec, reactionvec,NULL,NULL);
+    if (NRVARIABLES > 0) addVec2Mat(variablevalues,variablevec,0,numbertimesteps,NRVARIABLES);
+    if (NRREACTIONS > 0) addVec2Mat(reactionvalues,reactionvec,0,numbertimesteps,NRREACTIONS);
+    if (NREVENTS > 0) /* determine eventdataold to be able to detect directions of events */
+        model(timesimvector[0], initialconditions, NULL, &modeldata, DOFLAG_EVENTS, NULL, NULL, eventdataold, NULL);
+    k = 1;
+    tendstep = timesimvector[k]; 
+    nreventshappend = 0; 
+    while(1) {
+        flag = CVode(cvode_mem, tendstep, u, &treturn, CV_NORMAL);
+        if (flag < 0) {
+            if (flag == CV_TOO_MUCH_WORK) errorMsg("CVODE Error: CV_TOO_MUCH_WORK");
+            else if (flag == CV_TOO_MUCH_ACC) errorMsg("CVODE Error: CV_TOO_MUCH_ACC");
+            else if (flag == CV_ERR_FAILURE || flag == CV_CONV_FAILURE) errorMsg("CVODE Error: CV_ERR_FAILURE");
+            else {
+                sprintf(stringbuffer, "CVODE Error Flag: %d",flag);
+                errorMsg(stringbuffer);
+            }
+        }
+        statevec = NV_DATA_S(u);
+        if (flag == CV_ROOT_RETURN) {
+            /* Event happened */
+            CVodeGetRootInfo(cvode_mem, eventvec);
+            eventcorrecttest = 0;
+            model(treturn, statevec, &eventcorrecttest, &modeldata, DOFLAG_EVENTASSIGN, NULL, NULL, eventdataold, eventvec);
+            flag = CVodeReInit(cvode_mem, f, treturn, u, CV_SS, reltol, &abstol);
+            if (eventcorrecttest > 0) {
+                nreventshappend += 1;  
+                if (nreventshappend == 1) {
+                    eventtimes = (double *) mxCalloc(1, sizeof(double));
+                    eventflagsdata = (double *) mxCalloc(NREVENTS, sizeof(double));
+                } else {
+                    eventtimes = (double *) mxRealloc((void *) eventtimes, nreventshappend*sizeof(double));
+                    eventflagsdata = (double *) mxRealloc((void *) eventflagsdata, NREVENTS*nreventshappend*sizeof(double));
+                }
+                eventtimes[nreventshappend-1] = treturn;
+                for (k2=0;k2<NREVENTS;k2++) eventflagsdata[NREVENTS*(nreventshappend-1)+k2] = (double)eventvec[k2];
+            }
+        }
+        if (tendstep == treturn) { 
+            addVec2Mat(statevalues,statevec,k,numbertimesteps,NRSTATES);
+            model(tendstep, statevec, NULL, &modeldata, DOFLAG_VARREAC, variablevec, reactionvec, NULL, NULL);
+            if (NRVARIABLES > 0) addVec2Mat(variablevalues,variablevec,k,numbertimesteps,NRVARIABLES);
+            if (NRREACTIONS > 0) addVec2Mat(reactionvalues,reactionvec,k,numbertimesteps,NRREACTIONS);
+            k = k+1;
+            if (k < numbertimesteps) 
+                tendstep = timesimvector[k];
+            else 
+                break; 
+        }
+        if (NREVENTS > 0) /* determine eventdataold to be able to detect directions of events */
+            model(treturn, statevec, NULL, &modeldata, DOFLAG_EVENTS, NULL, NULL, eventdataold, NULL);
+    }
+}
+
+    /*
+     * ==============================================
+     * CONSTRUCT OUTPUT VARIABLE
+     * ==============================================
+     */
+static mxArray* constructOutput()
+{
+    resultMX = mxCreateStructMatrix(1,1,0,NULL);
+    /* Create fields in result structure */
+    mxAddField(resultMX,"time");
+    mxAddField(resultMX,"states");
+    mxAddField(resultMX,"statevalues");
+    mxAddField(resultMX,"variables");
+    mxAddField(resultMX,"variablevalues");
+    mxAddField(resultMX,"reactions");
+    mxAddField(resultMX,"reactionvalues");
+    if (NREVENTS > 0) {
+        mxAddField(resultMX,"events");
+        mxAddField(resultMX,"eventtimes");
+        mxAddField(resultMX,"eventflags");
+    }
+    mxSetField(resultMX, 0, "time", mxDuplicateArray(timesimvectorMX));
+    mxSetField(resultMX, 0, "statevalues", statevaluesMX);
+    if (NRVARIABLES > 0) mxSetField(resultMX, 0, "variablevalues", variablevaluesMX);
+    if (NRREACTIONS > 0) mxSetField(resultMX, 0, "reactionvalues", reactionvaluesMX);
+    statesMX = mxCreateCellMatrix(1, NRSTATES);
+    for (k=0;k<NRSTATES;k++) mxSetCell(statesMX,k,mxCreateString(stateNames[k]));
+    mxSetField(resultMX, 0, "states", statesMX);
+    if (NRVARIABLES > 0) {
+        variablesMX = mxCreateCellMatrix(1, NRVARIABLES);
+        for (k=0;k<NRVARIABLES;k++) mxSetCell(variablesMX,k,mxCreateString(variableNames[k]));
+        mxSetField(resultMX, 0, "variables", variablesMX);
+    }
+    if (NRREACTIONS > 0) {
+        reactionsMX = mxCreateCellMatrix(1, NRREACTIONS);
+        for (k=0;k<NRREACTIONS;k++) mxSetCell(reactionsMX,k,mxCreateString(reactionNames[k]));
+        mxSetField(resultMX, 0, "reactions", reactionsMX);
+    }
+    if (NREVENTS > 0) {
+        eventsMX = mxCreateCellMatrix(1, NREVENTS);
+        for (k=0;k<NREVENTS;k++) mxSetCell(eventsMX,k,mxCreateString(eventNames[k]));
+        mxSetField(resultMX, 0, "events", eventsMX);
+        if (nreventshappend > 0) {
+            eventtimesMX = mxCreateDoubleMatrix(1,nreventshappend,mxREAL);
+            mxSetData(eventtimesMX, eventtimes);
+            mxSetField(resultMX, 0, "eventtimes", eventtimesMX);
+            eventflagsMX = mxCreateDoubleMatrix(NREVENTS,nreventshappend,mxREAL);
+            mxSetData(eventflagsMX, eventflagsdata);
+            mxSetField(resultMX, 0, "eventflags", eventflagsMX);
+        }
+    }
+    return resultMX;
+}
+
+/*
+ *========================================================================
+ * Initialization of variables
+ *========================================================================
+ */
+static void doInitilizationVariables()
+ {
+    timesimvectorMX = NULL;
+    timesimvector = NULL;
+    parametervectorMX = NULL;
+    parametervector = NULL;
+    parametervectorCVODES = NULL;
+    initialconditionsMX = NULL;
+    initialconditions = NULL;
+    optionsMX = NULL;
+    showIntegratorStatsMX = NULL;
+    showIntegratorStats = 0;
+    minstepMX = NULL;
+    maxstepMX = NULL;
+    maxnumstepsMX = NULL;
+    reltolMX = NULL;
+    abstolMX = NULL;
+    maxerrtestfailsMX = NULL;
+    maxorderMX = NULL;
+    maxconvfailsMX = NULL;
+    initstepMX = NULL;
+    maxnonlineariterMX = NULL;
+    xdotcalcMX = NULL;
+    resultMX = NULL;
+    result = NULL;
+    statesMX = NULL;
+    statevaluesMX = NULL;
+    statevalues = NULL;
+    variablesMX = NULL;
+    variablevaluesMX = NULL;
+    variablevalues = NULL;
+    reactionsMX = NULL;
+    reactionvaluesMX = NULL;
+    reactionvalues = NULL;
+    eventsMX = NULL;
+    eventtimesMX = NULL;
+    eventtimes = NULL;
+    eventflagsMX = NULL;
+    eventflags = NULL;
+    u = NULL;
+    statevec = NULL;
+    variablevec = NULL;
+    reactionvec = NULL;
+    eventvec = NULL;
+    eventdataold = NULL;
+    eventflagsdata = NULL;
+    timevectorEmpty = 0;
+    timevectorNotVector = 0;
+    timevectorIsScalar = 0;
+    methodMX = NULL;
+}
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/CVODEmex25.h b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/CVODEmex25.h
new file mode 100644
index 0000000000000000000000000000000000000000..c1c93de83ef9019427a1db8135680c409cdd6e26
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/CVODEmex25.h	
@@ -0,0 +1,32 @@
+/*
+ * CVODEmex25.h: MEX/CVODES Interface for Sundials CVODES version 2.5
+ *
+ * Information:
+ * ============
+ * IQM Tools Pro
+ */
+
+/* CVODE related flags */
+#define DOFLAG_DDT 0
+#define DOFLAG_VARREAC 1
+#define DOFLAG_EVENTS 2
+#define DOFLAG_EVENTASSIGN 3
+#define DOFLAG_CALCICS 4
+
+/* ParamData (contains pointer to parameter values passed to integrator) */
+typedef struct {
+    double *parametervector;
+} ParamData;
+
+/* Variables defined outside the library */
+extern double defaultICs_num[], defaultParam[];
+extern char  *defaultICs_nonnum[];
+extern char  *stateNames[], *parameterNames[], *variableNames[], *variableFormulas[], *reactionNames[], *eventNames[]; 
+extern const int NRSTATES, NRPARAMETERS, NRVARIABLES, NRREACTIONS, NREVENTS;
+extern const int hasOnlyNumericICs;
+extern int   *interpcseIQM_check; /* needed for spline function in mexsplineaddon.h */
+extern int   *interpcseSlopeIQM_check; /* needed for spline function in mexsplineaddon.h */
+
+/* Functions containing the model equations */
+extern void model(double time, double *stateVector, double *DDTvector, ParamData *paramdataPtr, int DOflag, double *variableVector, double *reactionVector, double *gout, int *eventVector);
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/SUNDIALS_VERSION_2.5.txt b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/SUNDIALS_VERSION_2.5.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ad1a2c0dbcf0225ff2997468e417e93d1c65d70f
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/SUNDIALS_VERSION_2.5.txt	
@@ -0,0 +1 @@
+ Just a reminder about which version of SUNDIALS CVODES is used :)
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/ar32.exe b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/ar32.exe
new file mode 100644
index 0000000000000000000000000000000000000000..86bccf5dc6f980d6338b9b37d03d498e68720f27
Binary files /dev/null and b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/ar32.exe differ
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/ar64.exe b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/ar64.exe
new file mode 100644
index 0000000000000000000000000000000000000000..befe5958086797d9c9fc9fdcc0eae6faa4697060
Binary files /dev/null and b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/ar64.exe differ
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/buildCVODElib.m b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/buildCVODElib.m
new file mode 100644
index 0000000000000000000000000000000000000000..b171dd9beafdb40538b5a2346486a2519c22bdc8
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/buildCVODElib.m	
@@ -0,0 +1,66 @@
+% This script generates a static library file for the CVODES integrator 
+% package, including the MEX interface for MATLAB. Windows Version.
+% Compiler used: LCC (MATLAB inbuild)
+%
+% Usually the user does not need to run this script, since for windows the 
+% precompiled library is distributed along with the IQM Tools Pro package.
+% However, if the user wants to change the source code of the interface the
+% new library can be build by running this script. The library file and 
+% the header files are then automatically copied/installed at the correct 
+% locations.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+
+% Copy files
+disp('Copying files ...');
+!copy CVODEmex25.c source_SUNDIALS_CVODES_25
+!copy CVODEmex25.h include_SUNDIALS_CVODES_25
+!copy mexmathaddon.h include_SUNDIALS_CVODES_25
+!copy mexsplineaddon.h include_SUNDIALS_CVODES_25
+
+% Change into source folder
+cd source_SUNDIALS_CVODES_25
+
+% Compile all files to object code using MinGW
+disp('Compiling files ...');
+mex -O -c -I../include_SUNDIALS_CVODES_25 CVODEmex25.c cvodea.c cvodea_io.c cvodes.c cvodes_band.c cvodes_bandpre.c cvodes_bbdpre.c cvodes_dense.c cvodes_diag.c cvodes_io.c cvodes_spbcgs.c cvodes_spbcgs.c cvodes_spils.c cvodes_sptfqmr.c nvector_serial.c sundials_band.c sundials_dense.c sundials_iterative.c sundials_math.c sundials_nvector.c sundials_smalldense.c sundials_spbcgs.c sundials_spgmr.c sundials_sptfqmr.c
+
+% Delete the copied files again
+disp('Deleting copied files ');
+delete CVODEmex25.c
+delete ../include_SUNDIALS_CVODES_25/CVODEmex25.h
+delete ../include_SUNDIALS_CVODES_25/mexmathaddon.h
+delete ../include_SUNDIALS_CVODES_25/mexsplineaddon.h
+
+% Bind the object code files into a library.
+disp('Generating library ');
+% Use different ar's for 32 and 64 bit systems
+if ~isempty(strfind(mexext,'32')),
+    % 32 bit system
+    system('"../ar32" rc CVODEmex25.lib *.obj');
+elseif ~isempty(strfind(mexext,'64')),
+    % 64 bit system
+    system('"../ar64" rc CVODEmex25.lib CVODEmex25.obj cvodes_band.obj cvodes_diag.obj cvodes_sptfqmr.obj sundials_iterative.obj sundials_spbcgs.obj cvodea.obj cvodes_bandpre.obj cvodes_io.obj nvector_serial.obj sundials_math.obj sundials_spgmr.obj cvodea_io.obj cvodes_bbdpre.obj cvodes_spbcgs.obj sundials_band.obj sundials_nvector.obj sundials_sptfqmr.obj cvodes.obj cvodes_dense.obj cvodes_spils.obj sundials_dense.obj sundials_smalldense.obj');
+else
+    error('You got a strange system from the future ... or from the past?');
+end
+
+% Delete all object code files
+disp('Deleting object files ');
+delete *.obj
+
+% Move generated lib file to parent folder
+disp('Finishing ');
+!move *.lib ../../lib
+cd ..
+
+% copy needed header files into the include folder of the package
+!copy CVODEmex25.h "../include"
+!copy mexmathaddon.h "../include"
+!copy kineticformulas.h "../include"
+!copy mexsplineaddon.h "../include"
+
+% display success message
+disp('The library has been build and all necessary files have been installed.');
+disp(' ');
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/buildCVODElibunix.m b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/buildCVODElibunix.m
new file mode 100644
index 0000000000000000000000000000000000000000..9d897a6200d18d250f4fa508c3af594142e5a19f
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/buildCVODElibunix.m	
@@ -0,0 +1,70 @@
+% This script generates a static library file for the CVODES integrator 
+% package, including the MEX interface for MATLAB. Unix/Linux Version.
+%
+% Before using the IQM Pro tools to create MEX simulation functions the 
+% user needs to build a static library that contains the SUNDIALS CVODES
+% package and the MEX interface functions. This library can be build by
+% running this script. The library file and the header files are then
+% automatically copied/installed at the correct locations.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+
+% Copy files
+disp('Copying files ...');
+!cp CVODEmex25.c source_SUNDIALS_CVODES_25
+!cp CVODEmex25.h include_SUNDIALS_CVODES_25
+!cp mexmathaddon.h include_SUNDIALS_CVODES_25
+!cp mexsplineaddon.h include_SUNDIALS_CVODES_25
+
+% Change into source folder
+cd source_SUNDIALS_CVODES_25
+
+% Compile all files to object code
+disp('Compiling files ...');
+mex -c -O -I../include_SUNDIALS_CVODES_25 ...
+        CVODEmex25.c ...
+        cvodea.c                cvodea_io.c ...
+        cvodes.c                cvodes_band.c ...
+        cvodes_bandpre.c        cvodes_bbdpre.c ...
+        cvodes_dense.c          cvodes_diag.c ...
+        cvodes_io.c             cvodes_spbcgs.c ...
+        cvodes_spbcgs.c         cvodes_spils.c ...
+        cvodes_sptfqmr.c        nvector_serial.c ...
+        sundials_band.c         ...
+        sundials_dense.c        sundials_iterative.c ...
+        sundials_math.c         sundials_nvector.c ...
+        sundials_smalldense.c   sundials_spbcgs.c ...
+        sundials_spgmr.c        sundials_sptfqmr.c
+
+% Delete the copied files again
+disp('Deleting copied files ...');
+delete CVODEmex25.c
+delete ../include_SUNDIALS_CVODES_25/CVODEmex25.h
+delete ../include_SUNDIALS_CVODES_25/mexmathaddon.h
+delete ../include_SUNDIALS_CVODES_25/mexsplineaddon.h
+
+% Bind the object code files into a library.
+% To be able to do that the lib.exe needs to be 
+% in the system path.
+disp('Generating library ...');
+!ar rc CVODEmex25.a *.o
+
+% Delete all object code files
+disp('Deleting object files ...');
+delete *.o
+
+% Move generated lib file to parent folder
+disp('Finishing ...');
+!mv *.a ../../lib
+cd ..
+
+% copy needed header files into the include folder of the package
+!cp CVODEmex25.h ../include
+!cp mexmathaddon.h ../include
+!cp kineticformulas.h ../include
+!cp mexsplineaddon.h "../include"
+
+% display success message
+disp('The library has been build and all necessary files have been installed.');
+disp(' ');
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/cvodes/cvodes.h b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/cvodes/cvodes.h
new file mode 100644
index 0000000000000000000000000000000000000000..cab8a95d95514f64d6b896879c51e7e5f90e3258
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/cvodes/cvodes.h	
@@ -0,0 +1,1604 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * ----------------------------------------------------------------- 
+ * Programmer(s): Radu Serban @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2005, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This is the interface file for the main CVODES integrator.
+ * -----------------------------------------------------------------
+ *
+ * CVODES is used to solve numerically the ordinary initial value    
+ * problem:                                                          
+ *                                                                   
+ *                 y' = f(t,y),                                      
+ *                 y(t0) = y0,                                       
+ *                                                                   
+ * where t0, y0 in R^N, and f: R x R^N -> R^N are given.             
+ *                                                                   
+ * Optionally, CVODES can perform forward or adjoint sensitivity 
+ * analysis to find sensitivities of the solution y with respect 
+ * to parameters in the right hand side f and/or in the initial         
+ * conditions y0.                                                    
+ *
+ * -----------------------------------------------------------------
+ */
+
+#ifndef _CVODES_H
+#define _CVODES_H
+
+#ifdef __cplusplus  /* wrapper to enable C++ usage */
+extern "C" {
+#endif
+
+#include <stdio.h>
+
+#include <sundials/sundials_nvector.h>
+
+  /*
+   * =================================================================
+   *              C V O D E S     C O N S T A N T S
+   * =================================================================
+   */
+
+  /*
+   * -----------------------------------------------------------------
+   * Enumerations for inputs to CVodeCreate, CVodeMalloc,
+   * CVodeReInit, CVodeSensMalloc, CVodeSensReInit, CVodeQuadMalloc,
+   * CVodeQuadReInit, CVodeSet*, CVode, and CVadjMalloc.
+   * -----------------------------------------------------------------
+   * Symbolic constants for the lmm, iter, and itol input parameters 
+   * to CVodeMalloc and CVodeReInit, the input parameter itask to CVode, 
+   * and the input parameter interp to CVadjMalloc, are given below.
+   *
+   * lmm:   The user of the CVODES package specifies whether to use
+   *        the CV_ADAMS or CV_BDF (backward differentiation formula)
+   *        linear multistep method. The BDF method is recommended
+   *        for stiff problems, and the CV_ADAMS method is recommended
+   *        for nonstiff problems.
+   *
+   * iter:  At each internal time step, a nonlinear equation must
+   *        be solved. The user can specify either CV_FUNCTIONAL
+   *        iteration, which does not require linear algebra, or a
+   *        CV_NEWTON iteration, which requires the solution of linear
+   *        systems. In the CV_NEWTON case, the user also specifies a
+   *        CVODE linear solver. CV_NEWTON is recommended in case of
+   *        stiff problems.
+   *
+   * itol:  This parameter specifies the relative and absolute
+   *        tolerance types to be used. The CV_SS tolerance type means
+   *        a scalar relative and absolute tolerance. The CV_SV
+   *        tolerance type means a scalar relative tolerance and a
+   *        vector absolute tolerance (a potentially different
+   *        absolute tolerance for each vector component). The CV_WF
+   *        tolerance type means that the user provides a function
+   *        (of type CVEwtFn) to set the error weight vector.
+   *
+   * ism:   This parameter specifies the sensitivity corrector type
+   *        to be used. In the CV_SIMULTANEOUS case, the nonlinear
+   *        systems for states and all sensitivities are solved
+   *        simultaneously. In the CV_STAGGERED case, the nonlinear
+   *        system for states is solved first and then, the
+   *        nonlinear systems for all sensitivities are solved
+   *        at the same time. Finally, in the CV_STAGGERED1 approach
+   *        all nonlinear systems are solved in a sequence.
+   *
+   * itask: The itask input parameter to CVode indicates the job
+   *        of the solver for the next user step. The CV_NORMAL
+   *        itask is to have the solver take internal steps until
+   *        it has reached or just passed the user specified tout
+   *        parameter. The solver then interpolates in order to
+   *        return an approximate value of y(tout). The CV_ONE_STEP
+   *        option tells the solver to just take one internal step
+   *        and return the solution at the point reached by that
+   *        step. The CV_NORMAL_TSTOP and CV_ONE_STEP_TSTOP modes are
+   *        similar to CV_NORMAL and CV_ONE_STEP, respectively, except
+   *        that the integration never proceeds past the value
+   *        tstop (specified through the routine CVodeSetStopTime).
+   *
+   * interp: Specifies the interpolation type used to evaluate the
+   *        forward solution during the backward integration phase.
+   *        CV_HERMITE specifies cubic Hermite interpolation.
+   *        CV_POYNOMIAL specifies the polynomial interpolation
+   * -----------------------------------------------------------------
+   */
+
+  /* lmm */
+#define CV_ADAMS          1
+#define CV_BDF            2
+
+  /* iter */
+#define CV_FUNCTIONAL     1
+#define CV_NEWTON         2
+
+  /* itol */
+#define CV_SS             1
+#define CV_SV             2
+#define CV_WF             3
+#define CV_EE             4
+
+  /* itask */
+#define CV_NORMAL         1
+#define CV_ONE_STEP       2
+#define CV_NORMAL_TSTOP   3
+#define CV_ONE_STEP_TSTOP 4
+
+  /* ism */
+#define CV_SIMULTANEOUS   1
+#define CV_STAGGERED      2
+#define CV_STAGGERED1     3
+
+  /* DQtype */
+#define CV_CENTERED       1
+#define CV_FORWARD        2
+
+  /* interp */
+#define CV_HERMITE        1
+#define CV_POLYNOMIAL     2
+
+  /* 
+   * ----------------------------------------
+   * CVODES return flags
+   * ----------------------------------------
+   */
+
+#define CV_SUCCESS               0
+#define CV_TSTOP_RETURN          1
+#define CV_ROOT_RETURN           2
+
+#define CV_WARNING              99
+
+#define CV_TOO_MUCH_WORK        -1
+#define CV_TOO_MUCH_ACC         -2
+#define CV_ERR_FAILURE          -3
+#define CV_CONV_FAILURE         -4
+
+#define CV_LINIT_FAIL           -5
+#define CV_LSETUP_FAIL          -6
+#define CV_LSOLVE_FAIL          -7
+#define CV_RHSFUNC_FAIL         -8
+#define CV_FIRST_RHSFUNC_ERR    -9
+#define CV_REPTD_RHSFUNC_ERR    -10
+#define CV_UNREC_RHSFUNC_ERR    -11
+#define CV_RTFUNC_FAIL          -12
+
+#define CV_MEM_FAIL             -20
+#define CV_MEM_NULL             -21
+#define CV_ILL_INPUT            -22
+#define CV_NO_MALLOC            -23
+#define CV_BAD_K                -24
+#define CV_BAD_T                -25
+#define CV_BAD_DKY              -26
+#define CV_TOO_CLOSE            -27
+
+#define CV_NO_QUAD              -30
+#define CV_QRHSFUNC_FAIL        -31
+#define CV_FIRST_QRHSFUNC_ERR   -32
+#define CV_REPTD_QRHSFUNC_ERR   -33
+#define CV_UNREC_QRHSFUNC_ERR   -34
+
+#define CV_BAD_IS               -40
+#define CV_NO_SENS              -41
+#define CV_SRHSFUNC_FAIL        -42
+#define CV_FIRST_SRHSFUNC_ERR   -43
+#define CV_REPTD_SRHSFUNC_ERR   -44
+#define CV_UNREC_SRHSFUNC_ERR   -45
+
+  /* 
+   * ----------------------------------------
+   * CVODEA return flags
+   * ----------------------------------------
+   */
+
+#define CV_ADJMEM_NULL         -101
+#define CV_BAD_TB0             -103
+#define CV_BCKMEM_NULL         -104
+#define CV_REIFWD_FAIL         -105
+#define CV_FWD_FAIL            -106
+#define CV_BAD_ITASK           -107
+#define CV_BAD_TBOUT           -108
+#define CV_GETY_BADT           -109
+
+  /*
+   * =================================================================
+   *              F U N C T I O N   T Y P E S
+   * =================================================================
+   */
+
+  /*
+   * -----------------------------------------------------------------
+   * Type : CVRhsFn
+   * -----------------------------------------------------------------
+   * The f function which defines the right hand side of the ODE
+   * system y' = f(t,y) must have type CVRhsFn.
+   * f takes as input the independent variable value t, and the
+   * dependent variable vector y.  It stores the result of f(t,y)
+   * in the vector ydot.  The y and ydot arguments are of type
+   * N_Vector.
+   * (Allocation of memory for ydot is handled within CVODES)
+   * The f_data parameter is the same as the f_data
+   * parameter set by the user through the CVodeSetFdata routine.
+   * This user-supplied pointer is passed to the user's f function
+   * every time it is called.
+   *
+   * A CVRhsFn should return 0 if successful, a negative value if
+   * an unrecoverable error occured, and a positive value if a 
+   * recoverable error (e.g. invalid y values) occured. 
+   * If an unrecoverable occured, the integration is halted. 
+   * If a recoverable error occured, then (in most cases) CVODES
+   * will try to correct and retry.
+   * -----------------------------------------------------------------
+   */
+
+  typedef int (*CVRhsFn)(realtype t, N_Vector y,
+                         N_Vector ydot, void *f_data);
+
+  /*
+   * -----------------------------------------------------------------
+   * Type : CVRootFn
+   * -----------------------------------------------------------------
+   * A function g, which defines a set of functions g_i(t,y) whose
+   * roots are sought during the integration, must have type CVRootFn.
+   * The function g takes as input the independent variable value
+   * t, and the dependent variable vector y.  It stores the nrtfn
+   * values g_i(t,y) in the realtype array gout.
+   * (Allocation of memory for gout is handled within CVODE.)
+   * The g_data parameter is the same as that passed by the user
+   * to the CVodeRootInit routine.  This user-supplied pointer is
+   * passed to the user's g function every time it is called.
+   *
+   * A CVRootFn should return 0 if successful or a non-zero value
+   * if an error occured (in which case the integration will be halted).
+   * -----------------------------------------------------------------
+   */
+
+  typedef int (*CVRootFn)(realtype t, N_Vector y, realtype *gout,
+                          void *g_data);
+
+  /*
+   * -----------------------------------------------------------------
+   * Type : CVEwtFn
+   * -----------------------------------------------------------------
+   * A function e, which sets the error weight vector ewt, must have
+   * type CVEwtFn.
+   * The function e takes as input the current dependent variable y.
+   * It must set the vector of error weights used in the WRMS norm:
+   * 
+   *   ||y||_WRMS = sqrt [ 1/N * sum ( ewt_i * y_i)^2 ]
+   *
+   * Typically, the vector ewt has components:
+   * 
+   *   ewt_i = 1 / (reltol * |y_i| + abstol_i)
+   *
+   * The e_data parameter is the same as that passed by the user
+   * to the CVodeSetEdata routine.  This user-supplied pointer is
+   * passed to the user's e function every time it is called.
+   * A CVEwtFn e must return 0 if the error weight vector has been
+   * successfuly set and a non-zero value otherwise.
+   * -----------------------------------------------------------------
+   */
+
+  typedef int (*CVEwtFn)(N_Vector y, N_Vector ewt, void *e_data);
+
+
+  /*
+   * -----------------------------------------------------------------
+   * Type : CVErrHandlerFn
+   * -----------------------------------------------------------------
+   * A function eh, which handles error messages, must have type
+   * CVErrHandlerFn.
+   * The function eh takes as input the error code, the name of the
+   * module reporting the error, the error message, and a pointer to
+   * user data, the same as that passed to CVodeSetErrHandlerFn.
+   * 
+   * All error codes are negative, except CV_WARNING which indicates 
+   * a warning (the solver continues).
+   *
+   * A CVErrHandlerFn has no return value.
+   * -----------------------------------------------------------------
+   */
+  
+  typedef void (*CVErrHandlerFn)(int error_code, 
+                                 const char *module, const char *function, 
+                                 char *msg, void *eh_data); 
+
+  /*
+   * -----------------------------------------------------------------
+   * Type : CVQuadRhsFn
+   * -----------------------------------------------------------------
+   * The fQ function which defines the right hand side of the
+   * quadrature equations yQ' = fQ(t,y) must have type CVQuadRhsFn.
+   * fQ takes as input the value of the independent variable t,
+   * the vector of states y and must store the result of fQ in
+   * yQdot. (Allocation of memory for yQdot is handled by CVODES).
+   * The fQ_data parameter is the same as the fQ_data parameter
+   * set by the user through the CVodeSetQuadFdata routine and is
+   * passed to the fQ function every time it is called.
+   *
+   * A CVQuadRhsFn should return 0 if successful, a negative value if
+   * an unrecoverable error occured, and a positive value if a 
+   * recoverable error (e.g. invalid y values) occured. 
+   * If an unrecoverable occured, the integration is halted. 
+   * If a recoverable error occured, then (in most cases) CVODES
+   * will try to correct and retry.
+   * -----------------------------------------------------------------
+   */
+
+  typedef int (*CVQuadRhsFn)(realtype t, N_Vector y, N_Vector yQdot,
+                             void *fQ_data);
+
+  /*
+   * -----------------------------------------------------------------
+   * Type : CVSensRhsFn
+   * -----------------------------------------------------------------
+   * The fS function which defines the right hand side of the
+   * sensitivity ODE systems s' = f_y * s + f_p must have type
+   * CVSensRhsFn.
+   * fS takes as input the number of sensitivities Ns, the
+   * independent variable value t, the states y and the
+   * corresponding value of f(t,y) in ydot, and the dependent
+   * sensitivity vectors yS. It stores the result of fS in ySdot.
+   * (Allocation of memory for ySdot is handled within CVODES)
+   * The fS_data parameter is the same as the fS_data parameter
+   * set by the user through the CVodeSetSensFdata routine and is
+   * passed to the fS function every time it is called.
+   *
+   * A CVSensRhsFn should return 0 if successful, a negative value if
+   * an unrecoverable error occured, and a positive value if a 
+   * recoverable error (e.g. invalid y or yS values) occured. 
+   * If an unrecoverable occured, the integration is halted. 
+   * If a recoverable error occured, then (in most cases) CVODES
+   * will try to correct and retry.
+   * -----------------------------------------------------------------
+   */
+
+  typedef int (*CVSensRhsFn)(int Ns, realtype t,
+                             N_Vector y, N_Vector ydot,
+                             N_Vector *yS, N_Vector *ySdot,
+                             void *fS_data,
+                             N_Vector tmp1, N_Vector tmp2);
+
+  /*
+   * -----------------------------------------------------------------
+   * Type : CVSensRhs1Fn
+   * -----------------------------------------------------------------
+   * The fS1 function which defines the right hand side of the i-th
+   * sensitivity ODE system s_i' = f_y * s_i + f_p must have type
+   * CVSensRhs1Fn.
+   * fS1 takes as input the number of sensitivities Ns, the current
+   * sensitivity iS, the independent variable value t, the states y
+   * and the corresponding value of f(t,y) in ydot, and the
+   * dependent sensitivity vector yS. It stores the result of fS in
+   * ySdot.
+   * (Allocation of memory for ySdot is handled within CVODES)
+   * The fS_data parameter is the same as the fS_data parameter
+   * set by the user through the CVodeSetSensFdata routine and is
+   * passed to the fS1 function every time it is called.
+   *
+   * A CVSensRhs1Fn should return 0 if successful, a negative value if
+   * an unrecoverable error occured, and a positive value if a 
+   * recoverable error (e.g. invalid y or yS values) occured. 
+   * If an unrecoverable occured, the integration is halted. 
+   * If a recoverable error occured, then (in most cases) CVODES
+   * will try to correct and retry.
+   * -----------------------------------------------------------------
+   */
+
+  typedef int (*CVSensRhs1Fn)(int Ns, realtype t,
+                              N_Vector y, N_Vector ydot,
+                              int iS, N_Vector yS, N_Vector ySdot,
+                              void *fS_data,
+                              N_Vector tmp1, N_Vector tmp2);
+
+  /*
+   * -----------------------------------------------------------------
+   * CVRhsFnB
+   *    The fB function which defines the right hand side of the
+   *    ODE systems to be integrated backwards must have type CVRhsFnB.
+   * -----------------------------------------------------------------
+   * CVQuadRhsFnB
+   *    The fQB function which defines the quadratures to be integrated
+   *    backwards must have type CVQuadRhsFnB.
+   * -----------------------------------------------------------------
+   */
+  
+  typedef int (*CVRhsFnB)(realtype t, N_Vector y,
+                          N_Vector yB, N_Vector yBdot,
+                          void *f_dataB);
+  
+  typedef int (*CVQuadRhsFnB)(realtype t, N_Vector y,
+                              N_Vector yB, N_Vector qBdot,
+                              void *fQ_dataB);
+
+  /*
+   * =================================================================
+   *          U S E R - C A L L A B L E   R O U T I N E S
+   * =================================================================
+   */
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : CVodeCreate
+   * -----------------------------------------------------------------
+   * CVodeCreate creates an internal memory block for a problem to
+   * be solved by CVODES.
+   *
+   * lmm  is the type of linear multistep method to be used.
+   *      The legal values are CV_ADAMS and CV_BDF (see previous
+   *      description).
+   *
+   * iter  is the type of iteration used to solve the nonlinear
+   *       system that arises during each internal time step.
+   *       The legal values are CV_FUNCTIONAL and CV_NEWTON.
+   *
+   * If successful, CVodeCreate returns a pointer to initialized
+   * problem memory. This pointer should be passed to CVodeMalloc.
+   * If an initialization error occurs, CVodeCreate prints an error
+   * message to standard err and returns NULL.
+   * -----------------------------------------------------------------
+   */
+
+  void *CVodeCreate(int lmm, int iter);
+
+  /*
+   * -----------------------------------------------------------------
+   * Integrator optional input specification functions
+   * -----------------------------------------------------------------
+   * The following functions can be called to set optional inputs
+   * to values other than the defaults given below:
+   *
+   * Function                |  Optional input / [ default value ]
+   * -----------------------------------------------------------------
+   *                         |
+   * CVodeSetErrHandlerFn    | user-provided ErrHandler function.
+   *                         | [internal]
+   *                         |
+   * CVodeSetErrFile         | the file pointer for an error file
+   *                         | where all CVODE warning and error
+   *                         | messages will be written if the default
+   *                         | internal error handling function is used. 
+   *                         | This parameter can be stdout (standard 
+   *                         | output), stderr (standard error), or a 
+   *                         | file pointer (corresponding to a user 
+   *                         | error file opened for writing) returned 
+   *                         | by fopen.
+   *                         | If not called, then all messages will
+   *                         | be written to the standard error stream.
+   *                         | [stderr]
+   *                         |
+   * CVodeSetFdata           | a pointer to user data that will be
+   *                         | passed to the user's f function every
+   *                         | time f is called.
+   *                         | [NULL]
+   *                         |
+   * CVodeSetEwtFn           | user-provide EwtSet function e and 
+   *                         | a pointer to user data that will be
+   *                         | passed to the user's e function every
+   *                         | time e is called.
+   *                         | [NULL]
+   *                         | [NULL]
+   *                         |
+   * CVodeSetMaxOrd          | maximum lmm order to be used by the
+   *                         | solver.
+   *                         | [12 for Adams , 5 for BDF]
+   *                         |
+   * CVodeSetMaxNumSteps     | maximum number of internal steps to be
+   *                         | taken by the solver in its attempt to
+   *                         | reach tout.
+   *                         | [500]
+   *                         |
+   * CVodeSetMaxHnilWarns    | maximum number of warning messages
+   *                         | issued by the solver that t+h==t on the
+   *                         | next internal step. A value of -1 means
+   *                         | no such messages are issued.
+   *                         | [10]
+   *                         |
+   * CVodeSetStabLimDet      | flag to turn on/off stability limit
+   *                         | detection (TRUE = on, FALSE = off).
+   *                         | When BDF is used and order is 3 or
+   *                         | greater, CVsldet is called to detect
+   *                         | stability limit.  If limit is detected,
+   *                         | the order is reduced.
+   *                         | [FALSE]
+   *                         |
+   * CVodeSetInitStep        | initial step size.
+   *                         | [estimated by CVODES]
+   *                         |
+   * CVodeSetMinStep         | minimum absolute value of step size
+   *                         | allowed.
+   *                         | [0.0]
+   *                         |
+   * CVodeSetMaxStep         | maximum absolute value of step size
+   *                         | allowed.
+   *                         | [infinity]
+   *                         |
+   * CVodeSetStopTime        | the independent variable value past
+   *                         | which the solution is not to proceed.
+   *                         | [infinity]
+   *                         |
+   * CVodeSetMaxErrTestFails | Maximum number of error test failures
+   *                         | in attempting one step.
+   *                         | [7]
+   *                         |
+   * CVodeSetMaxNonlinIters  | Maximum number of nonlinear solver
+   *                         | iterations at one solution.
+   *                         | [3]
+   *                         |
+   * CVodeSetMaxConvFails    | Maximum number of allowable conv.
+   *                         | failures in attempting one step.
+   *                         | [10]
+   *                         |
+   * CVodeSetNonlinConvCoef  | Coeficient in the nonlinear conv.
+   *                         | test.
+   *                         | [0.1]
+   *                         |
+   * -----------------------------------------------------------------
+   *                         |
+   * CVodeSetIterType        | Changes the current nonlinear iteration
+   *                         | type.
+   *                         | [set by CVodecreate]
+   *                         |
+   * CVodeSetTolerances      | Changes the integration tolerances
+   *                         | between calls to CVode().
+   *                         | [set by CVodeMalloc/CVodeReInit]
+   *                         |
+   * -----------------------------------------------------------------
+   * Return flag:
+   *   CV_SUCCESS   if successful
+   *   CV_MEM_NULL  if the cvode memory is NULL
+   *   CV_ILL_INPUT if an argument has an illegal value
+   * -----------------------------------------------------------------
+   */
+
+  int CVodeSetErrHandlerFn(void *cvode_mem, CVErrHandlerFn ehfun, void *eh_data);
+  int CVodeSetErrFile(void *cvode_mem, FILE *errfp);
+  int CVodeSetFdata(void *cvode_mem, void *f_data);
+  int CVodeSetEwtFn(void *cvode_mem, CVEwtFn efun, void *e_data);
+  int CVodeSetMaxOrd(void *cvode_mem, int maxord);
+  int CVodeSetMaxNumSteps(void *cvode_mem, long int mxsteps);
+  int CVodeSetMaxHnilWarns(void *cvode_mem, int mxhnil);
+  int CVodeSetStabLimDet(void *cvode_mem, booleantype stldet);
+  int CVodeSetInitStep(void *cvode_mem, realtype hin);
+  int CVodeSetMinStep(void *cvode_mem, realtype hmin);
+  int CVodeSetMaxStep(void *cvode_mem, realtype hmax);
+  int CVodeSetStopTime(void *cvode_mem, realtype tstop);
+  int CVodeSetMaxErrTestFails(void *cvode_mem, int maxnef);
+  int CVodeSetMaxNonlinIters(void *cvode_mem, int maxcor);
+  int CVodeSetMaxConvFails(void *cvode_mem, int maxncf);
+  int CVodeSetNonlinConvCoef(void *cvode_mem, realtype nlscoef);
+
+  int CVodeSetIterType(void *cvode_mem, int iter);
+  int CVodeSetTolerances(void *cvode_mem,
+                         int itol, realtype reltol, void *abstol);
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : CVodeMalloc
+   * -----------------------------------------------------------------
+   * CVodeMalloc allocates and initializes memory for a problem to
+   * to be solved by CVODES.
+   *
+   * cvode_mem is pointer to CVODES memory returned by CVodeCreate.
+   *
+   * f       is the right hand side function in y' = f(t,y).
+   *
+   * t0      is the initial value of t.
+   *
+   * y0      is the initial condition vector y(t0).
+   *
+   * itol    is the type of tolerances to be used.
+   *         The legal values are:
+   *            CV_SS (scalar relative and absolute  tolerances),
+   *            CV_SV (scalar relative tolerance and vector
+   *                  absolute tolerance).
+   *            CV_WF (indicates that the user will provide a
+   *                function to evaluate the error weights.
+   *                In this case, reltol and abstol are ignored.)
+   *
+   * reltol  is the relative tolerance scalar.
+   *
+   * abstol  is a pointer to the absolute tolerance scalar or
+   *         an N_Vector of absolute tolerances.
+   *
+   * The parameters itol, reltol, and abstol define a vector of
+   * error weights, ewt, with components
+   *   ewt[i] = 1/(reltol*abs(y[i]) + abstol)   (if itol = CV_SS), or
+   *   ewt[i] = 1/(reltol*abs(y[i]) + abstol[i])   (if itol = CV_SV).
+   * This vector is used in all error and convergence tests, which
+   * use a weighted RMS norm on all error-like vectors v:
+   *    WRMSnorm(v) = sqrt( (1/N) sum(i=1..N) (v[i]*ewt[i])^2 ),
+   * where N is the problem dimension.
+   *
+   * If successful, CVodeMalloc returns SUCCESS. If an argument has
+   * an illegal value, CVodeMalloc prints an error message to the
+   * file specified by errfp and returns one of the error flags
+   * defined below.
+   * -----------------------------------------------------------------
+   */
+
+  int CVodeMalloc(void *cvode_mem, CVRhsFn f,
+                  realtype t0, N_Vector y0,
+                  int itol, realtype reltol, void *abstol);
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : CVodeReInit
+   * -----------------------------------------------------------------
+   * CVodeReInit re-initializes CVode for the solution of a problem,
+   * where a prior call to CVodeMalloc has been made with the same
+   * problem size N. CVodeReInit performs the same input checking
+   * and initializations that CVodeMalloc does.
+   * But it does no memory allocation, assuming that the existing
+   * internal memory is sufficient for the new problem.
+   *
+   * The use of CVodeReInit requires that the maximum method order,
+   * maxord, is no larger for the new problem than for the problem
+   * specified in the last call to CVodeMalloc.  This condition is
+   * automatically fulfilled if the multistep method parameter lmm
+   * is unchanged (or changed from CV_ADAMS to CV_BDF) and the default
+   * value for maxord is specified.
+   *
+   * The first argument to CVodeReInit is:
+   *
+   * cvode_mem = pointer to CVODES memory returned by CVodeCreate.
+   *
+   * All the remaining arguments to CVodeReInit have names and
+   * meanings identical to those of CVodeMalloc.
+   *
+   * The return value of CVodeReInit is equal to CV_SUCCESS = 0 if
+   * there were no errors; otherwise it is a negative int equal to:
+   *   CV_MEM_NULL  indicating cvode_mem was NULL (i.e.,
+   *                CVodeCreate has not been called).
+   *   CV_NO_MALLOC indicating that cvode_mem has not been
+   *                allocated (i.e., CVodeMalloc has not been
+   *                called).
+   *   CV_ILL_INPUT indicating an input argument was illegal
+   *                (including an attempt to increase maxord).
+   * In case of an error return, an error message is also printed.
+   * -----------------------------------------------------------------
+   */
+
+  int CVodeReInit(void *cvode_mem, CVRhsFn f,
+                  realtype t0, N_Vector y0,
+                  int itol, realtype reltol, void *abstol);
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : CVodeRootInit
+   * -----------------------------------------------------------------
+   * CVodeRootInit initializes a rootfinding problem to be solved
+   * during the integration of the ODE system.  It must be called
+   * after CVodeCreate, and before CVode.  The arguments are:
+   *
+   * cvode_mem = pointer to CVODE memory returned by CVodeCreate.
+   *
+   * nrtfn     = number of functions g_i, an int >= 0.
+   *
+   * g         = name of user-supplied function, of type CVRootFn,
+   *             defining the functions g_i whose roots are sought.
+   *
+   * g_data    = a pointer to user data that will be passed to the 
+   *             user's g function every time g is called.
+   *
+   * If a new problem is to be solved with a call to CVodeReInit,
+   * where the new problem has no root functions but the prior one
+   * did, then call CVodeRootInit with nrtfn = 0.
+   *
+   * The return value of CVodeRootInit is CV_SUCCESS = 0 if there were
+   * no errors; otherwise it is a negative int equal to:
+   *   CV_MEM_NULL    indicating cvode_mem was NULL, or
+   *   CV_MEM_FAIL    indicating a memory allocation failed.
+   *                  (including an attempt to increase maxord).
+   *   CV_ILL_INPUT   indicating nrtfn > 0 but g = NULL.
+   * In case of an error return, an error message is also printed.
+   * -----------------------------------------------------------------
+   */
+
+  int CVodeRootInit(void *cvode_mem, int nrtfn, CVRootFn g, void *g_data);
+
+  /*
+   * -----------------------------------------------------------------
+   * Quadrature optional input specification functions
+   * -----------------------------------------------------------------
+   * The following functions can be called to set optional inputs
+   * to values other than the defaults given below:
+   *
+   * Function             |  Optional input / [ default value ]
+   * --------------------------------------------------------------
+   *                      |
+   * CVodeSetQuadFdata    | a pointer to user data that will be
+   *                      | passed to the user's fQ function every
+   *                      | time fQ is called.
+   *                      | [NULL]
+   *                      |
+   * CVodeSetQuadErrCon   | are quadrature variables considered in
+   *                      | the error control?
+   *                      | If yes, set tolerances for quadrature
+   *                      | integration. 
+   *                      | [errconQ = FALSE]
+   *                      | [ not tolerances]
+   *                      |
+   * -----------------------------------------------------------------
+   * If successful, these functions return CV_SUCCESS. If an argument
+   * has an illegal value, they return one of the error flags
+   * defined for the CVodeSet* routines.
+   * -----------------------------------------------------------------
+   */
+
+  int CVodeSetQuadFdata(void *cvode_mem, void *fQ_data);
+  int CVodeSetQuadErrCon(void *cvode_mem, booleantype errconQ, 
+                         int itolQ, realtype reltolQ, void *abstolQ);
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : CVodeQuadMalloc
+   * -----------------------------------------------------------------
+   * CVodeQuadMalloc allocates and initializes memory related to
+   * quadrature integration.
+   *
+   * cvode_mem is a pointer to CVODES memory returned by CVodeCreate
+   *
+   * fQ    is the user-provided integrand routine.
+   *
+   * yQ0   is an N_Vector with initial values for quadratures
+   *       (typically yQ0 has all zero components).
+   *
+   * Return values:
+   *  CV_SUCCESS if successful
+   *  CV_MEM_NULL if the cvode memory was NULL
+   *  CV_MEM_FAIL if a memory allocation failed
+   * -----------------------------------------------------------------
+   */
+
+  int CVodeQuadMalloc(void *cvode_mem, CVQuadRhsFn fQ, N_Vector yQ0);
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : CVodeQuadReInit
+   * -----------------------------------------------------------------
+   * CVodeQuadReInit re-initializes CVODES's quadrature related
+   * memory for a problem, assuming it has already been allocated
+   * in prior calls to CVodeMalloc and CVodeQuadMalloc.
+   *
+   * All problem specification inputs are checked for errors.
+   * The number of quadratures Nq is assumed to be unchanged
+   * since the previous call to CVodeQuadMalloc.
+   *
+   * Return values:
+   *  CV_SUCCESS  if successful
+   *  CV_MEM_NULL if the cvode memory was NULL
+   *  CV_NO_QUAD  if quadratures were not initialized
+   * -----------------------------------------------------------------
+   */
+
+  int CVodeQuadReInit(void *cvode_mem, CVQuadRhsFn fQ, N_Vector yQ0);
+
+  /*
+   * -----------------------------------------------------------------
+   * Forward sensitivity optional input specification functions
+   * -----------------------------------------------------------------
+   * The following functions can be called to set optional inputs
+   * to other values than the defaults given below:
+   *
+   * Function                   |  Optional input / [ default value ]
+   * -----------------------------------------------------------------
+   *                            |
+   * CVodeSetSensRhsFn          | sensitivity right hand side function
+   *                            | and user data pointer.
+   *                            | This function must compute right hand
+   *                            | sides for all sensitivity equations.
+   *                            | [CVODES difference quotient approx.]
+   *                            | [internal]
+   *                            |
+   * CVodeSetSensRhs1Fn         | the sensitivity right hand side
+   *                            | and user data pointer.
+   *                            | This function must compute right hand
+   *                            | sides for one sensitivity equation at a
+   *                            | time.
+   *                            | [CVODES difference quotient approx.]
+   *                            | [internal]
+   *                            |
+   * CVodeSetSensDQMethod       | controls the selection of finite
+   *                            | difference schemes used in evaluating
+   *                            | the sensitivity right hand sides:
+   *                            | (centered vs. forward and 
+   *                            | simultaneous vs. separate)
+   *                            | [DQtype=CV_CENTERED]
+   *                            | [DQrhomax=0.0]
+   *                            |
+   * CVodeSetSensParams         | parameter information:
+   *                            | p: pointer to problem parameters
+   *                            | plist: list of parameters with respect
+   *                            |        to which sensitivities are to be
+   *                            |        computed.
+   *                            | pbar: order of magnitude info. 
+   *                            |       Typically, if p[plist[i]] is nonzero, 
+   *                            |       pbar[i]=p[plist[i]].
+   *                            | [p=NULL]
+   *                            | [plist=NULL]
+   *                            | [pbar=NULL]
+   *                            |
+   * CVodeSetSensErrCon         | are sensitivity variables considered in
+   *                            | the error control?
+   *                            | [FALSE]
+   *                            |
+   * CVodeSetSensTolerances     | type of sensi absolute tolerances.
+   *                            |
+   *                            | sensitivity relative tolerance scalar.
+   *                            |
+   *                            | pointer to the array of sensi
+   *                            | abs tol scalars or a pointer
+   *                            | to the array of N_Vector sensi
+   *                            | absolute tolerances.
+   *                            | [itolS = itol]
+   *                            | [reltolS = reltol]
+   *                            | [abstolS estimated by CVODES]
+   *                            |
+   * CVodeSetSensMaxNonlinIters | Maximum number of nonlinear solver
+   *                            | iterations at one solution.
+   *                            | [3]
+   *                            |
+   * -----------------------------------------------------------------
+   * The return values are the same as for CVodeSet*
+   * -----------------------------------------------------------------
+   */
+
+  int CVodeSetSensRhsFn(void *cvode_mem, CVSensRhsFn f, void *fS_dataS);
+  int CVodeSetSensRhs1Fn(void *cvode_mem, CVSensRhs1Fn fS, void *fS_data);
+  int CVodeSetSensDQMethod(void *cvode_mem, int DQtype, realtype DQrhomax);
+  int CVodeSetSensErrCon(void *cvode_mem, booleantype errconS);
+  int CVodeSetSensMaxNonlinIters(void *cvode_mem, int maxcorS);
+  int CVodeSetSensParams(void *cvode_mem, realtype *p, realtype *pbar, int *plist);
+  int CVodeSetSensTolerances(void *cvode_mem, int itolS,
+                             realtype reltolS, void *abstolS);
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : CVodeSensMalloc
+   * -----------------------------------------------------------------
+   * CVodeSensMalloc allocates and initializes memory related to
+   * sensitivity computations.
+   *
+   * cvode_mem is pointer to CVODES memory returned by CVodeCreate
+   *
+   * Ns        is the number of sensitivities to be computed.
+   *
+   * ism       is the type of corrector used in sensitivity
+   *           analysis. The legal values are: CV_SIMULTANEOUS,
+   *           CV_STAGGERED, and CV_STAGGERED1 (see previous description)
+   *
+   * yS0       is the array of initial condition vectors for
+   *           sensitivity variables.
+   *
+   * Return values:
+   *   CV_SUCCESS
+   *   CV_MEM_NULL
+   *   CV_ILL_INPUT 
+   *   CV_MEM_FAIL
+   * -----------------------------------------------------------------
+   */
+
+  int CVodeSensMalloc(void *cvode_mem, int Ns, int ism, N_Vector *yS0);
+    
+  /*
+   * -----------------------------------------------------------------
+   * Function : CVodeSensReInit
+   * -----------------------------------------------------------------
+   * CVodeSensReInit re-initializes CVODES's sensitivity related
+   * memory for a problem, assuming it has already been allocated
+   * in prior calls to CVodeMalloc and CvodeSensMalloc.
+   *
+   * All problem specification inputs are checked for errors.
+   * The number of sensitivities Ns is assumed to be unchanged
+   * since the previous call to CVodeSensMalloc.
+   * If any error occurs during initialization, it is reported to
+   * the file whose file pointer is errfp.
+   *
+   * CVodeSensReInit potentially does some minimal memory allocation
+   * (for the sensitivity absolute tolerance and for arrays of
+   * counters used by the CV_STAGGERED1 method).
+   *
+   * The return value is equal to CV_SUCCESS = 0 if there were no
+   * errors; otherwise it is a negative int equal to:
+   *   CV_MEM_NULL  indicating cvode_mem was NULL, or
+   *   CV_NO_SENS   indicating there was not a prior call to
+   *                CVodeSensMalloc.
+   *   CV_ILL_INPUT indicating an input argument was illegal
+   *                (including an attempt to increase maxord).
+   *   CV_MEM_FAIL  indicating a memory request failed.
+   * In case of an error return, an error message is also printed.
+   * -----------------------------------------------------------------
+   */
+
+  int CVodeSensReInit(void *cvode_mem, int ism, N_Vector *yS0);
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : CVodeSensToggleOff
+   * -----------------------------------------------------------------
+   * CVodeSensToggleOff deactivates sensitivity calculations.
+   * It does NOT deallocate sensitivity-related memory so that 
+   * sensitivity computations can be later toggled ON (through
+   * CVodeSensReInit).
+   * 
+   * The return value is equal to CV_SUCCESS = 0 if there were no
+   * errors or CV_MEM_NULL if cvode_mem was NULL
+   * -----------------------------------------------------------------
+   */
+
+  int CVodeSensToggleOff(void *cvode_mem);
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : CVode
+   * -----------------------------------------------------------------
+   * CVode integrates the ODE over an interval in t.
+   * If itask is CV_NORMAL, then the solver integrates from its
+   * current internal t value to a point at or beyond tout, then
+   * interpolates to t = tout and returns y(tout) in the user-
+   * allocated vector yout. If itask is CV_ONE_STEP, then the solver
+   * takes one internal time step and returns in yout the value of
+   * y at the new internal time. In this case, tout is used only
+   * during the first call to CVode to determine the direction of
+   * integration and the rough scale of the problem.  If itask is
+   * CV_NORMAL_TSTOP or CV_ONE_STEP_TSTOP, then CVode returns the
+   * solution at tstop if that comes sooner than tout or the end of
+   * the next internal step, respectively.  In any case,
+   * the time reached by the solver is placed in (*tret). The
+   * user is responsible for allocating the memory for this value.
+   *
+   * cvode_mem is the pointer to CVODES memory returned by
+   *           CVodeCreate.
+   *
+   * tout  is the next time at which a computed solution is desired.
+   *
+   * yout  is the computed solution vector. In CV_NORMAL mode with no
+   *       errors and no roots found, yout=y(tout).
+   *
+   * tret  is a pointer to a real location. CVode sets (*tret) to
+   *       the time reached by the solver and returns yout=y(*tret).
+   *
+   * itask is CV_NORMAL, CV_ONE_STEP, CV_NORMAL_TSTOP, or CV_ONE_STEP_TSTOP.
+   *       These four modes are described above.
+   *
+   * Here is a brief description of each return value:
+   *
+   * CV_SUCCESS:     CVode succeeded and no roots were found.
+   *
+   * CV_ROOT_RETURN: CVode succeeded, and found one or more roots.
+   *                 If nrtfn > 1, call CVodeGetRootInfo to see
+   *                 which g_i were found to have a root at (*tret).
+   *
+   * CV_TSTOP_RETURN: CVode succeded and returned at tstop.
+   *
+   * CV_MEM_NULL:    The cvode_mem argument was NULL.
+   *
+   * CV_NO_MALLOC:   cvode_mem was not allocated.
+   *
+   * CV_ILL_INPUT:   One of the inputs to CVode is illegal. This
+   *                 includes the situation when a component of the
+   *                 error weight vectors becomes < 0 during
+   *                 internal time-stepping. The ILL_INPUT flag
+   *                 will also be returned if the linear solver
+   *                 routine CV--- (called by the user after
+   *                 calling CVodeCreate) failed to set one of the
+   *                 linear solver-related fields in cvode_mem or
+   *                 if the linear solver's init routine failed. In
+   *                 any case, the user should see the printed
+   *                 error message for more details.
+   *
+   * CV_TOO_MUCH_WORK: The solver took mxstep internal steps but
+   *                 could not reach tout. The default value for
+   *                 mxstep is MXSTEP_DEFAULT = 500.
+   *
+   * CV_TOO_MUCH_ACC: The solver could not satisfy the accuracy
+   *                 demanded by the user for some internal step.
+   *
+   * CV_ERR_FAILURE: Error test failures occurred too many times
+   *                 (= MXNEF = 7) during one internal time step or
+   *                 occurred with |h| = hmin.
+   *
+   * CV_CONV_FAILURE: Convergence test failures occurred too many
+   *                 times (= MXNCF = 10) during one internal time
+   *                 step or occurred with |h| = hmin.
+   *
+   * CV_LINIT_FAIL:  The linear solver's initialization function 
+   *                 failed.
+   *
+   * CV_LSETUP_FAIL: The linear solver's setup routine failed in an
+   *                 unrecoverable manner.
+   *
+   * CV_LSOLVE_FAIL: The linear solver's solve routine failed in an
+   *                 unrecoverable manner.
+   * -----------------------------------------------------------------
+   */
+
+  int CVode(void *cvode_mem, realtype tout, N_Vector yout,
+            realtype *tret, int itask);
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : CVodeGetDky
+   * -----------------------------------------------------------------
+   * CVodeGetDky computes the kth derivative of the y function at
+   * time t, where tn-hu <= t <= tn, tn denotes the current
+   * internal time reached, and hu is the last internal step size
+   * successfully used by the solver. The user may request
+   * k=0, 1, ..., qu, where qu is the current order. The
+   * derivative vector is returned in dky. This vector must be
+   * allocated by the caller. It is only legal to call this
+   * function after a successful return from CVode.
+   *
+   * cvode_mem is the pointer to CVODES memory returned by
+   *           CVodeCreate.
+   *
+   * t   is the time at which the kth derivative of y is evaluated.
+   *     The legal range for t is [tn-hu,tn] as described above.
+   *
+   * k   is the order of the derivative of y to be computed. The
+   *     legal range for k is [0,qu] as described above.
+   *
+   * dky is the output derivative vector [(D_k)y](t).
+   *
+   * The return values for CVodeGetDky are defined below.
+   * Here is a brief description of each return value:
+   *
+   * CV_SUCCESS: CVodeGetDky succeeded.
+   *
+   * CV_BAD_K : k is not in the range 0, 1, ..., qu.
+   *
+   * CV_BAD_T : t is not in the interval [tn-hu,tn].
+   *
+   * CV_BAD_DKY : The dky argument was NULL.
+   *
+   * CV_MEM_NULL : The cvode_mem argument was NULL.
+   * -----------------------------------------------------------------
+   */
+
+  int CVodeGetDky(void *cvode_mem, realtype t, int k, N_Vector dky);
+
+  /*
+   * -----------------------------------------------------------------
+   * Integrator optional output extraction functions
+   * -----------------------------------------------------------------
+   * The following functions can be called to get optional outputs
+   * and statistics related to the main integrator.
+   * -----------------------------------------------------------------
+   * CVodeGetWorkSpace returns the CVODES real and integer workspaces
+   * CVodeGetNumSteps returns the cumulative number of internal
+   *                  steps taken by the solver
+   * CVodeGetNumRhsEvals returns the number of calls to the user's
+   *                  f function
+   * CVodeGetNumLinSolvSetups returns the number of calls made to
+   *                  the linear solver's setup routine
+   * CVodeGetNumErrTestFails returns the number of local error test
+   *                  failures that have occured
+   * CVodeGetLastOrder returns the order used during the last
+   *                  internal step
+   * CVodeGetCurrentOrder returns the order to be used on the next
+   *                  internal step
+   * CVodeGetNumStabLimOrderReds returns the number of order
+   *                  reductions due to stability limit detection
+   * CVodeGetActualInitStep returns the actual initial step size
+   *                  used by CVODES
+   * CVodeGetLastStep returns the step size for the last internal
+   *                  step
+   * CVodeGetCurrentStep returns the step size to be attempted on
+   *                  the next internal step
+   * CVodeGetCurrentTime returns the current internal time reached
+   *                  by the solver
+   * CVodeGetTolScaleFactor returns a suggested factor by which the
+   *                  user's tolerances should be scaled when too
+   *                  much accuracy has been requested for some
+   *                  internal step
+   * CVodeGetErrWeights returns the current error weight vector.
+   *                    The user must allocate space for eweight.
+   * CVodeGetEstLocalErrors returns the vector of estimated local
+   *                  errors. The user must allocate space for ele.
+   * CVodeGetNumGEvals returns the number of calls to the user's
+   *                  g function (for rootfinding)
+   * CVodeGetRootInfo returns the indices for which g_i was found to 
+   *                  have a root. The user must allocate space for 
+   *                  rootsfound. For i = 0 ... nrtfn-1, 
+   *                  rootsfound[i] = 1 if g_i has a root, and = 0 if not.
+   *
+   * CVodeGet* return values:
+   *   CV_SUCCESS   if succesful
+   *   CV_MEM_NULL  if the cvode memory was NULL
+   *   CV_NO_SLDET  if stability limit was not turned on
+   * -----------------------------------------------------------------
+   */
+
+  int CVodeGetWorkSpace(void *cvode_mem, long int *lenrw, long int *leniw);
+  int CVodeGetNumSteps(void *cvode_mem, long int *nsteps);
+  int CVodeGetNumRhsEvals(void *cvode_mem, long int *nfevals);
+  int CVodeGetNumLinSolvSetups(void *cvode_mem, long int *nlinsetups);
+  int CVodeGetNumErrTestFails(void *cvode_mem, long int *netfails);
+  int CVodeGetLastOrder(void *cvode_mem, int *qlast);
+  int CVodeGetCurrentOrder(void *cvode_mem, int *qcur);
+  int CVodeGetNumStabLimOrderReds(void *cvode_mem, long int *nslred);
+  int CVodeGetActualInitStep(void *cvode_mem, realtype *hinused);
+  int CVodeGetLastStep(void *cvode_mem, realtype *hlast);
+  int CVodeGetCurrentStep(void *cvode_mem, realtype *hcur);
+  int CVodeGetCurrentTime(void *cvode_mem, realtype *tcur);
+  int CVodeGetTolScaleFactor(void *cvode_mem, realtype *tolsfac);
+  int CVodeGetErrWeights(void *cvode_mem, N_Vector eweight);
+  int CVodeGetEstLocalErrors(void *cvode_mem, N_Vector ele);
+  int CVodeGetNumGEvals(void *cvode_mem, long int *ngevals);
+  int CVodeGetRootInfo(void *cvode_mem, int *rootsfound);
+
+  /*
+   * -----------------------------------------------------------------
+   * As a convenience, the following functions provides the
+   * optional outputs in one group.
+   * -----------------------------------------------------------------
+   */
+
+  int CVodeGetIntegratorStats(void *cvode_mem, long int *nsteps,
+                              long int *nfevals, long int *nlinsetups,
+                              long int *netfails, int *qlast,
+                              int *qcur, realtype *hinused, realtype *hlast,
+                              realtype *hcur, realtype *tcur);
+
+  /*
+   * -----------------------------------------------------------------
+   * Nonlinear solver optional output extraction functions
+   * -----------------------------------------------------------------
+   * The following functions can be called to get optional outputs
+   * and statistics related to the nonlinear solver.
+   * -----------------------------------------------------------------
+   * CVodeGetNumNonlinSolvIters returns the number of nonlinear
+   *                            solver iterations performed.
+   * CVodeGetNumNonlinSolvConvFails returns the number of nonlinear
+   *                                convergence failures.
+   * -----------------------------------------------------------------
+   */
+
+  int CVodeGetNumNonlinSolvIters(void *cvode_mem, long int *nniters);
+  int CVodeGetNumNonlinSolvConvFails(void *cvode_mem, long int *nncfails);
+
+  /*
+   * -----------------------------------------------------------------
+   * As a convenience, the following function provides the
+   * nonlinear solver optional outputs in a group.
+   * -----------------------------------------------------------------
+   */
+
+  int CVodeGetNonlinSolvStats(void *cvode_mem, long int *nniters,
+                              long int *nncfails);
+
+
+  /*
+   * -----------------------------------------------------------------
+   * The following function returns the name of the constant 
+   * associated with a CVODES return flag
+   * -----------------------------------------------------------------
+   */
+
+  char *CVodeGetReturnFlagName(int flag);
+
+  /*
+   * -----------------------------------------------------------------
+   * Quadrature integration solution extraction routines
+   * -----------------------------------------------------------------
+   * The following functions can be called to obtain the quadrature
+   * variables after a successful integration step.
+   * If quadratures were not computed, they return CV_NO_QUAD.
+   * -----------------------------------------------------------------
+   */
+
+  int CVodeGetQuad(void *cvode_mem, realtype t, N_Vector yQout);
+  int CVodeGetQuadDky(void *cvode_mem, realtype t, int k, N_Vector dky);
+
+  /*
+   * -----------------------------------------------------------------
+   * Quadrature integration optional output extraction routines
+   * -----------------------------------------------------------------
+   * The following functions can be called to get optional outputs
+   * and statistics related to the integration of quadratures.
+   * -----------------------------------------------------------------
+   * CVodeGetQuadNumRhsEvals returns the number of calls to the
+   *                         user function fQ defining the right hand
+   *                         side of the quadrature variables.
+   * CVodeGetQuadNumErrTestFails returns the number of local error
+   *                             test failures for quadrature variables.
+   * CVodeGetQuadErrWeights returns the vector of error weights for
+   *                        the quadrature variables. The user must
+   *                        allocate space for ewtQ.
+   * -----------------------------------------------------------------
+   */
+
+  int CVodeGetQuadNumRhsEvals(void *cvode_mem, long int *nfQevals);
+  int CVodeGetQuadNumErrTestFails(void *cvode_mem, long int *nQetfails);
+  int CVodeGetQuadErrWeights(void *cvode_mem, N_Vector eQweight);
+
+  /*
+   * -----------------------------------------------------------------
+   * As a convenience, the following function provides the
+   * optional outputs in a group.
+   * -----------------------------------------------------------------
+   */
+
+  int CVodeGetQuadStats(void *cvode_mem, long int *nfQevals,
+                        long int *nQetfails);
+
+  /*
+   * -----------------------------------------------------------------
+   * Forward sensitivity solution extraction routines
+   * -----------------------------------------------------------------
+   * CVodeGetSensDky1 computes the kth derivative of the is-th
+   * sensitivity (is=1, 2, ..., Ns) of the y function at time t,
+   * where tn-hu <= t <= tn, tn denotes the current internal time
+   * reached, and hu is the last internal step size successfully
+   * used by the solver. The user may request k=0, 1, ..., qu,
+   * where qu is the current order.
+   * The is-th sensitivity derivative vector is returned in dky.
+   * This vector must be allocated by the caller. It is only legal
+   * to call this function after a successful return from CVode
+   * with sensitivty computations enabled.
+   * Arguments have the same meaning as in CVodeDky.
+   *
+   * CVodeGetSensDky computes the k-th derivative of all
+   * sensitivities of the y function at time t. It repeatedly calls
+   * CVodeGetSensDky. The argument dkyA must be a pointer to
+   * N_Vector and must be allocated by the user to hold at least Ns
+   * vectors.
+   *
+   * CVodeGetSens1 returns the is-th sensitivity of the y function
+   * at the time t. The argument ySout must be an N_Vector and must
+   * be allocated by the user.
+   *
+   * CVodeGetSens returns sensitivities of the y function at
+   * the time t. The argument ySout must be a pointer to N_Vector
+   * and must be allocated by the user to hold at least Ns vectors.
+   *
+   * Return values are similar to those of CVodeDky. Additionally,
+   * CVodeSensDky can return CV_NO_SENS if sensitivities were
+   * not computed and CV_BAD_IS if is < 0 or is >= Ns.
+   * -----------------------------------------------------------------
+   */
+
+  int CVodeGetSens(void *cvode_mem, realtype t, N_Vector *ySout);
+  int CVodeGetSens1(void *cvode_mem, realtype t, int is, N_Vector ySout);
+  int CVodeGetSensDky(void *cvode_mem, realtype t, int k,
+                      N_Vector *dkyA);
+  int CVodeGetSensDky1(void *cvode_mem, realtype t, int k,
+                       int is, N_Vector dky);
+
+  /*
+   * -----------------------------------------------------------------
+   * Forward sensitivity optional output extraction routines
+   * -----------------------------------------------------------------
+   * The following functions can be called to get optional outputs
+   * and statistics related to the integration of sensitivities.
+   * -----------------------------------------------------------------
+   * CVodeGetNumSensRhsEvals returns the number of calls to the
+   *                         sensitivity right hand side routine.
+   * CVodeGetNumRhsEvalsSens returns the number of calls to the
+   *                         user f routine due to finite difference
+   *                         evaluations of the sensitivity equations.
+   * CVodeGetNumSensErrTestFails returns the number of local error
+   *                             test failures for sensitivity variables.
+   * CVodeGetNumSensLinSolvSetups returns the number of calls made
+   *                              to the linear solver's setup routine
+   *                              due to sensitivity computations.
+   * CVodeGetSensErrWeights returns the sensitivity error weight
+   *                        vectors. The user need not allocate space
+   *                        for ewtS.
+   * -----------------------------------------------------------------
+   */
+
+  int CVodeGetNumSensRhsEvals(void *cvode_mem, long int *nfSevals);
+  int CVodeGetNumRhsEvalsSens(void *cvode_mem, long int *nfevalsS);
+  int CVodeGetNumSensErrTestFails(void *cvode_mem, long int *nSetfails);
+  int CVodeGetNumSensLinSolvSetups(void *cvode_mem, long int *nlinsetupsS);
+  int CVodeGetSensErrWeights(void *cvode_mem, N_Vector_S eSweight);
+
+  /*
+   * -----------------------------------------------------------------
+   * As a convenience, the following function provides the
+   * optional outputs in a group.
+   * -----------------------------------------------------------------
+   */
+
+  int CVodeGetSensStats(void *cvode_mem, long int *nfSevals, long int *nfevalsS,
+                        long int *nSetfails, long int *nlinsetupsS);
+
+  /*
+   * -----------------------------------------------------------------
+   * Sensitivity nonlinear solver optional output extraction
+   * -----------------------------------------------------------------
+   * The following functions can be called to get optional outputs
+   * and statistics related to the sensitivity nonlinear solver.
+   * -----------------------------------------------------------------
+   * CVodeGetNumSensNonlinSolvIters returns the total number of
+   *                                nonlinear iterations for sensitivity
+   *                                variables.
+   * CVodeGetNumSensNonlinSolvConvFails returns the total number of
+   *                                    nonlinear convergence failures
+   *                                    for sensitivity variables
+   * CVodeGetNumStgrSensNonlinSolvIters returns a vector of Ns
+   *                                    nonlinear iteration counters
+   *                                    for sensitivity variables
+   *                                    in the CV_STAGGERED1 method.
+   * CVodeGetNumStgrSensNonlinSolvConvFails returns a vector of Ns
+   *                                        nonlinear solver convergence
+   *                                        failure counters for
+   *                                        sensitivity variables in
+   *                                        the CV_STAGGERED1 method.
+   * -----------------------------------------------------------------
+   */
+
+  int CVodeGetNumSensNonlinSolvIters(void *cvode_mem, long int *nSniters);
+  int CVodeGetNumSensNonlinSolvConvFails(void *cvode_mem, long int *nSncfails);
+  int CVodeGetNumStgrSensNonlinSolvIters(void *cvode_mem, long int *nSTGR1niters);
+  int CVodeGetNumStgrSensNonlinSolvConvFails(void *cvode_mem, 
+                                             long int *nSTGR1ncfails);
+
+  /*
+   * -----------------------------------------------------------------
+   * As a convenience, the following function provides the      
+   * optional outputs in groups.                                    
+   * -----------------------------------------------------------------
+   */
+
+  int CVodeGetSensNonlinSolvStats(void *cvode_mem, long int *nSniters,
+                                  long int *nSncfails);
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : CVodeFree
+   * -----------------------------------------------------------------
+   * CVodeFree frees the problem memory cvode_mem allocated by
+   * CVodeMalloc.  Its only argument is the pointer cvode_mem
+   * returned by CVodeCreate.
+   * -----------------------------------------------------------------
+   */
+
+  void CVodeFree(void **cvode_mem);
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : CVodeQuadFree
+   * -----------------------------------------------------------------
+   * CVodeQuadFree frees the problem memory in cvode_mem allocated
+   * for quadrature integration. Its only argument is the pointer
+   * cvode_mem returned by CVodeCreate.
+   * -----------------------------------------------------------------
+   */
+
+  void CVodeQuadFree(void *cvode_mem);
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : CVodeSensFree
+   * -----------------------------------------------------------------
+   * CVodeSensFree frees the problem memory in cvode_mem allocated
+   * for sensitivity analysis. Its only argument is the pointer
+   * cvode_mem returned by CVodeCreate.
+   * -----------------------------------------------------------------
+   */
+
+  void CVodeSensFree(void *cvode_mem);
+
+  /*
+   * -----------------------------------------------------------------
+   * CVadjMalloc
+   * -----------------------------------------------------------------
+   * CVadjMalloc specifies some parameters for the adjoint problem and
+   * allocates space for the global CVODEA memory structure.
+   * -----------------------------------------------------------------
+   */
+  
+  void *CVadjMalloc(void *cvode_mem, long int steps, int interp);
+
+  /*
+   * -----------------------------------------------------------------
+   * CVadjSetInterpType
+   * -----------------------------------------------------------------
+   * Changes the interpolation type. 
+   * Must be called only after CVadjMalloc
+   * -----------------------------------------------------------------
+   */
+  
+  int CVadjSetInterpType(void *cvadj_mem, int interp);
+
+  /*
+   * -----------------------------------------------------------------
+   * CVodeF
+   * -----------------------------------------------------------------
+   * CVodeF integrates towards tout and returns solution into yout.
+   * In the same time, it stores check point data every 'steps'.
+   *
+   * CVodeF can be called repeatedly by the user.
+   *
+   * ncheckPtr points to the number of check points stored so far.
+   *
+   * Return values:
+   *    CV_SUCCESS
+   *    CVADJ_MEM_FAIL
+   *    any CVode return value
+   * -----------------------------------------------------------------
+   */
+
+  int CVodeF(void *cvadj_mem, realtype tout, N_Vector yout,
+             realtype *tret, int itask, int *ncheckPtr);
+
+  /*
+   * -----------------------------------------------------------------
+   * Interfaces to CVODES functions for setting-up the
+   *  backward integration
+   * -----------------------------------------------------------------
+   * CVodeCreateB, CVodeMallocB, CVodeSet*B
+   *    These functions are just wrappers around the corresponding
+   *    functions in cvodes.h, with some particularizations for the
+   *    backward integration.
+   * -----------------------------------------------------------------
+   * CVodeSetQuad*B, CVodeQuadMallocB, CVodeQuadReInitB
+   * -----------------------------------------------------------------
+   */
+
+  int CVodeCreateB(void *cvadj_mem, int lmmB, int iterB);
+
+  int CVodeMallocB(void *cvadj_mem, CVRhsFnB fB,
+                   realtype tB0, N_Vector yB0,
+                   int itolB, realtype reltolB, void *abstolB);
+  
+  int CVodeSetErrHandlerFnB(void *cvadj_mem, CVErrHandlerFn ehfunB, void *eh_dataB);
+  int CVodeSetErrFileB(void *cvadj_mem, FILE *errfpB);
+  int CVodeSetIterTypeB(void *cvadj_mem, int iterB);
+  int CVodeSetFdataB(void *cvadj_mem, void *f_dataB);
+  int CVodeSetMaxOrdB(void *cvadj_mem, int maxordB);
+  int CVodeSetMaxNumStepsB(void *cvadj_mem, long int mxstepsB);
+  int CVodeSetStabLimDetB(void *cvadj_mem, booleantype stldetB);
+  int CVodeSetInitStepB(void *cvadj_mem, realtype hinB);
+  int CVodeSetMinStepB(void *cvadj_mem, realtype hminB);
+  int CVodeSetMaxStepB(void *cvadj_mem, realtype hmaxB);
+  
+  int CVodeReInitB(void *cvadj_mem, CVRhsFnB fB,
+                   realtype tB0, N_Vector yB0,
+                   int itolB, realtype reltolB, void *abstolB);
+    
+  int CVodeSetQuadFdataB(void *cvadj_mem, void *fQ_dataB);
+  int CVodeSetQuadErrConB(void *cvadj_mem, booleantype errconQB,
+                          int itolQB, realtype reltolQB, void *abstolQB);
+  int CVodeQuadMallocB(void *cvadj_mem, CVQuadRhsFnB fQB, N_Vector yQB0);
+  int CVodeQuadReInitB(void *cvadj_mem, CVQuadRhsFnB fQB, N_Vector yQB0);
+    
+  /*
+   * -----------------------------------------------------------------
+   * CVodeB
+   * -----------------------------------------------------------------
+   * CVodeB performs the backward integration from tfinal to
+   * tinitial through a sequence of forward-backward runs in
+   * between consecutive check points. It returns the values of
+   * the adjoint variables and any existing quadrature variables
+   * at tinitial.
+   * -----------------------------------------------------------------
+   */
+  
+  int CVodeB(void *cvadj_mem, realtype tBout, N_Vector yBout,
+             realtype *tBret, int itaskB);
+  
+  /*
+   * -----------------------------------------------------------------
+   * CVodeGetQuadB
+   * -----------------------------------------------------------------
+   * CVodeGetQuadB extracts values for quadrature variables in
+   * the N_Vector qB.
+   * -----------------------------------------------------------------
+   */
+  
+  int CVodeGetQuadB(void *cvadj_mem, N_Vector qB);
+  
+  /*
+   * -----------------------------------------------------------------
+   * CVadjFree
+   * -----------------------------------------------------------------
+   * CVadjFree frees the memory allocated by CVadjMalloc.
+   * -----------------------------------------------------------------
+   */
+  
+  void CVadjFree(void **cvadj_mem);
+  
+  /*
+   * -----------------------------------------------------------------
+   * CVadjGetCVodeBmem
+   * -----------------------------------------------------------------
+   * CVadjGetCVodeBmem returns a (void *) pointer to the CVODES
+   * memory allocated for the backward problem. This pointer can
+   * then be used to call any of the CVodeGet* CVODES routines to
+   * extract optional output for the backward integration phase.
+   * -----------------------------------------------------------------
+   */
+  
+  void *CVadjGetCVodeBmem(void *cvadj_mem);
+
+  /*
+   * -----------------------------------------------------------------
+   * The following function returns the name of the constant 
+   * associated with a CVODEA-specific return flag
+   * -----------------------------------------------------------------
+   */
+  
+  char *CVadjGetReturnFlagName(int flag);
+
+
+  /*
+   * -----------------------------------------------------------------
+   * CVadjGetY
+   *    Returns the interpolated forward solution at time t. This
+   *    function is a wrapper around the interpType-dependent internal
+   *    function.
+   *    The calling function must allocate space for y.
+   * -----------------------------------------------------------------
+   */
+
+  int CVadjGetY(void *cvadj_mem, realtype t, N_Vector y);
+
+  /*
+   * -----------------------------------------------------------------
+   * CVadjGetCheckPointsInfo
+   *    Loads an array of nckpnts structures of type CVadjCheckPointRec.
+   *    The user must allocate space for ckpnt (ncheck+1).
+   * -----------------------------------------------------------------
+   */
+
+  typedef struct {
+    void *my_addr;
+    void *next_addr;
+    realtype t0;
+    realtype t1;
+    long int nstep;
+    int order;
+    realtype step;
+  } CVadjCheckPointRec;
+
+  int CVadjGetCheckPointsInfo(void *cvadj_mem, CVadjCheckPointRec *ckpnt);
+
+  /*
+   * -----------------------------------------------------------------
+   * CVadjGetDataPointHermite
+   *    Returns the 2 vectors stored for cubic Hermite interpolation 
+   *    at the data point 'which'. The user must allocate space for
+   *    y and yd. Returns CVADJ_MEM_NULL if cvadj_mem is NULL.
+   *    Returns CV_ILL_INPUT if interpType != CV_HERMITE.
+   * CVadjGetDataPointPolynomial
+   *    Returns the vector stored for polynomial interpolation 
+   *    at the data point 'which'. The user must allocate space for
+   *    y. Returns CVADJ_MEM_NULL if cvadj_mem is NULL.
+   *    Returns CV_ILL_INPUT if interpType != CV_POLYNOMIAL.
+   * -----------------------------------------------------------------
+   */
+
+  int CVadjGetDataPointHermite(void *cvadj_mem, long int which,
+                               realtype *t, N_Vector y, N_Vector yd);
+  
+  int CVadjGetDataPointPolynomial(void *cvadj_mem, long int which,
+                                  realtype *t, int *order, N_Vector y);
+
+  /* 
+   * ===============================================================
+   * DEVELOPMENT USER-CALLABLE FUNCTIONS
+   * ===============================================================
+   */
+
+  /*
+   * -----------------------------------------------------------------
+   * CVadjGetCurrentCheckPoint
+   *    Returns the address of the 'active' check point.
+   * -----------------------------------------------------------------
+   */
+
+  int CVadjGetCurrentCheckPoint(void *cvadj_mem, void **addr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/cvodes/cvodes_band.h b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/cvodes/cvodes_band.h
new file mode 100644
index 0000000000000000000000000000000000000000..8d441f996a84117747de9e76545d5c7a974ab131
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/cvodes/cvodes_band.h	
@@ -0,0 +1,294 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * ----------------------------------------------------------------- 
+ * Programmer(s): Radu Serban @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2005, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This is the header file for the CVODES band linear solver, CVBAND.
+ *
+ *
+ * Part I contains type definitions and function prototypes for using
+ * CVBAND on forward problems (IVP integration and/or FSA)
+ *
+ * Part II contains type definitions and function prototypes for using
+ * CVBAND on adjoint (backward) problems
+ * -----------------------------------------------------------------
+ */
+
+#ifndef _CVSBAND_H
+#define _CVSBAND_H
+
+#ifdef __cplusplus  /* wrapper to enable C++ usage */
+extern "C" {
+#endif
+
+#include <sundials/sundials_band.h>
+#include <sundials/sundials_nvector.h>
+
+  /*
+   * -----------------------------------------------------------------
+   * CVBAND solver constants
+   * -----------------------------------------------------------------
+   * CVB_MSBJ : maximum number of steps between band Jacobian
+   *            evaluations
+   *
+   * CVB_DGMAX : maximum change in gamma between band Jacobian
+   *             evaluations
+   * -----------------------------------------------------------------
+   */
+
+#define CVB_MSBJ  50
+#define CVB_DGMAX RCONST(0.2)
+
+  /*
+   * -----------------------------------------------------------------
+   * CVBAND return values
+   * -----------------------------------------------------------------
+   */
+
+#define CVBAND_SUCCESS           0
+#define CVBAND_MEM_NULL         -1
+#define CVBAND_LMEM_NULL        -2
+#define CVBAND_ILL_INPUT        -3
+#define CVBAND_MEM_FAIL         -4
+
+  /* Additional last_flag values */
+
+#define CVBAND_JACFUNC_UNRECVR  -5
+#define CVBAND_JACFUNC_RECVR    -6
+
+  /* Return values for adjoint module */
+
+#define CVBAND_ADJMEM_NULL      -101
+#define CVBAND_LMEMB_NULL       -102
+
+  /* 
+   * -----------------------------------------------------------------
+   * PART I - forward problems
+   * -----------------------------------------------------------------
+   */
+
+
+  /*
+   * -----------------------------------------------------------------
+   * Type : CVBandJacFn
+   * -----------------------------------------------------------------
+   * A band Jacobian approximation function Jac must have the
+   * prototype given below. Its parameters are:
+   *
+   * N is the length of all vector arguments.
+   *
+   * mupper is the upper half-bandwidth of the approximate banded
+   * Jacobian. This parameter is the same as the mupper parameter
+   * passed by the user to the CVBand function.
+   *
+   * mlower is the lower half-bandwidth of the approximate banded
+   * Jacobian. This parameter is the same as the mlower parameter
+   * passed by the user to the CVBand function.
+   *
+   * J is the band matrix (of type BandMat) that will be loaded
+   * by a CVBandJacFn with an approximation to the Jacobian matrix
+   * J = (df_i/dy_j) at the point (t,y).
+   * J is preset to zero, so only the nonzero elements need to be
+   * loaded. Three efficient ways to load J are:
+   *
+   * (1) (with macros - no explicit data structure references)
+   *    for (j=0; j < n; j++) {
+   *       col_j = BAND_COL(J,j);
+   *       for (i=j-mupper; i <= j+mlower; i++) {
+   *         generate J_ij = the (i,j)th Jacobian element
+   *         BAND_COL_ELEM(col_j,i,j) = J_ij;
+   *       }
+   *     }
+   *
+   * (2) (with BAND_COL macro, but without BAND_COL_ELEM macro)
+   *    for (j=0; j < n; j++) {
+   *       col_j = BAND_COL(J,j);
+   *       for (k=-mupper; k <= mlower; k++) {
+   *         generate J_ij = the (i,j)th Jacobian element, i=j+k
+   *         col_j[k] = J_ij;
+   *       }
+   *     }
+   *
+   * (3) (without macros - explicit data structure references)
+   *     offset = J->smu;
+   *     for (j=0; j < n; j++) {
+   *       col_j = ((J->data)[j])+offset;
+   *       for (k=-mupper; k <= mlower; k++) {
+   *         generate J_ij = the (i,j)th Jacobian element, i=j+k
+   *         col_j[k] = J_ij;
+   *       }
+   *     }
+   * Caution: J->smu is generally NOT the same as mupper.
+   *
+   * The BAND_ELEM(A,i,j) macro is appropriate for use in small
+   * problems in which efficiency of access is NOT a major concern.
+   *
+   * t is the current value of the independent variable.
+   *
+   * y is the current value of the dependent variable vector,
+   *      namely the predicted value of y(t).
+   *
+   * fy is the vector f(t,y).
+   *
+   * jac_data is a pointer to user data - the same as the jac_data
+   *          parameter passed to CVBand.
+   *
+   * NOTE: If the user's Jacobian routine needs other quantities,
+   *     they are accessible as follows: hcur (the current stepsize)
+   *     and ewt (the error weight vector) are accessible through
+   *     CVodeGetCurrentStep and CVodeGetErrWeights, respectively
+   *     (see cvode.h). The unit roundoff is available as
+   *     UNIT_ROUNDOFF defined in sundials_types.h
+   *
+   * tmp1, tmp2, and tmp3 are pointers to memory allocated for
+   * vectors of length N which can be used by a CVBandJacFn
+   * as temporary storage or work space.
+   *
+   * A CVBandJacFn should return 0 if successful, a positive value if 
+   * a recoverable error occurred, and a negative value if an 
+   * unrecoverable error occurred.
+   * -----------------------------------------------------------------
+   */
+
+  typedef int (*CVBandJacFn)(long int N, long int mupper, long int mlower,
+                             BandMat J, realtype t,
+                             N_Vector y, N_Vector fy, void *jac_data,
+                             N_Vector tmp1, N_Vector tmp2, N_Vector tmp3);
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : CVBand
+   * -----------------------------------------------------------------
+   * A call to the CVBand function links the main CVODE integrator
+   * with the CVBAND linear solver.
+   *
+   * cvode_mem is the pointer to the integrator memory returned by
+   *           CVodeCreate.
+   *
+   * N is the size of the ODE system.
+   *
+   * mupper is the upper bandwidth of the band Jacobian
+   *        approximation.
+   *
+   * mlower is the lower bandwidth of the band Jacobian
+   *        approximation.
+   *
+   * The return value of CVBand is one of:
+   *    CVBAND_SUCCESS   if successful
+   *    CVBAND_MEM_NULL  if the cvode memory was NULL
+   *    CVBAND_MEM_FAIL  if there was a memory allocation failure
+   *    CVBAND_ILL_INPUT if a required vector operation is missing or
+   *                     if a bandwidth has an illegal value.
+   * -----------------------------------------------------------------
+   */
+
+  int CVBand(void *cvode_mem, long int N,
+             long int mupper, long int mlower);
+
+  /*
+   * -----------------------------------------------------------------
+   * Optional inputs to the CVBAND linear solver
+   * -----------------------------------------------------------------
+   *
+   * CVBandSetJacFn specifies the band Jacobian approximation
+   *                routine to be used. A user-supplied bjac routine
+   *                must be of type CVBandJacFn. By default, a difference
+   *                quotient routine CVBandDQJac, supplied with this
+   *                solver is used.
+   *                It also specifies a pointer to user data which is
+   *                passed to the bjac routine every time it is called.
+   *
+   * The return value of CVBandSet* is one of:
+   *    CVBAND_SUCCESS   if successful
+   *    CVBAND_MEM_NULL  if the cvode memory was NULL
+   *    CVBAND_LMEM_NULL if the cvband memory was NULL
+   * -----------------------------------------------------------------
+   */
+
+  int CVBandSetJacFn(void *cvode_mem, CVBandJacFn bjac, void *jac_data);
+
+  /*
+   * -----------------------------------------------------------------
+   * Optional outputs from the CVBAND linear solver
+   * -----------------------------------------------------------------
+   *
+   * CVBandGetWorkSpace returns the real and integer workspace used
+   *                    by CVBAND.
+   * CVBandGetNumJacEvals returns the number of calls made to the
+   *                      Jacobian evaluation routine bjac.
+   * CVBandGetNumRhsEvals returns the number of calls to the user
+   *                      f routine due to finite difference Jacobian
+   *                      evaluation.
+   * CVBandGetLastFlag returns the last error flag set by any of
+   *                   the CVBAND interface functions.
+   *
+   * The return value of CVBandGet* is one of:
+   *    CVBAND_SUCCESS   if successful
+   *    CVBAND_MEM_NULL  if the cvode memory was NULL
+   *    CVBAND_LMEM_NULL if the cvband memory was NULL
+   * -----------------------------------------------------------------
+   */
+
+  int CVBandGetWorkSpace(void *cvode_mem, long int *lenrwLS, long int *leniwLS);
+  int CVBandGetNumJacEvals(void *cvode_mem, long int *njevals);
+  int CVBandGetNumRhsEvals(void *cvode_mem, long int *nfevalsLS);
+  int CVBandGetLastFlag(void *cvode_mem, int *flag);
+
+  /*
+   * -----------------------------------------------------------------
+   * The following function returns the name of the constant 
+   * associated with a CVBAND return flag
+   * -----------------------------------------------------------------
+   */
+
+  char *CVBandGetReturnFlagName(int flag);
+
+  /* 
+   * -----------------------------------------------------------------
+   * PART II - backward problems
+   * -----------------------------------------------------------------
+   */
+
+  /*
+   * -----------------------------------------------------------------
+   * Type : CVBandJacFnB
+   * -----------------------------------------------------------------
+   * A band Jacobian approximation function JacB for the adjoint 
+   * (backward) problem must have the prototype given below. 
+   * -----------------------------------------------------------------
+   */
+
+  typedef int (*CVBandJacFnB)(long int nB, long int mupperB,
+                              long int mlowerB, BandMat JB,
+                              realtype t, N_Vector y,
+                              N_Vector yB, N_Vector fyB,
+                              void *jac_dataB, N_Vector tmp1B,
+                              N_Vector tmp2B, N_Vector tmp3B);
+  
+  /*
+   * -----------------------------------------------------------------
+   * Functions: CVBandB, CVBandSet*B
+   * -----------------------------------------------------------------
+   * CVBandB links the main CVODE integrator with the CVBAND
+   * linear solver for the backward integration.
+   * -----------------------------------------------------------------
+   */
+
+  int CVBandB(void *cvadj_mem, long int nB,
+              long int mupperB, long int mlowerB);
+  
+  int CVBandSetJacFnB(void *cvadj_mem, CVBandJacFnB bjacB, void *jac_dataB);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/cvodes/cvodes_bandpre.h b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/cvodes/cvodes_bandpre.h
new file mode 100644
index 0000000000000000000000000000000000000000..d69a6f1502dcf465c239fd1fb9629db30e7eb5de
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/cvodes/cvodes_bandpre.h	
@@ -0,0 +1,300 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * ----------------------------------------------------------------- 
+ * Programmer(s): Radu Serban @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2005, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This is the header file for the CVBANDPRE module, which
+ * provides a banded difference quotient Jacobian-based
+ * preconditioner and solver routines for use with CVSPGMR,
+ * CVSPBCG, or CVSPTFQMR.
+ *
+ *
+ * Part I contains type definitions and function prototypes for using
+ * CVBANDPRE on forward problems (IVP integration and/or FSA)
+ *
+ * Part II contains type definitions and function prototypes for using
+ * CVBANDPRE on adjopint (backward) problems
+ * -----------------------------------------------------------------
+ */
+
+#ifndef _CVSBANDPRE_H
+#define _CVSBANDPRE_H
+
+#ifdef __cplusplus  /* wrapper to enable C++ usage */
+extern "C" {
+#endif
+
+  /* CVBANDPRE return values */
+
+#define CVBANDPRE_SUCCESS           0
+#define CVBANDPRE_PDATA_NULL      -11
+#define CVBANDPRE_RHSFUNC_UNRECVR -12
+
+#define CVBANDPRE_ADJMEM_NULL     -111
+#define CVBANDPRE_MEM_FAIL        -112
+
+#include <sundials/sundials_nvector.h>
+
+  /* 
+   * -----------------------------------------------------------------
+   * PART I - forward problems
+   * -----------------------------------------------------------------
+   *
+   * Summary:
+   * These routines provide a band matrix preconditioner based on
+   * difference quotients of the ODE right-hand side function f.
+   * The user supplies parameters
+   *   mu = upper half-bandwidth (number of super-diagonals)
+   *   ml = lower half-bandwidth (number of sub-diagonals)
+   * The routines generate a band matrix of bandwidth ml + mu + 1
+   * and use this to form a preconditioner for use with the Krylov
+   * linear solver in CVSP*. Although this matrix is intended to
+   * approximate the Jacobian df/dy, it may be a very crude
+   * approximation. The true Jacobian need not be banded, or its
+   * true bandwith may be larger than ml + mu + 1, as long as the
+   * banded approximation generated here is sufficiently accurate
+   * to speed convergence as a preconditioner.
+   *
+   * Usage:
+   *   The following is a summary of the usage of this module.
+   *   Details of the calls to CVodeCreate, CVodeMalloc, CVSp*,
+   *   and CVode are available in the User Guide.
+   *   To use these routines, the sequence of calls in the user
+   *   main program should be as follows:
+   *
+   *   #include <cvodes/cvodes_bandpre.h>
+   *   #include <nvector_serial.h>
+   *   ...
+   *   void *bp_data;
+   *   ...
+   *   Set y0
+   *   ...
+   *   cvode_mem = CVodeCreate(...);
+   *   ier = CVodeMalloc(...);
+   *   ...
+   *   bp_data = CVBandPrecAlloc(cvode_mem, N, mu, ml);
+   *   ...
+   *   flag = CVBPSptfqmr(cvode_mem, pretype, maxl, bp_data);
+   *     -or-
+   *   flag = CVBPSpgmr(cvode_mem, pretype, maxl, bp_data);
+   *     -or-
+   *   flag = CVBPSpbcg(cvode_mem, pretype, maxl, bp_data);
+   *   ...
+   *   flag = CVode(...);
+   *   ...
+   *   CVBandPrecFree(&bp_data);
+   *   ...
+   *   Free y0
+   *   ...
+   *   CVodeFree(cvode_mem);
+   *
+   * Notes:
+   * (1) Include this file for the CVBandPrecData type definition.
+   * (2) In the CVBandPrecAlloc call, the arguments N is the same
+   *     as in the call to CVodeMalloc.
+   * (3) In the CVBPSp* call, the user is free to specify
+   *     the input pretype and the optional input maxl. The last
+   *     argument must be the pointer returned by CVBandPrecAlloc.
+   * -----------------------------------------------------------------
+   */
+
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : CVBandPrecAlloc
+   * -----------------------------------------------------------------
+   * CVBandPrecAlloc allocates and initializes a CVBandPrecData
+   * structure to be passed to CVSp* (and subsequently used
+   * by CVBandPrecSetup and CVBandPrecSolve).
+   *
+   * The parameters of CVBandPrecAlloc are as follows:
+   *
+   * cvode_mem is the pointer to CVODE memory returned by CVodeCreate.
+   *
+   * N is the problem size.
+   *
+   * mu is the upper half bandwidth.
+   *
+   * ml is the lower half bandwidth.
+   *
+   * CVBandPrecAlloc returns the storage pointer of type
+   * CVBandPrecData, or NULL if the request for storage cannot be
+   * satisfied.
+   *
+   * NOTE: The band preconditioner assumes a serial implementation
+   *       of the NVECTOR package. Therefore, CVBandPrecAlloc will
+   *       first test for a compatible N_Vector internal
+   *       representation by checking for required functions.
+   * -----------------------------------------------------------------
+   */
+
+  void *CVBandPrecAlloc(void *cvode_mem, long int N,
+                        long int mu, long int ml);
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : CVBPSptfqmr
+   * -----------------------------------------------------------------
+   * CVBPSptfqmr links the CVBANDPPRE preconditioner to the CVSPTFQMR
+   * linear solver. It performs the following actions:
+   *  1) Calls the CVSPTFQMR specification routine and attaches the
+   *     CVSPTFQMR linear solver to the integrator memory;
+   *  2) Sets the preconditioner data structure for CVSPTFQMR
+   *  3) Sets the preconditioner setup routine for CVSPTFQMR
+   *  4) Sets the preconditioner solve routine for CVSPTFQMR
+   *
+   * Its first 3 arguments are the same as for CVSptfqmr (see
+   * cvsptfqmr.h). The last argument is the pointer to the CVBANDPPRE
+   * memory block returned by CVBandPrecAlloc. Note that the user need
+   * not call CVSptfqmr.
+   *
+   * Possible return values are:
+   *    CVSPILS_SUCCESS      if successful
+   *    CVSPILS_MEM_NULL     if the cvode memory was NULL
+   *    CVSPILS_LMEM_NULL    if the cvsptfqmr memory was NULL
+   *    CVSPILS_MEM_FAIL     if there was a memory allocation failure
+   *    CVSPILS_ILL_INPUT    if a required vector operation is missing
+   *    CVBANDPRE_PDATA_NULL if the bp_data was NULL
+   * -----------------------------------------------------------------
+   */
+
+  int CVBPSptfqmr(void *cvode_mem, int pretype, int maxl, void *p_data);
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : CVBPSpbcg
+   * -----------------------------------------------------------------
+   * CVBPSpbcg links the CVBANDPPRE preconditioner to the CVSPBCG
+   * linear solver. It performs the following actions:
+   *  1) Calls the CVSPBCG specification routine and attaches the
+   *     CVSPBCG linear solver to the integrator memory;
+   *  2) Sets the preconditioner data structure for CVSPBCG
+   *  3) Sets the preconditioner setup routine for CVSPBCG
+   *  4) Sets the preconditioner solve routine for CVSPBCG
+   *
+   * Its first 3 arguments are the same as for CVSpbcg (see
+   * cvspbcgs.h). The last argument is the pointer to the CVBANDPPRE
+   * memory block returned by CVBandPrecAlloc. Note that the user need
+   * not call CVSpbcg.
+   *
+   * Possible return values are:
+   *    CVSPILS_SUCCESS       if successful
+   *    CVSPILS_MEM_NULL      if the cvode memory was NULL
+   *    CVSPILS_LMEM_NULL     if the cvspbcg memory was NULL
+   *    CVSPILS_MEM_FAIL      if there was a memory allocation failure
+   *    CVSPILS_ILL_INPUT     if a required vector operation is missing
+   *    CVBANDPRE_PDATA_NULL  if the bp_data was NULL
+   * -----------------------------------------------------------------
+   */
+
+  int CVBPSpbcg(void *cvode_mem, int pretype, int maxl, void *p_data);
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : CVBPSpgmr
+   * -----------------------------------------------------------------
+   * CVBPSpgmr links the CVBANDPPRE preconditioner to the CVSPGMR
+   * linear solver. It performs the following actions:
+   *  1) Calls the CVSPGMR specification routine and attaches the
+   *     CVSPGMR linear solver to the integrator memory;
+   *  2) Sets the preconditioner data structure for CVSPGMR
+   *  3) Sets the preconditioner setup routine for CVSPGMR
+   *  4) Sets the preconditioner solve routine for CVSPGMR
+   *
+   * Its first 3 arguments are the same as for CVSpgmr (see
+   * cvspgmr.h). The last argument is the pointer to the CVBANDPPRE
+   * memory block returned by CVBandPrecAlloc. Note that the user need
+   * not call CVSpgmr.
+   *
+   * Possible return values are:
+   *    CVSPILS_SUCCESS       if successful
+   *    CVSPILS_MEM_NULL      if the cvode memory was NULL
+   *    CVSPILS_LMEM_NULL     if the cvspgmr memory was NULL
+   *    CVSPILS_MEM_FAIL      if there was a memory allocation failure
+   *    CVSPILS_ILL_INPUT     if a required vector operation is missing
+   *    CVBANDPRE_PDATA_NULL  if the bp_data was NULL
+   * -----------------------------------------------------------------
+   */
+
+  int CVBPSpgmr(void *cvode_mem, int pretype, int maxl, void *p_data);
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : CVBandPrecFree
+   * -----------------------------------------------------------------
+   * CVBandPrecFree frees the memory allocated by CVBandPrecAlloc
+   * in the argument bp_data.
+   * -----------------------------------------------------------------
+   */
+
+  void CVBandPrecFree(void **bp_data);
+
+  /*
+   * -----------------------------------------------------------------
+   * Optional output functions : CVBandPrecGet*
+   * -----------------------------------------------------------------
+   * CVBandPrecGetWorkSpace returns the real and integer work space used
+   *                        by CVBANDPRE.
+   * CVBandPrecGetNumRhsEvals returns the number of calls made from
+   *                          CVBANDPRE to the user's right-hand side
+   *                          routine f.
+   *
+   * The return value of CVBandPrecGet* is one of:
+   *    CVBANDPRE_SUCCESS    if successful
+   *    CVBANDPRE_PDATA_NULL if the bp_data memory was NULL
+   * -----------------------------------------------------------------
+   */
+
+  int CVBandPrecGetWorkSpace(void *bp_data, long int *lenrwLS, long int *leniwLS);
+  int CVBandPrecGetNumRhsEvals(void *bp_data, long int *nfevalsBP);
+
+  /*
+   * -----------------------------------------------------------------
+   * The following function returns the name of the constant 
+   * associated with a CVBANDPRE return flag
+   * -----------------------------------------------------------------
+   */
+  
+  char *CVBandPrecGetReturnFlagName(int flag);
+
+  /* 
+   * -----------------------------------------------------------------
+   * PART II - backward problems
+   * -----------------------------------------------------------------
+   */
+
+  /*
+   * -----------------------------------------------------------------
+   * Functions: CVBandPrecAllocB, CVBPSp*B
+   * -----------------------------------------------------------------
+   * Interface functions for the CVBANDPRE preconditioner to be used
+   * on the backward phase.
+   *
+   * CVBandPrecAllocB interfaces to the CVBANDPRE preconditioner
+   * for the backward integration. The pointer to the structure
+   * returned by this routine should then be used in the call to
+   * CVBPSp*B which interfaces to CVBPSPGMR/CVBPSPBCG/CVSPTFQMR.
+   * -----------------------------------------------------------------
+   */
+
+  int CVBandPrecAllocB(void *cvadj_mem, long int nB,
+                       long int muB, long int mlB);
+
+  int CVBPSptfqmrB(void *cvadj_mem, int pretypeB, int maxlB);
+  int CVBPSpbcgB(void *cvadj_mem, int pretypeB, int maxlB);
+  int CVBPSpgmrB(void *cvadj_mem, int pretypeB, int maxlB);
+
+  void CVBandPrecFreeB(void *cvadj_mem);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/cvodes/cvodes_bbdpre.h b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/cvodes/cvodes_bbdpre.h
new file mode 100644
index 0000000000000000000000000000000000000000..042281ec76fed636d0b3caffd96e6aef93b5740f
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/cvodes/cvodes_bbdpre.h	
@@ -0,0 +1,448 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * ----------------------------------------------------------------- 
+ * Programmer(s): Radu Serban @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2005, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This is the header file for the CVBBDPRE module, for a
+ * band-block-diagonal preconditioner, i.e. a block-diagonal
+ * matrix with banded blocks, for use with CVSPGMR/CVSPBCG/CVSPTFQMR, 
+ * and the parallel implementation of the NVECTOR module.
+ *
+ *
+ * Part I contains type definitions and function prototypes for using
+ * CVBBDPRE on forward problems (IVP integration and/or FSA)
+ *
+ * Part II contains type definitions and function prototypes for using
+ * CVBBDPRE on adjopint (backward) problems
+ * -----------------------------------------------------------------
+ */
+
+#ifndef _CVSBBDPRE_H
+#define _CVSBBDPRE_H
+
+#ifdef __cplusplus  /* wrapper to enable C++ usage */
+extern "C" {
+#endif
+
+#include <sundials/sundials_nvector.h>
+
+  /* CVBBDPRE return values */
+
+#define CVBBDPRE_SUCCESS            0
+#define CVBBDPRE_PDATA_NULL       -11
+#define CVBBDPRE_FUNC_UNRECVR     -12
+
+#define CVBBDPRE_ADJMEM_NULL      -111
+#define CVBBDPRE_PDATAB_NULL      -112
+#define CVBBDPRE_MEM_FAIL         -113
+
+
+  /* 
+   * -----------------------------------------------------------------
+   * PART I - forward problems
+   * -----------------------------------------------------------------
+   *
+   * Summary:
+   *
+   * These routines provide a preconditioner matrix that is
+   * block-diagonal with banded blocks. The blocking corresponds
+   * to the distribution of the dependent variable vector y among
+   * the processors. Each preconditioner block is generated from
+   * the Jacobian of the local part (on the current processor) of a
+   * given function g(t,y) approximating f(t,y). The blocks are
+   * generated by a difference quotient scheme on each processor
+   * independently. This scheme utilizes an assumed banded
+   * structure with given half-bandwidths, mudq and mldq.
+   * However, the banded Jacobian block kept by the scheme has
+   * half-bandwiths mukeep and mlkeep, which may be smaller.
+   *
+   * The user's calling program should have the following form:
+   *
+   *   #include <cvodes/cvodes_bbdpre.h>
+   *   #include <nvector_parallel.h>
+   *   ...
+   *   void *cvode_mem;
+   *   void *bbd_data;
+   *   ...
+   *   Set y0
+   *   ...
+   *   cvode_mem = CVodeCreate(...);
+   *   ier = CVodeMalloc(...);
+   *   ...
+   *   bbd_data = CVBBDPrecAlloc(cvode_mem, Nlocal, mudq ,mldq,
+   *                             mukeep, mlkeep, dqrely, gloc, cfn);
+   *   flag = CVBBDSpgmr(cvode_mem, pretype, maxl, bbd_data);
+   *      -or-
+   *   flag = CVBBDSpbcg(cvode_mem, pretype, maxl, bbd_data);
+   *      -or-
+   *   flag = CVBBDSptfqmr(cvode_mem, pretype, maxl, bbd_data);
+   *   ...
+   *   ier = CVode(...);
+   *   ...
+   *   CVBBDPrecFree(&bbd_data);
+   *   ...                                                           
+   *   CVodeFree(...);
+   * 
+   *   Free y0
+   *
+   * The user-supplied routines required are:
+   *
+   *   f    = function defining the ODE right-hand side f(t,y).
+   *
+   *   gloc = function defining the approximation g(t,y).
+   *
+   *   cfn  = function to perform communication need for gloc.
+   *
+   * Notes:
+   *
+   * 1) This header file is included by the user for the definition
+   *    of the CVBBDData type and for needed function prototypes.
+   *
+   * 2) The CVBBDPrecAlloc call includes half-bandwiths mudq and mldq
+   *    to be used in the difference quotient calculation of the
+   *    approximate Jacobian. They need not be the true
+   *    half-bandwidths of the Jacobian of the local block of g,
+   *    when smaller values may provide a greater efficiency.
+   *    Also, the half-bandwidths mukeep and mlkeep of the retained
+   *    banded approximate Jacobian block may be even smaller,
+   *    to reduce storage and computation costs further.
+   *    For all four half-bandwidths, the values need not be the
+   *    same on every processor.
+   *
+   * 3) The actual name of the user's f function is passed to
+   *    CVodeMalloc, and the names of the user's gloc and cfn
+   *    functions are passed to CVBBDPrecAlloc.
+   *
+   * 4) The pointer to the user-defined data block f_data, which is
+   *    set through CVodeSetFdata is also available to the user in
+   *    gloc and cfn.
+   *
+   * 5) For the CVSpgmr solver, the Gram-Schmidt type gstype,
+   *    is left to the user to specify through CVSpgmrSetGStype.
+   *
+   * 6) Optional outputs specific to this module are available by
+   *    way of routines listed below. These include work space sizes
+   *    and the cumulative number of gloc calls. The costs
+   *    associated with this module also include nsetups banded LU
+   *    factorizations, nlinsetups cfn calls, and npsolves banded
+   *    backsolve calls, where nlinsetups and npsolves are
+   *    integrator/CVSPGMR/CVSPBCG/CVSPTFQMR optional outputs.
+   * -----------------------------------------------------------------
+   */
+
+  /*
+   * -----------------------------------------------------------------
+   * Type : CVLocalFn
+   * -----------------------------------------------------------------
+   * The user must supply a function g(t,y) which approximates the
+   * right-hand side function f for the system y'=f(t,y), and which
+   * is computed locally (without interprocess communication).
+   * (The case where g is mathematically identical to f is allowed.)
+   * The implementation of this function must have type CVLocalFn.
+   *
+   * This function takes as input the local vector size Nlocal, the
+   * independent variable value t, the local real dependent
+   * variable vector y, and a pointer to the user-defined data
+   * block f_data. It is to compute the local part of g(t,y) and
+   * store this in the vector g.
+   * (Allocation of memory for y and g is handled within the
+   * preconditioner module.)
+   * The f_data parameter is the same as that specified by the user
+   * through the CVodeSetFdata routine.
+   *
+   * A CVLocalFn should return 0 if successful, a positive value if 
+   * a recoverable error occurred, and a negative value if an 
+   * unrecoverable error occurred.
+   * -----------------------------------------------------------------
+   */
+
+  typedef int (*CVLocalFn)(long int Nlocal, realtype t, N_Vector y,
+                           N_Vector g, void *f_data);
+
+  /*
+   * -----------------------------------------------------------------
+   * Type : CVCommFn
+   * -----------------------------------------------------------------
+   * The user may supply a function of type CVCommFn which performs
+   * all interprocess communication necessary to evaluate the
+   * approximate right-hand side function described above.
+   *
+   * This function takes as input the local vector size Nlocal,
+   * the independent variable value t, the dependent variable
+   * vector y, and a pointer to the user-defined data block f_data.
+   * The f_data parameter is the same as that specified by the user
+   * through the CVodeSetFdata routine. The CVCommFn cfn is
+   * expected to save communicated data in space defined within the
+   * structure f_data. Note: A CVCommFn cfn does not have a return value.
+   *
+   * Each call to the CVCommFn cfn is preceded by a call to the
+   * CVRhsFn f with the same (t,y) arguments. Thus cfn can omit any
+   * communications done by f if relevant to the evaluation of g.
+   * If all necessary communication was done by f, the user can
+   * pass NULL for cfn in CVBBDPrecAlloc (see below).
+   *
+   * A CVCommFn should return 0 if successful, a positive value if 
+   * a recoverable error occurred, and a negative value if an 
+   * unrecoverable error occurred.
+   * -----------------------------------------------------------------
+   */
+
+  typedef int (*CVCommFn)(long int Nlocal, realtype t, N_Vector y,
+                          void *f_data);
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : CVBBDPrecAlloc
+   * -----------------------------------------------------------------
+   * CVBBDPrecAlloc allocates and initializes a CVBBDData structure
+   * to be passed to CVSp* (and used by CVBBDPrecSetup and
+   * CVBBDPrecSolve).
+   *
+   * The parameters of CVBBDPrecAlloc are as follows:
+   *
+   * cvode_mem is the pointer to the integrator memory.
+   *
+   * Nlocal is the length of the local block of the vectors y etc.
+   *        on the current processor.
+   *
+   * mudq, mldq are the upper and lower half-bandwidths to be used
+   *            in the difference quotient computation of the local
+   *            Jacobian block.
+   *
+   * mukeep, mlkeep are the upper and lower half-bandwidths of the
+   *                retained banded approximation to the local Jacobian
+   *                block.
+   *
+   * dqrely is an optional input. It is the relative increment
+   *        in components of y used in the difference quotient
+   *        approximations. To specify the default, pass 0.
+   *        The default is dqrely = sqrt(unit roundoff).
+   *
+   * gloc is the name of the user-supplied function g(t,y) that
+   *      approximates f and whose local Jacobian blocks are
+   *      to form the preconditioner.
+   *
+   * cfn is the name of the user-defined function that performs
+   *     necessary interprocess communication for the
+   *     execution of gloc.
+   *
+   * CVBBDPrecAlloc returns the storage allocated (type *void),
+   * or NULL if the request for storage cannot be satisfied.
+   * -----------------------------------------------------------------
+   */
+
+  void *CVBBDPrecAlloc(void *cvode_mem, long int Nlocal, 
+                       long int mudq, long int mldq, 
+                       long int mukeep, long int mlkeep, 
+                       realtype dqrely,
+                       CVLocalFn gloc, CVCommFn cfn);
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : CVBBDSptfqmr
+   * -----------------------------------------------------------------
+   * CVBBDSptfqmr links the CVBBDPRE preconditioner to the CVSPTFQMR
+   * linear solver. It performs the following actions:
+   *  1) Calls the CVSPTFQMR specification routine and attaches the
+   *     CVSPTFQMR linear solver to the integrator memory;
+   *  2) Sets the preconditioner data structure for CVSPTFQMR
+   *  3) Sets the preconditioner setup routine for CVSPTFQMR
+   *  4) Sets the preconditioner solve routine for CVSPTFQMR
+   *
+   * Its first 3 arguments are the same as for CVSptfqmr (see
+   * cvsptfqmr.h). The last argument is the pointer to the CVBBDPRE
+   * memory block returned by CVBBDPrecAlloc. Note that the user need
+   * not call CVSptfqmr.
+   *
+   * Possible return values are:
+   *    CVSPILS_SUCCESS     if successful
+   *    CVSPILS_MEM_NULL    if the cvode memory was NULL
+   *    CVSPILS_LMEM_NULL   if the cvspbcg memory was NULL
+   *    CVSPILS_MEM_FAIL    if there was a memory allocation failure
+   *    CVSPILS_ILL_INPUT   if a required vector operation is missing
+   *    CVBBDPRE_PDATA_NULL if the bbd_data was NULL
+   * -----------------------------------------------------------------
+   */
+
+  int CVBBDSptfqmr(void *cvode_mem, int pretype, int maxl, void *bbd_data);
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : CVBBDSpbcg
+   * -----------------------------------------------------------------
+   * CVBBDSpbcg links the CVBBDPRE preconditioner to the CVSPBCG
+   * linear solver. It performs the following actions:
+   *  1) Calls the CVSPBCG specification routine and attaches the
+   *     CVSPBCG linear solver to the integrator memory;
+   *  2) Sets the preconditioner data structure for CVSPBCG
+   *  3) Sets the preconditioner setup routine for CVSPBCG
+   *  4) Sets the preconditioner solve routine for CVSPBCG
+   *
+   * Its first 3 arguments are the same as for CVSpbcg (see
+   * cvspbcgs.h). The last argument is the pointer to the CVBBDPRE
+   * memory block returned by CVBBDPrecAlloc. Note that the user need
+   * not call CVSpbcg.
+   *
+   * Possible return values are:
+   *    CVSPILS_SUCCESS      if successful
+   *    CVSPILS_MEM_NULL     if the cvode memory was NULL
+   *    CVSPILS_LMEM_NULL    if the cvspbcg memory was NULL
+   *    CVSPILS_MEM_FAIL     if there was a memory allocation failure
+   *    CVSPILS_ILL_INPUT    if a required vector operation is missing
+   *    CVBBDPRE_PDATA_NULL  if the bbd_data was NULL
+   * -----------------------------------------------------------------
+   */
+
+  int CVBBDSpbcg(void *cvode_mem, int pretype, int maxl, void *bbd_data);
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : CVBBDSpgmr
+   * -----------------------------------------------------------------
+   * CVBBDSpgmr links the CVBBDPRE preconditioner to the CVSPGMR
+   * linear solver. It performs the following actions:
+   *  1) Calls the CVSPGMR specification routine and attaches the
+   *     CVSPGMR linear solver to the integrator memory;
+   *  2) Sets the preconditioner data structure for CVSPGMR
+   *  3) Sets the preconditioner setup routine for CVSPGMR
+   *  4) Sets the preconditioner solve routine for CVSPGMR
+   *
+   * Its first 3 arguments are the same as for CVSpgmr (see
+   * cvspgmr.h). The last argument is the pointer to the CVBBDPRE
+   * memory block returned by CVBBDPrecAlloc. Note that the user need
+   * not call CVSpgmr.
+   *
+   * Possible return values are:
+   *    CVSPILS_SUCCESS      if successful
+   *    CVSPILS_MEM_NULL     if the cvode memory was NULL
+   *    CVSPILS_LMEM_NULL    if the cvspgmr memory was NULL
+   *    CVSPILS_MEM_FAIL     if there was a memory allocation failure
+   *    CVSPILS_ILL_INPUT    if a required vector operation is missing
+   *    CVBBDPRE_PDATA_NULL  if the bbd_data was NULL
+   * -----------------------------------------------------------------
+   */
+
+  int CVBBDSpgmr(void *cvode_mem, int pretype, int maxl, void *bbd_data);
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : CVBBDPrecReInit
+   * -----------------------------------------------------------------
+   * CVBBDPrecReInit re-initializes the BBDPRE module when solving a
+   * sequence of problems of the same size with CVSPGMR/CVBBDPRE,
+   * CVSPBCG/CVBBDPRE, or CVSPTFQMR/CVBBDPRE provided there is no change 
+   * in Nlocal, mukeep, or mlkeep. After solving one problem, and after 
+   * calling CVodeReInit to re-initialize the integrator for a subsequent 
+   * problem, call CVBBDPrecReInit. Then call CVSpgmrSet*, CVSpbcgSet*,
+   * or CVSptfqmrSet*  functions if necessary for any changes to CVSPGMR,
+   * CVSPBCG, or CVSPTFQMR parameters, before calling CVode.
+   *
+   * The first argument to CVBBDPrecReInit must be the pointer pdata
+   * that was returned by CVBBDPrecAlloc. All other arguments have
+   * the same names and meanings as those of CVBBDPrecAlloc.
+   *
+   * The return value of CVBBDPrecReInit is CVBBDPRE_SUCCESS, indicating
+   * success, or CVBBDPRE_PDATA_NULL if bbd_data was NULL.
+   * -----------------------------------------------------------------
+   */
+
+  int CVBBDPrecReInit(void *bbd_data, long int mudq, long int mldq,
+                      realtype dqrely, CVLocalFn gloc, CVCommFn cfn);
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : CVBBDPrecFree
+   * -----------------------------------------------------------------
+   * CVBBDPrecFree frees the memory block bbd_data allocated by the
+   * call to CVBBDAlloc.
+   * -----------------------------------------------------------------
+   */
+
+  void CVBBDPrecFree(void **bbd_data);
+
+  /*
+   * -----------------------------------------------------------------
+   * BBDPRE optional output extraction routines
+   * -----------------------------------------------------------------
+   * CVBBDPrecGetWorkSpace returns the BBDPRE real and integer work space
+   *                       sizes.
+   * CVBBDPrecGetNumGfnEvals returns the number of calls to gfn.
+   *
+   * The return value of CVBBDPrecGet* is one of:
+   *    CVBBDPRE_SUCCESS    if successful
+   *    CVBBDPRE_PDATA_NULL if the bbd_data memory was NULL
+   * -----------------------------------------------------------------
+   */
+
+  int CVBBDPrecGetWorkSpace(void *bbd_data, long int *lenrwBBDP, 
+                            long int *leniwBBDP);
+  int CVBBDPrecGetNumGfnEvals(void *bbd_data, long int *ngevalsBBDP);
+
+  /*
+   * -----------------------------------------------------------------
+   * The following function returns the name of the constant 
+   * associated with a CVBBDPRE return flag
+   * -----------------------------------------------------------------
+   */
+  
+  char *CVBBDPrecGetReturnFlagName(int flag);
+
+  /* 
+   * -----------------------------------------------------------------
+   * PART II - backward problems
+   * -----------------------------------------------------------------
+   */
+
+  /*
+   * -----------------------------------------------------------------
+   * Types: CVLocalFnB and CVCommFnB
+   * -----------------------------------------------------------------
+   * Local approximation function and inter-process communication
+   * function for the BBD preconditioner on the backward phase.
+   * -----------------------------------------------------------------
+   */
+
+  typedef int (*CVLocalFnB)(long int NlocalB, realtype t,
+                            N_Vector y, N_Vector yB, N_Vector gB,
+                            void *f_dataB);
+  
+  typedef int (*CVCommFnB)(long int NlocalB, realtype t,
+                           N_Vector y, N_Vector yB,
+                           void *f_dataB);
+
+  /*
+   * -----------------------------------------------------------------
+   * Functions: CVBBDPrecAllocB, CVBBDSp*B, CVBBDPrecReInit
+   * -----------------------------------------------------------------
+   * Interface functions for the CVBBDPRE preconditioner to be used on
+   * the backward phase.
+   * -----------------------------------------------------------------
+   */
+
+  int CVBBDPrecAllocB(void *cvadj_mem, long int NlocalB,
+                      long int mudqB, long int mldqB,
+                      long int mukeepB, long int mlkeepB,
+                      realtype dqrelyB,
+                      CVLocalFnB glocB, CVCommFnB cfnB);
+
+  int CVBBDSptfqmrB(void *cvadj_mem, int pretypeB, int maxlB);
+  int CVBBDSpbcgB(void *cvadj_mem, int pretypeB, int maxlB);
+  int CVBBDSpgmrB(void *cvadj_mem, int pretypeB, int maxlB);
+  
+  int CVBBDPrecReInitB(void *cvadj_mem, long int mudqB, long int mldqB,
+                       realtype dqrelyB, CVLocalFnB glocB, CVCommFnB cfnB);
+
+  void CVBBDPrecFreeB(void *cvadj_mem);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/cvodes/cvodes_dense.h b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/cvodes/cvodes_dense.h
new file mode 100644
index 0000000000000000000000000000000000000000..7a4bb85e3d90b1c64a9664c9e58a8667e7067410
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/cvodes/cvodes_dense.h	
@@ -0,0 +1,261 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * ----------------------------------------------------------------- 
+ * Programmer(s): Radu Serban @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2005, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This is the header file for the CVODES dense linear solver, CVDENSE.
+ *
+ *
+ * Part I contains type definitions and function prototypes for using
+ * CVDENSE on forward problems (IVP integration and/or FSA)
+ *
+ * Part II contains type definitions and function prototypes for using
+ * CVDENSE on adjoint (backward) problems
+ * -----------------------------------------------------------------
+ */
+
+#ifndef _CVSDENSE_H
+#define _CVSDENSE_H
+
+#ifdef __cplusplus  /* wrapper to enable C++ usage */
+extern "C" {
+#endif
+
+#include <sundials/sundials_dense.h>
+#include <sundials/sundials_nvector.h>
+
+  /*
+   * -----------------------------------------------------------------
+   * CVDENSE solver constants
+   * -----------------------------------------------------------------
+   * CVD_MSBJ : maximum number of steps between dense Jacobian
+   *            evaluations
+   *
+   * CVD_DGMAX : maximum change in gamma between dense Jacobian
+   *             evaluations
+   * -----------------------------------------------------------------
+   */
+
+#define CVD_MSBJ  50
+#define CVD_DGMAX RCONST(0.2)
+
+  /*
+   * -----------------------------------------------------------------
+   * CVDENSE return values
+   * -----------------------------------------------------------------
+   */
+
+#define CVDENSE_SUCCESS           0
+#define CVDENSE_MEM_NULL         -1
+#define CVDENSE_LMEM_NULL        -2
+#define CVDENSE_ILL_INPUT        -3
+#define CVDENSE_MEM_FAIL         -4
+
+  /* Additional last_flag values */
+
+#define CVDENSE_JACFUNC_UNRECVR  -5
+#define CVDENSE_JACFUNC_RECVR    -6
+
+  /* Return values for the adjoint module */
+
+#define CVDENSE_ADJMEM_NULL      -101
+#define CVDENSE_LMEMB_NULL       -102
+
+  /* 
+   * -----------------------------------------------------------------
+   * PART I - forward problems
+   * -----------------------------------------------------------------
+   */
+
+  /*
+   * -----------------------------------------------------------------
+   * Type : CVDenseJacFn
+   * -----------------------------------------------------------------
+   * A dense Jacobian approximation function Jac must have the
+   * prototype given below. Its parameters are:
+   *
+   * N is the problem size.
+   *
+   * J is the dense matrix (of type DenseMat) that will be loaded
+   * by a CVDenseJacFn with an approximation to the Jacobian matrix
+   * J = (df_i/dy_j) at the point (t,y).
+   * J is preset to zero, so only the nonzero elements need to be
+   * loaded. Two efficient ways to load J are:
+   *
+   * (1) (with macros - no explicit data structure references)
+   *     for (j=0; j < n; j++) {
+   *       col_j = DENSE_COL(J,j);
+   *       for (i=0; i < n; i++) {
+   *         generate J_ij = the (i,j)th Jacobian element
+   *         col_j[i] = J_ij;
+   *       }
+   *     }
+   *
+   * (2) (without macros - explicit data structure references)
+   *     for (j=0; j < n; j++) {
+   *       col_j = (J->data)[j];
+   *       for (i=0; i < n; i++) {
+   *         generate J_ij = the (i,j)th Jacobian element
+   *         col_j[i] = J_ij;
+   *       }
+   *     }
+   *
+   * The DENSE_ELEM(A,i,j) macro is appropriate for use in small
+   * problems in which efficiency of access is NOT a major concern.
+   *
+   * t is the current value of the independent variable.
+   *
+   * y is the current value of the dependent variable vector,
+   *   namely the predicted value of y(t).
+   *
+   * fy is the vector f(t,y).
+   *
+   * jac_data is a pointer to user data - the same as the jac_data
+   *          parameter passed to CVDense.
+   *
+   * NOTE: If the user's Jacobian routine needs other quantities,
+   *       they are accessible as follows: hcur (the current stepsize)
+   *       and ewt (the error weight vector) are accessible through
+   *       CVodeGetCurrentStep and CVodeGetErrWeights, respectively
+   *       (see cvode.h). The unit roundoff is available as
+   *       UNIT_ROUNDOFF defined in sundials_types.h.
+   *
+   * tmp1, tmp2, and tmp3 are pointers to memory allocated for
+   * vectors of length N which can be used by a CVDenseJacFn
+   * as temporary storage or work space.
+   *
+   * A CVDenseJacFn should return 0 if successful, a positive value if 
+   * a recoverable error occurred, and a negative value if an 
+   * unrecoverable error occurred.
+   * -----------------------------------------------------------------
+   */
+
+  typedef int (*CVDenseJacFn)(long int N, DenseMat J, realtype t,
+                              N_Vector y, N_Vector fy, void *jac_data,
+                              N_Vector tmp1, N_Vector tmp2, N_Vector tmp3);
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : CVDense
+   * -----------------------------------------------------------------
+   * A call to the CVDense function links the main integrator with
+   * the CVDENSE linear solver.
+   *
+   * cvode_mem is the pointer to the integrator memory returned by
+   *           CVodeCreate.
+   *
+   * N is the size of the ODE system.
+   *
+   * The return value of CVDense is one of:
+   *    CVDENSE_SUCCESS   if successful
+   *    CVDENSE_MEM_NULL  if the cvode memory was NULL
+   *    CVDENSE_MEM_FAIL  if there was a memory allocation failure
+   *    CVDENSE_ILL_INPUT if a required vector operation is missing
+   * -----------------------------------------------------------------
+   */
+
+  int CVDense(void *cvode_mem, long int N);
+
+  /*
+   * -----------------------------------------------------------------
+   * Optional inputs to the CVDENSE linear solver
+   * -----------------------------------------------------------------
+   *
+   * CVDenseSetJacFn specifies the dense Jacobian approximation
+   *                 routine to be used. A user-supplied djac routine
+   *                 must be of type CVDenseJacFn. By default, a
+   *                 difference quotient routine CVDenseDQJac, supplied
+   *                 with this solver is used.                     
+   *                 It also specifies a pointer to user data which is
+   *                 passed to the djac routine every time it is called.
+   *
+   * The return value of CVDenseSet* is one of:
+   *    CVDENSE_SUCCESS   if successful
+   *    CVDENSE_MEM_NULL  if the cvode memory was NULL
+   *    CVDENSE_LMEM_NULL if the cvdense memory was NULL
+   * -----------------------------------------------------------------
+   */
+
+  int CVDenseSetJacFn(void *cvode_mem, CVDenseJacFn djac, void *jac_data);
+
+  /*
+   * -----------------------------------------------------------------
+   * Optional outputs from the CVDENSE linear solver
+   * -----------------------------------------------------------------
+   *
+   * CVDenseGetWorkSpace returns the real and integer workspace used
+   *                     by CVDENSE.
+   * CVDenseGetNumJacEvals returns the number of calls made to the
+   *                       Jacobian evaluation routine djac.
+   * CVDenseGetNumRhsEvals returns the number of calls to the user
+   *                       f routine due to finite difference Jacobian
+   *                       evaluation.
+   * CVDenseGetLastFlag returns the last error flag set by any of
+   *                    the CVDENSE interface functions.
+   *
+   * The return value of CVDenseGet* is one of:
+   *    CVDENSE_SUCCESS   if successful
+   *    CVDENSE_MEM_NULL  if the cvode memory was NULL
+   *    CVDENSE_LMEM_NULL if the cvdense memory was NULL
+   * -----------------------------------------------------------------
+   */
+
+  int CVDenseGetWorkSpace(void *cvode_mem, long int *lenrwLS, long int *leniwLS);
+  int CVDenseGetNumJacEvals(void *cvode_mem, long int *njevals);
+  int CVDenseGetNumRhsEvals(void *cvode_mem, long int *nfevalsLS);
+  int CVDenseGetLastFlag(void *cvode_mem, int *flag);
+
+  /*
+   * -----------------------------------------------------------------
+   * The following function returns the name of the constant 
+   * associated with a CVDENSE return flag
+   * -----------------------------------------------------------------
+   */
+
+  char *CVDenseGetReturnFlagName(int flag);
+
+  /* 
+   * -----------------------------------------------------------------
+   * PART II - backward problems
+   * -----------------------------------------------------------------
+   */
+
+  /*
+   * -----------------------------------------------------------------
+   * Type: CVDenseJacFnB
+   * -----------------------------------------------------------------
+   * A dense Jacobian approximation function JacB for the adjoint
+   * (backward) problem must have the prototype given below. 
+   * -----------------------------------------------------------------
+   */
+
+  typedef int (*CVDenseJacFnB)(long int nB, DenseMat JB, realtype t,
+                               N_Vector y, N_Vector yB, N_Vector fyB,
+                               void *jac_dataB, N_Vector tmp1B,
+                               N_Vector tmp2B, N_Vector tmp3B);
+
+  /*
+   * -----------------------------------------------------------------
+   * Functions: CVDenseB, CVDenseSetJacFnB
+   * -----------------------------------------------------------------
+   * CVDenseB links the main CVODE integrator with the CVDENSE
+   * linear solver for the backward integration.
+   * -----------------------------------------------------------------
+   */
+
+  int CVDenseB(void *cvadj_mem, long int nB);
+  
+  int CVDenseSetJacFnB(void *cvadj_mem, CVDenseJacFnB djacB, void *jac_dataB);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/cvodes/cvodes_diag.h b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/cvodes/cvodes_diag.h
new file mode 100644
index 0000000000000000000000000000000000000000..527a5928d5a1013b6a174b524ab00036c0923639
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/cvodes/cvodes_diag.h	
@@ -0,0 +1,141 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * ----------------------------------------------------------------- 
+ * Programmer(s): Radu Serban @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2005, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This is the header file for the CVODES diagonal linear solver, 
+ * CVDIAG.
+ *
+ *
+ * Part I contains type definitions and function prototypes for using
+ * CVDIAG on forward problems (IVP integration and/or FSA)
+ *
+ * Part II contains type definitions and function prototypes for using
+ * CVDIAG on adjoint (backward) problems
+ * -----------------------------------------------------------------
+ */
+
+#ifndef _CVSDIAG_H
+#define _CVSDIAG_H
+
+#ifdef __cplusplus  /* wrapper to enable C++ usage */
+extern "C" {
+#endif
+
+#include <sundials/sundials_nvector.h>
+
+  /*
+   * -----------------------------------------------------------------
+   * CVDIAG return values
+   * -----------------------------------------------------------------
+   */
+
+#define CVDIAG_SUCCESS          0
+#define CVDIAG_MEM_NULL        -1
+#define CVDIAG_LMEM_NULL       -2
+#define CVDIAG_ILL_INPUT       -3
+#define CVDIAG_MEM_FAIL        -4
+
+  /* Additional last_flag values */
+
+#define CVDIAG_INV_FAIL        -5
+#define CVDIAG_RHSFUNC_UNRECVR -6
+#define CVDIAG_RHSFUNC_RECVR   -7
+
+  /* Return values for adjoint module */
+
+#define CVDIAG_ADJMEM_NULL     -101
+
+  /* 
+   * -----------------------------------------------------------------
+   * PART I - forward problems
+   * -----------------------------------------------------------------
+   */
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : CVDiag
+   * -----------------------------------------------------------------
+   * A call to the CVDiag function links the main integrator with
+   * the CVDIAG linear solver.
+   *
+   * cvode_mem is the pointer to the integrator memory returned by
+   *           CVodeCreate.
+   *
+   * The return value of CVDiag is one of:
+   *    CVDIAG_SUCCESS   if successful
+   *    CVDIAG_MEM_NULL  if the cvode memory was NULL
+   *    CVDIAG_MEM_FAIL  if there was a memory allocation failure
+   *    CVDIAG_ILL_INPUT if a required vector operation is missing
+   * -----------------------------------------------------------------
+   */
+
+  int CVDiag(void *cvode_mem);
+  
+  /*
+   * -----------------------------------------------------------------
+   * Optional outputs from the CVDIAG linear solver
+   * -----------------------------------------------------------------
+   *
+   * CVDiagGetWorkSpace returns the real and integer workspace used
+   *                    by CVDIAG.
+   * CVDiagGetNumRhsEvals returns the number of calls to the user
+   *                      f routine due to finite difference Jacobian
+   *                      evaluation.
+   *                      Note: The number of diagonal approximate
+   *                      Jacobians formed is equal to the number of
+   *                      CVDiagSetup calls. This number is available
+   *                      through CVodeGetNumLinSolvSetups.
+   * CVDiagGetLastFlag returns the last error flag set by any of
+   *                   the CVDIAG interface functions.
+   *
+   * The return value of CVDiagGet* is one of:
+   *    CVDIAG_SUCCESS   if successful
+   *    CVDIAG_MEM_NULL  if the cvode memory was NULL
+   *    CVDIAG_LMEM_NULL if the cvdiag memory was NULL
+   * -----------------------------------------------------------------
+   */
+
+  int CVDiagGetWorkSpace(void *cvode_mem, long int *lenrwLS, long int *leniwLS);
+  int CVDiagGetNumRhsEvals(void *cvode_mem, long int *nfevalsLS);
+  int CVDiagGetLastFlag(void *cvode_mem, int *flag);
+
+  /*
+   * -----------------------------------------------------------------
+   * The following function returns the name of the constant 
+   * associated with a CVDIAG return flag
+   * -----------------------------------------------------------------
+   */
+  
+  char *CVDiagGetReturnFlagName(int flag);
+
+  /* 
+   * -----------------------------------------------------------------
+   * PART II - backward problems
+   * -----------------------------------------------------------------
+   */
+
+  /*
+   * -----------------------------------------------------------------
+   * Function: CVDiagB
+   * -----------------------------------------------------------------
+   * CVDiagB links the main CVODE integrator with the CVDIAG
+   * linear solver for the backward integration.
+   * -----------------------------------------------------------------
+   */
+  
+  int CVDiagB(void *cvadj_mem);
+  
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/cvodes/cvodes_spbcgs.h b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/cvodes/cvodes_spbcgs.h
new file mode 100644
index 0000000000000000000000000000000000000000..b68d677d650356b8cb1f2debe0983c730ac77ed0
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/cvodes/cvodes_spbcgs.h	
@@ -0,0 +1,86 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * ----------------------------------------------------------------- 
+ * Programmer(s): Aaron Collier and Radu Serban @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2005, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This is the header file for the CVODES scaled preconditioned 
+ * Bi-CGSTAB linear solver, CVSPBCG.
+ *
+ * Part I contains function prototypes for using CVSPBCG on forward 
+ * problems (IVP integration and/or FSA)
+ *
+ * Part II contains function prototypes for using CVSPBCG on adjoint 
+ * (backward) problems
+ * -----------------------------------------------------------------
+ */
+
+#ifndef _CVSSPBCG_H
+#define _CVSSPBCG_H
+
+#ifdef __cplusplus  /* wrapper to enable C++ usage */
+extern "C" {
+#endif
+
+#include <cvodes/cvodes_spils.h>
+#include <sundials/sundials_spbcgs.h>
+
+  /* 
+   * -----------------------------------------------------------------
+   * PART I - forward problems
+   * -----------------------------------------------------------------
+   */
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : CVSpbcg
+   * -----------------------------------------------------------------
+   * A call to the CVSpbcg function links the main CVODE integrator
+   * with the CVSPBCG linear solver.
+   *
+   * cvode_mem is the pointer to the integrator memory returned by
+   *           CVodeCreate.
+   *
+   * pretype   is the type of user preconditioning to be done.
+   *           This must be one of the four enumeration constants
+   *           PREC_NONE, PREC_LEFT, PREC_RIGHT, or PREC_BOTH defined
+   *           in iterative.h. These correspond to no preconditioning,
+   *           left preconditioning only, right preconditioning
+   *           only, and both left and right preconditioning,
+   *           respectively.
+   *
+   * maxl      is the maximum Krylov dimension. This is an
+   *           optional input to the CVSPBCG solver. Pass 0 to
+   *           use the default value CVSPILS_MAXL=5.
+   *
+   * The return value of CVSpbcg is one of:
+   *    CVSPILS_SUCCESS   if successful
+   *    CVSPILS_MEM_NULL  if the cvode memory was NULL
+   *    CVSPILS_MEM_FAIL  if there was a memory allocation failure
+   *    CVSPILS_ILL_INPUT if a required vector operation is missing
+   * The above constants are defined in cvodes_spils.h
+   * -----------------------------------------------------------------
+   */
+
+  int CVSpbcg(void *cvode_mem, int pretype, int maxl);
+
+  /* 
+   * -----------------------------------------------------------------
+   * PART II - backward problems
+   * -----------------------------------------------------------------
+   */
+
+  int CVSpbcgB(void *cvadj_mem, int pretypeB, int maxlB);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/cvodes/cvodes_spgmr.h b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/cvodes/cvodes_spgmr.h
new file mode 100644
index 0000000000000000000000000000000000000000..90d45865b3f8faa0c98add2341f90a1f86d146f5
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/cvodes/cvodes_spgmr.h	
@@ -0,0 +1,87 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * ----------------------------------------------------------------- 
+ * Programmer(s): Radu Serban @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2005, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This is the header file for the CVODES scaled preconditioned 
+ * GMRES linear solver, CVSPGMR.
+ *
+ * Part I contains function prototypes for using CVSPGMR on forward 
+ * problems (IVP integration and/or FSA)
+ *
+ * Part II contains function prototypes for using CVSPGMR on adjoint 
+ * (backward) problems
+ * -----------------------------------------------------------------
+ */
+
+#ifndef _CVSSPGMR_H
+#define _CVSSPGMR_H
+
+#ifdef __cplusplus  /* wrapper to enable C++ usage */
+extern "C" {
+#endif
+
+#include <cvodes/cvodes_spils.h>
+#include <sundials/sundials_spgmr.h>
+
+  /* 
+   * -----------------------------------------------------------------
+   * PART I - forward problems
+   * -----------------------------------------------------------------
+   */
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : CVSpgmr
+   * -----------------------------------------------------------------
+   * A call to the CVSpgmr function links the main CVODE integrator
+   * with the CVSPGMR linear solver.
+   *
+   * cvode_mem is the pointer to the integrator memory returned by
+   *           CVodeCreate.
+   *
+   * pretype   is the type of user preconditioning to be done.
+   *           This must be one of the four enumeration constants
+   *           NONE, LEFT, RIGHT, or BOTH defined in iterative.h.
+   *           These correspond to no preconditioning,
+   *           left preconditioning only, right preconditioning
+   *           only, and both left and right preconditioning,
+   *           respectively.
+   *
+   * maxl      is the maximum Krylov dimension. This is an
+   *           optional input to the CVSPGMR solver. Pass 0 to
+   *           use the default value CVSPILS_MAXL=5.
+   *
+   * The return value of CVSpgmr is one of:
+   *    CVSPILS_SUCCESS   if successful
+   *    CVSPILS_MEM_NULL  if the cvode memory was NULL
+   *    CVSPILS_MEM_FAIL  if there was a memory allocation failure
+   *    CVSPILS_ILL_INPUT if a required vector operation is missing
+   * The above constants are defined in cvodes_spils.h
+   * -----------------------------------------------------------------
+   */
+
+  int CVSpgmr(void *cvode_mem, int pretype, int maxl);
+
+  /* 
+   * -----------------------------------------------------------------
+   * PART II - backward problems
+   * -----------------------------------------------------------------
+   */
+
+  int CVSpgmrB(void *cvadj_mem, int pretypeB, int maxlB);
+  
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/cvodes/cvodes_spils.h b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/cvodes/cvodes_spils.h
new file mode 100644
index 0000000000000000000000000000000000000000..93bbd7a0383596946db2eb92436065be9a0fb64e
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/cvodes/cvodes_spils.h	
@@ -0,0 +1,454 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * ----------------------------------------------------------------- 
+ * Programmer(s): Radu Serban @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2005, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This is the common header file for the Scaled, Preconditioned
+ * Iterative Linear Solvers in CVODE/CVODES.
+ *
+ * Part I contains type definitions and functions for using the 
+ * iterative linear solvers on forward problems 
+ * (IVP integration and/or FSA)
+ *
+ * Part II contains type definitions and functions for using the 
+ * iterative linear solvers on adjoint (backward) problems
+ * -----------------------------------------------------------------
+ */
+
+#ifndef _CVSSPILS_H
+#define _CVSSPILS_H
+
+#ifdef __cplusplus  /* wrapper to enable C++ usage */
+extern "C" {
+#endif
+
+#include <sundials/sundials_iterative.h>
+#include <sundials/sundials_nvector.h>
+
+  /*
+   * -----------------------------------------------------------------
+   * CVSPILS return values
+   * -----------------------------------------------------------------
+   */
+
+#define CVSPILS_SUCCESS          0
+#define CVSPILS_MEM_NULL        -1
+#define CVSPILS_LMEM_NULL       -2
+#define CVSPILS_ILL_INPUT       -3
+#define CVSPILS_MEM_FAIL        -4
+
+  /* Return values for the adjoint module */
+
+#define CVSPILS_ADJMEM_NULL     -101
+#define CVSPILS_LMEMB_NULL      -102
+
+  /*
+   * -----------------------------------------------------------------
+   * CVSPILS solver constants
+   * -----------------------------------------------------------------
+   * CVSPILS_MAXL   : default value for the maximum Krylov
+   *                  dimension
+   *
+   * CVSPILS_MSBPRE : maximum number of steps between
+   *                  preconditioner evaluations
+   *
+   * CVSPILS_DGMAX  : maximum change in gamma between
+   *                  preconditioner evaluations
+   *
+   * CVSPILS_DELT   : default value for factor by which the
+   *                  tolerance on the nonlinear iteration is
+   *                  multiplied to get a tolerance on the linear
+   *                  iteration
+   * -----------------------------------------------------------------
+   */
+
+#define CVSPILS_MAXL   5
+#define CVSPILS_MSBPRE 50
+#define CVSPILS_DGMAX  RCONST(0.2)
+#define CVSPILS_DELT   RCONST(0.05)
+
+  /* 
+   * -----------------------------------------------------------------
+   * PART I - forward problems
+   * -----------------------------------------------------------------
+   */
+
+  /*
+   * -----------------------------------------------------------------
+   * Type : CVSpilsPrecSetupFn
+   * -----------------------------------------------------------------
+   * The user-supplied preconditioner setup function PrecSetup and
+   * the user-supplied preconditioner solve function PrecSolve
+   * together must define left and right preconditoner matrices
+   * P1 and P2 (either of which may be trivial), such that the
+   * product P1*P2 is an approximation to the Newton matrix
+   * M = I - gamma*J.  Here J is the system Jacobian J = df/dy,
+   * and gamma is a scalar proportional to the integration step
+   * size h.  The solution of systems P z = r, with P = P1 or P2,
+   * is to be carried out by the PrecSolve function, and PrecSetup
+   * is to do any necessary setup operations.
+   *
+   * The user-supplied preconditioner setup function PrecSetup
+   * is to evaluate and preprocess any Jacobian-related data
+   * needed by the preconditioner solve function PrecSolve.
+   * This might include forming a crude approximate Jacobian,
+   * and performing an LU factorization on the resulting
+   * approximation to M.  This function will not be called in
+   * advance of every call to PrecSolve, but instead will be called
+   * only as often as necessary to achieve convergence within the
+   * Newton iteration.  If the PrecSolve function needs no
+   * preparation, the PrecSetup function can be NULL.
+   *
+   * For greater efficiency, the PrecSetup function may save
+   * Jacobian-related data and reuse it, rather than generating it
+   * from scratch.  In this case, it should use the input flag jok
+   * to decide whether to recompute the data, and set the output
+   * flag *jcurPtr accordingly.
+   *
+   * Each call to the PrecSetup function is preceded by a call to
+   * the RhsFn f with the same (t,y) arguments.  Thus the PrecSetup
+   * function can use any auxiliary data that is computed and
+   * saved by the f function and made accessible to PrecSetup.
+   *
+   * A function PrecSetup must have the prototype given below.
+   * Its parameters are as follows:
+   *
+   * t       is the current value of the independent variable.
+   *
+   * y       is the current value of the dependent variable vector,
+   *          namely the predicted value of y(t).
+   *
+   * fy      is the vector f(t,y).
+   *
+   * jok     is an input flag indicating whether Jacobian-related
+   *         data needs to be recomputed, as follows:
+   *           jok == FALSE means recompute Jacobian-related data
+   *                  from scratch.
+   *           jok == TRUE  means that Jacobian data, if saved from
+   *                  the previous PrecSetup call, can be reused
+   *                  (with the current value of gamma).
+   *         A Precset call with jok == TRUE can only occur after
+   *         a call with jok == FALSE.
+   *
+   * jcurPtr is a pointer to an output integer flag which is
+   *         to be set by PrecSetup as follows:
+   *         Set *jcurPtr = TRUE if Jacobian data was recomputed.
+   *         Set *jcurPtr = FALSE if Jacobian data was not recomputed,
+   *                        but saved data was reused.
+   *
+   * gamma   is the scalar appearing in the Newton matrix.
+   *
+   * P_data  is a pointer to user data - the same as the P_data
+   *         parameter passed to the CV*SetPreconditioner function.
+   *
+   * tmp1, tmp2, and tmp3 are pointers to memory allocated
+   *                      for N_Vectors which can be used by
+   *                      CVSpilsPrecSetupFn as temporary storage or
+   *                      work space.
+   *
+   * NOTE: If the user's preconditioner needs other quantities,
+   *       they are accessible as follows: hcur (the current stepsize)
+   *       and ewt (the error weight vector) are accessible through
+   *       CVodeGetCurrentStep and CVodeGetErrWeights, respectively).
+   *       The unit roundoff is available as UNIT_ROUNDOFF defined in
+   *       sundials_types.h.
+   *
+   * Returned value:
+   * The value to be returned by the PrecSetup function is a flag
+   * indicating whether it was successful.  This value should be
+   *   0   if successful,
+   *   > 0 for a recoverable error (step will be retried),
+   *   < 0 for an unrecoverable error (integration is halted).
+   * -----------------------------------------------------------------
+   */
+
+  typedef int (*CVSpilsPrecSetupFn)(realtype t, N_Vector y, N_Vector fy,
+                                    booleantype jok, booleantype *jcurPtr,
+                                    realtype gamma, void *P_data,
+                                    N_Vector tmp1, N_Vector tmp2,
+                                    N_Vector tmp3);
+
+  /*
+   * -----------------------------------------------------------------
+   * Type : CVSpilsPrecSolveFn
+   * -----------------------------------------------------------------
+   * The user-supplied preconditioner solve function PrecSolve
+   * is to solve a linear system P z = r in which the matrix P is
+   * one of the preconditioner matrices P1 or P2, depending on the
+   * type of preconditioning chosen.
+   *
+   * A function PrecSolve must have the prototype given below.
+   * Its parameters are as follows:
+   *
+   * t      is the current value of the independent variable.
+   *
+   * y      is the current value of the dependent variable vector.
+   *
+   * fy     is the vector f(t,y).
+   *
+   * r      is the right-hand side vector of the linear system.
+   *
+   * z      is the output vector computed by PrecSolve.
+   *
+   * gamma  is the scalar appearing in the Newton matrix.
+   *
+   * delta  is an input tolerance for use by PSolve if it uses
+   *        an iterative method in its solution.  In that case,
+   *        the residual vector Res = r - P z of the system
+   *        should be made less than delta in weighted L2 norm,
+   *        i.e., sqrt [ Sum (Res[i]*ewt[i])^2 ] < delta.
+   *        Note: the error weight vector ewt can be obtained
+   *        through a call to the routine CVodeGetErrWeights.
+   *
+   * lr     is an input flag indicating whether PrecSolve is to use
+   *        the left preconditioner P1 or right preconditioner
+   *        P2: lr = 1 means use P1, and lr = 2 means use P2.
+   *
+   * P_data is a pointer to user data - the same as the P_data
+   *        parameter passed to the CV*SetPreconditioner function.
+   *
+   * tmp    is a pointer to memory allocated for an N_Vector
+   *        which can be used by PSolve for work space.
+   *
+   * Returned value:
+   * The value to be returned by the PrecSolve function is a flag
+   * indicating whether it was successful.  This value should be
+   *   0 if successful,
+   *   positive for a recoverable error (step will be retried),
+   *   negative for an unrecoverable error (integration is halted).
+   * -----------------------------------------------------------------
+   */
+
+  typedef int (*CVSpilsPrecSolveFn)(realtype t, N_Vector y, N_Vector fy,
+                                    N_Vector r, N_Vector z,
+                                    realtype gamma, realtype delta,
+                                    int lr, void *P_data, N_Vector tmp);
+
+  /*
+   * -----------------------------------------------------------------
+   * Type : CVSpilsJacTimesVecFn
+   * -----------------------------------------------------------------
+   * The user-supplied function jtimes is to generate the product
+   * J*v for given v, where J is the Jacobian df/dy, or an
+   * approximation to it, and v is a given vector. It should return
+   * 0 if successful a positive value for a recoverable error or 
+   * a negative value for an unrecoverable failure.
+   *
+   * A function jtimes must have the prototype given below. Its
+   * parameters are as follows:
+   *
+   *   v        is the N_Vector to be multiplied by J.
+   *
+   *   Jv       is the output N_Vector containing J*v.
+   *
+   *   t        is the current value of the independent variable.
+   *
+   *   y        is the current value of the dependent variable
+   *            vector.
+   *
+   *   fy       is the vector f(t,y).
+   *
+   *   jac_data is a pointer to user Jacobian data, the same as the
+   *            jac_data parameter passed to the CV*SetJacTimesVecFn 
+   *            function.
+   *
+   *   tmp      is a pointer to memory allocated for an N_Vector
+   *            which can be used by Jtimes for work space.
+   * -----------------------------------------------------------------
+   */
+
+  typedef int (*CVSpilsJacTimesVecFn)(N_Vector v, N_Vector Jv, realtype t,
+                                      N_Vector y, N_Vector fy,
+                                      void *jac_data, N_Vector tmp);
+
+
+  /*
+   * -----------------------------------------------------------------
+   * Optional inputs to the CVSPILS linear solver
+   * -----------------------------------------------------------------
+   *
+   * CVSpilsSetPrecType resets the type of preconditioner, pretype,
+   *                from the value previously set.
+   *                This must be one of PREC_NONE, PREC_LEFT, 
+   *                PREC_RIGHT, or PREC_BOTH.
+   *
+   * CVSpilsSetGSType specifies the type of Gram-Schmidt
+   *                orthogonalization to be used. This must be one of
+   *                the two enumeration constants MODIFIED_GS or
+   *                CLASSICAL_GS defined in iterative.h. These correspond
+   *                to using modified Gram-Schmidt and classical
+   *                Gram-Schmidt, respectively.
+   *                Default value is MODIFIED_GS.
+   *
+   * CVSpilsSetMaxl resets the maximum Krylov subspace size, maxl,
+   *                from the value previously set.
+   *                An input value <= 0, gives the default value.
+   *
+   * CVSpilsSetDelt specifies the factor by which the tolerance on
+   *                the nonlinear iteration is multiplied to get a
+   *                tolerance on the linear iteration.
+   *                Default value is 0.05.
+   *
+   * CVSpilsSetPreconditioner specifies the PrecSetup and PrecSolve functions.
+   *                as well as a pointer to user preconditioner data.
+   *                This pointer is passed to PrecSetup and PrecSolve
+   *                every time these routines are called.
+   *                Default is NULL for al three arguments.
+   *
+   * CVSpilsSetJacTimesVecFn specifies the jtimes function and a pointer to
+   *                user Jacobian data. This pointer is passed to jtimes every 
+   *                time the jtimes routine is called.
+   *                Default is to use an internal finite difference
+   *                approximation routine.
+   *
+   * The return value of CVSpilsSet* is one of:
+   *    CVSPILS_SUCCESS   if successful
+   *    CVSPILS_MEM_NULL  if the cvode memory was NULL
+   *    CVSPILS_LMEM_NULL if the cvspgmr memory was NULL
+   *    CVSPILS_ILL_INPUT if an input has an illegal value
+   * -----------------------------------------------------------------
+   */
+
+  int CVSpilsSetPrecType(void *cvode_mem, int pretype);
+  int CVSpilsSetGSType(void *cvode_mem, int gstype);
+  int CVSpilsSetMaxl(void *cvode_mem, int maxl);
+  int CVSpilsSetDelt(void *cvode_mem, realtype delt);
+  int CVSpilsSetPreconditioner(void *cvode_mem, CVSpilsPrecSetupFn pset, 
+                               CVSpilsPrecSolveFn psolve, void *P_data);
+  int CVSpilsSetJacTimesVecFn(void *cvode_mem, 
+                              CVSpilsJacTimesVecFn jtimes, void *jac_data);
+
+  /*
+   * -----------------------------------------------------------------
+   * Optional outputs from the CVSPILS linear solver
+   * -----------------------------------------------------------------
+   * CVSpilsGetWorkSpace returns the real and integer workspace used
+   *                by the SPILS module.
+   *
+   * CVSpilsGetNumPrecEvals returns the number of preconditioner
+   *                 evaluations, i.e. the number of calls made
+   *                 to PrecSetup with jok==FALSE.
+   *
+   * CVSpilsGetNumPrecSolves returns the number of calls made to
+   *                 PrecSolve.
+   *
+   * CVSpilsGetNumLinIters returns the number of linear iterations.
+   *
+   * CVSpilsGetNumConvFails returns the number of linear
+   *                 convergence failures.
+   *
+   * CVSpilsGetNumJtimesEvals returns the number of calls to jtimes.
+   *
+   * CVSpilsGetNumRhsEvals returns the number of calls to the user
+   *                 f routine due to finite difference Jacobian
+   *                 times vector evaluation.
+   *
+   * CVSpilsGetLastFlag returns the last error flag set by any of
+   *                 the CVSPILS interface functions.
+   *
+   * The return value of CVSpilsGet* is one of:
+   *    CVSPILS_SUCCESS   if successful
+   *    CVSPILS_MEM_NULL  if the cvode memory was NULL
+   *    CVSPILS_LMEM_NULL if the cvspgmr memory was NULL
+   * -----------------------------------------------------------------
+   */
+
+  int CVSpilsGetWorkSpace(void *cvode_mem, long int *lenrwLS, long int *leniwLS);
+  int CVSpilsGetNumPrecEvals(void *cvode_mem, long int *npevals);
+  int CVSpilsGetNumPrecSolves(void *cvode_mem, long int *npsolves);
+  int CVSpilsGetNumLinIters(void *cvode_mem, long int *nliters);
+  int CVSpilsGetNumConvFails(void *cvode_mem, long int *nlcfails);
+  int CVSpilsGetNumJtimesEvals(void *cvode_mem, long int *njvevals);
+  int CVSpilsGetNumRhsEvals(void *cvode_mem, long int *nfevalsLS); 
+  int CVSpilsGetLastFlag(void *cvode_mem, int *flag);
+
+  /*
+   * -----------------------------------------------------------------
+   * The following function returns the name of the constant 
+   * associated with a CVSPILS return flag
+   * -----------------------------------------------------------------
+   */
+  
+  char *CVSpilsGetReturnFlagName(int flag);
+
+
+  /* 
+   * -----------------------------------------------------------------
+   * PART II - backward problems
+   * -----------------------------------------------------------------
+   */
+
+  /*
+   * -----------------------------------------------------------------
+   * Type : CVSpilsPrecSetupFnB
+   * -----------------------------------------------------------------
+   * A function PrecSetupB for the adjoint (backward) problem must have 
+   * the prototype given below.
+   * -----------------------------------------------------------------
+   */
+
+  typedef int (*CVSpilsPrecSetupFnB)(realtype t, N_Vector y,
+                                     N_Vector yB, N_Vector fyB,
+                                     booleantype jokB,
+                                     booleantype *jcurPtrB, realtype gammaB,
+                                     void *P_dataB,
+                                     N_Vector tmp1B, N_Vector tmp2B,
+                                     N_Vector tmp3B);
+
+
+  /*
+   * -----------------------------------------------------------------
+   * Type : CVSpilsPrecSolveFnB
+   * -----------------------------------------------------------------
+   * A function PrecSolveB for the adjoint (backward) problem  must 
+   * have the prototype given below.
+   * -----------------------------------------------------------------
+   */
+
+  typedef int (*CVSpilsPrecSolveFnB)(realtype t, N_Vector y,
+                                     N_Vector yB, N_Vector fyB,
+                                     N_Vector rB, N_Vector zB,
+                                     realtype gammaB, realtype deltaB,
+                                     int lrB, void *P_dataB, N_Vector tmpB);
+
+  /*
+   * -----------------------------------------------------------------
+   * Type : CVSpilsJacTimesVecFnB
+   * -----------------------------------------------------------------
+   * A function jtimesB for the adjoint (backward) problem must have 
+   * the prototype given below.
+   * -----------------------------------------------------------------
+   */
+
+  typedef int (*CVSpilsJacTimesVecFnB)(N_Vector vB, N_Vector JvB, realtype t,
+                                       N_Vector y, N_Vector yB, N_Vector fyB,
+                                       void *jac_dataB, N_Vector tmpB);
+
+  /*
+   * -----------------------------------------------------------------
+   * Functions
+   * -----------------------------------------------------------------
+   */
+
+  int CVSpilsSetPrecTypeB(void *cvadj_mem, int pretypeB);
+  int CVSpilsSetGSTypeB(void *cvadj_mem, int gstypeB);
+  int CVSpilsSetDeltB(void *cvadj_mem, realtype deltB);
+  int CVSpilsSetMaxlB(void *cvadj_mem, int maxlB);
+  int CVSpilsSetPreconditionerB(void *cvadj_mem, CVSpilsPrecSetupFnB psetB,
+                                CVSpilsPrecSolveFnB psolveB, void *P_dataB);
+  int CVSpilsSetJacTimesVecFnB(void *cvadj_mem, CVSpilsJacTimesVecFnB jtimesB,
+                               void *jac_dataB);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/cvodes/cvodes_sptfqmr.h b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/cvodes/cvodes_sptfqmr.h
new file mode 100644
index 0000000000000000000000000000000000000000..78bbb77fea668a05162b964d546ed0a910843289
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/cvodes/cvodes_sptfqmr.h	
@@ -0,0 +1,87 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * ----------------------------------------------------------------- 
+ * Programmer(s): Aaron Collier and Radu Serban @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2005, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This is the header file for the CVODES scaled preconditioned TFQMR 
+ * linear solver, CVSPTFQMR.
+ *
+ * Part I contains function prototypes for using CVSPTFQMR on forward 
+ * problems (IVP integration and/or FSA)
+ *
+ * Part II contains function prototypes for using CVSPTFQMR on adjoint 
+ * (backward) problems
+ * -----------------------------------------------------------------
+ */
+
+#ifndef _CVSSPTFQMR_H
+#define _CVSSPTFQMR_H
+
+#ifdef __cplusplus  /* wrapper to enable C++ usage */
+extern "C" {
+#endif
+
+#include <cvodes/cvodes_spils.h>
+#include <sundials/sundials_sptfqmr.h>
+
+  /* 
+   * -----------------------------------------------------------------
+   * PART I - forward problems
+   * -----------------------------------------------------------------
+   */
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : CVSptfqmr
+   * -----------------------------------------------------------------
+   * A call to the CVSptfqmr function links the main CVODE integrator
+   * with the CVSPTFQMR linear solver.
+   *
+   * cvode_mem is the pointer to the integrator memory returned by
+   *           CVodeCreate.
+   *
+   * pretype   is the type of user preconditioning to be done.
+   *           This must be one of the four enumeration constants
+   *           PREC_NONE, PREC_LEFT, PREC_RIGHT, or PREC_BOTH defined
+   *           in iterative.h. These correspond to no preconditioning,
+   *           left preconditioning only, right preconditioning
+   *           only, and both left and right preconditioning,
+   *           respectively.
+   *
+   * maxl      is the maximum Krylov dimension. This is an
+   *           optional input to the CVSPTFQMR solver. Pass 0 to
+   *           use the default value CVSPILS_MAXL=5.
+   *
+   * The return value of CVSptfqmr is one of:
+   *    CVSPILS_SUCCESS   if successful
+   *    CVSPILS_MEM_NULL  if the cvode memory was NULL
+   *    CVSPILS_MEM_FAIL  if there was a memory allocation failure
+   *    CVSPILS_ILL_INPUT if a required vector operation is missing
+   * The above constants are defined in cvodes_spils.h
+   * -----------------------------------------------------------------
+   */
+
+  int CVSptfqmr(void *cvode_mem, int pretype, int maxl);
+
+
+  /* 
+   * -----------------------------------------------------------------
+   * PART II - backward problems
+   * -----------------------------------------------------------------
+   */
+
+  int CVSptfqmrB(void *cvadj_mem, int pretypeB, int maxlB);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/nvector/nvector_serial.h b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/nvector/nvector_serial.h
new file mode 100644
index 0000000000000000000000000000000000000000..2bb736831428d48ca28bb41cd5461a9a3a7b614f
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/nvector/nvector_serial.h	
@@ -0,0 +1,265 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * ----------------------------------------------------------------- 
+ * Programmer(s): Scott D. Cohen, Alan C. Hindmarsh, Radu Serban,
+ *                and Aaron Collier @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2002, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This is the header file for the serial implementation of the
+ * NVECTOR module.
+ *
+ * Part I contains declarations specific to the serial
+ * implementation of the supplied NVECTOR module.
+ *
+ * Part II defines accessor macros that allow the user to
+ * efficiently use the type N_Vector without making explicit
+ * references to the underlying data structure.
+ *
+ * Part III contains the prototype for the constructor N_VNew_Serial
+ * as well as implementation-specific prototypes for various useful
+ * vector operations.
+ *
+ * Notes:
+ *
+ *   - The definition of the generic N_Vector structure can be found
+ *     in the header file sundials_nvector.h.
+ *
+ *   - The definition of the type 'realtype' can be found in the
+ *     header file sundials_types.h, and it may be changed (at the 
+ *     configuration stage) according to the user's needs. 
+ *     The sundials_types.h file also contains the definition
+ *     for the type 'booleantype'.
+ *
+ *   - N_Vector arguments to arithmetic vector operations need not
+ *     be distinct. For example, the following call:
+ *
+ *       N_VLinearSum_Serial(a,x,b,y,y);
+ *
+ *     (which stores the result of the operation a*x+b*y in y)
+ *     is legal.
+ * -----------------------------------------------------------------
+ */
+
+#ifndef _NVECTOR_SERIAL_H
+#define _NVECTOR_SERIAL_H
+
+#ifdef __cplusplus  /* wrapper to enable C++ usage */
+extern "C" {
+#endif
+
+#include <sundials/sundials_nvector.h>
+
+/*
+ * -----------------------------------------------------------------
+ * PART I: SERIAL implementation of N_Vector
+ * -----------------------------------------------------------------
+ */
+
+/* serial implementation of the N_Vector 'content' structure
+   contains the length of the vector, a pointer to an array
+   of 'realtype' components, and a flag indicating ownership of
+   the data */
+
+struct _N_VectorContent_Serial {
+  long int length;
+  booleantype own_data;
+  realtype *data;
+};
+
+typedef struct _N_VectorContent_Serial *N_VectorContent_Serial;
+
+/*
+ * -----------------------------------------------------------------
+ * PART II: macros NV_CONTENT_S, NV_DATA_S, NV_OWN_DATA_S,
+ *          NV_LENGTH_S, and NV_Ith_S
+ * -----------------------------------------------------------------
+ * In the descriptions below, the following user declarations
+ * are assumed:
+ *
+ * N_Vector v;
+ * long int i;
+ *
+ * (1) NV_CONTENT_S
+ *
+ *     This routines gives access to the contents of the serial
+ *     vector N_Vector.
+ *
+ *     The assignment v_cont = NV_CONTENT_S(v) sets v_cont to be
+ *     a pointer to the serial N_Vector content structure.
+ *
+ * (2) NV_DATA_S NV_OWN_DATA_S and NV_LENGTH_S
+ *
+ *     These routines give access to the individual parts of
+ *     the content structure of a serial N_Vector.
+ *
+ *     The assignment v_data = NV_DATA_S(v) sets v_data to be
+ *     a pointer to the first component of v. The assignment
+ *     NV_DATA_S(v) = data_V sets the component array of v to
+ *     be data_v by storing the pointer data_v.
+ *
+ *     The assignment v_len = NV_LENGTH_S(v) sets v_len to be
+ *     the length of v. The call NV_LENGTH_S(v) = len_v sets
+ *     the length of v to be len_v.
+ *
+ * (3) NV_Ith_S
+ *
+ *     In the following description, the components of an
+ *     N_Vector are numbered 0..n-1, where n is the length of v.
+ *
+ *     The assignment r = NV_Ith_S(v,i) sets r to be the value of
+ *     the ith component of v. The assignment NV_Ith_S(v,i) = r
+ *     sets the value of the ith component of v to be r.
+ *
+ * Note: When looping over the components of an N_Vector v, it is
+ * more efficient to first obtain the component array via
+ * v_data = NV_DATA_S(v) and then access v_data[i] within the
+ * loop than it is to use NV_Ith_S(v,i) within the loop.
+ * -----------------------------------------------------------------
+ */
+
+#define NV_CONTENT_S(v)  ( (N_VectorContent_Serial)(v->content) )
+
+#define NV_LENGTH_S(v)   ( NV_CONTENT_S(v)->length )
+
+#define NV_OWN_DATA_S(v) ( NV_CONTENT_S(v)->own_data )
+
+#define NV_DATA_S(v)     ( NV_CONTENT_S(v)->data )
+
+#define NV_Ith_S(v,i)    ( NV_DATA_S(v)[i] )
+
+/*
+ * -----------------------------------------------------------------
+ * PART III: functions exported by nvector_serial
+ * 
+ * CONSTRUCTORS:
+ *    N_VNew_Serial
+ *    N_VNewEmpty_Serial
+ *    N_VMake_Serial
+ *    N_VCloneVectorArray_Serial
+ *    N_VCloneVectorArrayEmpty_Serial
+ * DESTRUCTORS:
+ *    N_VDestroy_Serial
+ *    N_VDestroyVectorArray_Serial
+ * OTHER:
+ *    N_VPrint_Serial
+ * -----------------------------------------------------------------
+ */
+
+/*
+ * -----------------------------------------------------------------
+ * Function : N_VNew_Serial
+ * -----------------------------------------------------------------
+ * This function creates and allocates memory for a serial vector.
+ * -----------------------------------------------------------------
+ */
+
+N_Vector N_VNew_Serial(long int vec_length);
+
+/*
+ * -----------------------------------------------------------------
+ * Function : N_VNewEmpty_Serial
+ * -----------------------------------------------------------------
+ * This function creates a new serial N_Vector with an empty (NULL)
+ * data array.
+ * -----------------------------------------------------------------
+ */
+
+N_Vector N_VNewEmpty_Serial(long int vec_length);
+
+/*
+ * -----------------------------------------------------------------
+ * Function : N_VMake_Serial
+ * -----------------------------------------------------------------
+ * This function creates and allocates memory for a serial vector
+ * with a user-supplied data array.
+ * -----------------------------------------------------------------
+ */
+
+N_Vector N_VMake_Serial(long int vec_length, realtype *v_data);
+
+/*
+ * -----------------------------------------------------------------
+ * Function : N_VCloneVectorArray_Serial
+ * -----------------------------------------------------------------
+ * This function creates an array of 'count' SERIAL vectors by
+ * cloning a given vector w.
+ * -----------------------------------------------------------------
+ */
+
+N_Vector *N_VCloneVectorArray_Serial(int count, N_Vector w);
+
+/*
+ * -----------------------------------------------------------------
+ * Function : N_VCloneVectorArrayEmpty_Serial
+ * -----------------------------------------------------------------
+ * This function creates an array of 'count' SERIAL vectors each
+ * with an empty (NULL) data array by cloning w.
+ * -----------------------------------------------------------------
+ */
+
+N_Vector *N_VCloneVectorArrayEmpty_Serial(int count, N_Vector w);
+
+/*
+ * -----------------------------------------------------------------
+ * Function : N_VDestroyVectorArray_Serial
+ * -----------------------------------------------------------------
+ * This function frees an array of SERIAL vectors created with 
+ * N_VCloneVectorArray_Serial or N_VCloneVectorArrayEmpty_Serial.
+ * -----------------------------------------------------------------
+ */
+
+void N_VDestroyVectorArray_Serial(N_Vector *vs, int count);
+
+/*
+ * -----------------------------------------------------------------
+ * Function : N_VPrint_Serial
+ * -----------------------------------------------------------------
+ * This function prints the content of a serial vector to stdout.
+ * -----------------------------------------------------------------
+ */
+
+void N_VPrint_Serial(N_Vector v);
+
+/*
+ * -----------------------------------------------------------------
+ * serial implementations of various useful vector operations
+ * -----------------------------------------------------------------
+ */
+
+N_Vector N_VCloneEmpty_Serial(N_Vector w);
+N_Vector N_VClone_Serial(N_Vector w);
+void N_VDestroy_Serial(N_Vector v);
+void N_VSpace_Serial(N_Vector v, long int *lrw, long int *liw);
+realtype *N_VGetArrayPointer_Serial(N_Vector v);
+void N_VSetArrayPointer_Serial(realtype *v_data, N_Vector v);
+void N_VLinearSum_Serial(realtype a, N_Vector x, realtype b, N_Vector y, N_Vector z);
+void N_VConst_Serial(realtype c, N_Vector z);
+void N_VProd_Serial(N_Vector x, N_Vector y, N_Vector z);
+void N_VDiv_Serial(N_Vector x, N_Vector y, N_Vector z);
+void N_VScale_Serial(realtype c, N_Vector x, N_Vector z);
+void N_VAbs_Serial(N_Vector x, N_Vector z);
+void N_VInv_Serial(N_Vector x, N_Vector z);
+void N_VAddConst_Serial(N_Vector x, realtype b, N_Vector z);
+realtype N_VDotProd_Serial(N_Vector x, N_Vector y);
+realtype N_VMaxNorm_Serial(N_Vector x);
+realtype N_VWrmsNorm_Serial(N_Vector x, N_Vector w);
+realtype N_VWrmsNormMask_Serial(N_Vector x, N_Vector w, N_Vector id);
+realtype N_VMin_Serial(N_Vector x);
+realtype N_VWL2Norm_Serial(N_Vector x, N_Vector w);
+realtype N_VL1Norm_Serial(N_Vector x);
+void N_VCompare_Serial(realtype c, N_Vector x, N_Vector z);
+booleantype N_VInvTest_Serial(N_Vector x, N_Vector z);
+booleantype N_VConstrMask_Serial(N_Vector c, N_Vector x, N_Vector m);
+realtype N_VMinQuotient_Serial(N_Vector num, N_Vector denom);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/sundials/sundials_band.h b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/sundials/sundials_band.h
new file mode 100644
index 0000000000000000000000000000000000000000..db503c76e66831465c157693110c6636e5886214
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/sundials/sundials_band.h	
@@ -0,0 +1,605 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * -----------------------------------------------------------------
+ * Programmer(s): Alan C. Hindmarsh and Radu Serban @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2002, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This is the header file for a generic BAND linear solver
+ * package. There are two sets of band solver routines listed in
+ * this file: one set uses type BandMat defined below and the
+ * other set uses the type realtype ** for band matrix arguments.
+ * The two sets of band solver routines make it easy to work
+ * with two types of band matrices:
+ *
+ * (1) The BandMat type is intended for use with large
+ *     band matrices whose elements/columns may be stored in
+ *     non-contiguous memory locations or even distributed across
+ *     different process memory spaces. This type may be modified
+ *     to include such distribution information. If this is done,
+ *     then all the routines that use BandMat must be modified to
+ *     reflect the new data structure.
+ *
+ * (2) The set of routines that use realtype ** (and NOT the
+ *     BandMat type) is intended for use with small matrices
+ *     which can easily be allocated within a contiguous block of
+ *     memory for a single process.
+ *
+ * Routines that work with the type BandMat begin with "Band".
+ * The BandAllocMat function allocates a band matrix for use in
+ * the other matrix routines listed in this file. Matrix storage
+ * details are given in the documentation for the type BandMat.
+ * The BandAllocPiv function allocates memory for pivot
+ * information. The storage allocated by BandAllocMat and
+ * BandAllocPiv is deallocated by the routines BandFreeMat and
+ * BandFreePiv, respectively. The BandGBTRF and BandGBTRS
+ * routines perform the actual solution of a band linear system.
+ *
+ * Routines that work with realtype ** begin with "band" (except
+ * for the factor and solve routines which are called bandGBTRF and
+ * bandGBTRS, respectively). The underlying matrix storage is
+ * described in the documentation for bandalloc.
+ * -----------------------------------------------------------------
+ */
+
+#ifndef _BAND_H
+#define _BAND_H
+
+#ifdef __cplusplus  /* wrapper to enable C++ usage */
+extern "C" {
+#endif
+
+#include <sundials/sundials_types.h>
+
+/*
+ * -----------------------------------------------------------------
+ * Type: BandMat
+ * -----------------------------------------------------------------
+ * The type BandMat is the type of a large (possibly distributed)
+ * band matrix. It is defined to be a pointer to a structure
+ * with the following fields:
+ *
+ * size is the number of columns (== number of rows)
+ *
+ * mu   is the upper bandwidth, 0 <= mu <= size-1
+ *
+ * ml   is the lower bandwidth, 0 <= ml <= size-1
+ *
+ * smu  is the storage upper bandwidth, mu <= smu <= size-1.
+ *      The BandGBTRF routine writes the LU factors
+ *      into the storage for A. The upper triangular factor U,
+ *      however, may have an upper bandwidth as big as
+ *      MIN(size-1,mu+ml) because of partial pivoting. The smu
+ *      field holds the upper bandwidth allocated for A.
+ *
+ * data is a two dimensional array used for component storage.
+ *      The elements of a band matrix of type BandMat are
+ *      stored columnwise (i.e. columns are stored one on top
+ *      of the other in memory). Only elements within the
+ *      specified bandwidths are stored.
+ *
+ * If we number rows and columns in the band matrix starting
+ * from 0, then
+ *
+ * data[0] is a pointer to (smu+ml+1)*size contiguous locations
+ *         which hold the elements within the band of A
+ *
+ * data[j] is a pointer to the uppermost element within the band
+ *         in the jth column. This pointer may be treated as
+ *         an array indexed from smu-mu (to access the
+ *         uppermost element within the band in the jth
+ *         column) to smu+ml (to access the lowest element
+ *         within the band in the jth column). (Indices from 0
+ *         to smu-mu-1 give access to extra storage elements
+ *         required by BandGBTRF.)
+ *
+ * data[j][i-j+smu] is the (i,j)th element, j-mu <= i <= j+ml.
+ *
+ * The macros below allow a user to access individual matrix
+ * elements without writing out explicit data structure
+ * references and without knowing too much about the underlying
+ * element storage. The only storage assumption needed is that
+ * elements are stored columnwise and that a pointer into the jth
+ * column of elements can be obtained via the BAND_COL macro. The
+ * BAND_COL_ELEM macro selects an element from a column which has
+ * already been isolated via BAND_COL. BAND_COL_ELEM allows the
+ * user to avoid the translation from the matrix location (i,j)
+ * to the index in the array returned by BAND_COL at which the
+ * (i,j)th element is stored. See the documentation for BAND_COL
+ * and BAND_COL_ELEM for usage details. Users should use these
+ * macros whenever possible.
+ * -----------------------------------------------------------------
+ */
+
+typedef struct _BandMat {
+  long int size;
+  long int mu, ml, smu;
+  realtype **data;
+} *BandMat;
+
+/* BandMat accessor macros */
+
+/*
+ * -----------------------------------------------------------------
+ * Macro : BAND_ELEM
+ * -----------------------------------------------------------------
+ * Usage : BAND_ELEM(A,i,j) = a_ij;  OR
+ *         a_ij = BAND_ELEM(A,i,j);
+ * -----------------------------------------------------------------
+ * BAND_ELEM(A,i,j) references the (i,j)th element of the
+ * N by N band matrix A, where 0 <= i,j <= N-1. The location
+ * (i,j) should further satisfy j-(A->mu) <= i <= j+(A->ml).
+ * -----------------------------------------------------------------
+ */
+
+#define BAND_ELEM(A,i,j) ((A->data)[j][(i)-(j)+(A->smu)])
+
+/*
+ * -----------------------------------------------------------------
+ * Macro : BAND_COL
+ * -----------------------------------------------------------------
+ * Usage : col_j = BAND_COL(A,j);
+ * -----------------------------------------------------------------
+ * BAND_COL(A,j) references the diagonal element of the jth
+ * column of the N by N band matrix A, 0 <= j <= N-1. The type of
+ * the expression BAND_COL(A,j) is realtype *. The pointer
+ * returned by the call BAND_COL(A,j) can be treated as an array
+ * which is indexed from -(A->mu) to (A->ml).
+ * -----------------------------------------------------------------
+ */
+
+#define BAND_COL(A,j) (((A->data)[j])+(A->smu))
+
+/*
+ * -----------------------------------------------------------------
+ * Macro : BAND_COL_ELEM
+ * -----------------------------------------------------------------
+ * Usage : col_j = BAND_COL(A,j);
+ *         BAND_COL_ELEM(col_j,i,j) = a_ij;  OR
+ *         a_ij = BAND_COL_ELEM(col_j,i,j);
+ * -----------------------------------------------------------------
+ * This macro references the (i,j)th entry of the band matrix A
+ * when used in conjunction with BAND_COL as shown above. The
+ * index (i,j) should satisfy j-(A->mu) <= i <= j+(A->ml).
+ * -----------------------------------------------------------------
+ */
+
+#define BAND_COL_ELEM(col_j,i,j) (col_j[(i)-(j)])
+
+/* Functions that use the BandMat representation for a band matrix */
+
+/*
+ * -----------------------------------------------------------------
+ * Function : BandAllocMat
+ * -----------------------------------------------------------------
+ * Usage : A = BandAllocMat(N, mu, ml, smu);
+ *         if (A == NULL) ... memory request failed
+ * -----------------------------------------------------------------
+ * BandAllocMat allocates memory for an N by N band matrix with
+ * upper bandwidth mu, lower bandwidth ml, and storage upper
+ * bandwidth smu. Pass smu as follows depending on whether A will
+ * be factored by BandGBTRF:
+ *
+ * (1) Pass smu = mu if A will not be factored.
+ *
+ * (2) Pass smu = MIN(N-1,mu+ml) if A will be factored.
+ *
+ * BandAllocMat returns the storage allocated (type BandMat) or
+ * NULL if the request for matrix storage cannot be satisfied.
+ * See the documentation for the type BandMat for matrix storage
+ * details.
+ * -----------------------------------------------------------------
+ */
+
+BandMat BandAllocMat(long int N, long int mu, long int ml, 
+                     long int smu);
+
+/*
+ * -----------------------------------------------------------------
+ * Function : BandAllocPiv
+ * -----------------------------------------------------------------
+ * Usage : p = BandAllocPiv(N);
+ *         if (p == NULL) ... memory request failed
+ * -----------------------------------------------------------------
+ * BandAllocPiv allocates memory for pivot information to be
+ * filled in by the BandGBTRF routine during the factorization
+ * of an N by N band matrix. The underlying type for pivot
+ * information is an array of N integers and this routine returns
+ * the pointer to the memory it allocates. If the request for
+ * pivot storage cannot be satisfied, BandAllocPiv returns NULL.
+ * -----------------------------------------------------------------
+ */
+
+long int *BandAllocPiv(long int N);
+
+/*
+ * -----------------------------------------------------------------
+ * Function : BandGBTRF
+ * -----------------------------------------------------------------
+ * Usage : ier = BandGBTRF(A, p);
+ *         if (ier != 0) ... A is singular
+ * -----------------------------------------------------------------
+ * BandGBTRF performs the LU factorization of the N by N band
+ * matrix A. This is done using standard Gaussian elimination
+ * with partial pivoting.
+ *
+ * A successful LU factorization leaves the "matrix" A and the
+ * pivot array p with the following information:
+ *
+ * (1) p[k] contains the row number of the pivot element chosen
+ *     at the beginning of elimination step k, k=0, 1, ..., N-1.
+ *
+ * (2) If the unique LU factorization of A is given by PA = LU,
+ *     where P is a permutation matrix, L is a lower triangular
+ *     matrix with all 1's on the diagonal, and U is an upper
+ *     triangular matrix, then the upper triangular part of A
+ *     (including its diagonal) contains U and the strictly lower
+ *     triangular part of A contains the multipliers, I-L.
+ *
+ * BandGBTRF returns 0 if successful. Otherwise it encountered
+ * a zero diagonal element during the factorization. In this case
+ * it returns the column index (numbered from one) at which
+ * it encountered the zero.
+ *
+ * Important Note: A must be allocated to accommodate the increase
+ * in upper bandwidth that occurs during factorization. If
+ * mathematically, A is a band matrix with upper bandwidth mu and
+ * lower bandwidth ml, then the upper triangular factor U can
+ * have upper bandwidth as big as smu = MIN(n-1,mu+ml). The lower
+ * triangular factor L has lower bandwidth ml. Allocate A with
+ * call A = BandAllocMat(N,mu,ml,smu), where mu, ml, and smu are
+ * as defined above. The user does not have to zero the "extra"
+ * storage allocated for the purpose of factorization. This will
+ * handled by the BandGBTRF routine.
+ * -----------------------------------------------------------------
+ */
+
+long int BandGBTRF(BandMat A, long int *p);
+
+/*
+ * -----------------------------------------------------------------
+ * Function : BandGBTRS
+ * -----------------------------------------------------------------
+ * Usage : BandGBTRS(A, p, b);
+ * -----------------------------------------------------------------
+ * BandGBTRS solves the N-dimensional system A x = b using
+ * the LU factorization in A and the pivot information in p
+ * computed in BandGBTRF. The solution x is returned in b. This
+ * routine cannot fail if the corresponding call to BandGBTRF
+ * did not fail.
+ * -----------------------------------------------------------------
+ */
+
+void BandGBTRS(BandMat A, long int *p, realtype *b);
+
+/*
+ * -----------------------------------------------------------------
+ * Function : BandZero
+ * -----------------------------------------------------------------
+ * Usage : BandZero(A);
+ * -----------------------------------------------------------------
+ * A(i,j) <- 0.0,    j-(A->mu) <= i <= j+(A->ml).
+ * -----------------------------------------------------------------
+ */
+
+void BandZero(BandMat A);
+
+/*
+ * -----------------------------------------------------------------
+ * Function : BandCopy
+ * -----------------------------------------------------------------
+ * Usage : BandCopy(A, B, copymu, copyml);
+ * -----------------------------------------------------------------
+ * BandCopy copies the submatrix with upper and lower bandwidths
+ * copymu, copyml of the N by N band matrix A into the N by N
+ * band matrix B.
+ * -----------------------------------------------------------------
+ */
+
+void BandCopy(BandMat A, BandMat B, long int copymu, long int copyml);
+
+/*
+ * -----------------------------------------------------------------
+ * Function: BandScale
+ * -----------------------------------------------------------------
+ * Usage : BandScale(c, A);
+ * -----------------------------------------------------------------
+ * A(i,j) <- c*A(i,j),   j-(A->mu) <= i <= j+(A->ml).
+ * -----------------------------------------------------------------
+ */
+
+void BandScale(realtype c, BandMat A);
+
+/*
+ * -----------------------------------------------------------------
+ * Function : BandAddI
+ * -----------------------------------------------------------------
+ * Usage : BandAddI(A);
+ * -----------------------------------------------------------------
+ * A(j,j) <- A(j,j)+1.0,   0 <= j <= (A->size)-1.
+ * -----------------------------------------------------------------
+ */
+
+void BandAddI(BandMat A);
+
+/*
+ * -----------------------------------------------------------------
+ * Function : BandFreeMat
+ * -----------------------------------------------------------------
+ * Usage : BandFreeMat(A);
+ * -----------------------------------------------------------------
+ * BandFreeMat frees the memory allocated by BandAllocMat for
+ * the band matrix A.
+ * -----------------------------------------------------------------
+ */
+
+void BandFreeMat(BandMat A);
+
+/*
+ * -----------------------------------------------------------------
+ * Function : BandFreePiv
+ * -----------------------------------------------------------------
+ * Usage : BandFreePiv(p);
+ * -----------------------------------------------------------------
+ * BandFreePiv frees the memory allocated by BandAllocPiv for
+ * the pivot information array p.
+ * -----------------------------------------------------------------
+ */
+
+void BandFreePiv(long int *p);
+
+/*
+ * -----------------------------------------------------------------
+ * Function : BandPrint
+ * -----------------------------------------------------------------
+ * Usage : BandPrint(A);
+ * -----------------------------------------------------------------
+ * This routine prints the N by N band matrix A (upper and lower
+ * bandwidths A->mu and A->ml, respectively) to standard output
+ * as it would normally appear on paper. It is intended as a
+ * debugging tool with small values of N. The elements are
+ * printed using the %g/lg/Lg option. A blank line is printed
+ * before and after the matrix.
+ * -----------------------------------------------------------------
+ */
+
+void BandPrint(BandMat A);
+
+/* Functions that use the realtype ** representation for a band matrix */
+
+/*
+ * -----------------------------------------------------------------
+ * Function : bandalloc
+ * -----------------------------------------------------------------
+ * Usage : realtype **a;
+ *         a = bandalloc(n, smu, ml);
+ *         if (a == NULL) ... memory request failed
+ * -----------------------------------------------------------------
+ * bandalloc(n, smu, ml) allocates storage for an n by n band
+ * matrix A with storage upper bandwidth smu and lower bandwidth
+ * ml. It returns a pointer to the newly allocated storage if
+ * successful. If the memory request cannot be satisfied, then
+ * bandalloc returns NULL. If, mathematically, A has upper and
+ * lower bandwidths mu and ml, respectively, then the value
+ * passed to bandalloc for smu may need to be greater than mu.
+ * The bandGBTRF routine writes the LU factors into the storage
+ * (named "a" in the above usage documentation) for A (thus destroying
+ * the original elements of A). The upper triangular factor U,
+ * however, may have a larger upper bandwidth than the upper
+ * bandwidth mu of A. Thus some "extra" storage for A must be
+ * allocated if A is to be factored by bandGBTRF. Pass smu as follows:
+ *
+ * (1) Pass smu = mu if A will not be factored.
+ *
+ * (2) Pass smu = MIN(n-1,mu+ml) if A will be factored.
+ *
+ * The underlying type of the band matrix returned is realtype**.
+ * If we allocate a band matrix A in realtype **a by
+ * a = bandalloc(n,smu,ml), then a[0] is a pointer to
+ * n * (smu + ml + 1) contiguous storage locations and a[j] is a
+ * pointer to the uppermost element in the storage for the jth
+ * column. The expression a[j][i-j+smu] references the (i,j)th
+ * element of A, where 0 <= i,j <= n-1 and j-mu <= i <= j+ml.
+ * (The elements a[j][0], a[j][1], ..., a[j][smu-mu-1] are used
+ * by bandGBTRF and bandGBTRS.)
+ * -----------------------------------------------------------------
+ */
+
+realtype **bandalloc(long int n, long int smu, long int ml);
+
+/*
+ * -----------------------------------------------------------------
+ * Function : bandallocpiv
+ * -----------------------------------------------------------------
+ * Usage : long int *pivot;
+ *         pivot = bandallocpiv(n);
+ *         if (pivot == NULL) ... memory request failed
+ * -----------------------------------------------------------------
+ * bandallocpiv(n) allocates an array of n integers. It returns a
+ * pointer to the first element in the array if successful. It
+ * returns NULL if the memory request could not be satisfied.
+ * -----------------------------------------------------------------
+ */
+
+long int *bandallocpiv(long int n);
+
+/*
+ * -----------------------------------------------------------------
+ * Function : bandGBTRF
+ * -----------------------------------------------------------------
+ * Usage : long int ier;
+ *         ier = bandGBTRF(a,n,mu,ml,smu,p);
+ *         if (ier > 0) ... zero element encountered during
+ *                          the factorization
+ * -----------------------------------------------------------------
+ * bandGBTRF(a,n,mu,ml,smu,p) factors the n by n band matrix A 
+ * (upper and lower bandwidths mu and ml, storage upper bandwidth smu)
+ * stored in "a". It overwrites the elements of A with the LU
+ * factors and it keeps track of the pivot rows chosen in the
+ * pivot array p.
+ *
+ * A successful LU factorization leaves a and pivot array p with
+ * the following information:
+ *
+ * (1) p[k] contains the row number of the pivot element chosen
+ *     at the beginning of elimination step k, k=0, 1, ..., n-1.
+ *
+ * (2) If the unique LU factorization of A is given by PA = LU,
+ *     where P is a permutation matrix, L is a lower triangular
+ *     matrix with all 1's on the diagonal, and U is an upper
+ *     triangular matrix, then the upper triangular part of A
+ *     (including its diagonal) contains U and the strictly lower
+ *     triangular part of A contains the multipliers, I-L.
+ *
+ * bandGBTRF returns 0 if successful. Otherwise it encountered a zero
+ * diagonal element during the factorization. In this case it
+ * returns the column index (numbered from one) at which it
+ * encountered the zero.
+ *
+ * IMPORTANT NOTE: Suppose A is a band matrix with upper
+ * bandwidth mu and lower bandwidth ml, then the upper triangular
+ * factor U can have upper bandwidth as big as MIN(n-1,mu+ml)
+ * because of partial pivoting. The lower triangular factor L has
+ * lower bandwidth ml. Thus, if A is to be factored and
+ * backsolved using bandGBTRF and bandGBTRS, then it should be allocated
+ * as a = bandalloc(n,smu,ml), where smu = MIN(n-1,mu+ml). The
+ * call to bandGBTRF is ier = bandGBTRF(a,n,mu,ml,smu,p). The
+ * corresponding call to bandGBTRS is bandGBTRS(a,n,smu,ml,p,b). The user 
+ * does not need to zero the "extra" storage allocated for the 
+ * purpose of factorization. This is handled by the bandGBTRF routine. 
+ * If A is not going to be factored and backsolved, then it can be
+ * allocated as a = bandalloc(n,smu,ml). In either case, all
+ * routines in this section use the parameter name smu for a
+ * parameter which must be the "storage upper bandwidth" which
+ * was passed to bandalloc.
+ * -----------------------------------------------------------------
+ */
+
+long int bandGBTRF(realtype **a, long int n, long int mu, long int ml, 
+                   long int smu, long int *p);
+
+/*
+ * -----------------------------------------------------------------
+ * Function : bandGBTRS
+ * -----------------------------------------------------------------
+ * Usage : realtype *b;
+ *         ier = bandGBTRF(a,n,mu,ml,smu,p);
+ *         if (ier == 0) bandGBTRS(a,n,smu,ml,p,b);
+ * -----------------------------------------------------------------
+ * bandGBTRS(a,n,smu,ml,p,b) solves the n by n linear system
+ * Ax = b, where A is band matrix stored in "a" with storage
+ * upper bandwidth smu and lower bandwidth ml. It assumes that A
+ * has been LU factored and the pivot array p has been set by a
+ * successful call bandGBTRF(a,n,mu,ml,smu,p). The solution x is
+ * written into the b array.
+ * -----------------------------------------------------------------
+ */
+
+void bandGBTRS(realtype **a, long int n, long int smu, 
+               long int ml, long int *p, realtype *b);
+
+/*
+ * -----------------------------------------------------------------
+ * Function : bandzero
+ * -----------------------------------------------------------------
+ * Usage : bandzero(a,n,mu,ml,smu);
+ * -----------------------------------------------------------------
+ * a(i,j) <- 0.0,   0 <= i,j <= n-1, j-mu <= i <= j+ml.
+ * -----------------------------------------------------------------
+ */
+
+void bandzero(realtype **a, long int n, long int mu, 
+              long int ml, long int smu);
+
+/*
+ * -----------------------------------------------------------------
+ * Function : bandcopy
+ * -----------------------------------------------------------------
+ * Usage : bandcopy(a,b,n,a_smu,b_smu,copymu,copyml);
+ * -----------------------------------------------------------------
+ * b(i,j) <- a(i,j), 0 <= i,j <= n-1, j-copymu <= i <= j+copyml.
+ * -----------------------------------------------------------------
+ */
+
+void bandcopy(realtype **a, realtype **b, long int n, 
+              long int a_smu, long int b_smu,
+              long int copymu, long int copyml);
+
+/*
+ * -----------------------------------------------------------------
+ * Function : bandscale
+ * -----------------------------------------------------------------
+ * Usage : bandscale(c,a,n,mu,ml);
+ * -----------------------------------------------------------------
+ * a(i,j) <- c*a(i,j),   0 <= i,j <= n-1, j-mu <= i <= j+ml.
+ * -----------------------------------------------------------------
+ */
+
+void bandscale(realtype c, realtype **a, long int n, 
+               long int mu, long int ml, long int smu);
+
+/*
+ * -----------------------------------------------------------------
+ * Function : bandaddI
+ * -----------------------------------------------------------------
+ * Usage : bandaddI(a,n,smu);
+ * -----------------------------------------------------------------
+ * a(j,j) <- a(j,j)+1.0,   0 <= j <= n-1.
+ * -----------------------------------------------------------------
+ */
+
+void bandaddI(realtype **a, long int n, long int smu);
+
+/*
+ * -----------------------------------------------------------------
+ * Function : bandfreepiv
+ * -----------------------------------------------------------------
+ * Usage : bandfreepiv(p);
+ * -----------------------------------------------------------------
+ * bandfreepiv(p) frees the pivot array p allocated by
+ * bandallocpiv.
+ * -----------------------------------------------------------------
+ */
+
+void bandfreepiv(long int *p);
+
+/*
+ * -----------------------------------------------------------------
+ * Function : bandfree
+ * -----------------------------------------------------------------
+ * Usage : bandfree(a);
+ * -----------------------------------------------------------------
+ * bandfree(a) frees the band matrix a allocated by bandalloc.
+ * -----------------------------------------------------------------
+ */
+
+void bandfree(realtype **a);
+
+/*
+ * -----------------------------------------------------------------
+ * Function : bandprint
+ * -----------------------------------------------------------------
+ * Usage : bandprint(a,n,mu,ml,smu);
+ * -----------------------------------------------------------------
+ * bandprint(a,n,mu,ml,smu) prints the n by n band matrix stored
+ * in a (with upper bandwidth mu and lower bandwidth ml) to
+ * standard output as it would normally appear on paper. It is
+ * intended as a debugging tool with small values of n. The
+ * elements are printed using the %g/lg/Lg option. A blank line
+ * is printed before and after the matrix.
+ * -----------------------------------------------------------------
+ */
+
+void bandprint(realtype **a, long int n, long int mu, long int ml, 
+               long int smu);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/sundials/sundials_config.h b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/sundials/sundials_config.h
new file mode 100644
index 0000000000000000000000000000000000000000..518483b0fa13b104f37d7926882549dbe0f6fe61
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/sundials/sundials_config.h	
@@ -0,0 +1,2 @@
+#define SUNDIALS_DOUBLE_PRECISION
+#define SUNDIALS_USE_GENERIC_MATH
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/sundials/sundials_dense.h b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/sundials/sundials_dense.h
new file mode 100644
index 0000000000000000000000000000000000000000..a5d975b3fe4b5fca6a8784be5528a970bff711ea
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/sundials/sundials_dense.h	
@@ -0,0 +1,313 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * -----------------------------------------------------------------
+ * Programmer: Radu Serban @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2006, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This is the header file for a generic package of DENSE matrix
+ * operations.  The routines listed in this file all use type
+ * DenseMat, defined below, for M by N matrices.
+ * These routines in turn call routines in the smalldense module,
+ * which use the type realtype** for matrices. This separation allows
+ * for possible modifications in which matrices of type DenseMat
+ * may not be stored contiguously, while small matrices can still
+ * be treated with the routines in smalldense.
+ *
+ * Routines that work with the type DenseMat begin with "Dense".
+ * The DenseAllocMat function allocates a dense matrix for use in
+ * the other DenseMat routines listed in this file. Matrix
+ * storage details are given in the documentation for the type
+ * DenseMat. The DenseAllocPiv function allocates memory for
+ * pivot information. The storage allocated by DenseAllocMat and
+ * DenseAllocPiv is deallocated by the routines DenseFreeMat and
+ * DenseFreePiv, respectively. The DenseGETRF and DenseGETRS
+ * routines perform the actual solution of a dense linear system.
+ *
+ * Routines that work with realtype** begin with "den". 
+ * The underlying matrix storage is described in the documentation 
+ * for denalloc in smalldense.h
+ * -----------------------------------------------------------------
+ */
+
+#ifndef _DENSE_H
+#define _DENSE_H
+
+#ifdef __cplusplus  /* wrapper to enable C++ usage */
+extern "C" {
+#endif
+
+#include <sundials/sundials_types.h>
+#include <sundials/sundials_smalldense.h>
+
+  /*
+   * ==================================================================
+   * Type definitions
+   * ==================================================================
+   */
+
+  /*
+   * -----------------------------------------------------------------
+   * Type : DenseMat
+   * -----------------------------------------------------------------
+   * The type DenseMat is defined to be a pointer to a structure
+   * with sizes (M and N) and a data field. The M and N fields 
+   * indicates the number of rows and columns, respectively of a dense 
+   * matrix, while the data field is a two dimensional array used for 
+   * component storage. The elements of a dense matrix are stored 
+   * columnwise (i.e columns are stored one on top of the other in 
+   * memory). If A is of type DenseMat, then the (i,j)th element 
+   * of A (with 0 <= i < M and 0 <= j < N) is given by the expression 
+   * (A->data)[j][i] or by the expression (A->data)[0][j*n+i]. 
+   * The macros below allow a user to access efficiently individual
+   * matrix elements without writing out explicit data structure
+   * references and without knowing too much about the underlying
+   * element storage. The only storage assumption needed is that
+   * elements are stored columnwise and that a pointer to the jth
+   * column of elements can be obtained via the DENSE_COL macro.
+   * Users should use these macros whenever possible.
+   * -----------------------------------------------------------------
+   */
+
+  typedef struct _DenseMat {
+    long int M;
+    long int N;
+    realtype **data;
+  } *DenseMat;
+
+  /*
+   * ==================================================================
+   * Data accessor macros
+   * ==================================================================
+   */
+
+  /*
+   * -----------------------------------------------------------------
+   * Macro : DENSE_ELEM
+   * -----------------------------------------------------------------
+   * Usage : DENSE_ELEM(A,i,j) = a_ij;  OR
+   *         a_ij = DENSE_ELEM(A,i,j);
+   * -----------------------------------------------------------------
+   * DENSE_ELEM(A,i,j) references the (i,j)th element of the M by N
+   * DenseMat A, 0 <= i < M ; 0 <= j < N.
+   * -----------------------------------------------------------------
+   */
+
+#define DENSE_ELEM(A,i,j) ((A->data)[j][i])
+
+  /*
+   * -----------------------------------------------------------------
+   * Macro : DENSE_COL
+   * -----------------------------------------------------------------
+   * Usage : col_j = DENSE_COL(A,j);
+   * -----------------------------------------------------------------
+   * DENSE_COL(A,j) references the jth column of the M by N
+   * DenseMat A, 0 <= j < N. The type of the expression DENSE_COL(A,j) 
+   * is (realtype *). After the assignment in the usage above, col_j 
+   * may be treated as an array indexed from 0 to M-1. 
+   * The (i,j)-th element of A is thus referenced by col_j[i].
+   * -----------------------------------------------------------------
+   */
+
+#define DENSE_COL(A,j) ((A->data)[j])
+
+  /*
+   * ==================================================================
+   * Function prototypes
+   * ==================================================================
+   */
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : DenseAllocMat
+   * -----------------------------------------------------------------
+   * Usage : A = DenseAllocMat(M, N);
+   *         if (A == NULL) ... memory request failed
+   * -----------------------------------------------------------------
+   * DenseAllocMat allocates memory for an M by N dense matrix and
+   * returns the storage allocated (type DenseMat). DenseAllocMat
+   * returns NULL if the request for matrix storage cannot be
+   * satisfied. See the above documentation for the type DenseMat
+   * for matrix storage details.
+   * -----------------------------------------------------------------
+   */
+
+  DenseMat DenseAllocMat(long int M, long int N);
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : DenseAllocPiv
+   * -----------------------------------------------------------------
+   * Usage : p = DenseAllocPiv(N);
+   *         if (p == NULL) ... memory request failed
+   * -----------------------------------------------------------------
+   * DenseAllocPiv allocates memory for pivot information to be
+   * filled in by the DenseGETRF routine during the factorization
+   * of an N by N dense matrix. The underlying type for pivot
+   * information is an array of N integers and this routine returns
+   * the pointer to the memory it allocates. If the request for
+   * pivot storage cannot be satisfied, DenseAllocPiv returns NULL.
+   * -----------------------------------------------------------------
+   */
+
+  long int *DenseAllocPiv(long int N);
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : DenseGETRF
+   * -----------------------------------------------------------------
+   * Usage : ier = DenseGETRF(A, p);
+   *         if (ier != 0) ... A is singular
+   * -----------------------------------------------------------------
+   * DenseGETRF performs the LU factorization of the M by N dense
+   * matrix A. This is done using standard Gaussian elimination
+   * with partial (row) pivoting. Note that this applies only
+   * to matrices with M >= N and full column rank.
+   *
+   * A successful LU factorization leaves the matrix A and the
+   * pivot array p with the following information:
+   *
+   * (1) p[k] contains the row number of the pivot element chosen
+   *     at the beginning of elimination step k, k=0, 1, ..., N-1.
+   *
+   * (2) If the unique LU factorization of A is given by PA = LU,
+   *     where P is a permutation matrix, L is a lower trapezoidal
+   *     matrix with all 1's on the diagonal, and U is an upper
+   *     triangular matrix, then the upper triangular part of A
+   *     (including its diagonal) contains U and the strictly lower
+   *     trapezoidal part of A contains the multipliers, I-L.
+   *
+   * For square matrices (M=N), L is unit lower triangular.
+   *
+   * DenseGETRF returns 0 if successful. Otherwise it encountered
+   * a zero diagonal element during the factorization. In this case
+   * it returns the column index (numbered from one) at which
+   * it encountered the zero.
+   * -----------------------------------------------------------------
+   */
+
+  long int DenseGETRF(DenseMat A, long int *p);
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : DenseGETRS
+   * -----------------------------------------------------------------
+   * Usage : DenseGETRS(A, p, b);
+   * -----------------------------------------------------------------
+   * DenseGETRS solves the N-dimensional system A x = b using
+   * the LU factorization in A and the pivot information in p
+   * computed in DenseGETRF. The solution x is returned in b. This
+   * routine cannot fail if the corresponding call to DenseGETRF
+   * did not fail.
+   * DenseGETRS does NOT check for a square matrix!
+   * -----------------------------------------------------------------
+   */
+
+  void DenseGETRS(DenseMat A, long int *p, realtype *b);
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : DenseZero
+   * -----------------------------------------------------------------
+   * Usage : DenseZero(A);
+   * -----------------------------------------------------------------
+   * DenseZero sets all the elements of the M by N matrix A to 0.0.
+   * -----------------------------------------------------------------
+   */
+
+  void DenseZero(DenseMat A);
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : DenseCopy
+   * -----------------------------------------------------------------
+   * Usage : DenseCopy(A, B);
+   * -----------------------------------------------------------------
+   * DenseCopy copies the contents of the M by N matrix A into the
+   * M by N matrix B.
+   * -----------------------------------------------------------------
+   */
+
+  void DenseCopy(DenseMat A, DenseMat B);
+
+  /*
+   * -----------------------------------------------------------------
+   * Function: DenseScale
+   * -----------------------------------------------------------------
+   * Usage : DenseScale(c, A);
+   * -----------------------------------------------------------------
+   * DenseScale scales the elements of the M by N matrix A by the
+   * constant c and stores the result back in A.
+   * -----------------------------------------------------------------
+   */
+
+  void DenseScale(realtype c, DenseMat A);
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : DenseAddI
+   * -----------------------------------------------------------------
+   * Usage : DenseAddI(A);
+   * -----------------------------------------------------------------
+   * DenseAddI adds 1.0 to the main diagonal (A_ii, i=1,2,...,N-1) of
+   * the M by N matrix A (M >= N) and stores the result back in A.
+   * DenseAddI is typically used with square matrices.
+   * DenseAddI does not check for M >= N and therefore a segmentation
+   * fault will occur if M < N!
+   * -----------------------------------------------------------------
+   */
+
+  void DenseAddI(DenseMat A);
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : DenseFreeMat
+   * -----------------------------------------------------------------
+   * Usage : DenseFreeMat(A);
+   * -----------------------------------------------------------------
+   * DenseFreeMat frees the memory allocated by DenseAllocMat for
+   * the M by N matrix A.
+   * -----------------------------------------------------------------
+   */
+
+  void DenseFreeMat(DenseMat A);
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : DenseFreePiv
+   * -----------------------------------------------------------------
+   * Usage : DenseFreePiv(p);
+   * -----------------------------------------------------------------
+   * DenseFreePiv frees the memory allocated by DenseAllocPiv for
+   * the pivot information array p.
+   * -----------------------------------------------------------------
+   */
+
+  void DenseFreePiv(long int *p);
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : DensePrint
+   * -----------------------------------------------------------------
+   * Usage : DensePrint(A);
+   * -----------------------------------------------------------------
+   * This routine prints the M by N dense matrix A to standard output
+   * as it would normally appear on paper. It is intended as a 
+   * debugging tool with small values of M and N. The elements are
+   * printed using the %g/%lg/%Lg option. A blank line is printed
+   * before and after the matrix.
+   * -----------------------------------------------------------------
+   */
+
+  void DensePrint(DenseMat A);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/sundials/sundials_fnvector.h b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/sundials/sundials_fnvector.h
new file mode 100644
index 0000000000000000000000000000000000000000..335337fc985164b28b5e280c0c96377fa31fa76d
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/sundials/sundials_fnvector.h	
@@ -0,0 +1,41 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * ----------------------------------------------------------------- 
+ * Programmer(s): Radu Serban and Aaron Collier @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2002, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This file (companion of nvector.h) contains definitions 
+ * needed for the initialization of vector operations in Fortran.
+ * -----------------------------------------------------------------
+ */
+
+
+#ifndef _FNVECTOR_H
+#define _FNVECTOR_H
+
+#ifdef __cplusplus  /* wrapper to enable C++ usage */
+extern "C" {
+#endif
+
+#ifndef _SUNDIALS_CONFIG_H
+#define _SUNDIALS_CONFIG_H
+#include <sundials/sundials_config.h>
+#endif
+
+/* SUNDIALS solver IDs */
+
+#define FCMIX_CVODE   1
+#define FCMIX_IDA     2
+#define FCMIX_KINSOL  3
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/sundials/sundials_iterative.h b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/sundials/sundials_iterative.h
new file mode 100644
index 0000000000000000000000000000000000000000..0ed0b5c0f6e45dad2e6d9a98dabc263f6bf571cb
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/sundials/sundials_iterative.h	
@@ -0,0 +1,242 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * ----------------------------------------------------------------- 
+ * Programmer(s): Scott D. Cohen and Alan C. Hindmarsh @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2002, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This header file contains declarations intended for use by
+ * generic iterative solvers of Ax = b. The enumeration gives
+ * symbolic names for the type  of preconditioning to be used.
+ * The function type declarations give the prototypes for the
+ * functions to be called within an iterative linear solver, that
+ * are responsible for
+ *    multiplying A by a given vector v (ATimesFn), and
+ *    solving the preconditioner equation Pz = r (PSolveFn).
+ * -----------------------------------------------------------------
+ */
+
+#ifndef _ITERATIVE_H
+#define _ITERATIVE_H
+
+#ifdef __cplusplus  /* wrapper to enable C++ usage */
+extern "C" {
+#endif
+
+#include <sundials/sundials_nvector.h>
+
+
+/*
+ * -----------------------------------------------------------------
+ * enum : types of preconditioning                                
+ * -----------------------------------------------------------------
+ * PREC_NONE  : The iterative linear solver should not use             
+ *              preconditioning.                                       
+ *                                                                
+ * PREC_LEFT  : The iterative linear solver uses preconditioning on    
+ *              the left only.                                         
+ *                                                                
+ * PREC_RIGHT : The iterative linear solver uses preconditioning on    
+ *              the right only.                                        
+ *                                                                
+ * PREC_BOTH  : The iterative linear solver uses preconditioning on    
+ *              both the left and the right.                           
+ * -----------------------------------------------------------------
+ */
+
+enum { PREC_NONE, PREC_LEFT, PREC_RIGHT, PREC_BOTH };
+
+/*
+ * -----------------------------------------------------------------
+ * enum : types of Gram-Schmidt routines                          
+ * -----------------------------------------------------------------
+ * MODIFIED_GS  : The iterative solver uses the modified          
+ *                Gram-Schmidt routine ModifiedGS listed in this  
+ *                file.                                           
+ *                                                                
+ * CLASSICAL_GS : The iterative solver uses the classical         
+ *                Gram-Schmidt routine ClassicalGS listed in this 
+ *                file.                                           
+ * -----------------------------------------------------------------
+ */
+
+enum { MODIFIED_GS = 1, CLASSICAL_GS = 2 };
+
+/*
+ * -----------------------------------------------------------------
+ * Type: ATimesFn                                                 
+ * -----------------------------------------------------------------
+ * An ATimesFn multiplies Av and stores the result in z. The      
+ * caller is responsible for allocating memory for the z vector.  
+ * The parameter A_data is a pointer to any information about A   
+ * which the function needs in order to do its job. The vector v  
+ * is unchanged. An ATimesFn returns 0 if successful and a        
+ * non-zero value if unsuccessful.                                
+ * -----------------------------------------------------------------
+ */
+
+typedef int (*ATimesFn)(void *A_data, N_Vector v, N_Vector z);
+
+/*
+ * -----------------------------------------------------------------
+ * Type: PSolveFn                                                 
+ * -----------------------------------------------------------------
+ * A PSolveFn solves the preconditioner equation Pz = r for the   
+ * vector z. The caller is responsible for allocating memory for  
+ * the z vector. The parameter P_data is a pointer to any         
+ * information about P which the function needs in order to do    
+ * its job. The parameter lr is input, and indicates whether P    
+ * is to be taken as the left preconditioner or the right         
+ * preconditioner: lr = 1 for left and lr = 2 for right.          
+ * If preconditioning is on one side only, lr can be ignored.     
+ * The vector r is unchanged.                                     
+ * A PSolveFn returns 0 if successful and a non-zero value if     
+ * unsuccessful.  On a failure, a negative return value indicates 
+ * an unrecoverable condition, while a positive value indicates   
+ * a recoverable one, in which the calling routine may reattempt  
+ * the solution after updating preconditioner data.               
+ * -----------------------------------------------------------------
+ */
+
+typedef int (*PSolveFn)(void *P_data, N_Vector r, N_Vector z, int lr);
+
+/*
+ * -----------------------------------------------------------------
+ * Function: ModifiedGS                                           
+ * -----------------------------------------------------------------
+ * ModifiedGS performs a modified Gram-Schmidt orthogonalization  
+ * of the N_Vector v[k] against the p unit N_Vectors at           
+ * v[k-1], v[k-2], ..., v[k-p].                                   
+ *                                                                
+ * v is an array of (k+1) N_Vectors v[i], i=0, 1, ..., k.         
+ * v[k-1], v[k-2], ..., v[k-p] are assumed to have L2-norm        
+ * equal to 1.                                                    
+ *                                                                
+ * h is the output k by k Hessenberg matrix of inner products.    
+ * This matrix must be allocated row-wise so that the (i,j)th     
+ * entry is h[i][j]. The inner products (v[i],v[k]),              
+ * i=i0, i0+1, ..., k-1, are stored at h[i][k-1]. Here            
+ * i0=MAX(0,k-p).                                                 
+ *                                                                
+ * k is the index of the vector in the v array that needs to be   
+ * orthogonalized against previous vectors in the v array.        
+ *                                                                
+ * p is the number of previous vectors in the v array against     
+ * which v[k] is to be orthogonalized.                            
+ *                                                                
+ * new_vk_norm is a pointer to memory allocated by the caller to  
+ * hold the Euclidean norm of the orthogonalized vector v[k].     
+ *                                                                
+ * If (k-p) < 0, then ModifiedGS uses p=k. The orthogonalized     
+ * v[k] is NOT normalized and is stored over the old v[k]. Once   
+ * the orthogonalization has been performed, the Euclidean norm   
+ * of v[k] is stored in (*new_vk_norm).                           
+ *                                                                
+ * ModifiedGS returns 0 to indicate success. It cannot fail.      
+ * -----------------------------------------------------------------
+ */                                                                
+
+int ModifiedGS(N_Vector *v, realtype **h, int k, int p, 
+               realtype *new_vk_norm);
+
+/*
+ * -----------------------------------------------------------------
+ * Function: ClassicalGS                                          
+ * -----------------------------------------------------------------
+ * ClassicalGS performs a classical Gram-Schmidt                  
+ * orthogonalization of the N_Vector v[k] against the p unit      
+ * N_Vectors at v[k-1], v[k-2], ..., v[k-p]. The parameters v, h, 
+ * k, p, and new_vk_norm are as described in the documentation    
+ * for ModifiedGS.                                                
+ *                                                                
+ * temp is an N_Vector which can be used as workspace by the      
+ * ClassicalGS routine.                                           
+ *                                                                
+ * s is a length k array of realtype which can be used as         
+ * workspace by the ClassicalGS routine.                          
+ *
+ * ClassicalGS returns 0 to indicate success. It cannot fail.     
+ * -----------------------------------------------------------------
+ */
+
+int ClassicalGS(N_Vector *v, realtype **h, int k, int p, 
+                realtype *new_vk_norm, N_Vector temp, realtype *s);
+
+/*
+ * -----------------------------------------------------------------
+ * Function: QRfact                                               
+ * -----------------------------------------------------------------
+ * QRfact performs a QR factorization of the Hessenberg matrix H. 
+ *                                                                
+ * n is the problem size; the matrix H is (n+1) by n.             
+ *                                                                
+ * h is the (n+1) by n Hessenberg matrix H to be factored. It is  
+ * stored row-wise.                                               
+ *                                                                
+ * q is an array of length 2*n containing the Givens rotations    
+ * computed by this function. A Givens rotation has the form:     
+ * | c  -s |                                                      
+ * | s   c |.                                                     
+ * The components of the Givens rotations are stored in q as      
+ * (c, s, c, s, ..., c, s).                                       
+ *                                                                
+ * job is a control flag. If job==0, then a new QR factorization  
+ * is performed. If job!=0, then it is assumed that the first     
+ * n-1 columns of h have already been factored and only the last  
+ * column needs to be updated.                                    
+ *                                                                
+ * QRfact returns 0 if successful. If a zero is encountered on    
+ * the diagonal of the triangular factor R, then QRfact returns   
+ * the equation number of the zero entry, where the equations are 
+ * numbered from 1, not 0. If QRsol is subsequently called in     
+ * this situation, it will return an error because it could not   
+ * divide by the zero diagonal entry.                             
+ * -----------------------------------------------------------------
+ */                                                                
+
+int QRfact(int n, realtype **h, realtype *q, int job);
+
+/*                                                                
+ * -----------------------------------------------------------------
+ * Function: QRsol                                                
+ * -----------------------------------------------------------------
+ * QRsol solves the linear least squares problem                  
+ *                                                                
+ * min (b - H*x, b - H*x), x in R^n,                              
+ *                                                                
+ * where H is a Hessenberg matrix, and b is in R^(n+1).           
+ * It uses the QR factors of H computed by QRfact.                
+ *                                                                
+ * n is the problem size; the matrix H is (n+1) by n.             
+ *                                                                
+ * h is a matrix (computed by QRfact) containing the upper        
+ * triangular factor R of the original Hessenberg matrix H.       
+ *                                                                
+ * q is an array of length 2*n (computed by QRfact) containing    
+ * the Givens rotations used to factor H.                         
+ *                                                                
+ * b is the (n+1)-vector appearing in the least squares problem   
+ * above.                                                         
+ *                                                                
+ * On return, b contains the solution x of the least squares      
+ * problem, if QRsol was successful.                              
+ *                                                                
+ * QRsol returns a 0 if successful.  Otherwise, a zero was        
+ * encountered on the diagonal of the triangular factor R.        
+ * In this case, QRsol returns the equation number (numbered      
+ * from 1, not 0) of the zero entry.                              
+ * -----------------------------------------------------------------
+ */                                                                
+
+int QRsol(int n, realtype **h, realtype *q, realtype *b);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/sundials/sundials_math.h b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/sundials/sundials_math.h
new file mode 100644
index 0000000000000000000000000000000000000000..34c2f5ba56e4b1ef26cd5ef4448dce15b73a7c82
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/sundials/sundials_math.h	
@@ -0,0 +1,139 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * -----------------------------------------------------------------
+ * Programmer(s): Scott D. Cohen, Alan C. Hindmarsh and
+ *                Aaron Collier @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2002, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This is the header file for a simple C-language math library. The
+ * routines listed here work with the type realtype as defined in
+ * the header file sundials_types.h.
+ * -----------------------------------------------------------------
+ */
+
+#ifndef _SUNDIALSMATH_H
+#define _SUNDIALSMATH_H
+
+#ifdef __cplusplus  /* wrapper to enable C++ usage */
+extern "C" {
+#endif
+
+#include <sundials/sundials_types.h>
+
+/*
+ * -----------------------------------------------------------------
+ * Macros : MIN and MAX
+ * -----------------------------------------------------------------
+ * MIN(A,B) returns the minimum of A and B
+ *
+ * MAX(A,B) returns the maximum of A and B
+ *
+ * SQR(A) returns A^2
+ * -----------------------------------------------------------------
+ */
+
+#ifndef MIN
+#define MIN(A, B) ((A) < (B) ? (A) : (B))
+#endif
+
+#ifndef MAX
+#define MAX(A, B) ((A) > (B) ? (A) : (B))
+#endif
+
+#ifndef SQR
+#define SQR(A) ((A)*(A))
+#endif
+
+#ifndef ABS
+#define ABS RAbs
+#endif
+
+#ifndef SQRT
+#define SQRT RSqrt
+#endif
+
+#ifndef EXP
+#define EXP RExp
+#endif
+
+/*
+ * -----------------------------------------------------------------
+ * Function : RPowerI
+ * -----------------------------------------------------------------
+ * Usage : int exponent;
+ *         realtype base, ans;
+ *         ans = RPowerI(base,exponent);
+ * -----------------------------------------------------------------
+ * RPowerI returns the value of base^exponent, where base is of type
+ * realtype and exponent is of type int.
+ * -----------------------------------------------------------------
+ */
+
+realtype RPowerI(realtype base, int exponent);
+
+/*
+ * -----------------------------------------------------------------
+ * Function : RPowerR
+ * -----------------------------------------------------------------
+ * Usage : realtype base, exponent, ans;
+ *         ans = RPowerR(base,exponent);
+ * -----------------------------------------------------------------
+ * RPowerR returns the value of base^exponent, where both base and
+ * exponent are of type realtype. If base < ZERO, then RPowerR
+ * returns ZERO.
+ * -----------------------------------------------------------------
+ */
+
+realtype RPowerR(realtype base, realtype exponent);
+
+/*
+ * -----------------------------------------------------------------
+ * Function : RSqrt
+ * -----------------------------------------------------------------
+ * Usage : realtype sqrt_x;
+ *         sqrt_x = RSqrt(x);
+ * -----------------------------------------------------------------
+ * RSqrt(x) returns the square root of x. If x < ZERO, then RSqrt
+ * returns ZERO.
+ * -----------------------------------------------------------------
+ */
+
+realtype RSqrt(realtype x);
+
+/*
+ * -----------------------------------------------------------------
+ * Function : RAbs (a.k.a. ABS)
+ * -----------------------------------------------------------------
+ * Usage : realtype abs_x;
+ *         abs_x = RAbs(x);
+ * -----------------------------------------------------------------
+ * RAbs(x) returns the absolute value of x.
+ * -----------------------------------------------------------------
+ */
+
+realtype RAbs(realtype x);
+
+/*
+ * -----------------------------------------------------------------
+ * Function : RExp (a.k.a. EXP)
+ * -----------------------------------------------------------------
+ * Usage : realtype exp_x;
+ *         exp_x = RExp(x);
+ * -----------------------------------------------------------------
+ * RExp(x) returns e^x (base-e exponential function).
+ * -----------------------------------------------------------------
+ */
+
+realtype RExp(realtype x);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/sundials/sundials_nvector.h b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/sundials/sundials_nvector.h
new file mode 100644
index 0000000000000000000000000000000000000000..fcf685008f7f39c78c64af44f83a97cf61d79c34
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/sundials/sundials_nvector.h	
@@ -0,0 +1,373 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * ----------------------------------------------------------------- 
+ * Programmer(s): Radu Serban and Aaron Collier @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2002, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This is the header file for a generic NVECTOR package.
+ * It defines the N_Vector structure (_generic_N_Vector) which
+ * contains the following fields:
+ *   - an implementation-dependent 'content' field which contains
+ *     the description and actual data of the vector
+ *   - an 'ops' filed which contains a structure listing operations
+ *     acting on such vectors
+ *
+ * Part I of this file contains type declarations for the
+ * _generic_N_Vector and _generic_N_Vector_Ops structures, as well
+ * as references to pointers to such structures (N_Vector).
+ *
+ * Part II of this file contains the prototypes for the vector
+ * functions which operate on N_Vector.
+ *
+ * At a minimum, a particular implementation of an NVECTOR must
+ * do the following:
+ *  - specify the 'content' field of N_Vector,
+ *  - implement the operations on those N_Vectors,
+ *  - provide a constructor routine for new vectors
+ *
+ * Additionally, an NVECTOR implementation may provide the following:
+ *  - macros to access the underlying N_Vector data
+ *  - a constructor for an array of N_Vectors
+ *  - a constructor for an empty N_Vector (i.e., a new N_Vector with
+ *    a NULL data pointer).
+ *  - a routine to print the content of an N_Vector
+ * -----------------------------------------------------------------
+ */
+
+#ifndef _NVECTOR_H
+#define _NVECTOR_H
+
+#ifdef __cplusplus  /* wrapper to enable C++ usage */
+extern "C" {
+#endif
+
+#include <sundials/sundials_types.h>
+
+/*
+ * -----------------------------------------------------------------
+ * Generic definition of N_Vector
+ * -----------------------------------------------------------------
+ */
+
+/* Forward reference for pointer to N_Vector_Ops object */
+typedef struct _generic_N_Vector_Ops *N_Vector_Ops;
+
+/* Forward reference for pointer to N_Vector object */
+typedef struct _generic_N_Vector *N_Vector;
+
+/* Define array of N_Vectors */
+typedef N_Vector *N_Vector_S;
+
+/* Structure containing function pointers to vector operations  */  
+struct _generic_N_Vector_Ops {
+  N_Vector    (*nvclone)(N_Vector);
+  N_Vector    (*nvcloneempty)(N_Vector);
+  void        (*nvdestroy)(N_Vector);
+  void        (*nvspace)(N_Vector, long int *, long int *);
+  realtype*   (*nvgetarraypointer)(N_Vector);
+  void        (*nvsetarraypointer)(realtype *, N_Vector);
+  void        (*nvlinearsum)(realtype, N_Vector, realtype, N_Vector, N_Vector); 
+  void        (*nvconst)(realtype, N_Vector);
+  void        (*nvprod)(N_Vector, N_Vector, N_Vector);
+  void        (*nvdiv)(N_Vector, N_Vector, N_Vector);
+  void        (*nvscale)(realtype, N_Vector, N_Vector);
+  void        (*nvabs)(N_Vector, N_Vector);
+  void        (*nvinv)(N_Vector, N_Vector);
+  void        (*nvaddconst)(N_Vector, realtype, N_Vector);
+  realtype    (*nvdotprod)(N_Vector, N_Vector);
+  realtype    (*nvmaxnorm)(N_Vector);
+  realtype    (*nvwrmsnorm)(N_Vector, N_Vector);
+  realtype    (*nvwrmsnormmask)(N_Vector, N_Vector, N_Vector);
+  realtype    (*nvmin)(N_Vector);
+  realtype    (*nvwl2norm)(N_Vector, N_Vector);
+  realtype    (*nvl1norm)(N_Vector);
+  void        (*nvcompare)(realtype, N_Vector, N_Vector);
+  booleantype (*nvinvtest)(N_Vector, N_Vector);
+  booleantype (*nvconstrmask)(N_Vector, N_Vector, N_Vector);
+  realtype    (*nvminquotient)(N_Vector, N_Vector);
+};
+
+/*
+ * -----------------------------------------------------------------
+ * A vector is a structure with an implementation-dependent
+ * 'content' field, and a pointer to a structure of vector
+ * operations corresponding to that implementation.
+ * -----------------------------------------------------------------
+ */
+
+struct _generic_N_Vector {
+  void *content;
+  struct _generic_N_Vector_Ops *ops;
+};
+  
+/*
+ * -----------------------------------------------------------------
+ * Functions exported by NVECTOR module
+ * -----------------------------------------------------------------
+ */
+
+/*
+ * -----------------------------------------------------------------
+ * N_VClone
+ *   Creates a new vector of the same type as an existing vector.
+ *   It does not copy the vector, but rather allocates storage for
+ *   the new vector.
+ *
+ * N_VCloneEmpty
+ *   Creates a new vector of the same type as an existing vector,
+ *   but does not allocate storage.
+ *
+ * N_VDestroy
+ *   Destroys a vector created with N_VClone.
+ *
+ * N_VSpace
+ *   Returns space requirements for one N_Vector (type 'realtype' in
+ *   lrw and type 'long int' in liw).
+ *
+ * N_VGetArrayPointer
+ *   Returns a pointer to the data component of the given N_Vector.
+ *   NOTE: This function assumes that the internal data is stored
+ *   as a contiguous 'realtype' array. This routine is only used in
+ *   the solver-specific interfaces to the dense and banded linear
+ *   solvers, as well as the interfaces to  the banded preconditioners
+ *   distributed with SUNDIALS.
+ *   
+ * N_VSetArrayPointer
+ *   Overwrites the data field in the given N_Vector with a user-supplied
+ *   array of type 'realtype'.
+ *   NOTE: This function assumes that the internal data is stored
+ *   as a contiguous 'realtype' array. This routine is only used in
+ *   the interfaces to the dense linear solver.
+ *
+ * N_VLinearSum
+ *   Performs the operation z = a*x + b*y
+ *
+ * N_VConst
+ *   Performs the operation z[i] = c for i = 0, 1, ..., N-1
+ *
+ * N_VProd
+ *   Performs the operation z[i] = x[i]*y[i] for i = 0, 1, ..., N-1
+ *
+ * N_VDiv
+ *   Performs the operation z[i] = x[i]/y[i] for i = 0, 1, ..., N-1
+ *
+ * N_VScale
+ *   Performs the operation z = c*x
+ *
+ * N_VAbs
+ *   Performs the operation z[i] = |x[i]| for i = 0, 1, ..., N-1
+ *
+ * N_VInv
+ *   Performs the operation z[i] = 1/x[i] for i = 0, 1, ..., N-1
+ *   This routine does not check for division by 0. It should be
+ *   called only with an N_Vector x which is guaranteed to have
+ *   all non-zero components.
+ *
+ * N_VAddConst
+ *   Performs the operation z[i] = x[i] + b   for i = 0, 1, ..., N-1
+ *
+ * N_VDotProd
+ *   Returns the dot product of two vectors:
+ *         sum (i = 0 to N-1) {x[i]*y[i]}
+ *
+ * N_VMaxNorm
+ *   Returns the maximum norm of x:
+ *         max (i = 0 to N-1) ABS(x[i])
+ *
+ * N_VWrmsNorm
+ *   Returns the weighted root mean square norm of x with weight 
+ *   vector w:
+ *         sqrt [(sum (i = 0 to N-1) {(x[i]*w[i])^2})/N]
+ *
+ * N_VWrmsNormMask
+ *   Returns the weighted root mean square norm of x with weight
+ *   vector w, masked by the elements of id:
+ *         sqrt [(sum (i = 0 to N-1) {(x[i]*w[i]*msk[i])^2})/N]
+ *   where msk[i] = 1.0 if id[i] > 0 and
+ *         msk[i] = 0.0 if id[i] < 0
+ *
+ * N_VMin
+ *   Returns the smallest element of x:
+ *         min (i = 0 to N-1) x[i]
+ *
+ * N_VWL2Norm
+ *   Returns the weighted Euclidean L2 norm of x with weight 
+ *   vector w:
+ *         sqrt [(sum (i = 0 to N-1) {(x[i]*w[i])^2})]
+ *
+ * N_VL1Norm
+ *   Returns the L1 norm of x:
+ *         sum (i = 0 to N-1) {ABS(x[i])}
+ *
+ * N_VCompare
+ *   Performs the operation
+ *          z[i] = 1.0 if ABS(x[i]) >= c   i = 0, 1, ..., N-1
+ *                 0.0 otherwise
+ *
+ * N_VInvTest
+ *   Performs the operation z[i] = 1/x[i] with a test for 
+ *   x[i] == 0.0 before inverting x[i].
+ *   This routine returns TRUE if all components of x are non-zero 
+ *   (successful inversion) and returns FALSE otherwise.
+ *
+ * N_VConstrMask
+ *   Performs the operation : 
+ *       m[i] = 1.0 if constraint test fails for x[i]
+ *       m[i] = 0.0 if constraint test passes for x[i]
+ *   where the constraint tests are as follows:
+ *      If c[i] = +2.0, then x[i] must be >  0.0.
+ *      If c[i] = +1.0, then x[i] must be >= 0.0.
+ *      If c[i] = -1.0, then x[i] must be <= 0.0.
+ *      If c[i] = -2.0, then x[i] must be <  0.0.
+ *   This routine returns a boolean FALSE if any element failed
+ *   the constraint test, TRUE if all passed. It also sets a
+ *   mask vector m, with elements equal to 1.0 where the
+ *   corresponding constraint test failed, and equal to 0.0
+ *   where the constraint test passed.
+ *   This routine is specialized in that it is used only for
+ *   constraint checking.
+ *
+ * N_VMinQuotient
+ *   Performs the operation : 
+ *       minq  = min ( num[i]/denom[i]) over all i such that   
+ *       denom[i] != 0.
+ *   This routine returns the minimum of the quotients obtained
+ *   by term-wise dividing num[i] by denom[i]. A zero element
+ *   in denom will be skipped. If no such quotients are found,
+ *   then the large value BIG_REAL is returned.
+ *
+ * -----------------------------------------------------------------
+ *
+ * The following table lists the vector functions used by
+ * different modules in SUNDIALS. The symbols in the table
+ * have the following meaning:
+ * S    -  called by the solver;
+ * D    -  called by the dense linear solver module
+ * B    -  called by the band linear solver module
+ * Di   -  called by the diagonal linear solver module
+ * I    -  called by the iterative linear solver module
+ * BP   -  called by the band preconditioner module
+ * BBDP -  called by the band-block diagonal preconditioner module
+ * F    -  called by the Fortran-to-C interface
+ *
+ *                  ------------------------------------------------
+ *                                         MODULES                  
+ * NVECTOR          ------------------------------------------------
+ * FUNCTIONS          CVODE/CVODES          IDA             KINSOL    
+ * -----------------------------------------------------------------
+ * N_VClone           S Di I                S I BBDP        S I BBDP
+ * -----------------------------------------------------------------
+ * N_VCloneEmpty      F                     F               F
+ * -----------------------------------------------------------------
+ * N_VDestroy         S Di I                S I BBDP        S I BBDP
+ * -----------------------------------------------------------------
+ * N_VSpace           S                     S               S         
+ * -----------------------------------------------------------------
+ * N_VGetArrayPointer D B BP BBDP F         D B BBDP        BBDP F     
+ * -----------------------------------------------------------------
+ * N_VSetArrayPointer D F                   D               F
+ * -----------------------------------------------------------------
+ * N_VLinearSum       S D Di I              S D I           S I       
+ * -----------------------------------------------------------------
+ * N_VConst           S I                   S I             I       
+ * -----------------------------------------------------------------
+ * N_VProd            S Di I                S I             S I       
+ * -----------------------------------------------------------------
+ * N_VDiv             S Di I                S I             S I
+ * -----------------------------------------------------------------
+ * N_VScale           S D B Di I BP BBDP    S D B I BBDP    S I BBDP  
+ * -----------------------------------------------------------------
+ * N_VAbs             S                     S               S         
+ * -----------------------------------------------------------------
+ * N_VInv             S Di                  S               S         
+ * -----------------------------------------------------------------
+ * N_VAddConst        S Di                  S                        
+ * -----------------------------------------------------------------
+ * N_VDotProd         I                     I               I         
+ * -----------------------------------------------------------------
+ * N_VMaxNorm         S                     S               S         
+ * -----------------------------------------------------------------
+ * N_VWrmsNorm        S D B I BP BBDP       S                         
+ * -----------------------------------------------------------------
+ * N_VWrmsNormMask                          S                         
+ * -----------------------------------------------------------------
+ * N_VMin             S                     S               S         
+ * -----------------------------------------------------------------
+ * N_VWL2Norm                                               S I       
+ * -----------------------------------------------------------------
+ * N_VL1Norm                                                I
+ * -----------------------------------------------------------------
+ * N_VCompare         Di                    S                         
+ * -----------------------------------------------------------------
+ * N_VInvTest         Di                                              
+ * -----------------------------------------------------------------
+ * N_VConstrMask                            S               S         
+ * -----------------------------------------------------------------
+ * N_VMinQuotient                           S               S         
+ * -----------------------------------------------------------------
+ */
+  
+N_Vector N_VClone(N_Vector w);
+N_Vector N_VCloneEmpty(N_Vector w);
+void N_VDestroy(N_Vector v);
+void N_VSpace(N_Vector v, long int *lrw, long int *liw);
+realtype *N_VGetArrayPointer(N_Vector v);
+void N_VSetArrayPointer(realtype *v_data, N_Vector v);
+void N_VLinearSum(realtype a, N_Vector x, realtype b, N_Vector y, N_Vector z);
+void N_VConst(realtype c, N_Vector z);
+void N_VProd(N_Vector x, N_Vector y, N_Vector z);
+void N_VDiv(N_Vector x, N_Vector y, N_Vector z);
+void N_VScale(realtype c, N_Vector x, N_Vector z);
+void N_VAbs(N_Vector x, N_Vector z);
+void N_VInv(N_Vector x, N_Vector z);
+void N_VAddConst(N_Vector x, realtype b, N_Vector z);
+realtype N_VDotProd(N_Vector x, N_Vector y);
+realtype N_VMaxNorm(N_Vector x);
+realtype N_VWrmsNorm(N_Vector x, N_Vector w);
+realtype N_VWrmsNormMask(N_Vector x, N_Vector w, N_Vector id);
+realtype N_VMin(N_Vector x);
+realtype N_VWL2Norm(N_Vector x, N_Vector w);
+realtype N_VL1Norm(N_Vector x);
+void N_VCompare(realtype c, N_Vector x, N_Vector z);
+booleantype N_VInvTest(N_Vector x, N_Vector z);
+booleantype N_VConstrMask(N_Vector c, N_Vector x, N_Vector m);
+realtype N_VMinQuotient(N_Vector num, N_Vector denom);
+
+/*
+ * -----------------------------------------------------------------
+ * Additional functions exported by NVECTOR module
+ * -----------------------------------------------------------------
+ */
+
+/*
+ * -----------------------------------------------------------------
+ * N_VCloneEmptyVectorArray
+ *   Creates (by cloning 'w') an array of 'count' empty N_Vectors 
+ *
+ * N_VCloneVectorArray
+ *   Creates (by cloning 'w') an array of 'count' N_Vectors 
+ *
+ * N_VDestroyVectorArray
+ *   Frees memory for an array of 'count' N_Vectors that was
+ *   created by a call to N_VCloneVectorArray
+ *
+ * These functions are used by the SPGMR iterative linear solver 
+ * module and by the CVODES and IDAS solvers.
+ * -----------------------------------------------------------------
+ */
+
+N_Vector *N_VCloneEmptyVectorArray(int count, N_Vector w);
+N_Vector *N_VCloneVectorArray(int count, N_Vector w);
+void N_VDestroyVectorArray(N_Vector *vs, int count);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/sundials/sundials_smalldense.h b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/sundials/sundials_smalldense.h
new file mode 100644
index 0000000000000000000000000000000000000000..fbfd4d87a23fc83fdfebd0c059a6cfc4fe4b9ef2
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/sundials/sundials_smalldense.h	
@@ -0,0 +1,222 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * -----------------------------------------------------------------
+ * Programmer: Radu Serban @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2006, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This is the header file for a generic DENSE linear solver
+ * package, intended for small m by n dense matrices, with m<=n.
+ * These routines use the type realtype** for dense matrix arguments.
+ * -----------------------------------------------------------------
+ */
+
+#ifndef _SMALLDENSE_H
+#define _SMALLDENSE_H
+
+#ifdef __cplusplus  /* wrapper to enable C++ usage */
+extern "C" {
+#endif
+
+#include <sundials/sundials_types.h>
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : denalloc
+   * -----------------------------------------------------------------
+   * Usage : realtype **a;
+   *         a = denalloc(m, n);
+   *         if (a == NULL) ... memory request failed
+   * -----------------------------------------------------------------
+   * denalloc(m, n) allocates storage for an m by n dense matrix.
+   * It returns a pointer to the newly allocated storage if successful. 
+   * If the memory request cannot be satisfied, then denalloc returns 
+   * NULL. The underlying type of the dense matrix returned is a double
+   * pointer to realtype. If we allocate a dense matrix a by 
+   * a = denalloc(m, n), then a[j][i] references the (i,j)-th element 
+   * of the matrix a, 0 <= i < m, 0 <= j < n,  and a[j] is a pointer 
+   * to the first element in the jth column of a. The location a[0] 
+   * contains a pointer to m*n contiguous locations which contain the 
+   * elements of a.
+   * -----------------------------------------------------------------
+   */
+
+  realtype **denalloc(long int m, long int n);
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : denallocpiv
+   * -----------------------------------------------------------------
+   * Usage : long int *pivot;
+   *         pivot = denallocpiv(n);
+   *         if (pivot == NULL) ... memory request failed
+   * -----------------------------------------------------------------
+   * denallocpiv(n) allocates an array of n long int. It returns
+   * a pointer to the first element in the array if successful.
+   * It returns NULL if the memory request could not be satisfied.
+   * -----------------------------------------------------------------
+   */
+
+  long int *denallocpiv(long int n);
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : denGETRF
+   * -----------------------------------------------------------------
+   * Usage : long int ier;
+   *         ier = denGETRF(a,m,n,p);
+   *         if (ier > 0) ... zero element encountered during
+   *                          the factorization
+   * -----------------------------------------------------------------
+   * denGETRF(a,m,n,p) factors the m by n dense matrix a, m>=n.
+   * It overwrites the elements of a with its LU factors and keeps 
+   * track of the pivot rows chosen in the pivot array p.
+   *
+   * A successful LU factorization leaves the matrix a and the
+   * pivot array p with the following information:
+   *
+   * (1) p[k] contains the row number of the pivot element chosen
+   *     at the beginning of elimination step k, k=0, 1, ..., n-1.
+   *
+   * (2) If the unique LU factorization of a is given by Pa = LU,
+   *     where P is a permutation matrix, L is a lower trapezoidal
+   *     matrix with all 1.0 on the diagonal, and U is an upper
+   *     triangular matrix, then the upper triangular part of a
+   *     (including its diagonal) contains U and the strictly lower
+   *     trapezoidal part of a contains the multipliers, I-L.
+   *
+   * Note that for square matrices (m=n), L is unit lower triangular.
+   *
+   * denGETRF returns 0 if successful. Otherwise it encountered a
+   * zero diagonal element during the factorization. In this case
+   * it returns the column index (numbered from one) at which it
+   * encountered the zero.
+   * -----------------------------------------------------------------
+   */
+
+  long int denGETRF(realtype **a, long int m, long int n, long int *p);
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : denGETRS
+   * -----------------------------------------------------------------
+   * Usage : realtype *b;
+   *         ier = denGETRF(a,n,n,p);
+   *         if (ier == 0) denGETRS(a,n,p,b);
+   * -----------------------------------------------------------------
+   * denGETRS(a,n,p,b) solves the n by n linear system a*x = b.
+   * It assumes that a has been LU factored and the pivot array p has
+   * been set by a successful call to denGETRF(a,n,n,p). 
+   * denGETRS does not check whether a is square!
+   * The solution x is written into the b array.
+   * -----------------------------------------------------------------
+   */
+
+  void denGETRS(realtype **a, long int n, long int *p, realtype *b);
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : denzero
+   * -----------------------------------------------------------------
+   * Usage : denzero(a,m,n);
+   * -----------------------------------------------------------------
+   * denzero(a,m,n) sets all the elements of the m by n dense matrix
+   * a to be 0.0.
+   * -----------------------------------------------------------------
+   */
+
+  void denzero(realtype **a, long int m, long int n);
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : dencopy
+   * -----------------------------------------------------------------
+   * Usage : dencopy(a,b,m,n);
+   * -----------------------------------------------------------------
+   * dencopy(a,b,n) copies the m by n dense matrix a into the
+   * m by n dense matrix b.
+   * -----------------------------------------------------------------
+   */
+
+  void dencopy(realtype **a, realtype **b, long int m, long int n);
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : denscale
+   * -----------------------------------------------------------------
+   * Usage : denscale(c,a,m,n);
+   * -----------------------------------------------------------------
+   * denscale(c,a,m,n) scales every element in the m by n dense
+   * matrix a by c.
+   * -----------------------------------------------------------------
+   */
+
+  void denscale(realtype c, realtype **a, long int m, long int n);
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : denaddI
+   * -----------------------------------------------------------------
+   * Usage : denaddI(a,n);
+   * -----------------------------------------------------------------
+   * denaddI(a,n) increments the diagonal elements of the dense 
+   * m by n matrix a by 1.0. (a_ii <= a_ii + 1, i=1,2,..n-1.)
+   * denaddI is typically used with square matrices.
+   * denaddI does NOT check for m >= n! Therefore, a segmentation 
+   * fault will occur if m<n!
+   * -----------------------------------------------------------------
+   */
+
+  void denaddI(realtype **a, long int n);
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : denfreepiv
+   * -----------------------------------------------------------------
+   * Usage : denfreepiv(p);
+   * -----------------------------------------------------------------
+   * denfreepiv(p) frees the pivot array p allocated by
+   * denallocpiv.
+   * -----------------------------------------------------------------
+   */
+
+  void denfreepiv(long int *p);
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : denfree
+   * -----------------------------------------------------------------
+   * Usage : denfree(a);
+   * -----------------------------------------------------------------
+   * denfree(a) frees the dense matrix a allocated by denalloc.
+   * -----------------------------------------------------------------
+   */
+
+  void denfree(realtype **a);
+
+  /*
+   * -----------------------------------------------------------------
+   * Function : denprint
+   * -----------------------------------------------------------------
+   * Usage : denprint(a,m,n);
+   * -----------------------------------------------------------------
+   * denprint(a,m,n) prints the m by n dense matrix a to standard
+   * output as it would normally appear on paper. It is intended as
+   * a debugging tool with small values of m and n. The elements are
+   * printed using the %g/%lg/%Lg option. A blank line is printed
+   * before and after the matrix.
+   * -----------------------------------------------------------------
+   */
+
+  void denprint(realtype **a, long int m, long int n);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/sundials/sundials_spbcgs.h b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/sundials/sundials_spbcgs.h
new file mode 100644
index 0000000000000000000000000000000000000000..652a76414cc91b408c4ca18e2fc597fb55b8f158
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/sundials/sundials_spbcgs.h	
@@ -0,0 +1,199 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * -----------------------------------------------------------------
+ * Programmer(s): Peter Brown and Aaron Collier @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2004, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This is the header file for the implementation of the scaled,
+ * preconditioned Bi-CGSTAB (SPBCG) iterative linear solver.
+ * -----------------------------------------------------------------
+ */
+
+#ifndef _SPBCG_H
+#define _SPBCG_H
+
+#ifdef __cplusplus  /* wrapper to enable C++ usage */
+extern "C" {
+#endif
+
+#include <sundials/sundials_iterative.h>
+
+/*
+ * -----------------------------------------------------------------
+ * Types: struct SpbcgMemRec and struct *SpbcgMem
+ * -----------------------------------------------------------------
+ * A variable declaration of type struct *SpbcgMem denotes a pointer
+ * to a data structure of type struct SpbcgMemRec. The SpbcgMemRec
+ * structure contains numerous fields that must be accessed by the
+ * SPBCG linear solver module.
+ *
+ *  l_max  maximum Krylov subspace dimension that SpbcgSolve will
+ *         be permitted to use
+ *
+ *  r  vector (type N_Vector) which holds the scaled, preconditioned
+ *     linear system residual
+ *
+ *  r_star  vector (type N_Vector) which holds the initial scaled,
+ *          preconditioned linear system residual
+ *
+ *  p, q, u and Ap  vectors (type N_Vector) used for workspace by
+ *                  the SPBCG algorithm
+ *
+ *  vtemp  scratch vector (type N_Vector) used as temporary vector
+ *         storage
+ * -----------------------------------------------------------------
+ */
+
+typedef struct {
+
+  int l_max;
+
+  N_Vector r_star;
+  N_Vector r;
+  N_Vector p;
+  N_Vector q;
+  N_Vector u;
+  N_Vector Ap;
+  N_Vector vtemp;
+
+} SpbcgMemRec, *SpbcgMem;
+
+/*
+ * -----------------------------------------------------------------
+ * Function : SpbcgMalloc
+ * -----------------------------------------------------------------
+ * SpbcgMalloc allocates additional memory needed by the SPBCG
+ * linear solver module.
+ *
+ *  l_max  maximum Krylov subspace dimension that SpbcgSolve will
+ *         be permitted to use
+ *
+ *  vec_tmpl  implementation-specific template vector (type N_Vector)
+ *            (created using either N_VNew_Serial or N_VNew_Parallel)
+ *
+ * If successful, SpbcgMalloc returns a non-NULL memory pointer. If
+ * an error occurs, then a NULL pointer is returned.
+ * -----------------------------------------------------------------
+ */
+
+SpbcgMem SpbcgMalloc(int l_max, N_Vector vec_tmpl);
+
+/*
+ * -----------------------------------------------------------------
+ * Function : SpbcgSolve
+ * -----------------------------------------------------------------
+ * SpbcgSolve solves the linear system Ax = b by means of a scaled
+ * preconditioned Bi-CGSTAB (SPBCG) iterative method.
+ *
+ *  mem  pointer to an internal memory block allocated during a
+ *       prior call to SpbcgMalloc
+ *
+ *  A_data  pointer to a data structure containing information
+ *          about the coefficient matrix A (passed to user-supplied
+ *          function referenced by atimes (function pointer))
+ *
+ *  x  vector (type N_Vector) containing initial guess x_0 upon
+ *     entry, but which upon return contains an approximate solution
+ *     of the linear system Ax = b (solution only valid if return
+ *     value is either SPBCG_SUCCESS or SPBCG_RES_REDUCED)
+ *
+ *  b  vector (type N_Vector) set to the right-hand side vector b
+ *     of the linear system (undisturbed by function)
+ *
+ *  pretype  variable (type int) indicating the type of
+ *           preconditioning to be used (see sundials_iterative.h)
+ *
+ *  delta  tolerance on the L2 norm of the scaled, preconditioned
+ *         residual (if return value == SPBCG_SUCCESS, then
+ *         ||sb*P1_inv*(b-Ax)||_L2 <= delta)
+ *
+ *  P_data  pointer to a data structure containing preconditioner
+ *          information (passed to user-supplied function referenced
+ *          by psolve (function pointer))
+ *
+ *  sx  vector (type N_Vector) containing positive scaling factors
+ *      for x (pass sx == NULL if scaling NOT required)
+ *
+ *  sb  vector (type N_Vector) containing positive scaling factors
+ *      for b (pass sb == NULL if scaling NOT required)
+ *
+ *  atimes  user-supplied routine responsible for computing the
+ *          matrix-vector product Ax (see sundials_iterative.h)
+ *
+ *  psolve  user-supplied routine responsible for solving the
+ *          preconditioned linear system Pz = r (ignored if
+ *          pretype == PREC_NONE) (see sundials_iterative.h)
+ *
+ *  res_norm  pointer (type realtype*) to the L2 norm of the
+ *            scaled, preconditioned residual (if return value
+ *            is either SPBCG_SUCCESS or SPBCG_RES_REDUCED, then
+ *            *res_norm = ||sb*P1_inv*(b-Ax)||_L2, where x is
+ *            the computed approximate solution, sb is the diagonal
+ *            scaling matrix for the right-hand side b, and P1_inv
+ *            is the inverse of the left-preconditioner matrix)
+ *
+ *  nli  pointer (type int*) to the total number of linear
+ *       iterations performed
+ *
+ *  nps  pointer (type int*) to the total number of calls made
+ *       to the psolve routine
+ * -----------------------------------------------------------------
+ */
+
+int SpbcgSolve(SpbcgMem mem, void *A_data, N_Vector x, N_Vector b,
+               int pretype, realtype delta, void *P_data, N_Vector sx,
+               N_Vector sb, ATimesFn atimes, PSolveFn psolve,
+               realtype *res_norm, int *nli, int *nps);
+
+/* Return values for SpbcgSolve */
+
+#define SPBCG_SUCCESS            0  /* SPBCG algorithm converged          */
+#define SPBCG_RES_REDUCED        1  /* SPBCG did NOT converge, but the
+				       residual was reduced               */
+#define SPBCG_CONV_FAIL          2  /* SPBCG algorithm failed to converge */
+#define SPBCG_PSOLVE_FAIL_REC    3  /* psolve failed recoverably          */
+#define SPBCG_ATIMES_FAIL_REC    4  /* atimes failed recoverably          */
+#define SPBCG_PSET_FAIL_REC      5  /* pset faild recoverably             */
+
+#define SPBCG_MEM_NULL          -1  /* mem argument is NULL               */
+#define SPBCG_ATIMES_FAIL_UNREC -2  /* atimes returned failure flag       */
+#define SPBCG_PSOLVE_FAIL_UNREC -3  /* psolve failed unrecoverably        */
+#define SPBCG_PSET_FAIL_UNREC   -4  /* pset failed unrecoverably          */
+
+/*
+ * -----------------------------------------------------------------
+ * Function : SpbcgFree
+ * -----------------------------------------------------------------
+ * SpbcgFree frees the memory allocated by a call to SpbcgMalloc.
+ * It is illegal to use the pointer mem after a call to SpbcgFree.
+ * -----------------------------------------------------------------
+ */
+
+void SpbcgFree(SpbcgMem mem);
+
+/*
+ * -----------------------------------------------------------------
+ * Macro : SPBCG_VTEMP
+ * -----------------------------------------------------------------
+ * This macro provides access to the vector r in the
+ * memory block of the SPBCG module. The argument mem is the
+ * memory pointer returned by SpbcgMalloc, of type SpbcgMem,
+ * and the macro value is of type N_Vector.
+ *
+ * Note: Only used by IDA (r contains P_inverse F if nli_inc == 0).
+ * -----------------------------------------------------------------
+ */
+
+#define SPBCG_VTEMP(mem) (mem->r)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/sundials/sundials_spgmr.h b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/sundials/sundials_spgmr.h
new file mode 100644
index 0000000000000000000000000000000000000000..cd9b00f37ec2f634e152eead941175c6f668149d
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/sundials/sundials_spgmr.h	
@@ -0,0 +1,296 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * ----------------------------------------------------------------- 
+ * Programmer(s): Scott D. Cohen, Alan C. Hindmarsh and
+ *                Radu Serban @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2002, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This is the header file for the implementation of SPGMR Krylov
+ * iterative linear solver.  The SPGMR algorithm is based on the
+ * Scaled Preconditioned GMRES (Generalized Minimal Residual)
+ * method.
+ *
+ * The SPGMR algorithm solves a linear system A x = b.
+ * Preconditioning is allowed on the left, right, or both.
+ * Scaling is allowed on both sides, and restarts are also allowed.
+ * We denote the preconditioner and scaling matrices as follows:
+ *   P1 = left preconditioner
+ *   P2 = right preconditioner
+ *   S1 = diagonal matrix of scale factors for P1-inverse b
+ *   S2 = diagonal matrix of scale factors for P2 x
+ * The matrices A, P1, and P2 are not required explicitly; only
+ * routines that provide A, P1-inverse, and P2-inverse as
+ * operators are required.
+ *
+ * In this notation, SPGMR applies the underlying GMRES method to
+ * the equivalent transformed system
+ *   Abar xbar = bbar , where
+ *   Abar = S1 (P1-inverse) A (P2-inverse) (S2-inverse) ,
+ *   bbar = S1 (P1-inverse) b , and   xbar = S2 P2 x .
+ *
+ * The scaling matrices must be chosen so that vectors S1
+ * P1-inverse b and S2 P2 x have dimensionless components.
+ * If preconditioning is done on the left only (P2 = I), by a
+ * matrix P, then S2 must be a scaling for x, while S1 is a
+ * scaling for P-inverse b, and so may also be taken as a scaling
+ * for x.  Similarly, if preconditioning is done on the right only
+ * (P1 = I, P2 = P), then S1 must be a scaling for b, while S2 is
+ * a scaling for P x, and may also be taken as a scaling for b.
+ *
+ * The stopping test for the SPGMR iterations is on the L2 norm of
+ * the scaled preconditioned residual:
+ *      || bbar - Abar xbar ||_2  <  delta
+ * with an input test constant delta.
+ *
+ * The usage of this SPGMR solver involves supplying two routines
+ * and making three calls.  The user-supplied routines are
+ *    atimes (A_data, x, y) to compute y = A x, given x,
+ * and
+ *    psolve (P_data, x, y, lr)
+ *                to solve P1 x = y or P2 x = y for x, given y.
+ * The three user calls are:
+ *    mem  = SpgmrMalloc(lmax, vec_tmpl);
+ *           to initialize memory,
+ *    flag = SpgmrSolve(mem,A_data,x,b,...,
+ *                      P_data,s1,s2,atimes,psolve,...);
+ *           to solve the system, and
+ *    SpgmrFree(mem);
+ *           to free the memory created by SpgmrMalloc.
+ * Complete details for specifying atimes and psolve and for the
+ * usage calls are given in the paragraphs below and in iterative.h.
+ * -----------------------------------------------------------------
+ */
+
+#ifndef _SPGMR_H
+#define _SPGMR_H
+
+#ifdef __cplusplus  /* wrapper to enable C++ usage */
+extern "C" {
+#endif
+
+#include <sundials/sundials_iterative.h>
+
+/*
+ * -----------------------------------------------------------------
+ * Types: SpgmrMemRec, SpgmrMem
+ * -----------------------------------------------------------------
+ * SpgmrMem is a pointer to an SpgmrMemRec which contains
+ * the memory needed by SpgmrSolve. The SpgmrMalloc routine
+ * returns a pointer of type SpgmrMem which should then be passed
+ * in subsequent calls to SpgmrSolve. The SpgmrFree routine frees
+ * the memory allocated by SpgmrMalloc.
+ *
+ * l_max is the maximum Krylov dimension that SpgmrSolve will be
+ * permitted to use.
+ *
+ * V is the array of Krylov basis vectors v_1, ..., v_(l_max+1),
+ * stored in V[0], ..., V[l_max], where l_max is the second
+ * parameter to SpgmrMalloc. Each v_i is a vector of type
+ * N_Vector.
+ *
+ * Hes is the (l_max+1) x l_max Hessenberg matrix. It is stored
+ * row-wise so that the (i,j)th element is given by Hes[i][j].
+ *
+ * givens is a length 2*l_max array which represents the
+ * Givens rotation matrices that arise in the algorithm. The
+ * Givens rotation matrices F_0, F_1, ..., F_j, where F_i is
+ *
+ *             1
+ *               1
+ *                 c_i  -s_i      <--- row i
+ *                 s_i   c_i
+ *                           1
+ *                             1
+ *
+ * are represented in the givens vector as
+ * givens[0]=c_0, givens[1]=s_0, givens[2]=c_1, givens[3]=s_1,
+ * ..., givens[2j]=c_j, givens[2j+1]=s_j.
+ *
+ * xcor is a vector (type N_Vector) which holds the scaled,
+ * preconditioned correction to the initial guess.
+ *
+ * yg is a length (l_max+1) array of realtype used to hold "short"
+ * vectors (e.g. y and g).
+ *
+ * vtemp is a vector (type N_Vector) used as temporary vector
+ * storage during calculations.
+ * -----------------------------------------------------------------
+ */
+  
+typedef struct _SpgmrMemRec {
+
+  int l_max;
+
+  N_Vector *V;
+  realtype **Hes;
+  realtype *givens;
+  N_Vector xcor;
+  realtype *yg;
+  N_Vector vtemp;
+
+} SpgmrMemRec, *SpgmrMem;
+
+/*
+ * -----------------------------------------------------------------
+ * Function : SpgmrMalloc
+ * -----------------------------------------------------------------
+ * SpgmrMalloc allocates the memory used by SpgmrSolve. It
+ * returns a pointer of type SpgmrMem which the user of the
+ * SPGMR package should pass to SpgmrSolve. The parameter l_max
+ * is the maximum Krylov dimension that SpgmrSolve will be
+ * permitted to use. The parameter vec_tmpl is a pointer to an
+ * N_Vector used as a template to create new vectors by duplication.
+ * This routine returns NULL if there is a memory request failure.
+ * -----------------------------------------------------------------
+ */
+
+SpgmrMem SpgmrMalloc(int l_max, N_Vector vec_tmpl);
+
+/*
+ * -----------------------------------------------------------------
+ * Function : SpgmrSolve
+ * -----------------------------------------------------------------
+ * SpgmrSolve solves the linear system Ax = b using the SPGMR
+ * method. The return values are given by the symbolic constants
+ * below. The first SpgmrSolve parameter is a pointer to memory
+ * allocated by a prior call to SpgmrMalloc.
+ *
+ * mem is the pointer returned by SpgmrMalloc to the structure
+ * containing the memory needed by SpgmrSolve.
+ *
+ * A_data is a pointer to information about the coefficient
+ * matrix A. This pointer is passed to the user-supplied function
+ * atimes.
+ *
+ * x is the initial guess x_0 upon entry and the solution
+ * N_Vector upon exit with return value SPGMR_SUCCESS or
+ * SPGMR_RES_REDUCED. For all other return values, the output x
+ * is undefined.
+ *
+ * b is the right hand side N_Vector. It is undisturbed by this
+ * function.
+ *
+ * pretype is the type of preconditioning to be used. Its
+ * legal possible values are enumerated in iterativ.h. These
+ * values are PREC_NONE=0, PREC_LEFT=1, PREC_RIGHT=2, and
+ * PREC_BOTH=3.
+ *
+ * gstype is the type of Gram-Schmidt orthogonalization to be
+ * used. Its legal values are enumerated in iterativ.h. These
+ * values are MODIFIED_GS=0 and CLASSICAL_GS=1.
+ *
+ * delta is the tolerance on the L2 norm of the scaled,
+ * preconditioned residual. On return with value SPGMR_SUCCESS,
+ * this residual satisfies || s1 P1_inv (b - Ax) ||_2 <= delta.
+ *
+ * max_restarts is the maximum number of times the algorithm is
+ * allowed to restart.
+ *
+ * P_data is a pointer to preconditioner information. This
+ * pointer is passed to the user-supplied function psolve.
+ *
+ * s1 is an N_Vector of positive scale factors for P1-inv b, where
+ * P1 is the left preconditioner. (Not tested for positivity.)
+ * Pass NULL if no scaling on P1-inv b is required.
+ *
+ * s2 is an N_Vector of positive scale factors for P2 x, where
+ * P2 is the right preconditioner. (Not tested for positivity.)
+ * Pass NULL if no scaling on P2 x is required.
+ *
+ * atimes is the user-supplied function which performs the
+ * operation of multiplying A by a given vector. Its description
+ * is given in iterative.h.
+ *
+ * psolve is the user-supplied function which solves a
+ * preconditioner system Pz = r, where P is P1 or P2. Its full
+ * description is  given in iterativ.h. The psolve function will
+ * not be called if pretype is NONE; in that case, the user
+ * should pass NULL for psolve.
+ *
+ * res_norm is a pointer to the L2 norm of the scaled,
+ * preconditioned residual. On return with value SPGMR_SUCCESS or
+ * SPGMR_RES_REDUCED, (*res_norm) contains the value
+ * || s1 P1_inv (b - Ax) ||_2 for the computed solution x.
+ * For all other return values, (*res_norm) is undefined. The
+ * caller is responsible for allocating the memory (*res_norm)
+ * to be filled in by SpgmrSolve.
+ *
+ * nli is a pointer to the number of linear iterations done in
+ * the execution of SpgmrSolve. The caller is responsible for
+ * allocating the memory (*nli) to be filled in by SpgmrSolve.
+ *
+ * nps is a pointer to the number of calls made to psolve during
+ * the execution of SpgmrSolve. The caller is responsible for
+ * allocating the memory (*nps) to be filled in by SpgmrSolve.
+ *
+ * Note: Repeated calls can be made to SpgmrSolve with varying
+ * input arguments. If, however, the problem size N or the
+ * maximum Krylov dimension l_max changes, then a call to
+ * SpgmrMalloc must be made to obtain new memory for SpgmrSolve
+ * to use.
+ * -----------------------------------------------------------------
+ */                                                                
+     
+int SpgmrSolve(SpgmrMem mem, void *A_data, N_Vector x, N_Vector b,
+               int pretype, int gstype, realtype delta, 
+               int max_restarts, void *P_data, N_Vector s1, 
+               N_Vector s2, ATimesFn atimes, PSolveFn psolve, 
+               realtype *res_norm, int *nli, int *nps);
+
+
+/* Return values for SpgmrSolve */
+
+#define SPGMR_SUCCESS            0  /* Converged                     */
+#define SPGMR_RES_REDUCED        1  /* Did not converge, but reduced
+                                       norm of residual              */
+#define SPGMR_CONV_FAIL          2  /* Failed to converge            */
+#define SPGMR_QRFACT_FAIL        3  /* QRfact found singular matrix  */
+#define SPGMR_PSOLVE_FAIL_REC    4  /* psolve failed recoverably     */
+#define SPGMR_ATIMES_FAIL_REC    5  /* atimes failed recoverably     */
+#define SPGMR_PSET_FAIL_REC      6  /* pset faild recoverably        */
+
+#define SPGMR_MEM_NULL          -1  /* mem argument is NULL          */
+#define SPGMR_ATIMES_FAIL_UNREC -2  /* atimes returned failure flag  */
+#define SPGMR_PSOLVE_FAIL_UNREC -3  /* psolve failed unrecoverably   */
+#define SPGMR_GS_FAIL           -4  /* Gram-Schmidt routine faiuled  */        
+#define SPGMR_QRSOL_FAIL        -5  /* QRsol found singular R        */
+#define SPGMR_PSET_FAIL_UNREC   -6  /* pset failed unrecoverably     */
+
+/*
+ * -----------------------------------------------------------------
+ * Function : SpgmrFree
+ * -----------------------------------------------------------------
+ * SpgmrMalloc frees the memory allocated by SpgmrMalloc. It is
+ * illegal to use the pointer mem after a call to SpgmrFree.
+ * -----------------------------------------------------------------
+ */                                                                
+
+void SpgmrFree(SpgmrMem mem);
+
+/*
+ * -----------------------------------------------------------------
+ * Macro: SPGMR_VTEMP
+ * -----------------------------------------------------------------
+ * This macro provides access to the work vector vtemp in the
+ * memory block of the SPGMR module.  The argument mem is the
+ * memory pointer returned by SpgmrMalloc, of type SpgmrMem,
+ * and the macro value is of type N_Vector.
+ * On a return from SpgmrSolve with *nli = 0, this vector
+ * contains the scaled preconditioned initial residual,
+ * s1 * P1_inverse * (b - A x_0).
+ * -----------------------------------------------------------------
+ */
+
+#define SPGMR_VTEMP(mem) (mem->vtemp)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/sundials/sundials_sptfqmr.h b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/sundials/sundials_sptfqmr.h
new file mode 100644
index 0000000000000000000000000000000000000000..fa52e026ed34a29d41369bac29f388e62d8584cb
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/sundials/sundials_sptfqmr.h	
@@ -0,0 +1,254 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * -----------------------------------------------------------------
+ * Programmer(s): Aaron Collier @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2005, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This is the header file for the implementation of the scaled
+ * preconditioned Transpose-Free Quasi-Minimal Residual (SPTFQMR)
+ * linear solver.
+ *
+ * The SPTFQMR algorithm solves a linear system of the form Ax = b.
+ * Preconditioning is allowed on the left (PREC_LEFT), right
+ * (PREC_RIGHT), or both (PREC_BOTH).  Scaling is allowed on both
+ * sides.  We denote the preconditioner and scaling matrices as
+ * follows:
+ *   P1 = left preconditioner
+ *   P2 = right preconditioner
+ *   S1 = diagonal matrix of scale factors for P1-inverse b
+ *   S2 = diagonal matrix of scale factors for P2 x
+ * The matrices A, P1, and P2 are not required explicitly; only
+ * routines that provide A, P1-inverse, and P2-inverse as operators
+ * are required.
+ *
+ * In this notation, SPTFQMR applies the underlying TFQMR method to
+ * the equivalent transformed system:
+ *   Abar xbar = bbar, where
+ *   Abar = S1 (P1-inverse) A (P2-inverse) (S2-inverse),
+ *   bbar = S1 (P1-inverse) b, and
+ *   xbar = S2 P2 x.
+ *
+ * The scaling matrices must be chosen so that vectors
+ * S1 P1-inverse b and S2 P2 x have dimensionless components.  If
+ * preconditioning is done on the left only (P2 = I), by a matrix P,
+ * then S2 must be a scaling for x, while S1 is a scaling for
+ * P-inverse b, and so may also be taken as a scaling for x.
+ * Similarly, if preconditioning is done on the right only (P1 = I,
+ * P2 = P), then S1 must be a scaling for b, while S2 is a scaling
+ * for P x, and may also be taken as a scaling for b.
+ *
+ * The stopping test for the SPTFQMR iterations is on the L2-norm of
+ * the scaled preconditioned residual:
+ *   || bbar - Abar xbar ||_2 < delta
+ * with an input test constant delta.
+ *
+ * The usage of this SPTFQMR solver involves supplying two routines
+ * and making three calls.  The user-supplied routines are:
+ *   atimes(A_data, x, y) to compute y = A x, given x,
+ * and
+ *   psolve(P_data, x, y, lr) to solve P1 x = y or P2 x = y for x,
+ *                            given y.
+ * The three user calls are:
+ *   mem  = SptfqmrMalloc(lmax, vec_tmpl);
+ *          to initialize memory
+ *   flag = SptfqmrSolve(mem, A_data, x, b, pretype, delta, P_data,
+ *                       sx, sb, atimes, psolve, res_norm, nli, nps);
+ *          to solve the system, and
+ *   SptfqmrFree(mem);
+ *          to free the memory allocated by SptfqmrMalloc().
+ * Complete details for specifying atimes() and psolve() and for the
+ * usage calls are given in the paragraphs below and in the header
+ * file sundials_iterative.h.
+ * -----------------------------------------------------------------
+ */
+
+#ifndef _SPTFQMR_H
+#define _SPTFQMR_H
+
+#ifdef __cplusplus  /* wrapper to enable C++ usage */
+extern "C" {
+#endif
+
+#include <sundials/sundials_iterative.h>
+
+/*
+ * -----------------------------------------------------------------
+ * Types: struct SptfqmrMemRec and struct *SptfqmrMem
+ * -----------------------------------------------------------------
+ * A variable declaration of type struct *SptfqmrMem denotes a pointer
+ * to a data structure of type struct SptfqmrMemRec. The SptfqmrMemRec
+ * structure contains numerous fields that must be accessed by the
+ * SPTFQMR linear solver module.
+ *
+ *  l_max  maximum Krylov subspace dimension that SptfqmrSolve will
+ *         be permitted to use
+ *
+ *  r_star  vector (type N_Vector) which holds the initial scaled,
+ *          preconditioned linear system residual
+ *
+ *  q/d/v/p/u/r  vectors (type N_Vector) used for workspace by
+ *               the SPTFQMR algorithm
+ *
+ *  vtemp1/vtemp2/vtemp3  scratch vectors (type N_Vector) used as
+ *                        temporary storage
+ * -----------------------------------------------------------------
+ */
+
+typedef struct {
+
+  int l_max;
+
+  N_Vector r_star;
+  N_Vector q;
+  N_Vector d;
+  N_Vector v;
+  N_Vector p;
+  N_Vector *r;
+  N_Vector u;
+  N_Vector vtemp1;
+  N_Vector vtemp2;
+  N_Vector vtemp3;
+
+} SptfqmrMemRec, *SptfqmrMem;
+
+/*
+ * -----------------------------------------------------------------
+ * Function : SptfqmrMalloc
+ * -----------------------------------------------------------------
+ * SptfqmrMalloc allocates additional memory needed by the SPTFQMR
+ * linear solver module.
+ *
+ *  l_max  maximum Krylov subspace dimension that SptfqmrSolve will
+ *         be permitted to use
+ *
+ *  vec_tmpl  implementation-specific template vector (type N_Vector)
+ *            (created using either N_VNew_Serial or N_VNew_Parallel)
+ *
+ * If successful, SptfqmrMalloc returns a non-NULL memory pointer. If
+ * an error occurs, then a NULL pointer is returned.
+ * -----------------------------------------------------------------
+ */
+
+SptfqmrMem SptfqmrMalloc(int l_max, N_Vector vec_tmpl);
+
+/*
+ * -----------------------------------------------------------------
+ * Function : SptfqmrSolve
+ * -----------------------------------------------------------------
+ * SptfqmrSolve solves the linear system Ax = b by means of a scaled
+ * preconditioned Transpose-Free Quasi-Minimal Residual (SPTFQMR)
+ * method.
+ *
+ *  mem  pointer to an internal memory block allocated during a
+ *       prior call to SptfqmrMalloc
+ *
+ *  A_data  pointer to a data structure containing information
+ *          about the coefficient matrix A (passed to user-supplied
+ *          function referenced by atimes (function pointer))
+ *
+ *  x  vector (type N_Vector) containing initial guess x_0 upon
+ *     entry, but which upon return contains an approximate solution
+ *     of the linear system Ax = b (solution only valid if return
+ *     value is either SPTFQMR_SUCCESS or SPTFQMR_RES_REDUCED)
+ *
+ *  b  vector (type N_Vector) set to the right-hand side vector b
+ *     of the linear system (undisturbed by function)
+ *
+ *  pretype  variable (type int) indicating the type of
+ *           preconditioning to be used (see sundials_iterative.h)
+ *
+ *  delta  tolerance on the L2 norm of the scaled, preconditioned
+ *         residual (if return value == SPTFQMR_SUCCESS, then
+ *         ||sb*P1_inv*(b-Ax)||_L2 <= delta)
+ *
+ *  P_data  pointer to a data structure containing preconditioner
+ *          information (passed to user-supplied function referenced
+ *          by psolve (function pointer))
+ *
+ *  sx  vector (type N_Vector) containing positive scaling factors
+ *      for x (pass sx == NULL if scaling NOT required)
+ *
+ *  sb  vector (type N_Vector) containing positive scaling factors
+ *      for b (pass sb == NULL if scaling NOT required)
+ *
+ *  atimes  user-supplied routine responsible for computing the
+ *          matrix-vector product Ax (see sundials_iterative.h)
+ *
+ *  psolve  user-supplied routine responsible for solving the
+ *          preconditioned linear system Pz = r (ignored if
+ *          pretype == PREC_NONE) (see sundials_iterative.h)
+ *
+ *  res_norm  pointer (type realtype*) to the L2 norm of the
+ *            scaled, preconditioned residual (if return value
+ *            is either SPTFQMR_SUCCESS or SPTFQMR_RES_REDUCED, then
+ *            *res_norm = ||sb*P1_inv*(b-Ax)||_L2, where x is
+ *            the computed approximate solution, sb is the diagonal
+ *            scaling matrix for the right-hand side b, and P1_inv
+ *            is the inverse of the left-preconditioner matrix)
+ *
+ *  nli  pointer (type int*) to the total number of linear
+ *       iterations performed
+ *
+ *  nps  pointer (type int*) to the total number of calls made
+ *       to the psolve routine
+ * -----------------------------------------------------------------
+ */
+
+int SptfqmrSolve(SptfqmrMem mem, void *A_data, N_Vector x, N_Vector b,
+		 int pretype, realtype delta, void *P_data, N_Vector sx,
+		 N_Vector sb, ATimesFn atimes, PSolveFn psolve,
+		 realtype *res_norm, int *nli, int *nps);
+
+/* Return values for SptfqmrSolve */
+
+#define SPTFQMR_SUCCESS            0  /* SPTFQMR algorithm converged          */
+#define SPTFQMR_RES_REDUCED        1  /* SPTFQMR did NOT converge, but the
+				         residual was reduced                 */
+#define SPTFQMR_CONV_FAIL          2  /* SPTFQMR algorithm failed to converge */
+#define SPTFQMR_PSOLVE_FAIL_REC    3  /* psolve failed recoverably            */
+#define SPTFQMR_ATIMES_FAIL_REC    4  /* atimes failed recoverably            */
+#define SPTFQMR_PSET_FAIL_REC      5  /* pset faild recoverably               */
+
+#define SPTFQMR_MEM_NULL          -1  /* mem argument is NULL                 */
+#define SPTFQMR_ATIMES_FAIL_UNREC -2  /* atimes returned failure flag         */
+#define SPTFQMR_PSOLVE_FAIL_UNREC -3  /* psolve failed unrecoverably          */
+#define SPTFQMR_PSET_FAIL_UNREC   -4  /* pset failed unrecoverably            */
+
+/*
+ * -----------------------------------------------------------------
+ * Function : SptfqmrFree
+ * -----------------------------------------------------------------
+ * SptfqmrFree frees the memory allocated by a call to SptfqmrMalloc.
+ * It is illegal to use the pointer mem after a call to SptfqmrFree.
+ * -----------------------------------------------------------------
+ */
+
+void SptfqmrFree(SptfqmrMem mem);
+
+/*
+ * -----------------------------------------------------------------
+ * Macro : SPTFQMR_VTEMP
+ * -----------------------------------------------------------------
+ * This macro provides access to the work vector vtemp1 in the
+ * memory block of the SPTFQMR module. The argument mem is the
+ * memory pointer returned by SptfqmrMalloc, of type SptfqmrMem,
+ * and the macro value is of type N_Vector.
+ *
+ * Note: Only used by IDA (vtemp1 contains P_inverse F if
+ *       nli_inc == 0).
+ * -----------------------------------------------------------------
+ */
+
+#define SPTFQMR_VTEMP(mem) (mem->vtemp1)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/sundials/sundials_types.h b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/sundials/sundials_types.h
new file mode 100644
index 0000000000000000000000000000000000000000..0e3f26dde30328eae3ecec6ebb8a2470d46c4364
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/include_SUNDIALS_CVODES_25/sundials/sundials_types.h	
@@ -0,0 +1,114 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * ----------------------------------------------------------------- 
+ * Programmer(s): Scott Cohen, Alan Hindmarsh, Radu Serban, and
+ *                Aaron Collier @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2002, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ *------------------------------------------------------------------
+ * This header file exports two types: realtype and booleantype,
+ * as well as the constants TRUE and FALSE.
+ *
+ * Users should include the header file sundials_types.h in every
+ * program file and use the exported name realtype instead of
+ * float, double or long double.
+ *
+ * The constants SUNDIALS_SINGLE_PRECISION, SUNDIALS_DOUBLE_PRECISION
+ * and SUNDIALS_LONG_DOUBLE_PRECISION indicate the underlying data
+ * type of realtype. It is set at the configuration stage.
+ *
+ * The legal types for realtype are float, double and long double.
+ *
+ * The macro RCONST gives the user a convenient way to define
+ * real-valued constants. To use the constant 1.0, for example,
+ * the user should write the following:
+ *
+ *   #define ONE RCONST(1.0)
+ *
+ * If realtype is defined as a double, then RCONST(1.0) expands
+ * to 1.0. If realtype is defined as a float, then RCONST(1.0)
+ * expands to 1.0F. If realtype is defined as a long double,
+ * then RCONST(1.0) expands to 1.0L. There is never a need to
+ * explicitly cast 1.0 to (realtype).
+ *------------------------------------------------------------------
+ */
+  
+#ifndef _SUNDIALSTYPES_H
+#define _SUNDIALSTYPES_H
+
+#ifdef __cplusplus  /* wrapper to enable C++ usage */
+extern "C" {
+#endif
+
+#ifndef _SUNDIALS_CONFIG_H
+#define _SUNDIALS_CONFIG_H
+#include <sundials/sundials_config.h>
+#endif
+
+#include <float.h>
+  
+#if defined(SUNDIALS_SINGLE_PRECISION)
+
+typedef float realtype;
+#define RCONST(x) x##F
+#define BIG_REAL FLT_MAX
+#define SMALL_REAL FLT_MIN
+#define UNIT_ROUNDOFF FLT_EPSILON
+
+#elif defined(SUNDIALS_DOUBLE_PRECISION)
+
+typedef double realtype;
+#define RCONST(x) x
+#define BIG_REAL DBL_MAX
+#define SMALL_REAL DBL_MIN
+#define UNIT_ROUNDOFF DBL_EPSILON
+
+#elif defined(SUNDIALS_EXTENDED_PRECISION)
+
+typedef long double realtype;
+#define RCONST(x) x##L
+#define BIG_REAL LDBL_MAX
+#define SMALL_REAL LDBL_MIN
+#define UNIT_ROUNDOFF LDBL_EPSILON
+
+#endif
+
+/*
+ *------------------------------------------------------------------
+ * Type : booleantype
+ *------------------------------------------------------------------
+ * Constants : FALSE and TRUE
+ *------------------------------------------------------------------
+ * ANSI C does not have a built-in boolean data type. Below is the
+ * definition for a new type called booleantype. The advantage of
+ * using the name booleantype (instead of int) is an increase in
+ * code readability. It also allows the programmer to make a
+ * distinction between int and boolean data. Variables of type
+ * booleantype are intended to have only the two values FALSE and
+ * TRUE which are defined below to be equal to 0 and 1,
+ * respectively.
+ *------------------------------------------------------------------
+ */
+
+#ifndef booleantype
+#define booleantype int
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/kineticformulas.h b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/kineticformulas.h
new file mode 100644
index 0000000000000000000000000000000000000000..7b9dec99d643572d1e697f537e2a398fe36d9825
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/kineticformulas.h	
@@ -0,0 +1,193 @@
+/*
+ * kineticformulas.h: Include file for specification of useful kinetic formulas
+ *
+ * Information:
+ * ============
+ * IQM Tools Pro
+ */
+
+double kin_mass_action_irr(double k, double substrate)
+{
+    return k*substrate;    
+}
+
+double kin_mass_action_rev(double k1, double substrate, double k2, double product)
+{
+    return k1*substrate - k2*product;    
+}
+
+double kin_degradation(double kdeg, double substrate)
+{
+    return kdeg*substrate;    
+}
+
+double kin_michaelis_menten_irr(double V, double substrate, double Km)
+{
+    return V*substrate / ( Km + substrate );    
+}
+
+double kin_hill_cooperativity_irr(double V, double substrate, double h, double Shalve)
+{
+    return V*pow(substrate,h) / (pow(Shalve,h) + pow(substrate,h));    
+}
+
+double kin_mixed_inihib_irr(double V, double substrate, double Km, double inhibitor, double Kis, double Kic)
+{
+    return V*substrate / ( Km*(1+inhibitor/Kis) + substrate*(1+inhibitor/Kic) );    
+}
+
+double kin_noncomp_inihib_irr(double V, double substrate, double Km, double inhibitor, double Ki)
+{
+    return V*substrate / ( (Km+substrate)*(1+inhibitor/Ki) );
+}
+
+double kin_uncomp_inihib_irr(double V, double substrate, double Km, double inhibitor, double Ki)
+{
+    return V*substrate / ( Km + substrate*(1+inhibitor/Ki) );
+}
+
+double kin_comp_inihib_irr(double V, double substrate, double Km, double inhibitor, double Ki)
+{
+    return V*substrate / ( Km*(1+inhibitor/Ki) + substrate );
+}
+
+double kin_substrate_inihib_irr(double V, double substrate, double Km, double Ki)
+{
+    return V*substrate / ( Km + substrate + Km*pow((substrate/Ki),2.0) );
+}
+
+double kin_allosteric_inihib_mwc_irr(double V, double substrate, double Ks, double n, double L, double inhibitor, double Ki)
+{
+    return V*substrate*pow((Ks+substrate),(n-1.0)) / ( L*pow((Ks*(1+inhibitor/Ki)),n) + pow((Ks+substrate),n) );
+}
+
+double kin_allosteric_inihib_empirical_rev(double Vf, double substrate, double Kms, double Vr, double product, double Kmp, double inhibitor, double Ki, double n)
+{
+    return (Vf*substrate/Kms - Vr*product/Kmp) / (1 + substrate/Kms + product/Kmp + pow((inhibitor/Ki),n));
+}
+
+double kin_catalytic_activation_irr(double V, double substrate, double activator, double Kms, double Ka)
+{
+    return V*substrate*activator / ( (Kms + substrate)*(Ka+activator) );
+}
+
+double kin_catalytic_activation_rev(double Vf, double substrate, double Kms, double Vr, double product, double Kmp, double activator, double Ka)
+{
+    return ( Vf*substrate/Kms - Vr*product/Kmp )*activator / ( (1+substrate/Kms+product/Kmp)*(Ka+activator) );
+}
+
+double kin_comp_inihib_rev(double Vf, double substrate, double Kms, double Vr, double product, double Kmp, double inhibitor, double Ki)
+{
+    return (Vf*substrate/Kms - Vr*product/Kmp) / ( 1+substrate/Kms+product/Kmp+inhibitor/Ki );
+}
+
+double kin_constantflux(double v)
+{
+    return v;
+}
+
+double kin_hyperbolic_modifier_irr(double V,double substrate,double b,double modifier,double a,double Kd,double Km)
+{
+    return V*substrate*(1+b*modifier/(a*Kd)) / ( Km*(1+modifier/Kd) + substrate*(1+modifier/(a*Kd)) );
+}
+
+double kin_hyperbolic_modifier_rev(double Vf,double substrate,double Kms,double Vr,double product,double Kmp,double b,double modifier,double a,double Kd)
+{
+    return (Vf*substrate/Kms - Vr*product/Kmp)*(1+b*modifier/(a*Kd)) / ( 1+modifier/Kd+(substrate/Kms+product/Kmp)*(1+modifier/(a*Kd)) );
+}
+
+double kin_hill_rev(double Vf,double substrate,double Shalve,double product,double Keq,double Phalve,double h)
+{
+    return Vf*substrate/Shalve*(1-product/(substrate*Keq))*pow((substrate/Shalve+product/Phalve),(h-1.0)) / ( 1+pow((substrate/Shalve + product/Phalve),h) );
+}
+
+double kin_iso_uni_uni_rev(double Vf,double substrate,double product,double Keq,double Kii,double Kms,double Kmp)
+{
+    return Vf*(substrate-product/Keq) / ( substrate*(1+product/Kii) + Kms*(1+product/Kmp) );
+}
+
+double kin_mixed_activation_irr(double V,double substrate,double activator,double Kms,double Kas,double Kac)
+{
+    return V*substrate*activator / ( Kms*(Kas+activator) + substrate*(Kac+activator) );
+}
+
+double kin_mixed_activation_rev(double Vf,double substrate,double Kms,double Vr,double product,double Kmp,double activator,double Kas,double Kac)
+{
+    return (Vf*substrate/Kms - Vr*product/Kmp)*activator / ( Kas+activator+(substrate/Kms+product/Kmp)*(Kac+activator) );
+}
+
+double kin_mixed_inihib_rev(double Vf,double substrate,double Kms,double Vr,double product,double Kmp,double inhibitor,double Kis,double Kic)
+{
+    return (Vf*substrate/Kms - Vr*product/Kmp) / ( 1+inhibitor/Kis+(substrate/Kms+product/Kmp)*(1+inhibitor/Kic) );
+}
+
+double kin_noncomp_inihib_rev(double Vf,double substrate,double Kms,double Vr,double product,double Kmp,double inhibitor,double Ki)
+{
+    return (Vf*substrate/Kms-Vr*product/Kmp) / ( (1+substrate/Kms+product/Kmp)*(1+inhibitor/Ki) );
+}
+
+double kin_ordered_bi_bi_rev(double Vf,double substratea,double substrateb,double productp,double productq,double Keq,double Kip,double Kma,double Kmb,double Kia,double Vr,double Kmq,double Kmp,double Kib)
+{
+    return Vf*(substratea*substrateb-productp*productq/Keq) / (substratea*substrateb*(1+productp/Kip) + Kma*substrateb + Kmb*(substratea+Kia)+Vf/(Vr*Keq)*(Kmq*productp*(1+substratea/Kia) + productq*(Kmp*(1+Kia*substrateb/(Kma*Kmb))+productp*(1+substrateb/Kib))) );
+}
+
+double kin_ordered_bi_uni_rev(double Vf,double substratea,double substrateb,double product,double Keq,double Kma,double Kmb,double Vr,double Kmp,double Kia)
+{
+    return Vf*(substratea*substrateb-product/Keq) / ( substratea*substrateb+Kma*substrateb+Kmb*substratea+Vf/(Vr*Keq)*(Kmp+product*(1+substratea/Kia)) );
+}
+
+double kin_ordered_uni_bi_rev(double Vf,double substrate,double productp,double productq,double Keq,double Kms,double Kip,double Vr,double Kmq,double Kmp)
+{
+    return Vf*(substrate-productp*productq/Keq) / ( Kms+substrate*(1+productp/Kip)+Vf/(Vr*Keq)*(Kmq*productp+Kmp*productq+productp*productq) );
+}
+
+double kin_michaelis_menten_rev(double Vf,double substrate,double Kms,double Vr,double product,double Kmp)
+{
+    return (Vf*substrate/Kms+Vr*product/Kmp) / ( 1+substrate/Kms+product/Kmp );
+}
+
+double kin_substrate_inihib_rev(double Vf,double substrate,double Kms,double Vr,double product,double Kmp,double Ki)
+{
+    return (Vf*substrate/Kms-Vr*product/Kmp) / ( 1+substrate/Kms+product/Kmp+pow((substrate/Ki),2.0) );
+}
+
+double kin_uncomp_inihib_rev(double Vf,double substrate,double Kms,double Vr,double product,double Kmp,double inhibitor,double Ki)
+{
+    return ( Vf*substrate/Kms-Vr*product/Kmp ) / ( 1+(substrate/Kms+product/Kmp)*(1+inhibitor/Ki) );
+}
+
+double kin_uni_uni_rev(double Vf,double substrate,double product,double Keq,double Kms,double Kmp)
+{
+    return Vf*( substrate-product/Keq ) / ( substrate+Kms*(1+product/Kmp) );
+}
+
+double kin_specific_activation_irr(double V,double substrate,double activator,double Kms,double Ka)
+{
+    return V*substrate*activator/( Kms*Ka+(Kms+substrate)*activator );
+}
+
+double kin_specific_activation_rev(double Vf,double substrate,double Kms,double Vr,double product,double Kmp,double activator,double Ka)
+{
+    return ( Vf*substrate/Kms-Vr*product/Kmp )*activator / ( Ka+(1+substrate/Kms+product/Kmp)*activator );
+}
+
+double kin_substrate_activation_irr(double V,double substrate,double Ksa,double Ksc)
+{
+    return V*pow((substrate/Ksa),2.0) / ( 1+substrate/Ksc+substrate/Ksa+pow((substrate/Ksa),2.0) );
+}
+
+double kin_ping_pong_bi_bi_rev(double Vf,double substratea,double substrateb,double productp,double productq,double Keq,double Kiq,double Kma,double Kmb,double Vr,double Kmq,double Kia,double Kmp)
+{
+    return Vf*( substratea*substrateb-productp*productq/Keq ) / (substratea*substrateb*(1+productq/Kiq)+Kma*substrateb+Kmb*substratea+Vf/(Vr*Keq)*(Kmq*productp*(1+substratea/Kia)+productq*(Kmp+productp)));
+}
+
+double kin_hill_1_modifier_rev(double Vf,double substrate,double Shalve,double product,double Keq,double Phalve,double h,double modifier,double Mhalve,double alpha)
+{
+    return Vf*substrate/Shalve*(1-product/(substrate*Keq))*pow((substrate/Shalve+product/Phalve),(h-1.0)) / ( (1+pow((modifier/Mhalve),h))/(1+alpha*pow((modifier/Mhalve),h))+pow((substrate/Shalve + product/Phalve),h) );
+}
+
+double kin_hill_2_modifiers_rev(double Vf,double substrate,double Shalve,double product,double Keq,double Phalve,double h,double modifierA,double MAhalve,double modifierB,double MBhalve,double alphaA,double alphaB,double alphaAB)
+{
+    return Vf*substrate/Shalve*(1-product/(substrate*Keq))*pow((substrate/Shalve+product/Phalve),(h-1.0)) / ( (1+pow((modifierA/MAhalve),h) + 1+pow((modifierB/MBhalve),h)) / ( 1+alphaA*pow((modifierA/MAhalve),h)+alphaB*pow((modifierB/MBhalve),h)+alphaA*alphaB*alphaAB*pow((modifierA/MAhalve),h)*pow((modifierB/MBhalve),h) ) + pow((substrate/Shalve + product/Phalve),h) );
+}
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/mexmathaddon.h b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/mexmathaddon.h
new file mode 100644
index 0000000000000000000000000000000000000000..1dac56a0515a41fe0b1e5db45dc5046d86326415
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/mexmathaddon.h	
@@ -0,0 +1,263 @@
+/*
+ * mexmathaddon.h: Include file for automatically generated MEX model files.
+ *
+ * Information:
+ * ============
+ * IQM Tools Pro 
+ */
+
+#define pi 3.141592653589793
+
+#ifdef __LCC__
+double max(double a, double b)
+{
+    if (a<b) return b;
+    else return a;
+}
+
+double min(double a, double b)
+{
+    if (a>b) return b;
+    else return a;
+}
+#endif
+
+#ifdef __GNUC__
+double max(double a, double b)
+{
+    return fmax(a,b);
+}
+
+double min(double a, double b)
+{
+    return fmin(a,b);
+}
+#endif
+
+
+
+double minIQM(int nargs, ...)
+{
+    int k;
+    double minimum;
+    double checkmin;
+    va_list vararg;
+    va_start(vararg, nargs);
+    minimum = va_arg(vararg, double);
+    for (k=1; k<nargs; k++ ) {
+        checkmin = va_arg(vararg, double);
+        if (checkmin < minimum) {
+            minimum = checkmin;
+        }
+    }
+    va_end (vararg);
+    return minimum;
+}
+
+double maxIQM(int nargs, ...)
+{
+    int k;
+    double maximum;
+    double checkmax;
+    va_list vararg;
+    va_start(vararg, nargs);
+    maximum = va_arg(vararg, double);
+    for (k=1; k<nargs; k++ ) {
+        checkmax = va_arg(vararg, double);
+        if (checkmax > maximum) {
+            maximum = checkmax;
+        }
+    }
+    va_end (vararg);
+    return maximum;
+}
+
+double indexmaxIQM(int nargs, ...)
+{
+    int k;
+    double maximum;
+    double indexmaximum;
+    double checkmax;
+    va_list vararg;
+    va_start(vararg, nargs);
+    maximum = va_arg(vararg, double);
+    indexmaximum = 1;
+    for (k=1; k<nargs; k++ ) {
+        checkmax = va_arg(vararg, double);
+        if (checkmax > maximum) {
+            maximum = checkmax;
+            indexmaximum = (double)k+1;
+        }
+    }
+    va_end (vararg);
+    return indexmaximum;
+}
+
+double sign(double a)
+{
+    if (a<0) return -1;
+    else if (a==0) return 0;
+    else if (a>0) return 1;
+    else return a;
+}
+
+double absIQM(double a)
+{
+    if (a < 0) return -a;
+    else return a;
+}
+
+double mod(double a, double b)
+{
+    if (b == 0) return a;
+    else if (a == b) return 0;
+    return sign(b)*absIQM(a-floor(a/b)*b);
+}
+
+double nthrootIQM(double a, double n)
+{
+    return pow(a,1.0/n);
+}
+
+double andIQM(int nargs, ...)
+{
+    int k;
+    va_list vararg;
+    va_start(vararg, nargs);
+    for (k=0; k<nargs; k++ ) {
+        if (va_arg(vararg, double) == 0) {
+            va_end (vararg);
+            return 0;
+        }
+    }
+    va_end (vararg);
+    return 1;
+}
+
+double orIQM(int nargs, ...)
+{
+    int k;
+    va_list vararg;
+    va_start(vararg, nargs);
+    for (k=0; k<nargs; k++ ) {
+        if (va_arg(vararg, double) != 0) {
+            va_end (vararg);
+            return 1;
+        }
+    }
+    va_end (vararg);
+    return 0;
+}
+
+double piecewiseIQM(int nargs, ...)
+{
+    int k, oddnumber;
+    double *data;
+    double returnvalue;
+    va_list vararg;
+    va_start(vararg, nargs);
+    /* Read in all variable input arguments in double array */
+    data = (double *)mxCalloc(nargs,sizeof(double));
+    for (k=0; k<nargs; k++ ) {
+        data[k] = va_arg(vararg, double);
+    }
+    /* 
+       Determine result
+       Check if odd or even number of input arguments
+     */
+    oddnumber = nargs % 2;
+    for (k=0;k<nargs-oddnumber;k+=2) {
+        if (data[k+1] != 0) {
+            returnvalue = data[k];
+            mxFree(data); /* free temporary array */
+            return returnvalue;
+        }
+    }
+    if (oddnumber != 0) {
+            returnvalue = data[nargs-1];
+            mxFree(data); /* free temporary array */
+            return returnvalue;
+    }
+    else {
+        mexErrMsgTxt("A piecewise statement is wrongly defined - missing (but needed) default value.");
+        mxFree(data); /* free temporary array */
+        return 0; /* statement never reached */
+    }
+}
+
+double piecewiseT0IQM(int nargs, ...) /* does the same as the piecewiseIQM function but does not lead to added events in the simulation model */
+{
+    int k, oddnumber;
+    double *data;
+    double returnvalue;
+    va_list vararg;
+    va_start(vararg, nargs);
+    /* Read in all variable input arguments in double array */
+    data = (double *)mxCalloc(nargs,sizeof(double));
+    for (k=0; k<nargs; k++ ) {
+        data[k] = va_arg(vararg, double);
+    }
+    /* 
+       Determine result
+       Check if odd or even number of input arguments
+     */
+    oddnumber = nargs % 2;
+    for (k=0;k<nargs-oddnumber;k+=2) {
+        if (data[k+1] != 0) {
+            returnvalue = data[k];
+            mxFree(data); /* free temporary array */
+            return returnvalue;
+        }
+    }
+    if (oddnumber != 0) {
+            returnvalue = data[nargs-1];
+            mxFree(data); /* free temporary array */
+            return returnvalue;
+    }
+    else {
+        mexErrMsgTxt("A piecewise statement is wrongly defined - missing (but needed) default value.");
+        mxFree(data); /* free temporary array */
+        return 0; /* statement never reached */
+    }
+}
+
+
+double piecewiseSmoothIQM(double t,double y0,double y1,double alpha) 
+{
+
+return (y0+y1*exp(alpha*t))/(1+exp(alpha*t));
+
+}
+        
+
+double gt(double a, double b)
+{
+    if (a > b) return 1;
+    else return 0;
+}
+
+double ge(double a, double b)
+{
+    if (a >= b) return 1;
+    else return 0;
+}
+
+double lt(double a, double b)
+{
+    if (a < b) return 1;
+    else return 0;
+}
+
+double le(double a, double b)
+{
+    if (a <= b) return 1;
+    else return 0;
+}
+
+double eq(double a, double b)
+{
+    if (a*b < 0) return 0;
+    else if ( absIQM(a-b) < 10.0*mxGetEps() ) return 1;
+    else return 0;
+}
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/mexsplineaddon.h b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/mexsplineaddon.h
new file mode 100644
index 0000000000000000000000000000000000000000..eb8d9b6e0dfbf98b143569abcf7018d4e6abc067
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/mexsplineaddon.h	
@@ -0,0 +1,1895 @@
+/*
+ * mexsplineaddon.h: contains the function interpcseIQM, interpcsexIQM and '
+ *      the function interpcsIQM
+ *      Cubic spline interpolation with (and without) endpoints for use 
+ *      by the CVODE integrator in the SBPD package
+ *
+ * The interpcsIQM is a function for cubic spline interpolation, but without the 
+ * possibility of defining slopes at the endpoints.
+ * 
+ * The interpcseIQM function allows to define slopes at the endpoints. The 
+ * spline coefficients are only calculated once and then only evaluated (faster)
+ * 
+ * the interpcsexIQM function determines the spline coefficients each time, allowing to 
+ * implement time dependent spline functions (slower).
+ *
+ */
+
+/* interpcseIQM and interpcsexIQM FUNCTIONS:
+ * Original C-code for spline interpolation taken from:
+ *   http://www.mech.uq.edu.au/staff/jacobs/nm_lib/cmathsrc/spline.c
+ *
+ * The syntax of this MEX function (to be used via CVODE interface) is as follows:
+ *
+ * yy = interpcseIQM(nargs,n,x1,x2,...,xn,y1,y2,...,yn,xx)
+ * yy = interpcseIQM(nargs,n,e1,e2,x1,x2,...,xn,y1,y2,...,yn,xx)
+ *
+ * nargs:  number of arguments
+ * n:      number of points in the x and y vectors
+ * xi:     x-values 
+ * yi:     y-values
+ * xx:     x-value at which to evaluate the spline function (do NOT allow multiple)
+ * e1,e2:  endpoint derivatives (if specified, both need to be given)
+ * yy:     interpolated value
+ */
+
+/*
+ *========================================================================
+ * Initialization of the spline related functions
+ *========================================================================
+ */
+void spline (int n, int e1, int e2, double s1, double s2, double x[], double y[], double b[], double c[], double d[], int *flag);
+double seval (int n, double xx, double x[], double y[], double b[], double c[], double d[], int *last);
+double deriv (int n, double xx, double x[], double b[], double c[], double d[], int *last);
+
+/*
+ *========================================================================
+ * Declare variables for the interpcseIQM function
+ *========================================================================
+ */
+#define MAX_INTERPCSEIQM 10000    /* defined maximum number of interpcseIQM functions in the model */
+int*    interpcseIQM_check = NULL; /* is initialized each new integration start to NULL ... required */
+double* xvec[MAX_INTERPCSEIQM];
+double* yvec[MAX_INTERPCSEIQM];
+double* bvec[MAX_INTERPCSEIQM];
+double* cvec[MAX_INTERPCSEIQM];
+double* dvec[MAX_INTERPCSEIQM];
+
+int*    interpcseSlopeIQM_check = NULL; /* is initialized each new integration start to NULL ... required */
+double* xvecslope[MAX_INTERPCSEIQM];
+double* yvecslope[MAX_INTERPCSEIQM];
+double* bvecslope[MAX_INTERPCSEIQM];
+double* cvecslope[MAX_INTERPCSEIQM];
+double* dvecslope[MAX_INTERPCSEIQM];
+
+/*
+ *========================================================================
+ * INTERFACE FUNCTION for interpcseIQM ... 
+ *========================================================================
+ */
+double interpcseIQM(int nargs, ...)
+{
+    /*************************************************************/
+    /* Define the variables needed for the spline function calls */
+    /*************************************************************/
+    int    index_pw; /* index of the interpcseIQM function */
+    int    n;
+    double *x;
+    double *y;
+    double xx;
+    double s1,s2;
+    int    e1,e2;
+    double *b;
+    double *c;
+    double *d;
+    int    flag;
+    int    last;
+    int    k;
+    double yy;
+    int    newCall;
+    double b2,c2,d2,x0,x1,y0,y1;
+    
+    /***************************************/
+    /* Handle the variable input arguments */
+    /***************************************/
+    /* Initialize the va_list */
+    va_list vararg;
+    va_start(vararg, nargs);
+    /* Get the index of the current interpcseIQM function */
+    index_pw = (int) va_arg(vararg, double);
+    /* Get the number of the x and y axis nodes for interpolation */
+    n = (int) va_arg(vararg, double);
+    /* Get the xx value at which to interpolate */
+    xx = va_arg(vararg, double);
+    
+    /* Check if too many interpcseIQM functions in the model (unlikely) */
+    if (index_pw >= MAX_INTERPCSEIQM) {
+        mexErrMsgTxt("interpcseIQM_CVODE: To many calls to interpcseIQM in the model.");
+    }
+    
+    /* Check if memory already obtained for handling the different calls */
+    if (interpcseIQM_check == NULL) interpcseIQM_check = (int *) mxCalloc(MAX_INTERPCSEIQM, sizeof(int));
+    
+    /* Check if new call or subsequent call */
+    if (interpcseIQM_check[index_pw] == 69) {
+        newCall = 0;
+    } else {
+        newCall = 1;
+        interpcseIQM_check[index_pw] = 69;
+    }
+
+    if (newCall == 1 || n == 2) {
+        /* First call to this function ... get the information */
+        /* Check if the number of input argument is plausible and define slopes */
+        if (nargs == 3+2*n) {
+            /* Plausible, but no slopes defined */
+            e1 = 0; s1 = 0; /* set s1 to 0 but it is not used */
+            e2 = 0; s2 = 0; /* set s2 to 0 but it is not used */
+        } else if (nargs == 3+2*n+2) {
+            /* Plausible, slopes are defined */
+            e1 = 1; s1 = va_arg(vararg, double);
+            e2 = 1; s2 = va_arg(vararg, double);
+        } else {
+            mexErrMsgTxt("interpcseIQM_CVODE: Incorrect number of input arguments (increase MAX_INTERPCSEIQM in mexsplineaddon.h).");
+        }
+        
+        /***********/
+        /* If n==2 */
+        /***********/
+        if (n == 2) {
+            if (e1 == 0 || e2 == 0) mexErrMsgTxt("interpcseIQM: n=2 requires the definition of slopes.");
+            x0 = va_arg(vararg, double);
+            x1 = va_arg(vararg, double);
+            y0 = va_arg(vararg, double);
+            y1 = va_arg(vararg, double);
+            /* End the variable input handling */
+            va_end (vararg);
+            b2 = s1;
+            c2 = -(-3.0*y1+3.0*y0+(s2+2.0*s1)*x1+(-s2-2.0*s1)*x0)/(pow(x1, 2.0)-2.0*x0*x1+pow(x0, 2.0));
+            d2 = (-2.0*y1+2.0*y0+(s2+s1)*x1+(-s2-s1)*x0)/(pow(x1, 3.0)-3.0*x0*pow(x1, 2.0)+3.0*pow(x0, 2.0)*x1-pow(x0, 3.0));
+            yy = y0 + b2*(xx-x0) + c2*pow(xx-x0, 2.0) + d2*pow(xx-x0, 3.0);   
+        } else {
+            /***********/
+            /* If n!=2 */
+            /***********/
+            /* Allocate memory for x and y */
+            x  = (double *) mxCalloc(n, sizeof(double));
+            y  = (double *) mxCalloc(n, sizeof(double));
+            /* Parse input arguments into x and y */
+            for (k=0;k<n;k++) x[k] = va_arg(vararg, double);
+            for (k=0;k<n;k++) y[k] = va_arg(vararg, double);
+            /* End the variable input handling */
+            va_end (vararg);
+        
+            /*****************************/
+            /* Allocate memory for b,c,d */
+            /*****************************/
+            b  = (double *) mxCalloc(n, sizeof(double));
+            c  = (double *) mxCalloc(n, sizeof(double));
+            d  = (double *) mxCalloc(n, sizeof(double));
+            
+            /****************************/
+            /* Call the spline function */
+            /****************************/
+            spline(n, e1, e2, s1, s2, x, y, b, c, d, &flag);
+            
+            /*********************************/
+            /* Save b,c,d,x,y for next calls */
+            /*********************************/
+            xvec[index_pw] = x;
+            yvec[index_pw] = y;
+            bvec[index_pw] = b;
+            cvec[index_pw] = c;
+            dvec[index_pw] = d;
+            
+            /***************************************/
+            /* Call the spline evaluation function */
+            /***************************************/
+            yy = seval (n, xx, x, y, b, c, d, &last);            
+        }
+    } else {
+        /* get x,y,b,c,d pointers */
+        x = xvec[index_pw];
+        y = yvec[index_pw];
+        b = bvec[index_pw];
+        c = cvec[index_pw];
+        d = dvec[index_pw];
+        /***************************************/
+        /* Call the spline evaluation function */
+        /***************************************/
+        yy = seval(n, xx, x, y, b, c, d, &last);
+    }
+    
+    /*********************************/
+    /* Return the interpolated value */
+    /*********************************/
+    return yy;
+}
+
+
+/*
+ *========================================================================
+ * INTERFACE FUNCTION for interpcseIQM ... 
+ *========================================================================
+ */
+double interpcseSlopeIQM(int nargs, ...)
+{
+    /*************************************************************/
+    /* Define the variables needed for the spline function calls */
+    /*************************************************************/
+    int    index_pw; /* index of the interpcseSlopeIQM function */
+    int    n;
+    double *x;
+    double *y;
+    double xx;
+    double s1,s2;
+    int    e1,e2;
+    double *b;
+    double *c;
+    double *d;
+    int    flag;
+    int    last;
+    int    k;
+    double yy;
+    int    newCall;
+    double b2,c2,d2,x0,x1,y0,y1;
+    
+    /***************************************/
+    /* Handle the variable input arguments */
+    /***************************************/
+    /* Initialize the va_list */
+    va_list vararg;
+    va_start(vararg, nargs);
+    /* Get the index of the current interpcseSlopeIQM function */
+    index_pw = (int) va_arg(vararg, double);
+    /* Get the number of the x and y axis nodes for interpolation */
+    n = (int) va_arg(vararg, double);
+    /* Get the xx value at which to interpolate */
+    xx = va_arg(vararg, double);
+    
+    /* Check if too many interpcseSlopeIQM functions in the model (unlikely) */
+    if (index_pw >= MAX_INTERPCSEIQM) {
+        mexErrMsgTxt("interpcseSlopeIQM_CVODE: To many calls to interpcseIQM in the model.");
+    }
+    
+    /* Check if memory already obtained for handling the different calls */
+    if (interpcseSlopeIQM_check == NULL) interpcseSlopeIQM_check = (int *) mxCalloc(MAX_INTERPCSEIQM, sizeof(int));
+    
+    /* Check if new call or subsequent call */
+    if (interpcseSlopeIQM_check[index_pw] == 69) {
+        newCall = 0;
+    } else {
+        newCall = 1;
+        interpcseSlopeIQM_check[index_pw] = 69;
+    }
+
+    if (newCall == 1 || n == 2) {
+        /* First call to this function ... get the information */
+        /* Check if the number of input argument is plausible and define slopes */
+        if (nargs == 3+2*n) {
+            /* Plausible, but no slopes defined */
+            e1 = 0; s1 = 0; /* set s1 to 0 but it is not used */
+            e2 = 0; s2 = 0; /* set s2 to 0 but it is not used */
+        } else if (nargs == 3+2*n+2) {
+            /* Plausible, slopes are defined */
+            e1 = 1; s1 = va_arg(vararg, double);
+            e2 = 1; s2 = va_arg(vararg, double);
+        } else {
+            mexErrMsgTxt("interpcseSlopeIQM_CVODE: Incorrect number of input arguments (increase MAX_INTERPCSEIQM in mexsplineaddon.h).");
+        }
+        
+        /***********/
+        /* If n==2 */
+        /***********/
+        if (n == 2) {
+            if (e1 == 0 || e2 == 0) mexErrMsgTxt("interpcseSlopeIQM_CVODE: n=2 requires the definition of slopes.");
+            x0 = va_arg(vararg, double);
+            x1 = va_arg(vararg, double);
+            y0 = va_arg(vararg, double);
+            y1 = va_arg(vararg, double);
+            /* End the variable input handling */
+            va_end (vararg);
+            b2 = s1;
+            c2 = -(-3.0*y1+3.0*y0+(s2+2.0*s1)*x1+(-s2-2.0*s1)*x0)/(pow(x1, 2.0)-2.0*x0*x1+pow(x0, 2.0));
+            d2 = (-2.0*y1+2.0*y0+(s2+s1)*x1+(-s2-s1)*x0)/(pow(x1, 3.0)-3.0*x0*pow(x1, 2.0)+3.0*pow(x0, 2.0)*x1-pow(x0, 3.0));
+            yy = b2 + 2.0*c2*(xx-x0) + 3.0*d2*pow(xx-x0, 2.0);   
+        } else {
+            /***********/
+            /* If n!=2 */
+            /***********/
+            /* Allocate memory for x and y */
+            x  = (double *) mxCalloc(n, sizeof(double));
+            y  = (double *) mxCalloc(n, sizeof(double));
+            /* Parse input arguments into x and y */
+            for (k=0;k<n;k++) x[k] = va_arg(vararg, double);
+            for (k=0;k<n;k++) y[k] = va_arg(vararg, double);
+            /* End the variable input handling */
+            va_end (vararg);
+        
+            /*****************************/
+            /* Allocate memory for b,c,d */
+            /*****************************/
+            b  = (double *) mxCalloc(n, sizeof(double));
+            c  = (double *) mxCalloc(n, sizeof(double));
+            d  = (double *) mxCalloc(n, sizeof(double));
+            
+            /****************************/
+            /* Call the spline function */
+            /****************************/
+            spline(n, e1, e2, s1, s2, x, y, b, c, d, &flag);
+            
+            /*********************************/
+            /* Save b,c,d,x,y for next calls */
+            /*********************************/
+            xvecslope[index_pw] = x;
+            yvecslope[index_pw] = y;
+            bvecslope[index_pw] = b;
+            cvecslope[index_pw] = c;
+            dvecslope[index_pw] = d;
+            
+            /***************************************/
+            /* Call the spline evaluation function */
+            /***************************************/
+            yy = deriv(n, xx, x, b, c, d, &last);            
+        }
+    } else {
+        /* get x,y,b,c,d pointers */
+        x = xvecslope[index_pw];
+        y = yvecslope[index_pw];
+        b = bvecslope[index_pw];
+        c = cvecslope[index_pw];
+        d = dvecslope[index_pw];
+        /***************************************/
+        /* Call the spline evaluation function */
+        /***************************************/
+        yy = deriv(n, xx, x, b, c, d, &last);
+    }
+    
+    /*********************************/
+    /* Return the interpolated value */
+    /*********************************/
+    return yy;
+}
+
+/*
+ *========================================================================
+ * INTERFACE FUNCTION for interpcsexIQM ... 
+ *========================================================================
+ */
+double interpcsexIQM(int nargs, ...)
+{
+    /*************************************************************/
+    /* Define the variables needed for the spline function calls */
+    /*************************************************************/
+    int    n;
+    double *x;
+    double *y;
+    double xx;
+    double s1,s2;
+    int    e1,e2;
+    double *b;
+    double *c;
+    double *d;
+    int    flag;
+    int    last;
+    int    k;
+    double yy;
+    double b2, c2, d2;
+    double x0,x1,y0,y1;
+    
+    /***************************************/
+    /* Handle the variable input arguments */
+    /***************************************/
+    /* Initialize the va_list */
+    va_list vararg;
+    va_start(vararg, nargs);
+    /* Get the number of the x and y axis nodes for interpolation */
+    n = (int) va_arg(vararg, double);
+    /* Check if the number of input argument is plausible and define slopes */
+    if (nargs == 1+2*n+1) {
+        /* Plausible, but no slopes defined */
+        e1 = 0; s1 = 0; /* set s1 to 0 but it is not used */
+        e2 = 0; s2 = 0; /* set s2 to 0 but it is not used */
+    } else if (nargs == 1+2*n+1+2) {
+        /* Plausible, slopes are defined */
+        e1 = 1; s1 = va_arg(vararg, double);
+        e2 = 1; s2 = va_arg(vararg, double);
+    } else {
+        mexErrMsgTxt("interpcseIQM_CVODE: Incorrect number of input arguments.");
+    }
+    
+    /***********/
+    /* If n==2 */
+    /***********/
+    if (n==2) {        
+        if (e1 == 0 || e2 == 0) mexErrMsgTxt("interpcseIQM: n=2 requires the definition of slopes.");
+        x0 = va_arg(vararg, double);
+        x1 = va_arg(vararg, double);
+        y0 = va_arg(vararg, double);
+        y1 = va_arg(vararg, double);
+
+        /* Get the xx value at which to interpolate */
+        xx = va_arg(vararg, double);
+        /* End the variable input handling */
+        va_end(vararg);
+
+        b2 = s1;
+        c2 = -(-3.0*y1+3.0*y0+(s2+2.0*s1)*x1+(-s2-2.0*s1)*x0)/(pow(x1,2.0)-2.0*x0*x1+pow(x0,2.0));
+        d2 = (-2.0*y1+2.0*y0+(s2+s1)*x1+(-s2-s1)*x0)/(pow(x1,3.0)-3.0*x0*pow(x1,2.0)+3.0*pow(x0,2.0)*x1-pow(x0,3.0));
+        yy = y0 + b2*(xx-x0) + c2*pow(xx-x0,2.0) + d2*pow(xx-x0,3.0);
+    } else {
+        /***********/
+        /* If n!=2 */
+        /***********/
+        /* Allocate memory for x and y */
+        x  = (double *) mxCalloc(n, sizeof(double));
+        y  = (double *) mxCalloc(n, sizeof(double));
+        /* Parse input arguments into x and y */
+        for (k=0;k<n;k++) x[k] = va_arg(vararg, double);
+        for (k=0;k<n;k++) y[k] = va_arg(vararg, double);
+        
+        /* Get the xx value at which to interpolate */
+        xx = va_arg(vararg, double);
+        /* End the variable input handling */
+        va_end(vararg);
+        
+        /*****************************/
+        /* Allocate memory for b,c,d */
+        /*****************************/
+        b  = (double *) mxCalloc(n, sizeof(double));
+        c  = (double *) mxCalloc(n, sizeof(double));
+        d  = (double *) mxCalloc(n, sizeof(double));
+        
+        /****************************/
+        /* Call the spline function */
+        /****************************/
+        spline(n, e1, e2, s1, s2, x, y, b, c, d, &flag);
+        
+        /***************************************/
+        /* Call the spline evaluation function */
+        /***************************************/
+        yy = seval(n, xx, x, y, b, c, d, &last);
+        
+        /***************/
+        /* Free memory */
+        /***************/
+        mxFree(x);
+        mxFree(y);
+        mxFree(b);
+        mxFree(c);
+        mxFree(d);
+    }
+    
+    /*********************************/
+    /* Return the interpolated value */
+    /*********************************/
+    return yy;
+}
+
+
+/*
+ *========================================================================
+ * INTERFACE FUNCTION for interpcsexSlopeIQM ... 
+ *========================================================================
+ */
+double interpcsexSlopeIQM(int nargs, ...)
+{
+    /*************************************************************/
+    /* Define the variables needed for the spline function calls */
+    /*************************************************************/
+    int    n;
+    double *x;
+    double *y;
+    double xx;
+    double s1,s2;
+    int    e1,e2;
+    double *b;
+    double *c;
+    double *d;
+    int    flag;
+    int    last;
+    int    k;
+    double yy;
+    double b2, c2, d2;
+    double x0,x1,y0,y1;
+    
+    /***************************************/
+    /* Handle the variable input arguments */
+    /***************************************/
+    /* Initialize the va_list */
+    va_list vararg;
+    va_start(vararg, nargs);
+    /* Get the number of the x and y axis nodes for interpolation */
+    n = (int) va_arg(vararg, double);
+    /* Check if the number of input argument is plausible and define slopes */
+    if (nargs == 1+2*n+1) {
+        /* Plausible, but no slopes defined */
+        e1 = 0; s1 = 0; /* set s1 to 0 but it is not used */
+        e2 = 0; s2 = 0; /* set s2 to 0 but it is not used */
+    } else if (nargs == 1+2*n+1+2) {
+        /* Plausible, slopes are defined */
+        e1 = 1; s1 = va_arg(vararg, double);
+        e2 = 1; s2 = va_arg(vararg, double);
+    } else {
+        mexErrMsgTxt("interpcsexSlopeIQM_CVODE: Incorrect number of input arguments.");
+    }
+    
+    /***********/
+    /* If n==2 */
+    /***********/
+    if (n==2) {        
+        if (e1 == 0 || e2 == 0) mexErrMsgTxt("interpcsexSlopeIQM: n=2 requires the definition of slopes.");
+        x0 = va_arg(vararg, double);
+        x1 = va_arg(vararg, double);
+        y0 = va_arg(vararg, double);
+        y1 = va_arg(vararg, double);
+
+        /* Get the xx value at which to interpolate */
+        xx = va_arg(vararg, double);
+        /* End the variable input handling */
+        va_end(vararg);
+
+        b2 = s1;
+        c2 = -(-3.0*y1+3.0*y0+(s2+2.0*s1)*x1+(-s2-2.0*s1)*x0)/(pow(x1,2.0)-2.0*x0*x1+pow(x0,2.0));
+        d2 = (-2.0*y1+2.0*y0+(s2+s1)*x1+(-s2-s1)*x0)/(pow(x1,3.0)-3.0*x0*pow(x1,2.0)+3.0*pow(x0,2.0)*x1-pow(x0,3.0));
+        yy = b2 + 2.0*c2*(xx-x0) + 3.0*d2*pow(xx-x0,2.0);
+    } else {
+        /***********/
+        /* If n!=2 */
+        /***********/
+        /* Allocate memory for x and y */
+        x  = (double *) mxCalloc(n, sizeof(double));
+        y  = (double *) mxCalloc(n, sizeof(double));
+        /* Parse input arguments into x and y */
+        for (k=0;k<n;k++) x[k] = va_arg(vararg, double);
+        for (k=0;k<n;k++) y[k] = va_arg(vararg, double);
+        
+        /* Get the xx value at which to interpolate */
+        xx = va_arg(vararg, double);
+        /* End the variable input handling */
+        va_end(vararg);
+        
+        /*****************************/
+        /* Allocate memory for b,c,d */
+        /*****************************/
+        b  = (double *) mxCalloc(n, sizeof(double));
+        c  = (double *) mxCalloc(n, sizeof(double));
+        d  = (double *) mxCalloc(n, sizeof(double));
+        
+        /****************************/
+        /* Call the spline function */
+        /****************************/
+        spline(n, e1, e2, s1, s2, x, y, b, c, d, &flag);
+        
+        /***************************************/
+        /* Call the spline evaluation function */
+        /***************************************/
+        yy = deriv(n, xx, x, b, c, d, &last);
+        
+        /***************/
+        /* Free memory */
+        /***************/
+        mxFree(x);
+        mxFree(y);
+        mxFree(b);
+        mxFree(c);
+        mxFree(d);
+    }
+    
+    /*********************************/
+    /* Return the interpolated value */
+    /*********************************/
+    return yy;
+}
+
+/*=========================================================================
+   Cubic spline coefficients
+   -------------------------
+   Evaluate the coefficients b[i], c[i], d[i], i = 0, 1, .. n-1 for
+   a cubic interpolating spline
+
+   S(xx) = Y[i] + b[i] * w + c[i] * w**2 + d[i] * w**3
+   where w = xx - x[i]
+   and   x[i] <= xx <= x[i+1]
+
+   The n supplied data points are x[i], y[i], i = 0 ... n-1.
+
+   Input :
+   -------
+   n       : The number of data points or knots (n >= 2)
+   end1,
+   end2    : = 1 to specify the slopes at the end points
+             = 0 to obtain the default conditions
+   slope1,
+   slope2  : the slopes at the end points x[0] and x[n-1]
+             respectively
+   x[]     : the abscissas of the knots in strictly
+             increasing order
+   y[]     : the ordinates of the knots
+
+   Output :
+   --------
+   b, c, d : arrays of spline coefficients as defined above
+             (See note 2 for a definition.)
+   iflag   : status flag
+            = 0 normal return
+            = 1 less than two data points; cannot interpolate
+            = 2 x[] are not in ascending order
+
+   This C code written by ...  Peter & Nigel,
+   ----------------------      Design Software,
+                               42 Gubberley St,
+                               Kenmore, 4069,
+                               Australia.
+
+   Version ... 1.1, 30 September 1987
+   -------     2.0, 6 April 1989    (start with zero subscript)
+                                     remove ndim from parameter list
+               2.1, 28 April 1989   (check on x[])
+               2.2, 10 Oct   1989   change number order of matrix
+
+   Notes ...
+   -----
+   (1) The accompanying function seval() may be used to evaluate the
+       spline while deriv will provide the first derivative.
+   (2) Using p to denote differentiation
+       y[i] = S(X[i])
+       b[i] = Sp(X[i])
+       c[i] = Spp(X[i])/2
+       d[i] = Sppp(X[i])/6  ( Derivative from the right )
+   (3) Since the zero elements of the arrays ARE NOW used here,
+       all arrays to be passed from the main program should be
+       dimensioned at least [n].  These routines will use elements
+       [0 .. n-1].
+   (4) Adapted from the text
+       Forsythe, G.E., Malcolm, M.A. and Moler, C.B. (1977)
+       "Computer Methods for Mathematical Computations"
+       Prentice Hall
+   (5) Note that although there are only n-1 polynomial segments,
+       n elements are requird in b, c, d.  The elements b[n-1],
+       c[n-1] and d[n-1] are set to continue the last segment
+       past x[n-1].
+=========================================================================*/
+void spline (int n, int end1, int end2,
+            double slope1, double slope2,
+            double x[], double y[],
+            double b[], double c[], double d[],
+            int *iflag)
+{  /* begin procedure spline() */
+
+int    nm1, ib, i;
+double t;
+int    ascend;
+
+nm1    = n - 1;
+*iflag = 0;
+
+if (n < 2)
+  {  /* no possible interpolation */
+  *iflag = 1;
+  return;
+  }
+
+ascend = 1;
+for (i = 1; i < n; ++i) if (x[i] <= x[i-1]) ascend = 0;
+if (!ascend)
+   {
+   *iflag = 2;
+   return;
+   }
+
+if (n >= 3)
+   {    /* ---- At least quadratic ---- */
+
+   /* ---- Set up the symmetric tri-diagonal system
+           b = diagonal
+           d = offdiagonal
+           c = right-hand-side  */
+   d[0] = x[1] - x[0];
+   c[1] = (y[1] - y[0]) / d[0];
+   for (i = 1; i < nm1; ++i)
+      {
+      d[i]   = x[i+1] - x[i];
+      b[i]   = 2.0 * (d[i-1] + d[i]);
+      c[i+1] = (y[i+1] - y[i]) / d[i];
+      c[i]   = c[i+1] - c[i];
+      }
+
+   /* ---- Default End conditions
+           Third derivatives at x[0] and x[n-1] obtained
+           from divided differences  */
+   b[0]   = -d[0];
+   b[nm1] = -d[n-2];
+   c[0]   = 0.0;
+   c[nm1] = 0.0;
+   if (n != 3)
+      {
+      c[0]   = c[2] / (x[3] - x[1]) - c[1] / (x[2] - x[0]);
+      c[nm1] = c[n-2] / (x[nm1] - x[n-3]) - c[n-3] / (x[n-2] - x[n-4]);
+      c[0]   = c[0] * d[0] * d[0] / (x[3] - x[0]);
+      c[nm1] = -c[nm1] * d[n-2] * d[n-2] / (x[nm1] - x[n-4]);
+      }
+
+   /* Alternative end conditions -- known slopes */
+   if (end1 == 1)
+      {
+      b[0] = 2.0 * (x[1] - x[0]);
+      c[0] = (y[1] - y[0]) / (x[1] - x[0]) - slope1;
+      }
+   if (end2 == 1)
+      {
+      b[nm1] = 2.0 * (x[nm1] - x[n-2]);
+      c[nm1] = slope2 - (y[nm1] - y[n-2]) / (x[nm1] - x[n-2]);
+      }
+
+   /* Forward elimination */
+   for (i = 1; i < n; ++i)
+     {
+     t    = d[i-1] / b[i-1];
+     b[i] = b[i] - t * d[i-1];
+     c[i] = c[i] - t * c[i-1];
+     }
+
+   /* Back substitution */
+   c[nm1] = c[nm1] / b[nm1];
+   for (ib = 0; ib < nm1; ++ib)
+      {
+      i    = n - ib - 2;
+      c[i] = (c[i] - d[i] * c[i+1]) / b[i];
+      }
+
+   /* c[i] is now the sigma[i] of the text */
+
+   /* Compute the polynomial coefficients */
+   b[nm1] = (y[nm1] - y[n-2]) / d[n-2] + d[n-2] * (c[n-2] + 2.0 * c[nm1]);
+   for (i = 0; i < nm1; ++i)
+      {
+      b[i] = (y[i+1] - y[i]) / d[i] - d[i] * (c[i+1] + 2.0 * c[i]);
+      d[i] = (c[i+1] - c[i]) / d[i];
+      c[i] = 3.0 * c[i];
+      }
+   c[nm1] = 3.0 * c[nm1];
+   d[nm1] = d[n-2];
+
+   }  /* at least quadratic */
+
+else  /* if n >= 3 */
+   {  /* linear segment only  */
+   b[0] = (y[1] - y[0]) / (x[1] - x[0]);
+   c[0] = 0.0;
+   d[0] = 0.0;
+   b[1] = b[0];
+   c[1] = 0.0;
+   d[1] = 0.0;
+   }
+}  /* end of spline() */
+
+
+/*-------------------------------------------------------------------*/
+/*-----------------------------------------------------------------*/
+/*-----------------------------------------------------------------*/
+double seval (int n, double u,
+              double x[], double y[],
+              double b[], double c[], double d[],
+              int *last)
+/*-----------------------------------------------------------------*/
+/*Purpose ...
+  -------
+  Evaluate the cubic spline function
+
+  S(xx) = y[i] + b[i] * w + c[i] * w**2 + d[i] * w**3
+  where w = u - x[i]
+  and   x[i] <= u <= x[i+1]
+  Note that Horner's rule is used.
+  If u < x[0]   then i = 0 is used.
+  If u > x[n-1] then i = n-1 is used.
+
+  Input :
+  -------
+  n       : The number of data points or knots (n >= 2)
+  u       : the abscissa at which the spline is to be evaluated
+  Last    : the segment that was last used to evaluate U
+  x[]     : the abscissas of the knots in strictly increasing order
+  y[]     : the ordinates of the knots
+  b, c, d : arrays of spline coefficients computed by spline().
+
+  Output :
+  --------
+  seval   : the value of the spline function at u
+  Last    : the segment in which u lies
+
+  Notes ...
+  -----
+  (1) If u is not in the same interval as the previous call then a
+      binary search is performed to determine the proper interval.
+
+*/
+/*-------------------------------------------------------------------*/
+{  /* begin function seval() */
+
+int    i, j, k;
+double w;
+
+i = *last;
+if (i >= n-1) i = 0;
+if (i < 0)  i = 0;
+
+if ((x[i] > u) || (x[i+1] < u))
+  {  /* ---- perform a binary search ---- */
+  i = 0;
+  j = n;
+  do
+    {
+    k = (i + j) / 2;         /* split the domain to search */
+    if (u < x[k])  j = k;    /* move the upper bound */
+    if (u >= x[k]) i = k;    /* move the lower bound */
+    }                        /* there are no more segments to search */
+  while (j > i+1);
+  }
+*last = i;
+
+/* ---- Evaluate the spline ---- */
+w = u - x[i];
+w = y[i] + w * (b[i] + w * (c[i] + w * d[i]));
+return (w);
+}
+/*-------------------------------------------------------------------*/
+
+/*-------------------------------------------------------------------*/
+/*-----------------------------------------------------------------*/
+/*-----------------------------------------------------------------*/
+double deriv (int n, double u,
+              double x[],
+              double b[], double c[], double d[],
+              int *last)
+/*-----------------------------------------------------------------*/
+/* Purpose ...
+   -------
+   Evaluate the derivative of the cubic spline function
+
+   S(x) = B[i] + 2.0 * C[i] * w + 3.0 * D[i] * w**2
+   where w = u - X[i]
+   and   X[i] <= u <= X[i+1]
+   Note that Horner's rule is used.
+   If U < X[0] then i = 0 is used.
+   If U > X[n-1] then i = n-1 is used.
+
+   Input :
+   -------
+   n       : The number of data points or knots (n >= 2)
+   u       : the abscissa at which the derivative is to be evaluated
+   last    : the segment that was last used
+   x       : the abscissas of the knots in strictly increasing order
+   b, c, d : arrays of spline coefficients computed by spline()
+
+   Output :
+   --------
+   deriv : the value of the derivative of the spline
+           function at u
+   last  : the segment in which u lies
+
+   Notes ...
+   -----
+   (1) If u is not in the same interval as the previous call then a
+       binary search is performed to determine the proper interval.
+
+*/
+/*-------------------------------------------------------------------*/
+{  /* begin function deriv() */
+
+int    i, j, k;
+double w;
+
+i = *last;
+if (i >= n-1) i = 0;
+if (i < 0) i = 0;
+
+if ((x[i] > u) || (x[i+1] < u))
+  {  /* ---- perform a binary search ---- */
+  i = 0;
+  j = n;
+  do
+    {
+    k = (i + j) / 2;          /* split the domain to search */
+    if (u < x[k])  j = k;     /* move the upper bound */
+    if (u >= x[k]) i = k;     /* move the lower bound */
+    }                         /* there are no more segments to search */
+  while (j > i+1);
+  }
+*last = i;
+
+/* ---- Evaluate the derivative ---- */
+w = u - x[i];
+w = b[i] + w * (2.0 * c[i] + w * 3.0 * d[i]);
+return (w);
+
+} /* end of deriv() */
+/*-------------------------------------------------------------------*/
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*************************************************************/
+/*************************************************************/
+/*************************************************************/
+/*************************************************************/
+/*************************************************************/
+/* interpcsIQM function ... MEX version for CVODE use  */
+/*************************************************************/
+
+void spline_pchip_set( int n, double x[], double f[], double d[] );
+void spline_pchip_val( int n, double x[], double f[], double d[],  int ne, double xe, double *feptr );
+int i4_max( int i1, int i2 );
+int chfev( double x1, double x2, double f1, double f2, double d1, double d2, int ne, double xe, double *feptr, int next[] );
+double r8_min( double x, double y );
+double r8_max( double x, double y );
+double pchst( double arg1, double arg2 );
+
+
+/****************************************************************************/
+
+double interpcsIQM(int nargs, int n, double xe, ...)
+
+/****************************************************************************
+
+  Purpose:
+
+    interpcsIQM is the calling function to evaluate a piecewise cubic spline 
+    function and calculte the Hermite interpolant.
+
+
+  Modified:
+
+    1 October 2007
+
+  Author:
+
+    Basti Bergdahl,
+    Department of Applied Microbiology,
+    Lund Insitute of Technology.
+
+  Calling syntax:
+
+    interpcsIQM(NARGS, N, XE, X1,...,XN,F1,...,FN)
+
+  Parameters:
+
+    Input, int NARGS, the total number of input arguments (not counting NARGS itself).
+    The number should be even, otherwise an error will occure.
+
+    Input, int N, the number of data points (rows in the table).  N must be at least 2.
+
+    Input, double XE, point at which the function is to be evaluated.
+
+    Input, double X1,...,XN, the strictly increasing independent variable values.
+
+    Input, double F1,...,FN, dependent variable values to be interpolated.  This
+    routine is designed for monotonic data, but it will work for any F-array.
+    It will force extrema at points where monotonicity switches direction.
+
+    Output, double FE, the value of the cubic Hermite function at XE.
+*/
+{
+    va_list vararg;
+    int k, oddnumber;
+    int ne = 1;
+    double *data, *x, *f, *d, *feptr;
+    double fe;
+
+    /* Check if table data has been given */
+    if (nargs == 2)
+    {
+        mexErrMsgTxt("interpcsIQM error: Input incorrect. No data for the table has been supplied.");
+        return 0;
+    }
+
+    /* Check if odd or even number of input arguments */
+    oddnumber = nargs % 2;
+    if (oddnumber != 0)
+    {
+        mexErrMsgTxt("interpcsIQM error: Input incorrect. The number of inputs should be even.");
+        return 0;
+    }
+
+    /* If number of input arguments in odd, check if
+     * the X and Y vectors are of the same size */
+    if ((nargs-2)/2 != n)
+    {
+        mexErrMsgTxt("interpcsIQM error: Input incorrect. The X and Y vectors are either of different lengths or");
+        mexErrMsgTxt("an incorrect number for the data points has been given.");
+        return 0;
+    }
+
+    /* Read in all variable input arguments in double array */    
+    va_start(vararg, xe);
+    data = (double *)mxCalloc((n*2),sizeof(double));
+    for (k=0; k<nargs-2; k++ )
+    {
+        data[k] = va_arg(vararg, double);
+    }
+
+    /* Create the X and Y arrays making up the table */
+    x = (double *)mxCalloc(n,sizeof(double));
+    f = (double *)mxCalloc(n,sizeof(double));
+    for (k=0; k<n; k++)
+    {
+        x[k] = data[k];
+        f[k] = data[k+n];
+    }
+    mxFree(data); /* free temporary array */
+
+    /* handle off limit values */
+    if (xe < x[0]) return(f[0]);
+    if (xe > x[n-1]) return(f[n-1]);
+    
+    /* Calculate the derivatives for the piecewise cubic Hermite interpolant */
+    d = (double *)mxCalloc(n,sizeof(double));
+    spline_pchip_set(n, x, f, d);
+
+    /* Evaluate the cubic Hermite function at x */    
+    feptr = &fe;
+    spline_pchip_val(n, x, f, d, ne, xe, feptr);
+
+    return(fe);
+}
+
+
+
+/****************************************************************************/
+
+void spline_pchip_set( int n, double x[], double f[], double d[] )
+
+/****************************************************************************
+
+  Purpose:
+
+    SPLINE_PCHIP_SET sets derivatives for a piecewise cubic Hermite interpolant.
+
+  Discussion:
+
+    This routine computes what would normally be called a Hermite
+    interpolant.  However, the user is only required to supply function
+    values, not derivative values as well.  This routine computes
+    "suitable" derivative values, so that the resulting Hermite interpolant
+    has desirable shape and monotonicity properties.
+
+    The interpolant will have an extremum at each point where
+    monotonicity switches direction.
+
+    The resulting piecewise cubic Hermite function may be evaluated
+    by SPLINE_PCHIP_VAL..
+
+    This routine was originally called "PCHIM".
+
+  Modified:
+
+    14 August 2005
+
+  Author:
+
+    Fred Fritsch,
+    Mathematics and Statistics Division,
+    Lawrence Livermore National Laboratory.
+
+    C++ translation by John Burkardt.
+
+  Reference:
+
+    Fred Fritsch, Ralph Carlson,
+    Monotone Piecewise Cubic Interpolation,
+    SIAM Journal on Numerical Analysis,
+    Volume 17, Number 2, April 1980, pages 238-246.
+
+    Fred Fritsch, Judy Butland,
+    A Method for Constructing Local Monotone Piecewise
+    Cubic Interpolants,
+    SIAM Journal on Scientific and Statistical Computing,
+    Volume 5, Number 2, 1984, pages 300-304.
+
+  Parameters:
+
+    Input, int N, the number of data points.  N must be at least 2.
+
+    Input, double X[N], the strictly increasing independent
+    variable values.
+
+    Input, double F[N], dependent variable values to be interpolated.  This
+    routine is designed for monotonic data, but it will work for any F-array.
+    It will force extrema at points where monotonicity switches direction.
+
+    Output, double D[N], the derivative values at the
+    data points.  If the data are monotonic, these values will determine
+    a monotone cubic Hermite function.
+*/
+{
+  double del1;
+  double del2;
+  double dmax;
+  double dmin;
+  double drat1;
+  double drat2;
+  double dsave;
+  double h1;
+  double h2;
+  double hsum;
+  double hsumt3;
+  int i;
+  int ierr;
+  int nless1;
+  double temp;
+  double w1;
+  double w2;
+
+  /*  Check the arguments. */
+
+  if ( n < 2 )
+  {
+    ierr = -1;
+    mexErrMsgTxt("\n");
+    mexErrMsgTxt("SPLINE_PCHIP_SET - Fatal error!\n");
+    mexErrMsgTxt("  Number of data points less than 2.\n");
+    exit ( ierr );
+  }
+
+  for ( i = 1; i < n; i++ )
+  {
+    if ( x[i] <= x[i-1] )
+    {
+      ierr = -3;
+      mexErrMsgTxt("\n");
+      mexErrMsgTxt("SPLINE_PCHIP_SET - Fatal error!\n");
+      mexErrMsgTxt("  X array not strictly increasing.\n");
+      exit ( ierr );
+    }
+  }
+
+  ierr = 0;
+  nless1 = n - 1;
+  h1 = x[1] - x[0];
+  del1 = ( f[1] - f[0] ) / h1;
+  dsave = del1;
+
+/*  Special case N=2, use linear interpolation. */
+
+  if ( n == 2 )
+  {
+    d[0] = del1;
+    d[n-1] = del1;
+    return;
+  }
+
+/*  Normal case, 3 <= N. */
+
+  h2 = x[2] - x[1];
+  del2 = ( f[2] - f[1] ) / h2;
+
+/*  Set D(1) via non-centered three point formula, adjusted to be
+    shape preserving. */
+
+  hsum = h1 + h2;
+  w1 = ( h1 + hsum ) / hsum;
+  w2 = -h1 / hsum;
+  d[0] = w1 * del1 + w2 * del2;
+
+  if ( pchst ( d[0], del1 ) <= 0.0 )
+  {
+    d[0] = 0.0;
+  }
+
+/*  Need do this check only if monotonicity switches. */
+
+  else if ( pchst ( del1, del2 ) < 0.0 )
+  {
+     dmax = 3.0 * del1;
+
+     if ( fabs ( dmax ) < fabs ( d[0] ) )
+     {
+       d[0] = dmax;
+     }
+
+  }
+
+/*  Loop through interior points. */
+
+  for ( i = 2; i <= nless1; i++ )
+  {
+    if ( 2 < i )
+    {
+      h1 = h2;
+      h2 = x[i] - x[i-1];
+      hsum = h1 + h2;
+      del1 = del2;
+      del2 = ( f[i] - f[i-1] ) / h2;
+    }
+
+/*  Set D(I)=0 unless data are strictly monotonic. */
+
+    d[i-1] = 0.0;
+
+    temp = pchst ( del1, del2 );
+
+    if ( temp < 0.0 )
+    {
+      ierr = ierr + 1;
+      dsave = del2;
+    }
+
+/*  Count number of changes in direction of monotonicity. */
+
+    else if ( temp == 0.0 )
+    {
+      if ( del2 != 0.0 )
+      {
+        if ( pchst ( dsave, del2 ) < 0.0 )
+        {
+          ierr = ierr + 1;
+        }
+        dsave = del2;
+      }
+    }
+
+/*  Use Brodlie modification of Butland formula. */
+
+    else
+    {
+      hsumt3 = 3.0 * hsum;
+      w1 = ( hsum + h1 ) / hsumt3;
+      w2 = ( hsum + h2 ) / hsumt3;
+      dmax = r8_max ( fabs ( del1 ), fabs ( del2 ) );
+      dmin = r8_min ( fabs ( del1 ), fabs ( del2 ) );
+      drat1 = del1 / dmax;
+      drat2 = del2 / dmax;
+      d[i-1] = dmin / ( w1 * drat1 + w2 * drat2 );
+    }
+  }
+
+/*  Set D(N) via non-centered three point formula, adjusted to be
+    shape preserving. */
+
+  w1 = -h2 / hsum;
+  w2 = ( h2 + hsum ) / hsum;
+  d[n-1] = w1 * del1 + w2 * del2;
+
+  if ( pchst ( d[n-1], del2 ) <= 0.0 )
+  {
+    d[n-1] = 0.0;
+  }
+  else if ( pchst ( del1, del2 ) < 0.0 )
+  {
+
+/*  Need do this check only if monotonicity switches. */
+
+    dmax = 3.0 * del2;
+
+    if ( fabs ( dmax ) < abs ( d[n-1] ) )
+    {
+      d[n-1] = dmax;
+    }
+
+  }
+  return;
+}
+
+/****************************************************************************/
+
+void spline_pchip_val( int n, double x[], double f[], double d[],
+  int ne, double xe, double *feptr )
+
+/****************************************************************************
+
+  Purpose:
+
+    SPLINE_PCHIP_VAL evaluates a piecewise cubic Hermite function.
+
+  Description:
+
+    This routine may be used by itself for Hermite interpolation, or as an
+    evaluator for SPLINE_PCHIP_SET.
+
+    This routine evaluates the cubic Hermite function at the points XE.
+
+    Most of the coding between the call to CHFEV and the end of
+    the IR loop could be eliminated if it were permissible to
+    assume that XE is ordered relative to X.
+
+    CHFEV does not assume that X1 is less than X2.  Thus, it would
+    be possible to write a version of SPLINE_PCHIP_VAL that assumes a strictly
+    decreasing X array by simply running the IR loop backwards
+    and reversing the order of appropriate tests.
+
+    The present code has a minor bug, which I have decided is not
+    worth the effort that would be required to fix it.
+    If XE contains points in [X(N-1),X(N)], followed by points less than
+    X(N-1), followed by points greater than X(N), the extrapolation points
+    will be counted (at least) twice in the total returned in IERR.
+
+    The evaluation will be most efficient if the elements of XE are
+    increasing relative to X; that is, for all J <= K,
+      X(I) <= XE(J)
+    implies
+      X(I) <= XE(K).
+
+    If any of the XE are outside the interval [X(1),X(N)],
+    values are extrapolated from the nearest extreme cubic,
+    and a warning error is returned.
+
+    This routine was originally named "PCHFE".
+
+  Modified:
+
+    14 August 2005
+
+  Author:
+
+    Fred Fritsch,
+    Mathematics and Statistics Division,
+    Lawrence Livermore National Laboratory.
+
+    C++ translation by John Burkardt.
+
+  Reference:
+
+    Fred Fritsch, Ralph Carlson,
+    Monotone Piecewise Cubic Interpolation,
+    SIAM Journal on Numerical Analysis,
+    Volume 17, Number 2, April 1980, pages 238-246.
+
+  Parameters:
+
+    Input, int N, the number of data points.  N must be at least 2.
+
+    Input, double X[N], the strictly increasing independent
+    variable values.
+
+    Input, double F[N], the function values.
+
+    Input, double D[N], the derivative values.
+
+    Input, int NE, the number of evaluation points.
+
+    Input, double XE, point at which the function is to
+    be evaluated.
+
+    Output, double FE, the value of the cubic Hermite
+    function at XE.
+*/
+{
+  int i;
+  int ierc;
+  int ierr;
+  int ir;
+  int j;
+  int j_first;
+  int j_new;
+  int j_save;
+  int next[2];
+  int nj;
+
+/*  Check arguments. */
+
+  if ( n < 2 )
+  {
+    ierr = -1;
+    mexErrMsgTxt("\n");
+    mexErrMsgTxt("SPLINE_PCHIP_VAL - Fatal error!\n");
+    mexErrMsgTxt("Number of data points less than 2.\n");
+    exit ( ierr );
+  }
+
+  for ( i = 1; i < n; i++ )
+  {
+    if ( x[i] <= x[i-1] )
+    {
+      ierr = -3;
+      mexErrMsgTxt("\n");
+      mexErrMsgTxt("SPLINE_PCHIP_VAL - Fatal error!\n");
+      mexErrMsgTxt("X array not strictly increasing.\n");
+      exit ( ierr );
+    }
+  }
+
+  if ( ne < 1 )
+  {
+    ierr = -4;
+    mexErrMsgTxt("\n");
+    mexErrMsgTxt("SPLINE_PCHIP_VAL - Fatal error!\n");
+    mexErrMsgTxt("Number of evaluation points less than 1.\n");
+    return;
+  }
+
+  ierr = 0;
+
+/*  Loop over intervals.
+  The interval index is IL = IR-1.
+  The interval is X(IL) <= X < X(IR).
+*/
+  j_first = 1;
+  ir = 2;
+
+  for ( ; ; )
+  {
+/*
+  Skip out of the loop if have processed all evaluation points.
+*/
+    if ( ne < j_first )
+    {
+      break;
+    }
+/*
+  Locate all points in the interval.
+*/
+    j_save = ne + 1;
+
+    for ( j = j_first; j <= ne; j++ )
+    {
+      if ( x[ir-1] <= xe )
+      {
+        j_save = j;
+        if ( ir == n )
+        {
+          j_save = ne + 1;
+        }
+        break;
+      }
+    }
+/*
+  Have located first point beyond interval.
+*/
+    j = j_save;
+
+    nj = j - j_first;
+/*
+  Skip evaluation if no points in interval.
+*/
+    if ( nj != 0 )
+    {
+/*
+  Evaluate cubic at XE(J_FIRST:J-1).
+*/
+      ierc = chfev ( x[ir-2], x[ir-1], f[ir-2], f[ir-1], d[ir-2], d[ir-1],
+        nj, xe, feptr, next );
+
+      if ( ierc < 0 )
+      {
+        ierr = -5;
+        mexErrMsgTxt("\n");
+        mexErrMsgTxt("SPLINE_PCHIP_VAL - Fatal error!\n");
+        mexErrMsgTxt("Error return from CHFEV.\n");
+        exit ( ierr );
+      }
+/*
+  In the current set of XE points, there are NEXT(2) to the right of X(IR).
+*/
+      if ( next[1] != 0 )
+      {
+        if ( ir < n )
+        {
+          ierr = -5;
+          mexErrMsgTxt("\n");
+          mexErrMsgTxt("SPLINE_PCHIP_VAL - Fatal error!\n");
+          mexErrMsgTxt("IR < N.\n");
+          exit ( ierr );
+        }
+/*
+  These are actually extrapolation points.
+*/
+        ierr = ierr + next[1];
+
+      }
+/*
+  In the current set of XE points, there are NEXT(1) to the left of X(IR-1).
+*/
+      if ( next[0] != 0 )
+      {
+/*
+  These are actually extrapolation points.
+*/
+        if ( ir <= 2 )
+        {
+          ierr = ierr + next[0];
+        }
+        else
+        {
+          j_new = -1;
+
+          for ( i = j_first; i <= j-1; i++ )
+          {
+            if ( xe < x[ir-2] )
+            {
+              j_new = i;
+              break;
+            }
+          }
+
+          if ( j_new == -1 )
+          {
+            ierr = -5;
+            mexErrMsgTxt("\n");
+            mexErrMsgTxt("SPLINE_PCHIP_VAL - Fatal error!\n");
+            mexErrMsgTxt("  Could not bracket the data point.\n");
+            exit ( ierr );
+          }
+/*
+  Reset J.  This will be the new J_FIRST.
+*/
+          j = j_new;
+/*
+  Now find out how far to back up in the X array.
+*/
+          for ( i = 1; i <= ir-1; i++ )
+          {
+            if ( xe < x[i-1] )
+            {
+              break;
+            }
+          }
+/*
+  At this point, either XE(J) < X(1) or X(i-1) <= XE(J) < X(I) .
+
+  Reset IR, recognizing that it will be incremented before cycling.
+*/
+          ir = i4_max ( 1, i-1 );
+        }
+      }
+
+      j_first = j;
+    }
+
+    ir = ir + 1;
+
+    if ( n < ir )
+    {
+      break;
+    }
+
+  }
+
+  return;
+}
+
+/****************************************************************************/
+
+int chfev( double x1, double x2, double f1, double f2, double d1, double d2,
+  int ne, double xe, double *feptr, int next[] )
+
+/****************************************************************************
+
+  Purpose:
+
+    CHFEV evaluates a cubic polynomial given in Hermite form.
+
+  Discussion:
+
+    This routine evaluates a cubic polynomial given in Hermite form at an
+    array of points.  While designed for use by SPLINE_PCHIP_VAL, it may
+    be useful directly as an evaluator for a piecewise cubic
+    Hermite function in applications, such as graphing, where
+    the interval is known in advance.
+
+    The cubic polynomial is determined by function values
+    F1, F2 and derivatives D1, D2 on the interval [X1,X2].
+
+  Modified:
+
+    12 August 2005
+
+  Author:
+
+    Fred Fritsch,
+    Mathematics and Statistics Division,
+    Lawrence Livermore National Laboratory.
+
+    C++ translation by John Burkardt.
+
+  Reference:
+
+    Fred Fritsch, Ralph Carlson,
+    Monotone Piecewise Cubic Interpolation,
+    SIAM Journal on Numerical Analysis,
+    Volume 17, Number 2, April 1980, pages 238-246.
+
+    David Kahaner, Cleve Moler, Steven Nash,
+    Numerical Methods and Software,
+    Prentice Hall, 1989,
+    ISBN: 0-13-627258-4,
+    LC: TA345.K34.
+
+  Parameters:
+
+    Input, double X1, X2, the endpoints of the interval of
+    definition of the cubic.  X1 and X2 must be distinct.
+
+    Input, double F1, F2, the values of the function at X1 and
+    X2, respectively.
+
+    Input, double D1, D2, the derivative values at X1 and
+    X2, respectively.
+
+    Input, int NE, the number of evaluation points.
+
+    Input, double XE, the point at which the function is to
+    be evaluated.  If the value of XE is outside the interval
+    [X1,X2], a warning error is returned in NEXT.
+
+    Output, double FE, the value of the cubic function
+    at the point XE.
+
+    Output, int NEXT[2], indicates the number of extrapolation points:
+    NEXT[0] = number of evaluation points to the left of interval.
+    NEXT[1] = number of evaluation points to the right of interval.
+
+    Output, int CHFEV, error flag.
+    0, no errors.
+    -1, NE < 1.
+    -2, X1 == X2.
+*/
+{
+  double c2;
+  double c3;
+  double del1;
+  double del2;
+  double delta;
+  double h;
+  int ierr;
+  double x;
+  double fe;
+  double xma;
+  double xmi;
+
+  if ( ne < 1 )
+  {
+    ierr = -1;
+    mexErrMsgTxt("\n");
+    mexErrMsgTxt("CHFEV - Fatal error!\n");
+    mexErrMsgTxt("  Number of evaluation points is less than 1.\n");
+    printf("  NE = %d\n", ne);
+    return ierr;
+  }
+
+  h = x2 - x1;
+
+  if ( h == 0.0 )
+  {
+    ierr = -2;
+    mexErrMsgTxt("\n");
+    mexErrMsgTxt("CHFEV - Fatal error!\n");
+    mexErrMsgTxt("  The interval [X1,X2] is of zero length.\n");
+    return ierr;
+  }
+/*
+  Initialize.
+*/
+  ierr = 0;
+  next[0] = 0;
+  next[1] = 0;
+  xmi = r8_min ( 0.0, h );
+  xma = r8_max ( 0.0, h );
+/*
+  Compute cubic coefficients expanded about X1.
+*/
+  delta = ( f2 - f1 ) / h;
+  del1 = ( d1 - delta ) / h;
+  del2 = ( d2 - delta ) / h;
+  c2 = -( del1 + del1 + del2 );
+  c3 = ( del1 + del2 ) / h;
+    x = xe - x1;
+    fe = f1 + x * ( d1 + x * ( c2 + x * c3 ) );
+    *feptr = fe;
+/*
+  Count the extrapolation points.
+*/
+    if ( x < xmi )
+    {
+      next[0] = next[0] + 1;
+    }
+
+    if ( xma < x )
+    {
+      next[1] = next[1] + 1;
+    }
+
+
+  return 0;
+}
+
+/****************************************************************************/
+
+double pchst( double arg1, double arg2 )
+
+/****************************************************************************
+
+  Purpose:
+
+    PCHST: PCHIP sign-testing routine.
+
+  Discussion:
+
+    This routine essentially computes the sign of ARG1 * ARG2.
+
+    The object is to do this without multiplying ARG1 * ARG2, to avoid
+    possible over/underflow problems.
+
+  Modified:
+
+    12 August 2005
+
+  Author:
+
+    Fred Fritsch,
+    Mathematics and Statistics Division,
+    Lawrence Livermore National Laboratory.
+
+    C++ translation by John Burkardt.
+
+  Reference:
+
+    Fred Fritsch, Ralph Carlson,
+    Monotone Piecewise Cubic Interpolation,
+    SIAM Journal on Numerical Analysis,
+    Volume 17, Number 2, April 1980, pages 238-246.
+
+  Parameters:
+
+    Input, double ARG1, ARG2, two values to check.
+
+    Output, double PCHST,
+    -1.0, if ARG1 and ARG2 are of opposite sign.
+     0.0, if either argument is zero.
+    +1.0, if ARG1 and ARG2 are of the same sign.
+*/
+{
+  double value;
+
+  if ( arg1 == 0.0 )
+  {
+    value = 0.0;
+  }
+  else if ( arg1 < 0.0 )
+  {
+    if ( arg2 < 0.0 )
+    {
+      value = 1.0;
+    }
+    else if ( arg2 == 0.0 )
+    {
+      value = 0.0;
+    }
+    else if ( 0.0 < arg2 )
+    {
+      value = -1.0;
+    }
+  }
+  else if ( 0.0 < arg1 )
+  {
+    if ( arg2 < 0.0 )
+    {
+      value = -1.0;
+    }
+    else if ( arg2 == 0.0 )
+    {
+      value = 0.0;
+    }
+    else if ( 0.0 < arg2 )
+    {
+      value = 1.0;
+    }
+  }
+
+  return(value);
+}
+
+/****************************************************************************/
+
+double r8_max( double x, double y )
+
+/****************************************************************************
+
+  Purpose:
+
+    R8_MAX returns the maximum of two R8's.
+
+  Modified:
+
+    10 January 2002
+
+  Author:
+
+    John Burkardt
+
+  Parameters:
+
+    Input, double X, Y, the quantities to compare.
+
+    Output, double R8_MAX, the maximum of X and Y.
+*/
+{
+  if ( y < x )
+  {
+    return(x);
+  }
+  else
+  {
+    return(y);
+  }
+}
+/****************************************************************************/
+
+double r8_min( double x, double y )
+
+/****************************************************************************
+
+  Purpose:
+
+    R8_MIN returns the minimum of two R8's.
+
+  Modified:
+
+    09 May 2003
+
+  Author:
+
+    John Burkardt
+
+  Parameters:
+
+    Input, double X, Y, the quantities to compare.
+
+    Output, double R8_MIN, the minimum of X and Y.
+*/
+{
+  if ( y < x )
+  {
+    return(y);
+  }
+  else
+  {
+    return(x);
+  }
+}
+
+
+/****************************************************************************/
+
+int i4_max ( int i1, int i2 )
+
+/****************************************************************************
+
+  Purpose:
+
+    I4_MAX returns the maximum of two I4's.
+
+  Modified:
+
+    13 October 1998
+
+  Author:
+
+    John Burkardt
+
+  Parameters:
+
+    Input, int I1, I2, are two integers to be compared.
+
+    Output, int I4_MAX, the larger of I1 and I2.
+
+*/
+{
+  if ( i2 < i1 )
+  {
+    return(i1);
+  }
+  else
+  {
+    return(i2);
+  }
+
+}
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodea.c b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodea.c
new file mode 100644
index 0000000000000000000000000000000000000000..e5f0260d817b83ee0ead438a675ca2a789e01dca
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodea.c	
@@ -0,0 +1,1805 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * ----------------------------------------------------------------- 
+ * Programmer(s): Radu Serban @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2006, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This is the implementation file for the CVODEA adjoint integrator.
+ * -----------------------------------------------------------------
+ */
+
+/* 
+ * =================================================================
+ * IMPORTED HEADER FILES
+ * =================================================================
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "cvodes_impl.h"
+
+#include <sundials/sundials_math.h>
+#include <sundials/sundials_types.h>
+
+/* 
+ * =================================================================
+ * MACRO DEFINITIONS
+ * =================================================================
+ */
+
+#define loop for(;;)
+
+/* 
+ * =================================================================
+ * CVODEA PRIVATE CONSTANTS
+ * =================================================================
+ */
+
+#define ZERO        RCONST(0.0)        /* real 0.0   */
+#define ONE         RCONST(1.0)        /* real 1.0   */
+#define TWO         RCONST(2.0)        /* real 2.0   */
+#define HUNDRED     RCONST(100.0)      /* real 100.0 */
+#define FUZZ_FACTOR RCONST(1000000.0)  /* fuzz factor for CVadjGetY */
+
+/* 
+ * =================================================================
+ * PRIVATE FUNCTION PROTOTYPES
+ * =================================================================
+ */
+
+static booleantype CVAallocVectors(CVadjMem ca_mem);
+static void CVAfreeVectors(CVadjMem ca_mem);
+
+static CkpntMem CVAckpntInit(CVodeMem cv_mem);
+static CkpntMem CVAckpntNew(CVodeMem cv_mem);
+static void CVAckpntDelete(CkpntMem *ck_memPtr);
+
+static int  CVAdataStore(CVadjMem ca_mem, CkpntMem ck_mem);
+static int  CVAckpntGet(CVodeMem cv_mem, CkpntMem ck_mem); 
+
+static int CVAfindIndex(CVadjMem ca_mem, realtype t, 
+                        long int *indx, booleantype *newpoint);
+
+static booleantype CVAhermiteMalloc(CVadjMem ca_mem, long int steps);
+static void CVAhermiteFree(DtpntMem *dt_mem, long int steps);
+static int CVAhermiteGetY(CVadjMem ca_mem, realtype t, N_Vector y);
+static int CVAhermiteStorePnt(CVodeMem cv_mem, DtpntMem d);
+
+static booleantype CVApolynomialMalloc(CVadjMem ca_mem, long int steps);
+static void CVApolynomialFree(DtpntMem *dt_mem, long int steps);
+static int CVApolynomialGetY(CVadjMem ca_mem, realtype t, N_Vector y);
+static int CVApolynomialStorePnt(CVodeMem cv_mem, DtpntMem d);
+
+/* Wrappers */
+
+static int CVArhs(realtype t, N_Vector yB, 
+                  N_Vector yBdot, void *cvadj_mem);
+
+static int CVArhsQ(realtype t, N_Vector yB, 
+                   N_Vector qBdot, void *cvadj_mem);
+
+/* 
+ * =================================================================
+ * EXPORTED FUNCTIONS IMPLEMENTATION
+ * =================================================================
+ */
+
+/* 
+ * -----------------------------------------------------------------
+ * Readibility Constants
+ * -----------------------------------------------------------------
+ */
+
+#define uround      (ca_mem->ca_uround)
+#define tinitial    (ca_mem->ca_tinitial)
+#define tfinal      (ca_mem->ca_tfinal)
+#define nckpnts     (ca_mem->ca_nckpnts)
+#define nsteps      (ca_mem->ca_nsteps)
+#define ckpntData   (ca_mem->ca_ckpntData)
+#define newData     (ca_mem->ca_newData)
+#define np          (ca_mem->ca_np)
+#define ytmp        (ca_mem->ca_ytmp)
+#define f_B         (ca_mem->ca_fB)
+#define f_data_B    (ca_mem->ca_f_dataB)
+#define fQ_B        (ca_mem->ca_fQB)
+#define fQ_data_B   (ca_mem->ca_fQ_dataB)
+#define t_for_quad  (ca_mem->ca_t_for_quad)
+#define Y0          (ca_mem->ca_Y0)
+#define Y1          (ca_mem->ca_Y1)
+#define Y           (ca_mem->ca_Y)
+#define T           (ca_mem->ca_T)
+#define interpType  (ca_mem->ca_interpType)
+#define getY        (ca_mem->ca_getY)
+#define storePnt    (ca_mem->ca_storePnt)
+#define lfreeB      (ca_mem->ca_lfreeB)
+
+#define zn         (cv_mem->cv_zn)
+#define nst        (cv_mem->cv_nst)
+#define q          (cv_mem->cv_q)
+#define qu         (cv_mem->cv_qu)
+#define qprime     (cv_mem->cv_qprime)
+#define qwait      (cv_mem->cv_qwait)
+#define L          (cv_mem->cv_L)
+#define gammap     (cv_mem->cv_gammap)
+#define h          (cv_mem->cv_h)
+#define hprime     (cv_mem->cv_hprime)
+#define hscale     (cv_mem->cv_hscale)
+#define eta        (cv_mem->cv_eta)
+#define etamax     (cv_mem->cv_etamax)
+#define tn         (cv_mem->cv_tn)
+#define tretlast   (cv_mem->cv_tretlast)
+#define tau        (cv_mem->cv_tau)
+#define tq         (cv_mem->cv_tq)
+#define l          (cv_mem->cv_l)
+#define saved_tq5  (cv_mem->cv_saved_tq5)
+#define forceSetup (cv_mem->cv_forceSetup)
+#define f          (cv_mem->cv_f)
+#define lmm        (cv_mem->cv_lmm)
+#define iter       (cv_mem->cv_iter)
+#define itol       (cv_mem->cv_itol)
+#define reltol     (cv_mem->cv_reltol)
+#define Sabstol    (cv_mem->cv_Sabstol)
+#define Vabstol    (cv_mem->cv_Vabstol)
+#define efun       (cv_mem->cv_efun)
+#define f_data     (cv_mem->cv_f_data)
+#define errfp      (cv_mem->cv_errfp)
+#define h0u        (cv_mem->cv_h0u)
+#define quadr      (cv_mem->cv_quadr)
+#define errconQ    (cv_mem->cv_errconQ)
+#define znQ        (cv_mem->cv_znQ)
+#define itolQ      (cv_mem->cv_itolQ)
+#define reltolQ    (cv_mem->cv_reltolQ)
+#define SabstolQ   (cv_mem->cv_SabstolQ)
+#define VabstolQ   (cv_mem->cv_VabstolQ)
+#define fQ         (cv_mem->cv_fQ)
+#define tempv      (cv_mem->cv_tempv)
+#define tempvQ     (cv_mem->cv_tempvQ)
+
+#define t0_        (ck_mem->ck_t0)
+#define t1_        (ck_mem->ck_t1)
+#define zn_        (ck_mem->ck_zn)
+#define znQ_       (ck_mem->ck_znQ)
+#define quadr_     (ck_mem->ck_quadr)
+#define zqm_       (ck_mem->ck_zqm)
+#define nst_       (ck_mem->ck_nst)
+#define tretlast_  (ck_mem->ck_tretlast)
+#define q_         (ck_mem->ck_q)
+#define qprime_    (ck_mem->ck_qprime)
+#define qwait_     (ck_mem->ck_qwait)
+#define L_         (ck_mem->ck_L)
+#define gammap_    (ck_mem->ck_gammap)
+#define h_         (ck_mem->ck_h)
+#define hprime_    (ck_mem->ck_hprime)
+#define hscale_    (ck_mem->ck_hscale)
+#define eta_       (ck_mem->ck_eta)
+#define etamax_    (ck_mem->ck_etamax)
+#define tau_       (ck_mem->ck_tau)
+#define tq_        (ck_mem->ck_tq)
+#define l_         (ck_mem->ck_l)
+#define saved_tq5_ (ck_mem->ck_saved_tq5)
+#define next_      (ck_mem->ck_next)
+
+/*
+ * CVadjMalloc
+ *
+ * This routine allocates space for the global CVODEA memory
+ * structure.
+ */
+
+void *CVadjMalloc(void *cvode_mem, long int steps, int interp)
+{
+  CVadjMem ca_mem;
+  CVodeMem cv_mem;
+  booleantype allocOK;
+  long int i, ii;
+
+  /* Check arguments */
+  if (cvode_mem == NULL) {
+    CVProcessError(NULL, 0, "CVODEA", "CVadjMalloc", MSGAM_NULL_CVMEM);
+    return(NULL);
+  }
+  cv_mem = (CVodeMem)cvode_mem;
+
+  if (steps <= 0) {
+    CVProcessError(NULL, 0, "CVODEA", "CVadjMalloc", MSGAM_BAD_STEPS);
+    return(NULL);
+  }
+
+  if ( (interp != CV_HERMITE) && (interp != CV_POLYNOMIAL) ) {
+    CVProcessError(NULL, 0, "CVODEA", "CVadjMalloc", MSGAM_BAD_INTERP);
+    return(NULL);
+  } 
+
+  /* Allocate memory block */
+  ca_mem = NULL;
+  ca_mem = (CVadjMem) malloc(sizeof(struct CVadjMemRec));
+  if (ca_mem == NULL) {
+    CVProcessError(NULL, 0, "CVODEA", "CVadjMalloc", MSGAM_MEM_FAIL);
+    return(NULL);
+  }
+
+  /* Attach CVODES memory for forward runs */
+  ca_mem->cv_mem = cv_mem;
+
+  /* Set interpType */
+  interpType = interp;
+
+  /* Allocate memory for workspace vectors */
+  allocOK = CVAallocVectors(ca_mem);
+  if (!allocOK) {
+    free(ca_mem); ca_mem = NULL;
+    CVProcessError(NULL, 0, "CVODEA", "CVadjMalloc", MSGAM_MEM_FAIL);
+    return(NULL);
+  }
+
+  /* Initialize Check Points linked list */
+  ca_mem->ck_mem = NULL;
+  ca_mem->ck_mem = CVAckpntInit(cv_mem);
+  if (ca_mem->ck_mem == NULL) {
+    CVAfreeVectors(ca_mem);
+    free(ca_mem); ca_mem = NULL;
+    CVProcessError(NULL, 0, "CVODEA", "CVadjMalloc", MSGAM_MEM_FAIL);
+    return(NULL);
+  }
+
+  /* Allocate space for the array of Data Point structures */
+  
+  ca_mem->dt_mem = NULL;
+  ca_mem->dt_mem = (DtpntMem *) malloc((steps+1)*sizeof(struct DtpntMemRec *));
+  if (ca_mem->dt_mem == NULL) {
+    while (ca_mem->ck_mem != NULL) CVAckpntDelete(&(ca_mem->ck_mem));
+    CVAfreeVectors(ca_mem);
+    free(ca_mem); ca_mem = NULL;
+    CVProcessError(NULL, 0, "CVODEA", "CVadjMalloc", MSGAM_MEM_FAIL);
+    return(NULL);
+  }
+
+  for (i=0; i<=steps; i++) { 
+    ca_mem->dt_mem[i] = NULL;
+    ca_mem->dt_mem[i] = (DtpntMem) malloc(sizeof(struct DtpntMemRec));
+    if (ca_mem->dt_mem[i] == NULL) {
+      for(ii=0; ii<i; ii++) {free(ca_mem->dt_mem[ii]); ca_mem->dt_mem[ii] = NULL;}
+      free(ca_mem->dt_mem); ca_mem->dt_mem = NULL;
+      while (ca_mem->ck_mem != NULL) CVAckpntDelete(&(ca_mem->ck_mem));
+      CVAfreeVectors(ca_mem);
+      free(ca_mem); ca_mem = NULL;
+      CVProcessError(NULL, 0, "CVODEA", "CVadjMalloc", MSGAM_MEM_FAIL);
+      return(NULL);
+    }
+  }
+
+  switch (interpType) {
+
+  case CV_HERMITE:
+    /* Allocate Data Points memory */
+    allocOK = CVAhermiteMalloc(ca_mem, steps);
+    if (!allocOK) {
+      for(i=0; i<=steps; i++) {free(ca_mem->dt_mem[i]); ca_mem->dt_mem[i] = NULL;}
+      free(ca_mem->dt_mem); ca_mem->dt_mem = NULL;
+      while (ca_mem->ck_mem != NULL) CVAckpntDelete(&(ca_mem->ck_mem));
+      CVAfreeVectors(ca_mem);
+      free(ca_mem); ca_mem = NULL;
+      CVProcessError(NULL, 0, "CVODEA", "CVadjMalloc", MSGAM_MEM_FAIL);
+      return(NULL);
+    }
+    /* Attach interpolation functions getY and storePnt */
+    getY = CVAhermiteGetY;
+    storePnt = CVAhermiteStorePnt;
+    /* Rename zn[0] and zn[1] for use in interpolation */
+    Y0 = zn[0];
+    Y1 = zn[1];
+    break;
+  case CV_POLYNOMIAL:
+    /* Allocate Data Points memory */
+    allocOK = CVApolynomialMalloc(ca_mem, steps);
+    if (!allocOK) {
+      for(i=0; i<=steps; i++) {free(ca_mem->dt_mem[i]); ca_mem->dt_mem[i] = NULL;}
+      free(ca_mem->dt_mem); ca_mem->dt_mem = NULL;
+      while (ca_mem->ck_mem != NULL) CVAckpntDelete(&(ca_mem->ck_mem));
+      CVAfreeVectors(ca_mem);
+      free(ca_mem); ca_mem = NULL;
+      CVProcessError(NULL, 0, "CVODEA", "CVadjMalloc", MSGAM_MEM_FAIL);
+      return(NULL);
+    }
+    /* Attach interpolation functions getY and storePnt */
+    getY = CVApolynomialGetY;
+    storePnt = CVApolynomialStorePnt;
+    /* Rename zn for use in interpolation */
+    for (i=0;i<L_MAX;i++) Y[i] = zn[i];
+    break;
+  }
+
+  /* Other entries in ca_mem */
+  uround   = cv_mem->cv_uround;
+  nsteps   = steps;
+  tinitial = tn; 
+
+  /* Initialize nckpnts to ZERO */
+  nckpnts = 0;
+
+  /* Initialize backward cvode memory to NULL */
+  ca_mem->cvb_mem = NULL;
+
+  ca_mem->ca_lmemB = NULL;
+  ca_mem->ca_lfreeB = NULL;
+  ca_mem->ca_pmemB = NULL;
+  
+  ca_mem->ca_f_dataB = NULL;
+  ca_mem->ca_fQ_dataB = NULL;
+
+  return((void *)ca_mem);
+} 
+
+/* 
+ * CVadjSetInterpType
+ *
+ * Changes the interpolation type.
+ * Possible return values: CV_SUCCESS, CV_ADJMEM_NULL, CV_ILL_INPUT, CV_MEM_FAIL
+ */
+
+int CVadjSetInterpType(void *cvadj_mem, int interp)
+{
+  CVadjMem ca_mem;
+  CVodeMem cv_mem;
+  booleantype allocOK;
+  long int i;
+  
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CV_ADJMEM_NULL, "CVODEA", "CVadjSetInterpType", MSGAM_NULL_CAMEM);
+    return(CV_ADJMEM_NULL);
+  }
+  ca_mem = (CVadjMem) cvadj_mem;
+
+  cv_mem = ca_mem->cv_mem;
+
+  if ( (interp != CV_HERMITE) && (interp != CV_POLYNOMIAL) ) {
+    CVProcessError(NULL, CV_ILL_INPUT, "CVODEA", "CVadjSetInterpType", MSGAM_BAD_INTERP);
+    return(CV_ILL_INPUT);
+  } 
+
+  if (interp == interpType) return(CV_SUCCESS);
+
+  interpType = interp;
+
+
+  switch (interpType) {
+
+  case CV_HERMITE:
+    /* Delete Data Points memory */
+    CVApolynomialFree(ca_mem->dt_mem, nsteps);
+    /* Allocate Data Points memory */
+    allocOK = CVAhermiteMalloc(ca_mem, nsteps);
+    if (!allocOK) {
+      CVProcessError(NULL, CV_MEM_FAIL, "CVODEA", "CVadjSetInterpType", MSGAM_MEM_FAIL);
+      return(CV_MEM_FAIL);
+    }
+    /* Attach interpolation functions getY and storePnt */
+    getY = CVAhermiteGetY;
+    storePnt = CVAhermiteStorePnt;
+    /* Rename zn[0] and zn[1] for use in interpolation */
+    Y0 = zn[0];
+    Y1 = zn[1];
+    break;
+  case CV_POLYNOMIAL:
+    /* Delete Data Points memory */
+    CVAhermiteFree(ca_mem->dt_mem, nsteps);
+    /* Allocate Data Points memory */
+    allocOK = CVApolynomialMalloc(ca_mem, nsteps);
+    if (!allocOK) {
+      CVProcessError(NULL, CV_MEM_FAIL, "CVODEA", "CVadjSetInterpType", MSGAM_MEM_FAIL);
+      return(CV_MEM_FAIL);
+    }
+    /* Attach interpolation functions getY and storePnt */
+    getY = CVApolynomialGetY;
+    storePnt = CVApolynomialStorePnt;
+    /* Rename zn for use in interpolation */
+    for (i=0;i<L_MAX;i++) Y[i] = zn[i];
+    break;
+  }
+
+  return(CV_SUCCESS);
+
+}
+
+/*
+ * CVadjFree
+ *
+ * This routine frees the memory allocated by CVadjMalloc.
+ */
+
+void CVadjFree(void **cvadj_mem)
+{
+  void *cvode_bmem;
+  CVadjMem ca_mem;
+  long int i;
+
+  if (*cvadj_mem == NULL) return;
+
+  ca_mem = (CVadjMem) (*cvadj_mem);
+
+  /* Delete check points one by one */
+  while (ca_mem->ck_mem != NULL) CVAckpntDelete(&(ca_mem->ck_mem));
+
+  /* Free vectors at each data point */
+  switch (interpType) {
+  case CV_HERMITE:
+    CVAhermiteFree(ca_mem->dt_mem, nsteps);
+    break;
+  case CV_POLYNOMIAL:
+    CVApolynomialFree(ca_mem->dt_mem, nsteps);
+    break;
+  }
+  for(i=0; i<=nsteps; i++) {free(ca_mem->dt_mem[i]); ca_mem->dt_mem[i] = NULL;}
+  free(ca_mem->dt_mem); ca_mem->dt_mem = NULL;
+
+  /* Free workspace vectors in ca_mem */
+  CVAfreeVectors(ca_mem);
+
+  /* Free memory allocated by the linear solver */
+  if (lfreeB != NULL) lfreeB(ca_mem);
+
+  /* Free CVODES memory for backward run */
+  cvode_bmem = (void *)ca_mem->cvb_mem;
+  CVodeFree(&cvode_bmem);
+
+  /* Free CVODEA memory */
+  free(*cvadj_mem);
+  *cvadj_mem = NULL;
+}
+
+/*
+ * CVodeF
+ *
+ * This routine integrates to tout and returns solution into yout.
+ * In the same time, it stores check point data every 'steps' steps. 
+ * 
+ * CVodeF can be called repeatedly by the user.
+ *
+ * ncheckPtr points to the number of check points stored so far.
+ */
+
+int CVodeF(void *cvadj_mem, realtype tout, N_Vector yout, 
+           realtype *tret, int itask, int *ncheckPtr)
+{
+  CVadjMem ca_mem;
+  CVodeMem cv_mem;
+  CkpntMem tmp;
+  DtpntMem *dt_mem;
+  int cv_itask, flag;
+  booleantype iret;
+
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CV_ADJMEM_NULL, "CVODEA", "CVodeF", MSGAM_NULL_CAMEM);
+    return(CV_ADJMEM_NULL);
+  }
+  ca_mem = (CVadjMem) cvadj_mem;
+
+  cv_mem = ca_mem->cv_mem;
+  dt_mem = ca_mem->dt_mem;
+
+  iret = TRUE;
+  cv_itask = CV_ONE_STEP;
+
+  /* Interpret itask */
+  switch (itask) {
+  case CV_NORMAL:
+    iret = FALSE;
+    cv_itask = CV_ONE_STEP;
+    break;
+  case CV_ONE_STEP:
+    iret = TRUE;
+    cv_itask = CV_ONE_STEP;
+    break;
+  case CV_NORMAL_TSTOP:
+    iret = FALSE;
+    cv_itask = CV_ONE_STEP_TSTOP;
+    break;
+  case CV_ONE_STEP_TSTOP:
+    iret = TRUE;
+    cv_itask = CV_ONE_STEP_TSTOP;
+    break;
+  }
+
+  /* On the first step, load dt_mem[0].
+     On subsequent steps, test if taking a new step is necessary. */
+  if ( nst == 0) {
+
+    dt_mem[0]->t = ca_mem->ck_mem->ck_t0;
+    storePnt(cv_mem, dt_mem[0]);
+
+  } else if ( (tn - tout)*h >= ZERO ) {
+
+    /* If tout was passed, return interpolated solution. 
+       No changes to ck_mem or dt_mem are needed. */
+    *tret = tout;
+    flag = CVodeGetDky(cv_mem, tout, 0, yout);
+    *ncheckPtr = nckpnts;
+    newData = TRUE;
+    ckpntData = ca_mem->ck_mem;
+    np = nst % nsteps + 1;
+    return(flag);
+
+  }
+
+  /* Integrate to tout (in CV_ONE_STEP mode) while loading check points */
+  loop {
+
+    /* Perform one step of the integration */
+
+    flag = CVode(cv_mem, tout, yout, tret, cv_itask);
+    if (flag < 0) break;
+
+    /* Test if a new check point is needed */
+
+    if ( nst % nsteps == 0 ) {
+
+      ca_mem->ck_mem->ck_t1 = *tret;
+
+      /* Create a new check point, load it, and append it to the list */
+      tmp = CVAckpntNew(cv_mem);
+      if (tmp == NULL) {
+        CVProcessError(cv_mem, CV_MEM_FAIL, "CVODEA", "CVodeF", MSGAM_MEM_FAIL);
+        flag = CV_MEM_FAIL;
+        break;
+      }
+      tmp->ck_next = ca_mem->ck_mem;
+      ca_mem->ck_mem = tmp;
+      nckpnts++;
+      forceSetup = TRUE;
+      
+      /* Reset i=0 and load dt_mem[0] */
+      dt_mem[0]->t = ca_mem->ck_mem->ck_t0;
+      storePnt(cv_mem, dt_mem[0]);
+
+    } else {
+      
+      /* Load next point in dt_mem */
+      dt_mem[nst%nsteps]->t = *tret;
+      storePnt(cv_mem, dt_mem[nst%nsteps]);
+
+    }
+
+    /* Set t1 field of the current ckeck point structure
+       for the case in which there will be no future
+       check points */
+    ca_mem->ck_mem->ck_t1 = *tret;
+
+    /* tfinal is now set to *tret */
+    tfinal = *tret;
+
+    /* Return if in CV_ONE_STEP mode */
+    if (iret) break;
+
+    /* Return if tout reached */
+    if ( (*tret - tout)*h >= ZERO ) {
+      *tret = tout;
+      CVodeGetDky(cv_mem, tout, 0, yout);
+      break;
+    }
+
+  } /* end of loop() */
+
+  /* Get ncheck from ca_mem */ 
+  *ncheckPtr = nckpnts;
+
+  /* Data is available for the last interval */
+  newData = TRUE;
+  ckpntData = ca_mem->ck_mem;
+  np = nst % nsteps + 1;
+
+  return(flag);
+}
+
+/*
+ * CVodeCreateB, CVodeMallocB, and CVodeReInitB
+ *
+ * Wrappers for the backward phase around the corresponding 
+ * CVODES functions
+ */
+
+int CVodeCreateB(void *cvadj_mem, int lmmB, int iterB)
+{
+  CVadjMem ca_mem;
+  void *cvode_mem;
+
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CV_ADJMEM_NULL, "CVODEA", "CVodeCreateB", MSGAM_NULL_CAMEM);
+    return(CV_ADJMEM_NULL);
+  }
+
+  ca_mem = (CVadjMem) cvadj_mem;
+
+  cvode_mem = CVodeCreate(lmmB, iterB);
+
+  if (cvode_mem == NULL)
+    return(CV_MEM_FAIL);
+
+  ca_mem->cvb_mem = (CVodeMem) cvode_mem;
+
+  return(CV_SUCCESS);
+
+}
+
+int CVodeMallocB(void *cvadj_mem, CVRhsFnB fB, 
+                 realtype tB0, N_Vector yB0,
+                 int itolB, realtype reltolB, void *abstolB)
+{
+  CVadjMem ca_mem;
+  CVodeMem cv_mem;
+  int sign, flag;
+
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CV_ADJMEM_NULL, "CVODEA", "CVodeMallocB", MSGAM_NULL_CAMEM);
+    return(CV_ADJMEM_NULL);
+  }
+  ca_mem = (CVadjMem) cvadj_mem;
+
+  cv_mem = ca_mem->cvb_mem;
+
+  flag = CVodeMalloc(cv_mem, CVArhs, tB0, yB0,
+                     itolB, reltolB, abstolB);
+  if (flag != CV_SUCCESS) return(flag);
+
+  sign = (tfinal - tinitial > ZERO) ? 1 : -1;
+  if ( (sign*(tB0-tinitial) < ZERO) || (sign*(tfinal-tB0) < ZERO) ) {
+    CVProcessError(cv_mem, CV_BAD_TB0, "CVODEA", "CVodeMallocB", MSGAM_BAD_TB0);
+    return(CV_BAD_TB0);
+  }
+
+  f_B = fB;
+
+  CVodeSetMaxHnilWarns(cv_mem, -1);
+  CVodeSetFdata(cv_mem, cvadj_mem);
+
+  return(CV_SUCCESS);
+
+}
+
+int CVodeReInitB(void *cvadj_mem, CVRhsFnB fB, 
+                 realtype tB0, N_Vector yB0, 
+                 int itolB, realtype reltolB, void *abstolB)
+{
+  CVadjMem ca_mem;
+  CVodeMem cv_mem;
+  int sign, flag;
+
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CV_ADJMEM_NULL, "CVODEA", "CVodeReInitB", MSGAM_NULL_CAMEM);
+    return(CV_ADJMEM_NULL);
+  }
+  ca_mem = (CVadjMem) cvadj_mem;
+
+  cv_mem = ca_mem->cvb_mem;
+
+  flag = CVodeReInit(cv_mem, CVArhs, tB0, yB0,
+                     itolB, reltolB, abstolB);
+
+  if (flag != CV_SUCCESS) return(flag);
+
+  sign = (tfinal - tinitial > ZERO) ? 1 : -1;
+  if ( (sign*(tB0-tinitial) < ZERO) || (sign*(tfinal-tB0) < ZERO) ) {
+    CVProcessError(cv_mem, CV_BAD_TB0, "CVODEA", "CVodeReInitB", MSGAM_BAD_TB0);
+    return(CV_BAD_TB0);
+  }
+  
+  f_B  = fB;
+
+  CVodeSetMaxHnilWarns(cv_mem, -1);
+  CVodeSetFdata(cv_mem, cvadj_mem);
+
+  return(CV_SUCCESS);
+
+}
+
+/*
+ * CVodeQuadMallocB, and CVodeQuadReInitB
+ *
+ * Wrappers for the backward phase around the corresponding 
+ * CVODES functions
+ */
+
+int CVodeQuadMallocB(void *cvadj_mem, CVQuadRhsFnB fQB, N_Vector yQB0)
+{
+  CVadjMem ca_mem;
+  void *cvode_mem;
+  int flag;
+
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CV_ADJMEM_NULL, "CVODEA", "CVodeQuadMallocB", MSGAM_NULL_CAMEM);
+    return(CV_ADJMEM_NULL);
+  }
+  ca_mem = (CVadjMem) cvadj_mem;
+
+  fQ_B = fQB;
+
+  cvode_mem = (void *) ca_mem->cvb_mem;
+
+  flag = CVodeQuadMalloc(cvode_mem, CVArhsQ, yQB0);
+  if (flag != CV_SUCCESS) return(flag);
+
+  flag = CVodeSetQuadFdata(cvode_mem, cvadj_mem);
+
+  return(flag);
+
+}
+
+int CVodeQuadReInitB(void *cvadj_mem, CVQuadRhsFnB fQB, N_Vector yQB0)
+{
+  CVadjMem ca_mem;
+  void *cvode_mem;
+  int flag;
+
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CV_ADJMEM_NULL, "CVODEA", "CVodeQuadReInitB", MSGAM_NULL_CAMEM);
+    return(CV_ADJMEM_NULL);
+  }
+  ca_mem = (CVadjMem) cvadj_mem;
+
+  fQ_B = fQB;
+
+  cvode_mem = (void *) ca_mem->cvb_mem;
+
+  flag = CVodeQuadReInit(cvode_mem, CVArhsQ, yQB0);
+
+  return(flag);
+
+}
+
+/*
+ * CVodeB
+ *
+ * This routine performs the backward integration towards tBout. 
+ * When necessary, it performs a forward integration between two 
+ * consecutive check points to update interpolation data.
+ * itask can be CV_NORMAL or CV_ONE_STEP only.
+ *
+ * On a successful return, CVodeB returns either CV_SUCCESS
+ * (in ONE_STEP mode or if tBout was reached in NORMAL mode)
+ * unless the return time happens to be a checkpoint, in which
+ * case it returns CV_TSTOP_RETURN)
+ */
+
+int CVodeB(void *cvadj_mem, realtype tBout, N_Vector yBout, 
+           realtype *tBret, int itaskB)
+{
+  CVadjMem ca_mem;
+  CkpntMem ck_mem;
+  CVodeMem cvb_mem;
+  int sign, flag, cv_itask;
+  realtype tBn, hB, troundoff;
+  
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CV_ADJMEM_NULL, "CVODEA", "CVodeB", MSGAM_NULL_CAMEM);
+    return(CV_ADJMEM_NULL);
+  }
+  ca_mem  = (CVadjMem) cvadj_mem;
+
+  cvb_mem = ca_mem->cvb_mem;
+  if (cvb_mem == NULL) {
+    CVProcessError(NULL, CV_BCKMEM_NULL, "CVODEA", "CVodeB", MSGAM_NULL_CVMEM);
+    return(CV_BCKMEM_NULL);
+  }
+
+  if (itaskB == CV_NORMAL)
+    cv_itask = CV_NORMAL_TSTOP;
+  else if (itaskB == CV_ONE_STEP)
+    cv_itask = CV_ONE_STEP_TSTOP;
+  else {
+    CVProcessError(cvb_mem, CV_BAD_ITASK, "CVODEA", "CVodeB", MSGAM_BAD_ITASKB);
+    return(CV_BAD_ITASK);
+  }
+
+  ck_mem = ca_mem->ck_mem;
+
+  sign = (tfinal - tinitial > ZERO) ? 1 : -1;
+
+  if ( (sign*(tBout-tinitial) < ZERO) || (sign*(tfinal-tBout) < ZERO) ) {
+    CVProcessError(cvb_mem, CV_BAD_TBOUT, "CVODEA", "CVodeB", MSGAM_BAD_TBOUT);
+    return(CV_BAD_TBOUT);
+  }
+
+  /* Move ck_mem pointer to the checkpoint appropriate for
+     tBn (the current time reached by CVODES) */
+  tBn = cvb_mem->cv_tn;
+  troundoff = HUNDRED*uround*(ABS(tBn) + ABS(hB));
+  while ( sign*(tBn - t0_) <= troundoff ) {
+    if (next_ == NULL) break;
+    ck_mem = next_;
+  }
+
+  loop {
+
+    /* Store interpolation data if not available 
+       This is the 2nd forward integration pass */
+    if (ck_mem != ckpntData) {
+      flag = CVAdataStore(ca_mem, ck_mem);
+      if (flag != CV_SUCCESS) break;
+    }
+
+    /* Backward integration */
+    CVodeSetStopTime((void *)cvb_mem, t0_);
+    flag = CVode(cvb_mem, tBout, yBout, tBret, cv_itask);
+
+    /* If an error occured, return now */
+    if (flag < 0) break;
+
+    /* Set the time at which CVodeGetQuadB will evaluate any quadratures */
+    t_for_quad = *tBret;
+
+    /* If in CV_ONE_STEP mode, return now (flag=CV_SUCCESS or flag=CV_TSTOP_RETURN) */
+    if (itaskB == CV_ONE_STEP) break;
+
+    /* If succesfully reached tBout, return now */
+    if ( sign*(*tBret - tBout) <= ZERO) break;
+
+    /* Move check point in linked list to next one */
+    ck_mem = next_;
+
+  } 
+
+  return(flag);
+}
+
+/* 
+ * =================================================================
+ * PRIVATE FUNCTIONS
+ * =================================================================
+ */
+
+/*
+ * CVAallocVectors
+ *
+ * Allocate memory for adjoint workspace N_Vectors
+ */
+
+static booleantype CVAallocVectors(CVadjMem ca_mem)
+{
+  CVodeMem cv_mem;
+
+  cv_mem = ca_mem->cv_mem;
+
+  ytmp = NULL;
+  ytmp = N_VClone(tempv);
+  if (ytmp == NULL) {
+    return(FALSE);
+  }
+
+  return(TRUE);
+
+}
+
+/*
+ * CVAfreeVectors
+ * 
+ * Free memory allocated by CVAallocVectors
+ */
+
+static void CVAfreeVectors(CVadjMem ca_mem)
+{
+  N_VDestroy(ytmp);
+}
+
+
+/*
+ * CVAckpntInit
+ *
+ * This routine initializes the check point linked list with 
+ * information from the initial time.
+ */
+
+static CkpntMem CVAckpntInit(CVodeMem cv_mem)
+{
+  CkpntMem ck_mem;
+
+  /* Allocate space for ckdata */
+  ck_mem = NULL;
+  ck_mem = (CkpntMem) malloc(sizeof(struct CkpntMemRec));
+  if (ck_mem == NULL) return(NULL);
+
+  zn_[0] = NULL;
+  zn_[0] = N_VClone(tempv);
+  if (zn_[0] == NULL) {
+    free(ck_mem); ck_mem = NULL;
+    return(NULL);
+  }
+  
+  zn_[1] = NULL;
+  zn_[1] = N_VClone(tempv);
+  if (zn_[1] == NULL) {
+    N_VDestroy(zn_[0]);
+    free(ck_mem); ck_mem = NULL;
+    return(NULL);
+  }
+
+  /* zn_[qmax] was not allocated */
+  zqm_ = 0;
+
+  /* Load ckdata from cv_mem */
+  N_VScale(ONE, zn[0], zn_[0]);
+  t0_    = tn;
+  nst_   = 0;
+  q_     = 1;
+  h_     = 0.0;
+  
+  /* Do we need to carry quadratures */
+  quadr_ = quadr && errconQ;
+
+  if (quadr_) {
+    znQ_[0] = NULL;
+    znQ_[0] = N_VClone(tempvQ);
+    if (znQ_[0] == NULL) {
+      N_VDestroy(zn_[0]);
+      N_VDestroy(zn_[1]);
+      free(ck_mem); ck_mem = NULL;
+      return(NULL);
+    }
+    N_VScale(ONE, znQ[0], znQ_[0]);
+  }
+
+  /* Next in list */
+  next_  = NULL;
+
+  return(ck_mem);
+}
+
+/*
+ * CVAckpntNew
+ *
+ * This routine allocates space for a new check point and sets 
+ * its data from current values in cv_mem.
+ */
+
+static CkpntMem CVAckpntNew(CVodeMem cv_mem)
+{
+  CkpntMem ck_mem;
+  int j, jj;
+  int qmax; 
+
+  /* Allocate space for ckdata */
+  ck_mem = NULL;
+  ck_mem = (CkpntMem) malloc(sizeof(struct CkpntMemRec));
+  if (ck_mem == NULL) return(NULL);
+
+  /* Test if we need to allocate space for the last zn.
+     NOTE: zn(qmax) may be needed for a hot restart, if an order
+     increase is deemed necessary at the first step after a check 
+     point */
+  qmax = cv_mem->cv_qmax;
+  zqm_ = (q < qmax) ? qmax : 0;
+
+  for (j=0; j<=q; j++) {
+    zn_[j] = NULL;
+    zn_[j] = N_VClone(tempv);
+    if (zn_[j] == NULL) {
+      for (jj=0; jj<j; jj++) N_VDestroy(zn_[jj]);
+      free(ck_mem); ck_mem = NULL;
+      return(NULL);
+    }
+  }
+
+  if (q < qmax) {
+    zn_[qmax] = NULL;
+    zn_[qmax] = N_VClone(tempv);
+    if (zn_[qmax] == NULL) {
+      for (j=0; j<=q; j++) N_VDestroy(zn_[j]);
+      free(ck_mem); ck_mem = NULL;
+      return(NULL);
+    }
+  }
+
+  /* Test if we need to carry quadratures */
+  quadr_ = quadr && errconQ;
+
+  if (quadr_) {
+
+    for (j=0; j<=q; j++) {
+      znQ_[j] = NULL;
+      znQ_[j] = N_VClone(tempvQ);
+      if(znQ_[j] == NULL) {
+        for (jj=0; jj<j; jj++) N_VDestroy(znQ_[jj]);
+        if (q < qmax) N_VDestroy(zn_[qmax]);
+        for (j=0; j<=q; j++) N_VDestroy(zn_[j]);
+        free(ck_mem); ck_mem = NULL;
+        return(NULL);
+      }
+    }
+
+    if ( q < qmax) {
+      znQ_[qmax] = NULL;
+      znQ_[qmax] = N_VClone(tempvQ);
+      if (znQ_[qmax] == NULL) {
+        for (j=0; j<=q; j++) N_VDestroy(znQ_[j]);
+        N_VDestroy(zn_[qmax]);
+        for (j=0; j<=q; j++) N_VDestroy(zn_[j]);
+        free(ck_mem); ck_mem = NULL;
+        return(NULL);
+      }
+    }
+  }
+
+  /* Load check point data from cv_mem */
+
+  for (j=0; j<=q; j++) N_VScale(ONE, zn[j], zn_[j]);
+  if ( q < qmax ) N_VScale(ONE, zn[qmax], zn_[qmax]);
+
+  if(quadr_) {
+    for (j=0; j<=q; j++) N_VScale(ONE, znQ[j], znQ_[j]);
+    if ( q < qmax ) N_VScale(ONE, znQ[qmax], znQ_[qmax]);
+  }
+
+  for (j=0; j<=L_MAX; j++)     tau_[j] = tau[j];
+  for (j=0; j<=NUM_TESTS; j++) tq_[j] = tq[j];
+  for (j=0; j<=q; j++)         l_[j] = l[j];
+  nst_       = nst;
+  tretlast_  = tretlast;
+  q_         = q;
+  qprime_    = qprime;
+  qwait_     = qwait;
+  L_         = L;
+  gammap_    = gammap;
+  h_         = h;
+  hprime_    = hprime;
+  hscale_    = hscale;
+  eta_       = eta;
+  etamax_    = etamax;
+  t0_        = tn;
+  saved_tq5_ = saved_tq5;
+
+  return(ck_mem);
+}
+
+/*
+ * CVAckpntDelete
+ *
+ * This routine deletes the first check point in list.
+ */
+
+static void CVAckpntDelete(CkpntMem *ck_memPtr)
+{
+  CkpntMem tmp;
+  int j;
+
+  if (*ck_memPtr != NULL) {
+
+    /* store head of list */
+    tmp = *ck_memPtr;
+
+    /* move head of list */
+    *ck_memPtr = (*ck_memPtr)->ck_next;
+
+    /* free N_Vectors in tmp */
+    for (j=0;j<=tmp->ck_q;j++) N_VDestroy(tmp->ck_zn[j]);
+    if (tmp->ck_zqm != 0) N_VDestroy(tmp->ck_zn[tmp->ck_zqm]);
+
+    /* free N_Vectors for quadratures in tmp 
+       Note that at the check point at t_initial, only znQ_[0] 
+       was allocated*/
+    if(tmp->ck_quadr) {
+      if(tmp->ck_next != NULL) {
+        for (j=0;j<=tmp->ck_q;j++) N_VDestroy(tmp->ck_znQ[j]);
+        if (tmp->ck_zqm != 0) N_VDestroy(tmp->ck_znQ[tmp->ck_zqm]);
+      } else {
+        N_VDestroy(tmp->ck_znQ[0]);
+      }
+    }
+
+    free(tmp); tmp = NULL;
+
+  }
+}
+
+/*
+ * CVAdataStore
+ *
+ * This routine integrates the forward model starting at the check
+ * point ck_mem and stores y and yprime at all intermediate steps.
+ *
+ * Return values:
+ * CV_SUCCESS
+ * CV_REIFWD_FAIL
+ * CV_FWD_FAIL
+ */
+
+static int CVAdataStore(CVadjMem ca_mem, CkpntMem ck_mem)
+{
+  CVodeMem cv_mem;
+  DtpntMem *dt_mem;
+  realtype t;
+  long int i;
+  int flag;
+
+  cv_mem = ca_mem->cv_mem;
+  dt_mem = ca_mem->dt_mem;
+
+  /* Initialize cv_mem with data from ck_mem */
+  flag = CVAckpntGet(cv_mem, ck_mem);
+  if (flag != CV_SUCCESS)
+    return(CV_REIFWD_FAIL);
+
+  /* Set first structure in dt_mem[0] */
+  dt_mem[0]->t = t0_;
+  storePnt(cv_mem, dt_mem[0]);
+
+  /* Run CVode to set following structures in dt_mem[i] */
+
+  i = 1;
+  do {
+    flag = CVode(cv_mem, t1_, ytmp, &t, CV_ONE_STEP);
+    if (flag < 0) 
+      return(CV_FWD_FAIL);
+    dt_mem[i]->t = t;
+    storePnt(cv_mem, dt_mem[i]);
+    i++;
+  } while (t<t1_);
+
+
+  newData = TRUE;       /* New data is now available    */
+  ckpntData = ck_mem;   /* starting at this check point */
+  np = i;               /* and we have this many points */
+
+  return(CV_SUCCESS);
+}
+
+/*
+ * CVAckpntGet
+ *
+ * This routine prepares CVODES for a hot restart from
+ * the check point ck_mem
+ */
+
+static int CVAckpntGet(CVodeMem cv_mem, CkpntMem ck_mem) 
+{
+  int j;
+  int flag;
+  int qmax;
+  void *abstol;
+
+  abstol = NULL;
+
+  if (next_ == NULL) {
+
+    /* In this case, we just call the reinitialization routine,
+       but make sure we use the same initial stepsize as on 
+       the first run. */
+
+    CVodeSetInitStep(cv_mem, h0u);
+
+    switch (itol) {
+    case CV_SS:
+      abstol = (void *) &Sabstol;
+      break;
+    case CV_SV:
+      abstol = (void *)Vabstol;
+      break;
+    case CV_EE:
+      abstol = (void *)efun;
+      break;
+    }
+    flag = CVodeReInit(cv_mem, f, t0_, zn_[0], itol, reltol, abstol);
+    if (flag != CV_SUCCESS) return(flag);
+
+    if(quadr_) {
+      flag = CVodeQuadReInit(cv_mem, fQ, znQ_[0]);
+      if (flag != CV_SUCCESS) return(flag);
+    }
+
+  } else {
+    
+    qmax = cv_mem->cv_qmax;
+
+    /* Copy parameters from check point data structure */
+    nst       = nst_;
+    tretlast  = tretlast_;
+    q         = q_;
+    qprime    = qprime_;
+    qwait     = qwait_;
+    L         = L_;
+    gammap    = gammap_;
+    h         = h_;
+    hprime    = hprime_;
+    hscale    = hscale_;
+    eta       = eta_;
+    etamax    = etamax_;
+    tn        = t0_;
+    saved_tq5 = saved_tq5_;
+    
+    /* Copy the arrays from check point data structure */
+    for (j=0; j<=q; j++) N_VScale(ONE, zn_[j], zn[j]);
+    if ( q < qmax ) N_VScale(ONE, zn_[qmax], zn[qmax]);
+    if(quadr_) {
+      for (j=0; j<=q; j++) N_VScale(ONE, znQ_[j], znQ[j]);
+      if ( q < qmax ) N_VScale(ONE, znQ_[qmax], znQ[qmax]);
+    }
+    for (j=0; j<=L_MAX; j++)     tau[j] = tau_[j];
+    for (j=0; j<=NUM_TESTS; j++) tq[j] = tq_[j];
+    for (j=0; j<=q; j++)         l[j] = l_[j];
+    
+    /* Force a call to setup */
+    forceSetup = TRUE;
+
+  }
+
+  return(CV_SUCCESS);
+}
+
+/* 
+ * -----------------------------------------------------------------
+ * Functions for interpolation
+ * -----------------------------------------------------------------
+ */
+
+/*
+ * CVAfindIndex
+ *
+ * Finds the index in the array of data point strctures such that
+ *     dt_mem[indx-1].t <= t < dt_mem[indx].t
+ * If indx is changed from the previous invocation, then newpoint = TRUE
+ *
+ * If t is beyond the leftmost limit, but close enough, indx=0.
+ *
+ * Returns CV_SUCCESS if successful and CV_GETY_BADT if unable to
+ * find indx (t is too far beyond limits).
+ */
+
+static int CVAfindIndex(CVadjMem ca_mem, realtype t, 
+                        long int *indx, booleantype *newpoint)
+{
+  static long int ilast;
+  DtpntMem *dt_mem;
+  int sign;
+  booleantype to_left, to_right;
+
+  dt_mem = ca_mem->dt_mem;
+
+  *newpoint = FALSE;
+
+  /* Find the direction of integration */
+  sign = (tfinal - tinitial > ZERO) ? 1 : -1;
+
+  /* If this is the first time we use new data */
+  if (newData) {
+    ilast     = np-1;
+    *newpoint = TRUE;
+    newData   = FALSE;
+  }
+
+  /* Search for indx starting from ilast */
+  to_left  = ( sign*(t - dt_mem[ilast-1]->t) < ZERO);
+  to_right = ( sign*(t - dt_mem[ilast]->t)   > ZERO);
+
+  if ( to_left ) {
+    /* look for a new indx to the left */
+
+    *newpoint = TRUE;
+    
+    *indx = ilast;
+    loop {
+      if ( *indx == 0 ) break;
+      if ( sign*(t - dt_mem[*indx-1]->t) <= ZERO ) (*indx)--;
+      else                                         break;
+    }
+
+    if ( *indx == 0 )
+      ilast = 1;
+    else
+      ilast = *indx;
+
+    if ( *indx == 0 ) {
+      /* t is beyond leftmost limit. Is it too far? */  
+      if ( ABS(t - dt_mem[0]->t) > FUZZ_FACTOR * uround ) return(CV_GETY_BADT);
+    }
+
+  } else if ( to_right ) {
+    /* look for a new indx to the right */
+
+    *newpoint = TRUE;
+
+    *indx = ilast;
+    loop {
+      if ( sign*(t - dt_mem[*indx]->t) > ZERO) (*indx)++;
+      else                                     break;
+    }
+
+    ilast = *indx;
+
+
+  } else {
+    /* ilast is still OK */
+
+    *indx = ilast;
+
+  }
+
+  return(CV_SUCCESS);
+
+
+}
+
+/*
+ * CVadjGetY
+ *
+ * This routine returns the interpolated forward solution at time t.
+ * The user must allocate space for y.
+ */
+
+int CVadjGetY(void *cvadj_mem, realtype t, N_Vector y)
+{
+  int flag;
+  CVadjMem ca_mem;
+
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CV_ADJMEM_NULL, "CVODEA", "CVadjGetY", MSGAM_NULL_CAMEM);
+    return(CV_ADJMEM_NULL);
+  }
+  ca_mem  = (CVadjMem) cvadj_mem;
+  
+  flag = getY(ca_mem, t, y);
+
+  return(flag);
+}
+
+/* 
+ * -----------------------------------------------------------------
+ * Functions specific to cubic Hermite interpolation
+ * -----------------------------------------------------------------
+ */
+
+/*
+ * CVAhermiteMalloc
+ *
+ * This routine allocates memory for storing information at all
+ * intermediate points between two consecutive check points. 
+ * This data is then used to interpolate the forward solution 
+ * at any other time.
+ */
+
+static booleantype CVAhermiteMalloc(CVadjMem ca_mem, long int steps)
+{
+  CVodeMem cv_mem;
+  DtpntMem *dt_mem;
+  HermiteDataMem content;
+  long int i, ii=0;
+  booleantype allocOK;
+
+  allocOK = TRUE;
+
+  dt_mem = ca_mem->dt_mem;
+  cv_mem = ca_mem->cv_mem;
+
+  for (i=0; i<=steps; i++) {
+
+    content = NULL;
+    content = (HermiteDataMem) malloc(sizeof(struct HermiteDataMemRec));
+    if (content == NULL) {
+      ii = i;
+      allocOK = FALSE;
+      break;
+    }
+
+    content->y = NULL;
+    content->y = N_VClone(tempv);
+    if (content->y == NULL) {
+      free(content); content = NULL;
+      ii = i;
+      allocOK = FALSE;
+      break;
+    }
+
+    content->yd = NULL;
+    content->yd = N_VClone(tempv);
+    if (content->yd == NULL) {
+      N_VDestroy(content->y);
+      free(content); content = NULL;
+      ii = i;
+      allocOK = FALSE;
+      break;
+    }
+    
+    dt_mem[i]->content = content;
+
+  } 
+
+  if (!allocOK) {
+    for (i=0; i<ii; i++) {
+      content = (HermiteDataMem) (dt_mem[i]->content);
+      N_VDestroy(content->y);
+      N_VDestroy(content->yd);
+      free(dt_mem[i]->content); dt_mem[i]->content = NULL;
+    }
+  }
+
+  return(allocOK);
+}
+
+/*
+ * CVAhermiteFree
+ *
+ * This routine frees the memory allocated for data storage.
+ */
+
+static void CVAhermiteFree(DtpntMem *dt_mem, long int steps)
+{
+  long int i;
+  HermiteDataMem content;
+
+  for (i=0; i<=steps; i++) {
+    content = (HermiteDataMem) (dt_mem[i]->content);
+    N_VDestroy(content->y);
+    N_VDestroy(content->yd);
+    free(dt_mem[i]->content); dt_mem[i]->content = NULL;
+  }
+}
+
+/*
+ * CVAhermiteStorePnt ( -> storePnt )
+ *
+ * This routine stores a new point (y,yd) in the structure d for use
+ * in the cubic Hermite interpolation.
+ * Note that the time is already stored.
+ */
+
+static int CVAhermiteStorePnt(CVodeMem cv_mem, DtpntMem d)
+{
+  int retval;
+  HermiteDataMem content;
+
+  content = (HermiteDataMem) d->content;
+
+  N_VScale(ONE, zn[0], content->y);
+  
+  if (nst == 0)
+    retval = f(tn, content->y, content->yd, f_data);
+  else
+    N_VScale(ONE/h, zn[1], content->yd);
+
+  return(0);
+}
+
+/*
+ * CVAhermiteGetY ( -> getY )
+ *
+ * This routine uses cubic piece-wise Hermite interpolation for 
+ * the forward solution vector. 
+ * It is typically called by the wrapper routines before calling
+ * user provided routines (fB, djacB, bjacB, jtimesB, psolB) but
+ * can be directly called by the user through CVadjGetY
+ */
+
+static int CVAhermiteGetY(CVadjMem ca_mem, realtype t, N_Vector y)
+{
+  DtpntMem *dt_mem;
+  HermiteDataMem content0, content1;
+  realtype t0, t1, delta, factor;
+  N_Vector y0, yd0, y1, yd1;
+  int flag;
+  long int indx;
+  booleantype newpoint;
+
+  dt_mem = ca_mem->dt_mem;
+  
+  /* Get the index in dt_mem */
+
+  flag = CVAfindIndex(ca_mem, t, &indx, &newpoint);
+  if (flag != CV_SUCCESS) return(flag);
+
+  /* If we are beyond the left limit but close enough,
+     then return y at the left limit. */
+
+  if (indx == 0) {
+    content0 = (HermiteDataMem) (dt_mem[0]->content);
+    N_VScale(ONE, content0->y, y);
+    return(CV_SUCCESS);
+  }
+
+  /* Extract stuff from the appropriate data points */
+
+  t0 = dt_mem[indx-1]->t;
+  t1 = dt_mem[indx]->t;
+  delta = t1 - t0;
+
+  content0 = (HermiteDataMem) (dt_mem[indx-1]->content);
+  y0  = content0->y;
+  yd0 = content0->yd;
+
+  if (newpoint) {
+    
+    /* Recompute Y0 and Y1 */
+
+    content1 = (HermiteDataMem) (dt_mem[indx]->content);
+    y1  = content1->y;
+    yd1 = content1->yd;
+
+    N_VLinearSum(ONE, y1, -ONE, y0, Y0);
+    N_VLinearSum(ONE, yd1,  ONE, yd0, Y1);
+    N_VLinearSum(delta, Y1, -TWO, Y0, Y1);
+    N_VLinearSum(ONE, Y0, -delta, yd0, Y0);
+
+  }
+
+  /* Perform the actual interpolation. */
+
+  factor = t - t0;
+  N_VLinearSum(ONE, y0, factor, yd0, y);
+
+  factor = factor/delta;
+  factor = factor*factor;
+  N_VLinearSum(ONE, y, factor, Y0, y);
+
+  factor = factor*(t-t1)/delta;
+  N_VLinearSum(ONE, y, factor, Y1, y);
+
+  return(CV_SUCCESS);
+}
+
+/* 
+ * -----------------------------------------------------------------
+ * Functions specific to Polynomial interpolation
+ * -----------------------------------------------------------------
+ */
+
+/*
+ * CVApolynomialMalloc
+ *
+ * This routine allocates memory for storing information at all
+ * intermediate points between two consecutive check points. 
+ * This data is then used to interpolate the forward solution 
+ * at any other time.
+ */
+
+static booleantype CVApolynomialMalloc(CVadjMem ca_mem, long int steps)
+{
+  CVodeMem cv_mem;
+  DtpntMem *dt_mem;
+  PolynomialDataMem content;
+  long int i, ii=0;
+  booleantype allocOK;
+
+  allocOK = TRUE;
+
+  dt_mem = ca_mem->dt_mem;
+  cv_mem = ca_mem->cv_mem;
+
+  for (i=0; i<=steps; i++) {
+    content = NULL;
+    content = (PolynomialDataMem) malloc(sizeof(struct PolynomialDataMemRec));
+    if (content == NULL) {
+      ii = i;
+      allocOK = FALSE;
+      break;
+    }
+
+    content->y = NULL;
+    content->y = N_VClone(tempv);
+    if (content->y == NULL) {
+      free(content); content = NULL;
+      ii = i;
+      allocOK = FALSE;
+      break;
+    }
+
+    dt_mem[i]->content = content;
+  } 
+
+  if (!allocOK) {
+    for (i=0; i<ii; i++) {
+      content = (PolynomialDataMem) (dt_mem[i]->content);
+      N_VDestroy(content->y);
+      free(dt_mem[i]->content); dt_mem[i]->content = NULL;
+    }
+  }
+
+  return(allocOK);
+
+}
+
+/*
+ * CVApolynomialFree
+ *
+ * This routine frees the memeory allocated for data storage.
+ */
+
+static void CVApolynomialFree(DtpntMem *dt_mem, long int steps)
+{
+  long int i;
+  PolynomialDataMem content;
+
+  for (i=0; i<=steps; i++) {
+    content = (PolynomialDataMem) (dt_mem[i]->content);
+    N_VDestroy(content->y);
+    free(dt_mem[i]->content); dt_mem[i]->content = NULL;
+  }
+}
+
+/*
+ * CVApolynomialStorePnt ( -> storePnt )
+ *
+ * This routine stores a new point y in the structure d for use
+ * in the Polynomial interpolation.
+ * Note that the time is already stored.
+ */
+
+static int CVApolynomialStorePnt(CVodeMem cv_mem, DtpntMem d)
+{
+  PolynomialDataMem content;
+
+  content = (PolynomialDataMem) d->content;
+
+  N_VScale(ONE, zn[0], content->y);
+  content->order = qu;
+
+  return(0);
+}
+
+/*
+ * CVApolynomialGetY ( -> getY )
+ *
+ * This routine uses polynomial interpolation for the forward solution vector. 
+ * It is typically called by the wrapper routines before calling
+ * user provided routines (fB, djacB, bjacB, jtimesB, psolB)) but
+ * can be directly called by the user through CVadjGetY.
+ */
+
+static int CVApolynomialGetY(CVadjMem ca_mem, realtype t, N_Vector y)
+{
+  DtpntMem *dt_mem;
+  PolynomialDataMem content;
+  int flag, dir, order, i, j;
+  long int indx, base;
+  booleantype newpoint;
+  realtype dt, factor;
+
+  dt_mem = ca_mem->dt_mem;
+  
+  /* Get the index in dt_mem */
+
+  flag = CVAfindIndex(ca_mem, t, &indx, &newpoint);
+  if (flag != CV_SUCCESS) return(flag);
+
+  /* If we are beyond the left limit but close enough,
+     then return y at the left limit. */
+
+  if (indx == 0) {
+    content = (PolynomialDataMem) (dt_mem[0]->content);
+    N_VScale(ONE, content->y, y);
+    return(CV_SUCCESS);
+  }
+
+  /* Scaling factor */
+
+  dt = ABS(dt_mem[indx]->t - dt_mem[indx-1]->t);
+
+  /* Find the direction of the forward integration */
+
+  dir = (tfinal - tinitial > ZERO) ? 1 : -1;
+
+  /* Establish the base point depending on the integration direction.
+     Modify the base if there are not enough points for the current order */
+
+  if (dir == 1) {
+    base = indx;
+    content = (PolynomialDataMem) (dt_mem[base]->content);
+    order = content->order;
+    if(indx < order) base += order-indx;
+  } else {
+    base = indx-1;
+    content = (PolynomialDataMem) (dt_mem[base]->content);
+    order = content->order;
+    if (np-indx > order) base -= indx+order-np;
+  }
+
+  /* Recompute Y (divided differences for Newton polynomial) if needed */
+
+  if (newpoint) {
+
+    /* Store 0-th order DD */
+    if (dir == 1) {
+      for(j=0;j<=order;j++) {
+        T[j] = dt_mem[base-j]->t;
+        content = (PolynomialDataMem) (dt_mem[base-j]->content);
+        N_VScale(ONE, content->y, Y[j]);
+      }
+    } else {
+      for(j=0;j<=order;j++) {
+        T[j] = dt_mem[base-1+j]->t;
+        content = (PolynomialDataMem) (dt_mem[base-1+j]->content);
+        N_VScale(ONE, content->y, Y[j]);
+      }
+    }
+
+    /* Compute higher-order DD */
+    for(i=1;i<=order;i++) {
+      for(j=order;j>=i;j--) {
+        factor = dt/(T[j]-T[j-i]);
+        N_VLinearSum(factor, Y[j], -factor, Y[j-1], Y[j]);
+      }
+    }
+  }
+
+  /* Perform the actual interpolation using nested multiplications */
+
+  N_VScale(ONE, Y[order], y);
+  for (i=order-1; i>=0; i--) {
+    factor = (t-T[i])/dt;
+    N_VLinearSum(factor, y, ONE, Y[i], y);
+  }
+
+  return(CV_SUCCESS);
+
+}
+
+/* 
+ * =================================================================
+ * WRAPPERS FOR ADJOINT SYSTEM
+ * =================================================================
+ */
+/*
+ * CVArhs
+ *
+ * This routine interfaces to the CVRhsFnB routine provided by
+ * the user.
+ * NOTE: f_data actually contains cvadj_mem
+ */
+
+static int CVArhs(realtype t, N_Vector yB, 
+                  N_Vector yBdot, void *cvadj_mem)
+{
+  CVadjMem ca_mem;
+  CVodeMem cv_mem;
+  int flag, retval;
+
+  ca_mem = (CVadjMem) cvadj_mem;
+  cv_mem = ca_mem->cvb_mem;
+
+  /* Forward solution from interpolation */
+  flag = getY(ca_mem, t, ytmp);
+  if (flag != CV_SUCCESS) {
+    CVProcessError(cv_mem, -1, "CVODEA", "CVArhs", MSGAM_BAD_T);
+    return(-1);
+  }
+
+  /* Call user's adjoint RHS routine */
+  retval = f_B(t, ytmp, yB, yBdot, f_data_B);
+
+  return(retval);
+}
+
+/*
+ * CVArhsQ
+ *
+ * This routine interfaces to the CVQuadRhsFnB routine provided by
+ * the user.
+ * NOTE: fQ_data actually contains cvadj_mem
+ */
+
+static int CVArhsQ(realtype t, N_Vector yB, 
+                   N_Vector qBdot, void *cvadj_mem)
+{
+  CVadjMem ca_mem;
+  CVodeMem cv_mem;
+  int flag, retval;
+
+  ca_mem = (CVadjMem) cvadj_mem;
+  cv_mem = ca_mem->cvb_mem;
+
+  /* Forward solution from interpolation */
+  flag = getY(ca_mem, t, ytmp);
+  if (flag != CV_SUCCESS) {
+    CVProcessError(cv_mem, -1, "CVODEA", "CVArhsQ", MSGAM_BAD_T);
+    return(-1);
+  }
+
+  /* Call user's adjoint RHS routine */
+  retval = fQ_B(t, ytmp, yB, qBdot, fQ_data_B);
+
+  return(retval);
+}
+
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodea_io.c b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodea_io.c
new file mode 100644
index 0000000000000000000000000000000000000000..1aec134c2a097bf16c7fe014cc6baa0fd044eb8d
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodea_io.c	
@@ -0,0 +1,538 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * -----------------------------------------------------------------
+ * Programmer: Radu Serban @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2006, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This is the implementation file for the optional input and output
+ * functions for the adjoint module in the CVODES solver.
+ * -----------------------------------------------------------------
+ */
+
+/* 
+ * =================================================================
+ * IMPORTED HEADER FILES
+ * =================================================================
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "cvodes_impl.h"
+#include <sundials/sundials_types.h>
+
+/* 
+ * =================================================================
+ * CVODEA PRIVATE CONSTANTS
+ * =================================================================
+ */
+
+#define ONE         RCONST(1.0) 
+
+/* 
+ * =================================================================
+ * EXPORTED FUNCTIONS IMPLEMENTATION
+ * =================================================================
+ */
+
+/* 
+ * -----------------------------------------------------------------
+ * Readibility Constants
+ * -----------------------------------------------------------------
+ */
+
+#define interpType  (ca_mem->ca_interpType)
+#define f_data_B    (ca_mem->ca_f_dataB)
+#define fQ_data_B   (ca_mem->ca_fQ_dataB)
+#define t_for_quad  (ca_mem->ca_t_for_quad)
+#define ckpntData   (ca_mem->ca_ckpntData)
+
+#define t0_         (ck_mem->ck_t0)
+#define t1_         (ck_mem->ck_t1)
+#define nst_        (ck_mem->ck_nst)
+#define q_          (ck_mem->ck_q)
+#define h_          (ck_mem->ck_h)
+#define next_       (ck_mem->ck_next)
+
+/* 
+ * -----------------------------------------------------------------
+ * Optional input functions for backward integration
+ * -----------------------------------------------------------------
+ */
+
+/*
+ * CVodeSet***B
+ *
+ * Wrappers for the backward phase around the corresponding 
+ * CVODES optional input functions
+ */
+
+int CVodeSetErrHandlerFnB(void *cvadj_mem, CVErrHandlerFn ehfunB, void *eh_dataB)
+{
+  CVadjMem ca_mem;
+  void *cvode_mem;
+  int flag;
+
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CV_ADJMEM_NULL, "CVODEA", "CVodeSetErrHandlerB", MSGAM_NULL_CAMEM);
+    return(CV_ADJMEM_NULL);
+  }
+  ca_mem = (CVadjMem) cvadj_mem;
+  cvode_mem = (void *)ca_mem->cvb_mem;
+
+  flag = CVodeSetErrHandlerFn(cvode_mem, ehfunB, eh_dataB);
+
+  return(flag);
+}
+
+int CVodeSetErrFileB(void *cvadj_mem, FILE *errfpB)
+{
+  CVadjMem ca_mem;
+  void *cvode_mem;
+  int flag;
+
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CV_ADJMEM_NULL, "CVODEA", "CVodeSetErrFileB", MSGAM_NULL_CAMEM);
+    return(CV_ADJMEM_NULL);
+  }
+  ca_mem = (CVadjMem) cvadj_mem;
+  cvode_mem = (void *)ca_mem->cvb_mem;
+
+  flag = CVodeSetErrFile(cvode_mem, errfpB);
+
+  return(flag);
+}
+
+int CVodeSetIterTypeB(void *cvadj_mem, int iterB)
+{
+  CVadjMem ca_mem;
+  void *cvode_mem;
+  int flag;
+
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CV_ADJMEM_NULL, "CVODEA", "CVodeSetIterTypeB", MSGAM_NULL_CAMEM);
+    return(CV_ADJMEM_NULL);
+  }
+  ca_mem = (CVadjMem) cvadj_mem;
+  cvode_mem = (void *)ca_mem->cvb_mem;
+
+  flag = CVodeSetIterType(cvode_mem, iterB);
+  
+  return(flag);
+}
+
+int CVodeSetFdataB(void *cvadj_mem, void *f_dataB)
+{
+  CVadjMem ca_mem;
+
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CV_ADJMEM_NULL, "CVODEA", "CVodeSetFdataB", MSGAM_NULL_CAMEM);
+    return(CV_ADJMEM_NULL);
+  }
+  ca_mem = (CVadjMem) cvadj_mem;
+
+  f_data_B = f_dataB;
+
+  return(CV_SUCCESS);
+}
+
+int CVodeSetMaxOrdB(void *cvadj_mem, int maxordB)
+{
+  CVadjMem ca_mem;
+  void *cvode_mem;
+  int flag;
+
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CV_ADJMEM_NULL, "CVODEA", "CVodeSetMaxOrdB", MSGAM_NULL_CAMEM);
+    return(CV_ADJMEM_NULL);
+  }
+  ca_mem = (CVadjMem) cvadj_mem;
+  cvode_mem = (void *)ca_mem->cvb_mem;
+
+  flag = CVodeSetMaxOrd(cvode_mem, maxordB);
+
+  return(flag);
+}
+
+
+int CVodeSetMaxNumStepsB(void *cvadj_mem, long int mxstepsB)
+{
+  CVadjMem ca_mem;
+  void *cvode_mem;
+  int flag;
+
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CV_ADJMEM_NULL, "CVODEA", "CVodeSetMaxNumStepsB", MSGAM_NULL_CAMEM);
+    return(CV_ADJMEM_NULL);
+  }
+  ca_mem = (CVadjMem) cvadj_mem;
+  cvode_mem = (void *)ca_mem->cvb_mem;
+
+  flag = CVodeSetMaxNumSteps(cvode_mem, mxstepsB);
+
+  return(flag);
+}
+
+int CVodeSetStabLimDetB(void *cvadj_mem, booleantype stldetB)
+{
+  CVadjMem ca_mem;
+  void *cvode_mem;
+  int flag;
+
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CV_ADJMEM_NULL, "CVODEA", "CVodeSetStabLimDetB", MSGAM_NULL_CAMEM);
+    return(CV_ADJMEM_NULL);
+  }
+  ca_mem = (CVadjMem) cvadj_mem;
+  cvode_mem = (void *)ca_mem->cvb_mem;
+
+  flag = CVodeSetStabLimDet(cvode_mem, stldetB);
+
+  return(flag);
+}
+
+int CVodeSetInitStepB(void *cvadj_mem, realtype hinB)
+{
+  CVadjMem ca_mem;
+  void *cvode_mem;
+  int flag;
+
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CV_ADJMEM_NULL, "CVODEA", "CVodeSetInitStepB", MSGAM_NULL_CAMEM);
+    return(CV_ADJMEM_NULL);
+  }
+  ca_mem = (CVadjMem) cvadj_mem;
+  cvode_mem = (void *)ca_mem->cvb_mem;
+
+  flag = CVodeSetInitStep(cvode_mem, hinB);
+
+  return(flag);
+}
+
+int CVodeSetMinStepB(void *cvadj_mem, realtype hminB)
+{
+  CVadjMem ca_mem;
+  void *cvode_mem;
+  int flag;
+
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CV_ADJMEM_NULL, "CVODEA", "CVodeSetMinStepB", MSGAM_NULL_CAMEM);
+    return(CV_ADJMEM_NULL);
+  }
+  ca_mem = (CVadjMem) cvadj_mem;
+  cvode_mem = (void *)ca_mem->cvb_mem;
+
+  flag = CVodeSetMinStep(cvode_mem, hminB);
+
+  return(flag);
+}
+
+int CVodeSetMaxStepB(void *cvadj_mem, realtype hmaxB)
+{
+  CVadjMem ca_mem;
+  void *cvode_mem;
+  int flag;
+
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CV_ADJMEM_NULL, "CVODEA", "CVodeSetMaxStepB", MSGAM_NULL_CAMEM);
+    return(CV_ADJMEM_NULL);
+  }
+  ca_mem = (CVadjMem) cvadj_mem;
+  cvode_mem = (void *)ca_mem->cvb_mem;
+
+  flag = CVodeSetMaxStep(cvode_mem, hmaxB);
+
+  return(flag);
+}
+
+/*
+ * CVodeSetQuad*B
+ *
+ * Wrappers for the backward phase around the corresponding 
+ * CVODES quadrature optional input functions
+ */
+
+int CVodeSetQuadFdataB(void *cvadj_mem, void *fQ_dataB)
+{
+  CVadjMem ca_mem;
+
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CV_ADJMEM_NULL, "CVODEA", "CVodeSetQuadFdataB", MSGAM_NULL_CAMEM);
+    return(CV_ADJMEM_NULL);
+  }
+  ca_mem = (CVadjMem) cvadj_mem;
+
+  fQ_data_B = fQ_dataB;
+
+  return(CV_SUCCESS);
+}
+
+int CVodeSetQuadErrConB(void *cvadj_mem, booleantype errconQB,
+                        int itolQB, realtype reltolQB, void *abstolQB)
+{
+  CVadjMem ca_mem;
+  void *cvode_mem;
+  int flag;
+
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CV_ADJMEM_NULL, "CVODEA", "CVodeSetQuadErrConB", MSGAM_NULL_CAMEM);
+    return(CV_ADJMEM_NULL);
+  }
+  ca_mem = (CVadjMem) cvadj_mem;
+
+  cvode_mem = (void *)ca_mem->cvb_mem;
+
+  flag = CVodeSetQuadErrCon(cvode_mem, errconQB, itolQB, reltolQB, abstolQB);
+
+  return(flag);
+}
+
+/* 
+ * -----------------------------------------------------------------
+ * Optional output functions for backward integration
+ * -----------------------------------------------------------------
+ */
+
+/*
+ * CVodeGetQuadB
+ */
+
+int CVodeGetQuadB(void *cvadj_mem, N_Vector qB)
+{
+  CVadjMem ca_mem;
+  void *cvode_mem;
+  int flag;
+  
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CV_ADJMEM_NULL, "CVODEA", "CVodeGetQuadB", MSGAM_NULL_CAMEM);
+    return(CV_ADJMEM_NULL);
+  }
+  ca_mem  = (CVadjMem) cvadj_mem;
+  cvode_mem = (void *) ca_mem->cvb_mem;
+  
+  flag = CVodeGetQuad(cvode_mem, t_for_quad, qB);
+
+  return(flag);
+}
+
+/*
+ * CVadjGetCVodeBmem
+ *
+ * CVadjGetCVodeBmem returns a (void *) pointer to the CVODES     
+ * memory allocated for the backward problem. This pointer can    
+ * then be used to call any of the CVodeGet* CVODES routines to  
+ * extract optional output for the backward integration phase.
+ */
+
+void *CVadjGetCVodeBmem(void *cvadj_mem)
+{
+  CVadjMem ca_mem;
+  void *cvode_mem;
+  
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, 0, "CVODEA", "CVadjGetCVodeBmem", MSGAM_NULL_CAMEM);
+    return(NULL);
+  }
+  ca_mem  = (CVadjMem) cvadj_mem;
+  cvode_mem = (void *) ca_mem->cvb_mem;
+
+  return(cvode_mem);
+}
+
+/*
+ * CVadjGetReturnFlagName
+ *
+ * The following function returns the name of the constant 
+ * associated with a CVODEA-specific return flag
+ */
+
+char *CVadjGetReturnFlagName(int flag)
+{
+  char *name;
+
+  name = (char *)malloc(30*sizeof(char));
+
+  switch(flag) {
+  case CV_SUCCESS:
+    sprintf(name,"CV_SUCCESS");
+    break;
+  case CV_ADJMEM_NULL:
+    sprintf(name,"CV_ADJMEM_NULL");
+    break;
+  case CV_BAD_TB0:
+    sprintf(name,"CV_BAD_TB0");
+    break;
+  case CV_BCKMEM_NULL:
+    sprintf(name,"CV_BCKMEM_NULL");
+    break;
+  case CV_REIFWD_FAIL:
+    sprintf(name,"CV_REIFWD_FAIL");
+    break;
+  case CV_FWD_FAIL:
+    sprintf(name,"CV_FWD_FAIL");
+    break;
+  case CV_BAD_ITASK:
+    sprintf(name,"CV_BAD_ITASK");
+    break;
+  case CV_BAD_TBOUT:
+    sprintf(name,"CV_BAD_TBOUT");
+    break;
+  case CV_GETY_BADT:
+    sprintf(name,"CV_GETY_BADT");
+    break;
+  default:
+    sprintf(name,"NONE");
+  }
+
+  return(name);
+}
+
+/*
+ * CVadjGetCheckPointsInfo
+ *
+ * This routine loads an array of nckpnts structures of type CVadjCheckPointRec.
+ * The user must allocate space for ckpnt.
+ */
+
+int CVadjGetCheckPointsInfo(void *cvadj_mem, CVadjCheckPointRec *ckpnt)
+{
+  CVadjMem ca_mem;
+  CkpntMem ck_mem;
+  int i;
+
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CV_ADJMEM_NULL, "CVODEA", "CVadjGetCheckPointsInfo", MSGAM_NULL_CAMEM);
+    return(CV_ADJMEM_NULL);
+  }
+  ca_mem = (CVadjMem) cvadj_mem;
+  ck_mem = ca_mem->ck_mem;
+  i = 0;
+
+  while (ck_mem != NULL) {
+
+    ckpnt[i].my_addr = (void *) ck_mem;
+    ckpnt[i].next_addr = (void *) next_;
+    ckpnt[i].t0 = t0_;
+    ckpnt[i].t1 = t1_;
+    ckpnt[i].nstep = nst_;
+    ckpnt[i].order = q_;
+    ckpnt[i].step = h_;
+
+    ck_mem = next_;
+    i++;
+
+  }
+
+  return(CV_SUCCESS);
+
+}
+
+/*
+ * CVadjGetDataPointHermite
+ *
+ * This routine returns the solution stored in the data structure
+ * at the 'which' data point. Cubic Hermite interpolation.
+ */
+
+int CVadjGetDataPointHermite(void *cvadj_mem, long int which, 
+                             realtype *t, N_Vector y, N_Vector yd)
+{
+  CVadjMem ca_mem;
+  DtpntMem *dt_mem;
+  HermiteDataMem content;
+
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CV_ADJMEM_NULL, "CVODEA", "CVadjGetDataPointHermite", MSGAM_NULL_CAMEM);
+    return(CV_ADJMEM_NULL);
+  }
+  ca_mem = (CVadjMem) cvadj_mem;
+  dt_mem = ca_mem->dt_mem;
+
+  if (interpType != CV_HERMITE) {
+    CVProcessError(NULL, CV_ILL_INPUT, "CVODEA", "CVadjGetDataPointHermite", MSGAM_WRONG_INTERP);
+    return(CV_ILL_INPUT);
+  }
+
+  *t = dt_mem[which]->t;
+
+  content = (HermiteDataMem) (dt_mem[which]->content);
+
+  if (y != NULL)
+    N_VScale(ONE, content->y, y);
+
+  if (yd != NULL)
+    N_VScale(ONE, content->yd, yd);
+
+  return(CV_SUCCESS);
+}
+
+/*
+ * CVadjGetDataPointPolynomial
+ *
+ * This routine returns the solution stored in the data structure
+ * at the 'which' data point. Polynomial interpolation.
+ */
+
+int CVadjGetDataPointPolynomial(void *cvadj_mem, long int which, 
+                                realtype *t, int *order, N_Vector y)
+{
+  CVadjMem ca_mem;
+  DtpntMem *dt_mem;
+  PolynomialDataMem content;
+
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CV_ADJMEM_NULL, "CVODEA", "CVadjGetDataPointPolynomial", MSGAM_NULL_CAMEM);
+    return(CV_ADJMEM_NULL);
+  }
+  ca_mem = (CVadjMem) cvadj_mem;
+  dt_mem = ca_mem->dt_mem;
+
+  if (interpType != CV_POLYNOMIAL) {
+    CVProcessError(NULL, CV_ILL_INPUT, "CVODEA", "CVadjGetDataPointPolynomial", MSGAM_WRONG_INTERP);
+    return(CV_ILL_INPUT);
+  }
+
+  *t = dt_mem[which]->t;
+
+  content = (PolynomialDataMem) (dt_mem[which]->content);
+
+  if (y != NULL)
+    N_VScale(ONE, content->y, y);
+
+  *order = content->order;
+
+  return(CV_SUCCESS);
+}
+
+/* 
+ * -----------------------------------------------------------------
+ * UNDOCUMENTED development user-callable functions
+ * -----------------------------------------------------------------
+ */
+
+/*
+ * CVadjGetCurrentCheckPoint
+ *
+ * Returns the address of the 'active' check point.
+ */
+
+int CVadjGetCurrentCheckPoint(void *cvadj_mem, void **addr)
+{
+  CVadjMem ca_mem;
+
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CV_ADJMEM_NULL, "CVODEA", "CVadjGetCurrentCheckPoint", MSGAM_NULL_CAMEM);
+    return(CV_ADJMEM_NULL);
+  }
+  ca_mem = (CVadjMem) cvadj_mem;
+
+  *addr = (void *) ckpntData;
+
+  return(CV_SUCCESS);
+}
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes.c b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes.c
new file mode 100644
index 0000000000000000000000000000000000000000..2925a6171140f5b0a9f8bada7c9dd7d0e856a9a5
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes.c	
@@ -0,0 +1,7242 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * ----------------------------------------------------------------- 
+ * Programmer(s): Alan C. Hindmarsh and Radu Serban @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2006, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This is the implementation file for the main CVODES integrator
+ * with sensitivity analysis capabilities.
+ * -----------------------------------------------------------------
+ * 
+ * EXPORTED FUNCTIONS
+ * ------------------
+ *
+ *   Creation, allocation and re-initialization functions
+ *      CVodeCreate
+ *      CVodeMalloc 
+ *      CVodeReInit
+ *      CVodeRootInit      
+ *      CVodeQuadMalloc
+ *      CVodeQuadReInit   
+ *      CVodeSensMalloc
+ *      CVodeSensReInit             
+ *      CVodeSensToggleOff
+ *
+ *   Main solver function
+ *      CVode
+ *
+ *   Interpolated output and extraction functions
+ *      CVodeGetDky
+ *      CVodeGetQuad             
+ *      CVodeGetQuadDky
+ *      CVodeGetSens             
+ *      CVodeGetSens1
+ *      CVodeGetSensDky         
+ *      CVodeGetSensDky1
+ *
+ *   Deallocation functions
+ *      CVodeFree              
+ *      CVodeQuadFree
+ *      CVodeSensFree  
+ *
+ * PRIVATE FUNCTIONS
+ * -----------------
+ *
+ *      CVCheckNvector
+ *
+ *   Memory allocation/deallocation
+ *      CVAllocVectors         
+ *      CVFreeVectors
+ *      CVQuadAllocVectors      
+ *      CVQuadFreeVectors
+ *      CVSensAllocVectors     
+ *      CVSensFreeVectors
+ *
+ *   Initial stepsize calculation
+ *      CVHin                 
+ *      CVUpperBoundH0
+ *      CVYddNorm     
+ *
+ *   Initial setup
+ *      CVInitialSetup
+ *      CVEwtSet           
+ *      CVEwtSetSS
+ *      CVEwtSetSV         
+ *      CVQuadEwtSet
+ *      CVQuadEwtSetSS     
+ *      CVQuadEwtSetSV
+ *      CVSensEwtSet      
+ *      CVSensEwtSetEE
+ *      CVSensEwtSetSS    
+ *      CVSensEwtSetSV
+ *
+ *   Main CVStep function
+ *      CVStep
+ *
+ *   Functions called at beginning of step
+ *      CVAdjustParams
+ *      CVAdjustOrder    
+ *      CVAdjustAdams
+ *      CVAdjustBDF       
+ *      CVIncreaseBDF
+ *      CVDecreaseBDF     
+ *      CVRescale
+ *      CVPredict         
+ *      CVSet
+ *      CVSetAdams        
+ *      CVAdamsStart
+ *      CVAdamsFinish      
+ *      CVAltSum
+ *      CVSetBDF           
+ *      CVSetTqBDF
+ *
+ *   Nonlinear solver functions
+ *      CVNls              
+ *      CVNlsFunctional
+ *      CVNlsNewton        
+ *      CVNewtonIteration
+ *      CVQuadNls           
+ *      CVStgrNls
+ *      CVStgrNlsFunctional     
+ *      CVStgrNlsNewton
+ *      CVStgrNewtonIteration    
+ *      CVStgr1Nls
+ *      CVStgr1NlsFunctional    
+ *      CVStgr1NlsNewton
+ *      CVStgr1NewtonIteration   
+ *      CVHandleNFlag
+ *      CVRestore             
+ *
+ *   Error Test
+ *      CVDoErrorTest
+ *
+ *   Functions called after a successful step
+ *      CVCompleteStep      
+ *      CVPrepareNextStep
+ *      CVSetEta          
+ *      CVComputeEtaqm1
+ *      CVComputeEtaqp1   
+ *      CVChooseEta
+ *
+ *   Function to handle failures
+ *      CVHandleFailure   
+ *
+ *   Functions for BDF Stability Limit Detection  
+ *      CVBDFStab
+ *      CVsldet   
+ *
+ *   Functions for rootfinding
+ *      CVRcheck1
+ *      CVRcheck2         
+ *      CVRcheck3
+ *      CVRootfind  
+ *
+ *   Functions for combined norms
+ *      CVQuadUpdateNorm
+ *      CVQuadUpdateDsm     
+ *      CVSensNorm
+ *      CVSensUpdateNorm    
+ *      CVStgrUpdateDsm
+ *
+ *   Wrappers for sensitivity RHS
+ *      CVSensRhs           
+ *      CVSensRhs1
+ *
+ *   Internal DQ approximations for sensitivity RHS
+ *      CVSensRhsDQ         
+ *      CVSensRhs1DQ
+ *
+ *   Error message handling functions
+ *      CVProcessError      
+ *      CVErrHandler
+ *
+ * -----------------------------------------------------------------
+ */
+
+/* 
+ * =================================================================
+ * IMPORTED HEADER FILES
+ * =================================================================
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "cvodes_impl.h"
+#include <sundials/sundials_math.h>
+#include <sundials/sundials_types.h>
+
+/* 
+ * =================================================================
+ * MACRO DEFINITIONS
+ * =================================================================
+ */
+
+/* Macro: loop */
+#define loop for(;;)
+
+/* 
+ * =================================================================
+ * CVODES PRIVATE CONSTANTS
+ * =================================================================
+ */
+
+#define ZERO   RCONST(0.0)
+#define TINY   RCONST(1.0e-10)
+#define TENTH  RCONST(0.1)
+#define POINT2 RCONST(0.2)
+#define FOURTH RCONST(0.25)
+#define HALF   RCONST(0.5)
+#define ONE    RCONST(1.0)
+#define TWO    RCONST(2.0)
+#define THREE  RCONST(3.0)
+#define FOUR   RCONST(4.0)
+#define FIVE   RCONST(5.0)
+#define TWELVE RCONST(12.0)
+#define HUN    RCONST(100.0)
+
+/* 
+ * =================================================================
+ * CVODES ROUTINE-SPECIFIC CONSTANTS
+ * =================================================================
+ */
+
+/* 
+ * Control constants for lower-level functions used by CVStep 
+ * ----------------------------------------------------------
+ *
+ * CVHin return values:
+ *    CV_SUCCESS,
+ *    CV_RHSFUNC_FAIL,  CV_RPTD_RHSFUNC_ERR,
+ *    CV_QRHSFUNC_FAIL, CV_RPTD_QRHSFUNC_ERR,
+ *    CV_SRHSFUNC_FAIL, CV_RPTD_SRHSFUNC_ERR,
+ *    CV_TOO_CLOSE
+ *
+ * CVStep control constants:
+ *    DO_ERROR_TEST
+ *    PREDICT_AGAIN
+ *
+ * CVStep return values: 
+ *    CV_SUCCESS,
+ *    CV_CONV_FAILURE,      CV_ERR_FAILURE,
+ *    CV_LSETUP_FAIL,       CV_LSOLVE_FAIL, 
+ *    CV_RTFUNC_FAIL,
+ *    CV_RHSFUNC_FAIL,      CV_QRHSFUNC_FAIL,      CV_SRHSFUNC_FAIL,
+ *    CV_FIRST_RHSFUNC_ERR, CV_FIRST_QRHSFUNC_ERR, CV_FIRST_SRHSFUNC_ERR
+ *    CV_UNREC_RHSFUNC_ERR, CV_UNREC_QRHSFUNC_ERR, CV_UNREC_SRHSFUNC_ERR,
+ *    CV_REPTD_RHSFUNC_ERR, CV_REPTD_QRHSFUNC_ERR, CV_REPTD_SRHSFUNC_ERR 
+ *
+ * CVNls input nflag values:
+ *    FIRST_CALL
+ *    PREV_CONV_FAIL
+ *    PREV_ERR_FAIL
+ *    
+ * CVNls return values: 
+ *    CV_SUCCESS,
+ *    CV_LSETUP_FAIL,  CV_LSOLVE_FAIL, 
+ *    CV_RHSFUNC_FAIL, CV_SRHSFUNC_FAIL,
+ *    CONV_FAIL, 
+ *    RHSFUNC_RECVR,   SRHSFUNC_RECVR
+ * 
+ * CVNewtonIteration return values:
+ *    CV_SUCCESS, 
+ *    CV_LSOLVE_FAIL, 
+ *    CV_RHSFUNC_FAIL, CV_SRHSFUNC_FAIL,
+ *    CONV_FAIL,       TRY_AGAIN
+ *    RHSFUNC_RECVR,   SRHSFUNC_RECVR
+ *
+ */
+
+#define DO_ERROR_TEST    +2
+#define PREDICT_AGAIN    +3
+
+#define CONV_FAIL        +4 
+#define TRY_AGAIN        +5
+
+#define FIRST_CALL       +6
+#define PREV_CONV_FAIL   +7
+#define PREV_ERR_FAIL    +8
+
+#define RHSFUNC_RECVR    +9
+
+#define QRHSFUNC_RECVR   +11
+#define SRHSFUNC_RECVR   +12
+
+/*
+ * Control constants for lower-level rootfinding functions
+ * -------------------------------------------------------
+ *
+ * CVRcheck1 return values:
+ *    CV_SUCCESS,
+ *    CV_RTFUNC_FAIL,
+ *    INITROOT
+ * CVRcheck2 return values:
+ *    CV_SUCCESS,
+ *    CV_RTFUNC_FAIL,
+ *    CLOSERT,
+ *    RTFOUND
+ * CVRcheck3 return values:
+ *    CV_SUCCESS,
+ *    CV_RTFUNC_FAIL,
+ *    RTFOUND
+ * CVRootFind return values:
+ *    CV_SUCCESS,
+ *    CV_RTFUNC_FAIL,
+ *    RTFOUND
+ */
+
+#define RTFOUND          +1
+#define INITROOT         +2
+#define CLOSERT          +3
+
+/*
+ * Control constants for sensitivity DQ
+ * ------------------------------------
+ */
+
+#define CENTERED1        +1
+#define CENTERED2        +2
+#define FORWARD1         +3
+#define FORWARD2         +4
+
+
+/*
+ * Algorithmic constants
+ * ---------------------
+ *
+ * CVodeGetDky and CVStep
+ *
+ *    FUZZ_FACTOR fuzz factor used to estimate infinitesimal time intervals
+ *
+ * CVHin
+ *
+ *    HLB_FACTOR  factor for upper bound on initial step size
+ *    HUB_FACTOR  factor for lower bound on initial step size
+ *    H_BIAS      bias factor in selection of intial step size
+ *    MAX_ITERS   maximum attempts to compute the initial step size
+ *
+ * CVodeCreate 
+ *
+ *   CORTES       constant in nonlinear iteration convergence test
+ *
+ * CVStep
+ *
+ *    THRESH      if eta < THRESH reject a change in step size or order
+ *    ETAMX1      -+
+ *    ETAMX2       |
+ *    ETAMX3       |-> bounds for eta (step size change)
+ *    ETAMXF       |
+ *    ETAMIN       |
+ *    ETACF       -+
+ *    ADDON       safety factor in computing eta
+ *    BIAS1       -+
+ *    BIAS2        |-> bias factors in eta selection
+ *    BIAS3       -+
+ *    ONEPSM      (1+epsilon) used in testing if the step size is below its bound
+ *
+ *    SMALL_NST   nst > SMALL_NST => use ETAMX3 
+ *    MXNCF       max no. of convergence failures during one step try
+ *    MXNEF       max no. of error test failures during one step try
+ *    MXNEF1      max no. of error test failures before forcing a reduction of order
+ *    SMALL_NEF   if an error failure occurs and SMALL_NEF <= nef <= MXNEF1, then
+ *                reset eta =  MIN(eta, ETAMXF)
+ *    LONG_WAIT   number of steps to wait before considering an order change when
+ *                q==1 and MXNEF1 error test failures have occurred
+ *
+ * CVNls
+ *    
+ *    NLS_MAXCOR  maximum no. of corrector iterations for the nonlinear solver
+ *    CRDOWN      constant used in the estimation of the convergence rate (crate)
+ *                of the iterates for the nonlinear equation
+ *    DGMAX       iter == CV_NEWTON, |gamma/gammap-1| > DGMAX => call lsetup
+ *    RDIV        declare divergence if ratio del/delp > RDIV
+ *    MSBP        max no. of steps between lsetup calls
+ *    
+ */
+
+
+#define FUZZ_FACTOR RCONST(100.0)
+
+#define HLB_FACTOR RCONST(100.0)
+#define HUB_FACTOR RCONST(0.1)
+#define H_BIAS     HALF
+#define MAX_ITERS  4
+
+#define CORTES RCONST(0.1)
+
+#define THRESH RCONST(1.5)
+#define ETAMX1 RCONST(10000.0) 
+#define ETAMX2 RCONST(10.0)
+#define ETAMX3 RCONST(10.0)
+#define ETAMXF RCONST(0.2)
+#define ETAMIN RCONST(0.1)
+#define ETACF  RCONST(0.25)
+#define ADDON  RCONST(0.000001)
+#define BIAS1  RCONST(6.0)
+#define BIAS2  RCONST(6.0)
+#define BIAS3  RCONST(10.0)
+#define ONEPSM RCONST(1.000001)
+
+#define SMALL_NST    10
+#define MXNCF        10
+#define MXNEF         7
+#define MXNEF1        3
+#define SMALL_NEF     2
+#define LONG_WAIT    10
+
+#define NLS_MAXCOR 3
+#define CRDOWN RCONST(0.3)
+#define DGMAX  RCONST(0.3)
+
+#define RDIV      TWO
+#define MSBP       20
+
+/* 
+ * =================================================================
+ * PRIVATE FUNCTION PROTOTYPES
+ * =================================================================
+ */
+
+static booleantype CVCheckNvector(N_Vector tmpl);
+
+/* Memory allocation/deallocation */
+
+static booleantype CVAllocVectors(CVodeMem cv_mem, N_Vector tmpl, int tol);
+static void CVFreeVectors(CVodeMem cv_mem);
+
+static booleantype CVQuadAllocVectors(CVodeMem cv_mem, N_Vector tmpl);
+static void CVQuadFreeVectors(CVodeMem cv_mem);
+
+static booleantype CVSensAllocVectors(CVodeMem cv_mem, N_Vector tmpl);
+static void CVSensFreeVectors(CVodeMem cv_mem);
+
+/* Initial stepsize calculation */
+
+static int CVHin(CVodeMem cv_mem, realtype tout);
+static realtype CVUpperBoundH0(CVodeMem cv_mem, realtype tdist);
+static int CVYddNorm(CVodeMem cv_mem, realtype hg, realtype *yddnrm);
+
+/* Initial setup */
+
+static int CVInitialSetup(CVodeMem cv_mem);
+
+static int CVEwtSetSS(CVodeMem cv_mem, N_Vector ycur, N_Vector weight);
+static int CVEwtSetSV(CVodeMem cv_mem, N_Vector ycur, N_Vector weight);
+
+static int CVQuadEwtSet(CVodeMem cv_mem, N_Vector qcur, N_Vector weightQ);
+static int CVQuadEwtSetSS(CVodeMem cv_mem, N_Vector qcur, N_Vector weightQ);
+static int CVQuadEwtSetSV(CVodeMem cv_mem, N_Vector qcur, N_Vector weightQ);
+
+static int CVSensEwtSet(CVodeMem cv_mem, N_Vector *yScur, N_Vector *weightS);
+static int CVSensEwtSetEE(CVodeMem cv_mem, N_Vector *yScur, N_Vector *weightS);
+static int CVSensEwtSetSS(CVodeMem cv_mem, N_Vector *yScur, N_Vector *weightS);
+static int CVSensEwtSetSV(CVodeMem cv_mem, N_Vector *yScur, N_Vector *weightS);
+
+/* Main CVStep function */
+
+static int CVStep(CVodeMem cv_mem);
+
+/* Function called at beginning of step */
+
+static void CVAdjustParams(CVodeMem cv_mem);
+static void CVAdjustOrder(CVodeMem cv_mem, int deltaq);
+static void CVAdjustAdams(CVodeMem cv_mem, int deltaq);
+static void CVAdjustBDF(CVodeMem cv_mem, int deltaq);
+static void CVIncreaseBDF(CVodeMem cv_mem);
+static void CVDecreaseBDF(CVodeMem cv_mem);
+static void CVRescale(CVodeMem cv_mem);
+static void CVPredict(CVodeMem cv_mem);
+static void CVSet(CVodeMem cv_mem);
+static void CVSetAdams(CVodeMem cv_mem);
+static realtype CVAdamsStart(CVodeMem cv_mem, realtype m[]);
+static void CVAdamsFinish(CVodeMem cv_mem, realtype m[], realtype M[], realtype hsum);
+static realtype CVAltSum(int iend, realtype a[], int k);
+static void CVSetBDF(CVodeMem cv_mem);
+static void CVSetTqBDF(CVodeMem cv_mem, realtype hsum, realtype alpha0,
+                       realtype alpha0_hat, realtype xi_inv, realtype xistar_inv);
+
+/* Nonlinear solver functions */
+
+static int CVNls(CVodeMem cv_mem, int nflag);
+static int CVNlsFunctional(CVodeMem cv_mem);
+static int CVNlsNewton(CVodeMem cv_mem, int nflag);
+static int CVNewtonIteration(CVodeMem cv_mem);
+
+static int CVQuadNls(CVodeMem cv_mem);
+
+static int CVStgrNls(CVodeMem cv_mem);
+static int CVStgrNlsFunctional(CVodeMem cv_mem);
+static int CVStgrNlsNewton(CVodeMem cv_mem);
+static int CVStgrNewtonIteration(CVodeMem cv_mem);
+
+static int CVStgr1Nls(CVodeMem cv_mem, int is);
+static int CVStgr1NlsFunctional(CVodeMem cv_mem, int is);
+static int CVStgr1NlsNewton(CVodeMem cv_mem, int is);
+static int CVStgr1NewtonIteration(CVodeMem cv_mem, int is);
+
+static int CVHandleNFlag(CVodeMem cv_mem, int *nflagPtr, realtype saved_t,
+                         int *ncfPtr, long int *ncfnPtr);
+
+static void CVRestore(CVodeMem cv_mem, realtype saved_t);
+
+/* Error Test */
+
+static int CVDoErrorTest(CVodeMem cv_mem, int *nflagPtr, realtype saved_t, 
+                         realtype acor_nrm,
+                         int *nefPtr, long int *netfPtr, realtype *dsmPtr);
+
+/* Function called after a successful step */
+
+static void CVCompleteStep(CVodeMem cv_mem);
+static void CVPrepareNextStep(CVodeMem cv_mem, realtype dsm);
+static void CVSetEta(CVodeMem cv_mem);
+static realtype CVComputeEtaqm1(CVodeMem cv_mem);
+static realtype CVComputeEtaqp1(CVodeMem cv_mem);
+static void CVChooseEta(CVodeMem cv_mem);
+
+/* Function to handle failures */
+
+static int CVHandleFailure(CVodeMem cv_mem,int flag);
+
+/* Functions for BDF Stability Limit Detection */
+
+static void CVBDFStab(CVodeMem cv_mem);
+static int CVsldet(CVodeMem cv_mem);
+
+/* Functions for rootfinding */
+
+static int CVRcheck1(CVodeMem cv_mem);
+static int CVRcheck2(CVodeMem cv_mem);
+static int CVRcheck3(CVodeMem cv_mem);
+static int CVRootfind(CVodeMem cv_mem);
+
+/* Function for combined norms */
+
+static realtype CVQuadUpdateNorm(CVodeMem cv_mem, realtype old_nrm,
+                                 N_Vector xQ, N_Vector wQ);
+static realtype CVQuadUpdateDsm(CVodeMem cv_mem, realtype old_dsm, 
+                                realtype dsmQ);
+static realtype CVSensNorm(CVodeMem cv_mem, N_Vector *xS, N_Vector *wS);
+static realtype CVSensUpdateNorm(CVodeMem cv_mem, realtype old_nrm,
+                                 N_Vector *xS, N_Vector *wS);
+static realtype CVStgrUpdateDsm(CVodeMem cv_mem, realtype old_dsm, 
+                                realtype dsmS);
+
+/* Wrappers for sensitivity RHS */
+
+static int CVSensRhs(CVodeMem cv_mem, realtype time, 
+                     N_Vector ycur, N_Vector fcur, 
+                     N_Vector *yScur, N_Vector *fScur,
+                     N_Vector temp1, N_Vector temp2);
+static int CVSensRhs1(CVodeMem cv_mem, realtype time, 
+                      N_Vector ycur, N_Vector fcur, 
+                      int is, N_Vector yScur, N_Vector fScur,
+                      N_Vector temp1, N_Vector temp2);
+
+/* 
+ * =================================================================
+ * EXPORTED FUNCTIONS IMPLEMENTATION
+ * =================================================================
+ */
+
+/* 
+ * -----------------------------------------------------------------
+ * Creation, allocation and re-initialization functions
+ * -----------------------------------------------------------------
+ */
+
+/* 
+ * CVodeCreate
+ *
+ * CVodeCreate creates an internal memory block for a problem to 
+ * be solved by CVODES.
+ * If successful, CVodeCreate returns a pointer to the problem memory. 
+ * This pointer should be passed to CVodeMalloc.  
+ * If an initialization error occurs, CVodeCreate prints an error 
+ * message to standard err and returns NULL. 
+ */
+
+void *CVodeCreate(int lmm, int iter)
+{
+  int maxord;
+  CVodeMem cv_mem;
+
+  /* Test inputs */
+
+  if ((lmm != CV_ADAMS) && (lmm != CV_BDF)) {
+    CVProcessError(NULL, 0, "CVODES", "CVodeCreate", MSGCV_BAD_LMM);
+    return(NULL);
+  }
+  
+  if ((iter != CV_FUNCTIONAL) && (iter != CV_NEWTON)) {
+    CVProcessError(NULL, 0, "CVODES", "CVodeCreate", MSGCV_BAD_ITER);
+    return(NULL);
+  }
+
+  cv_mem = NULL;
+  cv_mem = (CVodeMem) malloc(sizeof(struct CVodeMemRec));
+  if (cv_mem == NULL) {
+    CVProcessError(NULL, 0, "CVODES", "CVodeCreate", MSGCV_CVMEM_FAIL);
+    return(NULL);
+  }
+
+  maxord = (lmm == CV_ADAMS) ? ADAMS_Q_MAX : BDF_Q_MAX;
+
+  /* copy input parameters into cv_mem */
+  cv_mem->cv_lmm  = lmm;
+  cv_mem->cv_iter = iter;
+
+  /* Set uround */
+  cv_mem->cv_uround = UNIT_ROUNDOFF;
+
+  /* Set default values for integrator optional inputs */
+  cv_mem->cv_f        = NULL;
+  cv_mem->cv_f_data   = NULL;
+  cv_mem->cv_efun     = NULL;
+  cv_mem->cv_e_data   = NULL;
+  cv_mem->cv_ehfun    = CVErrHandler;
+  cv_mem->cv_eh_data  = (void *) cv_mem;
+  cv_mem->cv_errfp    = stderr;
+  cv_mem->cv_qmax     = maxord;
+  cv_mem->cv_mxstep   = MXSTEP_DEFAULT;
+  cv_mem->cv_mxhnil   = MXHNIL_DEFAULT;
+  cv_mem->cv_sldeton  = FALSE;
+  cv_mem->cv_hin      = ZERO;
+  cv_mem->cv_hmin     = HMIN_DEFAULT;
+  cv_mem->cv_hmax_inv = HMAX_INV_DEFAULT;
+  cv_mem->cv_tstopset = FALSE;
+  cv_mem->cv_maxcor   = NLS_MAXCOR;
+  cv_mem->cv_maxnef   = MXNEF;
+  cv_mem->cv_maxncf   = MXNCF;
+  cv_mem->cv_nlscoef  = CORTES;
+
+  /* Initialize root finding variables */
+
+  cv_mem->cv_glo    = NULL;
+  cv_mem->cv_ghi    = NULL;
+  cv_mem->cv_grout  = NULL;
+  cv_mem->cv_iroots = NULL;
+  cv_mem->cv_gfun   = NULL;
+  cv_mem->cv_g_data = NULL;
+  cv_mem->cv_nrtfn  = 0;  
+
+  /* Set default values for quad. optional inputs */
+  cv_mem->cv_quadr    = FALSE;
+  cv_mem->cv_fQ       = NULL;
+  cv_mem->cv_fQ_data  = NULL;
+  cv_mem->cv_errconQ  = FALSE;
+
+  /* Set default values for sensi. optional inputs */
+  cv_mem->cv_sensi        = FALSE;
+  cv_mem->cv_fS_data      = (void *)cv_mem;
+  cv_mem->cv_fS           = CVSensRhsDQ;
+  cv_mem->cv_fS1          = CVSensRhs1DQ;
+  cv_mem->cv_fSDQ         = TRUE;
+  cv_mem->cv_ifS          = CV_ONESENS;
+  cv_mem->cv_DQtype       = CV_CENTERED;
+  cv_mem->cv_DQrhomax     = ZERO;
+  cv_mem->cv_p            = NULL;
+  cv_mem->cv_pbar         = NULL;
+  cv_mem->cv_plist        = NULL;
+  cv_mem->cv_errconS      = FALSE;
+  cv_mem->cv_maxcorS      = NLS_MAXCOR;
+  cv_mem->cv_ncfS1        = NULL;
+  cv_mem->cv_ncfnS1       = NULL;
+  cv_mem->cv_nniS1        = NULL;
+  cv_mem->cv_itolS        = CV_EE;
+
+  /* Set the saved values for qmax_alloc */
+
+  cv_mem->cv_qmax_alloc  = maxord;
+  cv_mem->cv_qmax_allocQ = maxord;
+  cv_mem->cv_qmax_allocS = maxord;
+
+  /* Initialize lrw and liw */
+
+  cv_mem->cv_lrw = 65 + 2*L_MAX + NUM_TESTS;
+  cv_mem->cv_liw = 52;
+
+  /* No mallocs have been done yet */
+
+  cv_mem->cv_VabstolMallocDone  = FALSE;
+  cv_mem->cv_MallocDone         = FALSE;
+
+  cv_mem->cv_VabstolQMallocDone = FALSE;
+  cv_mem->cv_quadMallocDone     = FALSE;
+
+  cv_mem->cv_VabstolSMallocDone = FALSE;
+  cv_mem->cv_SabstolSMallocDone = FALSE;
+  cv_mem->cv_sensMallocDone     = FALSE;
+
+  /* Return pointer to CVODES memory block */
+
+  return((void *)cv_mem);
+}
+
+/*-----------------------------------------------------------------*/
+
+#define iter (cv_mem->cv_iter)  
+#define lmm  (cv_mem->cv_lmm) 
+#define lrw  (cv_mem->cv_lrw)
+#define liw  (cv_mem->cv_liw)
+
+/*-----------------------------------------------------------------*/
+
+/*
+ * CVodeMalloc
+ * 
+ * CVodeMalloc allocates and initializes memory for a problem. All 
+ * problem inputs are checked for errors. If any error occurs during 
+ * initialization, it is reported to the file whose file pointer is 
+ * errfp and an error flag is returned. Otherwise, it returns CV_SUCCESS
+ */
+
+int CVodeMalloc(void *cvode_mem, CVRhsFn f, realtype t0, N_Vector y0, 
+                int itol, realtype reltol, void *abstol)
+{
+  CVodeMem cv_mem;
+  booleantype nvectorOK, allocOK, neg_abstol;
+  long int lrw1, liw1;
+  int i,k;
+
+  /* Check cvode_mem */
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeMalloc", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;
+
+  /* Check for legal input parameters */
+
+  if (y0==NULL) {
+    CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeMalloc", MSGCV_NULL_Y0);
+    return(CV_ILL_INPUT);
+  }
+
+  if ((itol != CV_SS) && (itol != CV_SV) && (itol != CV_WF)) {
+    CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeMalloc", MSGCV_BAD_ITOL);
+    return(CV_ILL_INPUT);
+  }
+
+  if (f == NULL) {
+    CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeMalloc", MSGCV_NULL_F);
+    return(CV_ILL_INPUT);
+  }
+
+  /* Test if all required vector operations are implemented */
+
+  nvectorOK = CVCheckNvector(y0);
+  if(!nvectorOK) {
+    CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeMalloc", MSGCV_BAD_NVECTOR);
+    return(CV_ILL_INPUT);
+  }
+
+  /* Test tolerances */
+
+  if (itol != CV_WF) {
+
+    if (abstol == NULL) {
+      CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeMalloc", MSGCV_NULL_ABSTOL);
+      return(CV_ILL_INPUT);
+    }
+
+    if (reltol < ZERO) {
+      CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeMalloc", MSGCV_BAD_RELTOL);
+      return(CV_ILL_INPUT);
+    }
+
+    if (itol == CV_SS)
+      neg_abstol = (*((realtype *)abstol) < ZERO);
+    else
+      neg_abstol = (N_VMin((N_Vector)abstol) < ZERO);
+
+    if (neg_abstol) {
+      CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeMalloc", MSGCV_BAD_ABSTOL);
+      return(CV_ILL_INPUT);
+    }
+
+  }
+
+  /* Set space requirements for one N_Vector */
+
+  if (y0->ops->nvspace != NULL) {
+    N_VSpace(y0, &lrw1, &liw1);
+  } else {
+    lrw1 = 0;
+    liw1 = 0;
+  }
+  cv_mem->cv_lrw1 = lrw1;
+  cv_mem->cv_liw1 = liw1;
+
+  /* Allocate the vectors (using y0 as a template) */
+
+  allocOK = CVAllocVectors(cv_mem, y0, itol);
+  if (!allocOK) {
+    CVProcessError(cv_mem, CV_MEM_FAIL, "CVODES", "CVodeMalloc", MSGCV_MEM_FAIL);
+    return(CV_MEM_FAIL);
+  }
+
+  /* Copy tolerances into memory */
+
+  cv_mem->cv_itol   = itol;
+  cv_mem->cv_reltol = reltol;      
+
+  if (itol == CV_SS)
+    cv_mem->cv_Sabstol = *((realtype *)abstol);
+  else if (itol == CV_SV)
+    N_VScale(ONE, (N_Vector)abstol, cv_mem->cv_Vabstol);
+
+  /* All error checking is complete at this point */
+
+  /* Copy the input parameters into CVODES state */
+
+  cv_mem->cv_f  = f;
+  cv_mem->cv_tn = t0;
+
+  /* Set step parameters */
+
+  cv_mem->cv_q      = 1;
+  cv_mem->cv_L      = 2;
+  cv_mem->cv_qwait  = cv_mem->cv_L;
+  cv_mem->cv_etamax = ETAMX1;
+
+  cv_mem->cv_qu     = 0;
+  cv_mem->cv_hu     = ZERO;
+  cv_mem->cv_tolsf  = ONE;
+
+  /* Set the linear solver addresses to NULL.
+     (We check != NULL later, in CVode, if using CV_NEWTON.) */
+
+  cv_mem->cv_linit  = NULL;
+  cv_mem->cv_lsetup = NULL;
+  cv_mem->cv_lsolve = NULL;
+  cv_mem->cv_lfree  = NULL;
+  cv_mem->cv_lmem   = NULL;
+
+  /* Set forceSetup to FALSE */
+
+  cv_mem->cv_forceSetup = FALSE;
+
+  /* Initialize zn[0] in the history array */
+
+  N_VScale(ONE, y0, cv_mem->cv_zn[0]);
+
+  /* Initialize all the counters */
+
+  cv_mem->cv_nst     = 0;
+  cv_mem->cv_nfe     = 0;
+  cv_mem->cv_ncfn    = 0;
+  cv_mem->cv_netf    = 0;
+  cv_mem->cv_nni     = 0;
+  cv_mem->cv_nsetups = 0;
+  cv_mem->cv_nhnil   = 0;
+  cv_mem->cv_nstlp   = 0;
+  cv_mem->cv_nscon   = 0;
+  cv_mem->cv_nge     = 0;
+
+  /* Initialize other integrator optional outputs */
+
+  cv_mem->cv_h0u      = ZERO;
+  cv_mem->cv_next_h   = ZERO;
+  cv_mem->cv_next_q   = 0;
+
+  /* Initialize Stablilty Limit Detection data */
+  /* NOTE: We do this even if stab lim det was not
+     turned on yet. This way, the user can turn it
+     on at any time */
+
+  cv_mem->cv_nor = 0;
+  for (i = 1; i <= 5; i++)
+    for (k = 1; k <= 3; k++) 
+      cv_mem->cv_ssdat[i-1][k-1] = ZERO;
+
+  /* Problem has been successfully initialized */
+
+  cv_mem->cv_MallocDone = TRUE;
+
+  return(CV_SUCCESS);
+}
+
+/*-----------------------------------------------------------------*/
+
+#define lrw1 (cv_mem->cv_lrw1)
+#define liw1 (cv_mem->cv_liw1)
+
+/*-----------------------------------------------------------------*/
+
+/*
+ * CVodeReInit
+ *
+ * CVodeReInit re-initializes CVODES's memory for a problem, assuming
+ * it has already been allocated in a prior CVodeMalloc call.
+ * All problem specification inputs are checked for errors.
+ * If any error occurs during initialization, it is reported to the
+ * file whose file pointer is errfp.
+ * The return value is CV_SUCCESS = 0 if no errors occurred, or
+ * a negative value otherwise.
+ */
+
+int CVodeReInit(void *cvode_mem, CVRhsFn f, realtype t0, N_Vector y0, 
+                int itol, realtype reltol, void *abstol)
+{
+  CVodeMem cv_mem;
+  booleantype neg_abstol;
+  int i,k;
+ 
+  /* Check cvode_mem */
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeReInit", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;
+
+  /* Check if cvode_mem was allocated */
+
+  if (cv_mem->cv_MallocDone == FALSE) {
+    CVProcessError(cv_mem, CV_NO_MALLOC, "CVODES", "CVodeReInit", MSGCV_NO_MALLOC);
+    return(CV_NO_MALLOC);
+  }
+
+  /* Check for legal input parameters */
+
+  if (y0 == NULL) {
+    CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeReInit", MSGCV_NULL_Y0);
+    return(CV_ILL_INPUT);
+  }
+  
+  if ((itol != CV_SS) && (itol != CV_SV) && (itol != CV_WF)) {
+    CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeReInit", MSGCV_BAD_ITOL);
+    return(CV_ILL_INPUT);
+  }
+
+  if (f == NULL) {
+    CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeReInit", MSGCV_NULL_F);
+    return(CV_ILL_INPUT);
+  }
+
+  /* Test tolerances */
+   
+  if (itol != CV_WF) {
+    
+    if (abstol == NULL) {
+      CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeReInit", MSGCV_NULL_ABSTOL);
+      return(CV_ILL_INPUT);
+    }
+
+    if (reltol < ZERO) {
+      CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeReInit", MSGCV_BAD_RELTOL);
+      return(CV_ILL_INPUT);
+    }
+
+    if (itol == CV_SS)
+      neg_abstol = (*((realtype *)abstol) < ZERO);
+    else
+      neg_abstol = (N_VMin((N_Vector)abstol) < ZERO);
+
+    if (neg_abstol) {
+      CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeReInit", MSGCV_BAD_ABSTOL);
+      return(CV_ILL_INPUT);
+    }
+
+  }
+
+  /* Copy tolerances into memory */
+
+  if ( (itol != CV_SV) && (cv_mem->cv_VabstolMallocDone) ) {
+    N_VDestroy(cv_mem->cv_Vabstol);
+    lrw -= lrw1;
+    liw -= liw1;
+    cv_mem->cv_VabstolMallocDone = FALSE;
+  }
+
+  if ( (itol == CV_SV) && !(cv_mem->cv_VabstolMallocDone) ) {
+    cv_mem->cv_Vabstol = NULL;
+    cv_mem->cv_Vabstol = N_VClone(y0);
+    lrw += lrw1;
+    liw += liw1;
+    cv_mem->cv_VabstolMallocDone = TRUE;
+  }
+
+  cv_mem->cv_itol   = itol;
+  cv_mem->cv_reltol = reltol;
+
+  if (itol == CV_SS)
+    cv_mem->cv_Sabstol = *((realtype *)abstol);
+  else if (itol == CV_SV)
+    N_VScale(ONE, (N_Vector)abstol, cv_mem->cv_Vabstol);
+
+  /* All error checking is complete at this point */
+  
+  /* Copy the input parameters into CVODES state */
+
+  cv_mem->cv_f = f;
+  cv_mem->cv_tn = t0;
+
+  /* Set step parameters */
+
+  cv_mem->cv_q      = 1;
+  cv_mem->cv_L      = 2;
+  cv_mem->cv_qwait  = cv_mem->cv_L;
+  cv_mem->cv_etamax = ETAMX1;
+
+  cv_mem->cv_qu     = 0;
+  cv_mem->cv_hu     = ZERO;
+  cv_mem->cv_tolsf  = ONE;
+
+  /* Set forceSetup to FALSE */
+
+  cv_mem->cv_forceSetup = FALSE;
+
+  /* Initialize zn[0] in the history array */
+
+  N_VScale(ONE, y0, cv_mem->cv_zn[0]);
+ 
+  /* Initialize all the counters */
+
+  cv_mem->cv_nst     = 0;
+  cv_mem->cv_nfe     = 0;
+  cv_mem->cv_ncfn    = 0;
+  cv_mem->cv_netf    = 0;
+  cv_mem->cv_nni     = 0;
+  cv_mem->cv_nsetups = 0;
+  cv_mem->cv_nhnil   = 0;
+  cv_mem->cv_nstlp   = 0;
+  cv_mem->cv_nscon   = 0;
+  cv_mem->cv_nge     = 0;
+
+  /* Initialize other integrator optional outputs */
+
+  cv_mem->cv_h0u      = ZERO;
+  cv_mem->cv_next_h   = ZERO;
+  cv_mem->cv_next_q   = 0;
+
+  /* Initialize Stablilty Limit Detection data */
+
+  cv_mem->cv_nor = 0;
+  for (i = 1; i <= 5; i++)
+    for (k = 1; k <= 3; k++) 
+      cv_mem->cv_ssdat[i-1][k-1] = ZERO;
+  
+  /* Problem has been successfully re-initialized */
+
+  return(CV_SUCCESS);
+}
+
+/*-----------------------------------------------------------------*/
+
+#define gfun   (cv_mem->cv_gfun)
+#define g_data (cv_mem->cv_g_data) 
+#define glo    (cv_mem->cv_glo)
+#define ghi    (cv_mem->cv_ghi)
+#define grout  (cv_mem->cv_grout)
+#define iroots (cv_mem->cv_iroots)
+
+/*-----------------------------------------------------------------*/
+
+/*
+ * CVodeRootInit
+ *
+ * CVodeRootInit initializes a rootfinding problem to be solved
+ * during the integration of the ODE system.  It loads the root
+ * function pointer and the number of root functions, and allocates
+ * workspace memory.  The return value is CV_SUCCESS = 0 if no errors
+ * occurred, or a negative value otherwise.
+ */
+
+int CVodeRootInit(void *cvode_mem, int nrtfn, CVRootFn g, void *gdata)
+{
+  CVodeMem cv_mem;
+  int nrt;
+
+  /* Check cvode_mem */
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeRootInit", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;
+
+  nrt = (nrtfn < 0) ? 0 : nrtfn;
+
+  /* If rerunning CVodeRootInit() with a different number of root
+     functions (changing number of gfun components), then free
+     currently held memory resources */
+  if ((nrt != cv_mem->cv_nrtfn) && (cv_mem->cv_nrtfn > 0)) {
+    free(glo); glo = NULL;
+    free(ghi); ghi = NULL;
+    free(grout); grout = NULL;
+    free(iroots); iroots = NULL;
+
+    lrw -= 3* (cv_mem->cv_nrtfn);
+    liw -= cv_mem->cv_nrtfn;
+
+  }
+
+  /* If CVodeRootInit() was called with nrtfn == 0, then set cv_nrtfn to
+     zero and cv_gfun to NULL before returning */
+  if (nrt == 0) {
+    cv_mem->cv_nrtfn = nrt;
+    gfun = NULL;
+    g_data = NULL;
+    return(CV_SUCCESS);
+  }
+
+  /* Store user's data pointer */
+  g_data = gdata;
+
+  /* If rerunning CVodeRootInit() with the same number of root functions
+     (not changing number of gfun components), then check if the root
+     function argument has changed */
+  /* If g != NULL then return as currently reserved memory resources
+     will suffice */
+  if (nrt == cv_mem->cv_nrtfn) {
+    if (g != gfun) {
+      if (g == NULL) {
+	free(glo); glo = NULL;
+	free(ghi); ghi = NULL;
+	free(grout); grout = NULL;
+	free(iroots); iroots = NULL;
+        
+        lrw -= 3*nrt;
+        liw -= nrt;
+
+        CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeRootInit", MSGCV_NULL_G);
+	return(CV_ILL_INPUT);
+      }
+      else {
+	gfun = g;
+	return(CV_SUCCESS);
+      }
+    }
+    else return(CV_SUCCESS);
+  }
+
+  /* Set variable values in CVode memory block */
+  cv_mem->cv_nrtfn = nrt;
+  if (g == NULL) {
+    CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeRootInit", MSGCV_NULL_G);
+    return(CV_ILL_INPUT);
+  }
+  else gfun = g;
+
+  /* Allocate necessary memory and return */
+  glo = NULL;
+  glo = (realtype *) malloc(nrt*sizeof(realtype));
+  if (glo == NULL) {
+    CVProcessError(cv_mem, CV_MEM_FAIL, "CVODES", "CVodeRootInit", MSGCV_MEM_FAIL);
+    return(CV_MEM_FAIL);
+  }
+    
+  ghi = NULL;
+  ghi = (realtype *) malloc(nrt*sizeof(realtype));
+  if (ghi == NULL) {
+    free(glo); glo = NULL;
+    CVProcessError(cv_mem, CV_MEM_FAIL, "CVODES", "CVodeRootInit", MSGCV_MEM_FAIL);
+    return(CV_MEM_FAIL);
+  }
+    
+  grout = NULL;
+  grout = (realtype *) malloc(nrt*sizeof(realtype));
+  if (grout == NULL) {
+    free(glo); glo = NULL;
+    free(ghi); ghi = NULL;
+    CVProcessError(cv_mem, CV_MEM_FAIL, "CVODES", "CVodeRootInit", MSGCV_MEM_FAIL);
+    return(CV_MEM_FAIL);
+  }
+
+  iroots = NULL;
+  iroots = (int *) malloc(nrt*sizeof(int));
+  if (iroots == NULL) {
+    free(glo); glo = NULL;
+    free(ghi); ghi = NULL;
+    free(grout); grout = NULL;
+    CVProcessError(cv_mem, CV_MEM_FAIL, "CVODES", "CVodeRootInit", MSGCV_MEM_FAIL);
+    return(CV_MEM_FAIL);
+  }
+
+  lrw += 3*nrt;
+  liw += nrt;
+
+  return(CV_SUCCESS);
+}
+
+/*
+ * CVodeQuadMalloc
+ *
+ * CVodeQuadMalloc allocates and initializes quadrature related 
+ * memory for a problem. All problem specification inputs are 
+ * checked for errors. If any error occurs during initialization, 
+ * it is reported to the file whose file pointer is errfp. 
+ * The return value is CV_SUCCESS = 0 if no errors occurred, or
+ * a negative value otherwise.
+ */
+
+int CVodeQuadMalloc(void *cvode_mem, CVQuadRhsFn fQ, N_Vector yQ0)
+{
+  CVodeMem cv_mem;
+  booleantype allocOK;
+  long int lrw1Q, liw1Q;
+
+  /* Check cvode_mem */
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeQuadMalloc", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;
+
+  /* Set space requirements for one N_Vector */
+  N_VSpace(yQ0, &lrw1Q, &liw1Q);
+  cv_mem->cv_lrw1Q = lrw1Q;
+  cv_mem->cv_liw1Q = liw1Q;
+
+  /* Allocate the vectors (using yQ0 as a template) */
+  allocOK = CVQuadAllocVectors(cv_mem, yQ0);
+  if (!allocOK) {
+    CVProcessError(cv_mem, CV_MEM_FAIL, "CVODES", "CVodeQuadMalloc", MSGCV_MEM_FAIL);
+    return(CV_MEM_FAIL);
+  }
+
+  /* Initialize znQ[0] in the history array */
+  N_VScale(ONE, yQ0, cv_mem->cv_znQ[0]);
+
+  /* Copy the input parameters into CVODES state */
+  cv_mem->cv_fQ = fQ;
+
+  /* Initialize counters */
+  cv_mem->cv_nfQe  = 0;
+  cv_mem->cv_netfQ = 0;
+
+  /* Quadrature integration turned ON */
+  cv_mem->cv_quadr = TRUE;
+  cv_mem->cv_quadMallocDone = TRUE;
+
+  /* Quadrature initialization was successfull */
+  return(CV_SUCCESS);
+}
+
+/*-----------------------------------------------------------------*/
+
+#define lrw1Q (cv_mem->cv_lrw1Q)
+#define liw1Q (cv_mem->cv_liw1Q)
+
+/*-----------------------------------------------------------------*/
+
+/*
+ * CVodeQuadReInit
+ *
+ * CVodeQuadReInit re-initializes CVODES's quadrature related memory 
+ * for a problem, assuming it has already been allocated in prior 
+ * calls to CVodeMalloc and CVodeQuadMalloc. 
+ * All problem specification inputs are checked for errors.
+ * If any error occurs during initialization, it is reported to the
+ * file whose file pointer is errfp.
+ * The return value is CV_SUCCESS = 0 if no errors occurred, or
+ * a negative value otherwise.
+ */
+
+int CVodeQuadReInit(void *cvode_mem, CVQuadRhsFn fQ, N_Vector yQ0)
+{
+  CVodeMem cv_mem;
+
+  /* Check cvode_mem */
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeQuadReInit", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;
+
+  /* Ckeck if quadrature was initialized? */
+  if (cv_mem->cv_quadMallocDone == FALSE) {
+    CVProcessError(cv_mem, CV_NO_QUAD, "CVODES", "CVodeQuadReInit", MSGCV_NO_QUAD);
+    return(CV_NO_QUAD);
+  }
+
+  /* Initialize znQ[0] in the history array */
+  N_VScale(ONE, yQ0, cv_mem->cv_znQ[0]);
+
+  /* Copy the input parameters into CVODES state */
+  cv_mem->cv_fQ = fQ;
+
+  /* Initialize counters */
+  cv_mem->cv_nfQe  = 0;
+  cv_mem->cv_netfQ = 0;
+
+  /* Quadrature integration turned ON */
+  cv_mem->cv_quadr = TRUE;
+
+  /* Quadrature re-initialization was successfull */
+  return(CV_SUCCESS);
+}
+
+/*-----------------------------------------------------------------*/
+
+#define ifS          (cv_mem->cv_ifS)
+#define fSDQ         (cv_mem->cv_fSDQ)
+#define stgr1alloc   (cv_mem->cv_stgr1alloc)
+#define nniS1        (cv_mem->cv_nniS1)
+#define ncfnS1       (cv_mem->cv_ncfnS1)
+#define ncfS1        (cv_mem->cv_ncfS1)
+
+/*-----------------------------------------------------------------*/
+
+/*
+ * CVodeSenMalloc
+ *
+ * CVodeSensMalloc allocates and initializes sensitivity related 
+ * memory for a problem. All problem specification inputs are 
+ * checked for errors. If any error occurs during initialization, 
+ * it is reported to the file whose file pointer is errfp. 
+ * The return value is CV_SUCCESS = 0 if no errors occurred, or
+ * a negative value otherwise.
+ */
+
+int CVodeSensMalloc(void *cvode_mem, int Ns, int ism, N_Vector *yS0)
+{
+  CVodeMem    cv_mem;
+  booleantype allocOK;
+  int is;
+  
+  /* Check cvode_mem */
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSensMalloc", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;
+
+  /* Check if Ns is legal */
+  if (Ns<=0) {
+    CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSensMalloc", MSGCV_BAD_NS);
+    return(CV_ILL_INPUT);
+  }
+  cv_mem->cv_Ns = Ns;
+
+  /* Check if ism is legal */
+  if ((ism!=CV_SIMULTANEOUS) && (ism!=CV_STAGGERED) && (ism!=CV_STAGGERED1)) {
+    CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSensMalloc", MSGCV_BAD_ISM);
+    return(CV_ILL_INPUT);
+  }
+  cv_mem->cv_ism = ism;
+   
+  /* Check if yS0 is non-null */
+  if (yS0 == NULL) {
+    CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSensMalloc", MSGCV_NULL_YS0);
+    return(CV_ILL_INPUT);
+  }
+
+  /* Allocate ncfS1, ncfnS1, and nniS1 if needed */
+  if (ism == CV_STAGGERED1) {
+    stgr1alloc = TRUE;
+    ncfS1 = NULL;
+    ncfS1 = (int*)malloc(Ns*sizeof(int));
+    ncfnS1 = NULL;
+    ncfnS1 = (long int*)malloc(Ns*sizeof(long int));
+    nniS1 = NULL;
+    nniS1 = (long int*)malloc(Ns*sizeof(long int));
+    if ( (ncfS1 == NULL) || (ncfnS1 == NULL) || (nniS1 == NULL) ) {
+      CVProcessError(cv_mem, CV_MEM_FAIL, "CVODES", "CVodeSensMalloc", MSGCV_MEM_FAIL);
+      return(CV_MEM_FAIL);
+    }
+  } else {
+    stgr1alloc = FALSE;
+  }
+
+  /* Allocate the vectors (using yS0[0] as a template) */
+  allocOK = CVSensAllocVectors(cv_mem, yS0[0]);
+  if (!allocOK) {
+    if (stgr1alloc) {
+      free(ncfS1); ncfS1 = NULL;
+      free(ncfnS1); ncfnS1 = NULL;
+      free(nniS1); nniS1 = NULL;
+    }
+    CVProcessError(cv_mem, CV_MEM_FAIL, "CVODES", "CVodeSensMalloc", MSGCV_MEM_FAIL);
+    return(CV_MEM_FAIL);
+  }
+  
+  /*---------------------------------------------- 
+    All error checking is complete at this point 
+    -----------------------------------------------*/
+
+  /* Initialize znS[0] in the history array */
+  for (is=0; is<Ns; is++) 
+    N_VScale(ONE, yS0[is], cv_mem->cv_znS[0][is]);
+
+  /* Initialize all sensitivity related counters */
+  cv_mem->cv_nfSe     = 0;
+  cv_mem->cv_nfeS     = 0;
+  cv_mem->cv_ncfnS    = 0;
+  cv_mem->cv_netfS    = 0;
+  cv_mem->cv_nniS     = 0;
+  cv_mem->cv_nsetupsS = 0;
+  if (ism==CV_STAGGERED1)
+    for (is=0; is<Ns; is++) {
+      ncfnS1[is] = 0;
+      nniS1[is] = 0;
+    }
+
+  /* Set default values for plist and pbar */
+  for (is=0; is<Ns; is++) {
+    cv_mem->cv_plist[is] = is;
+    cv_mem->cv_pbar[is] = ONE;
+  }
+
+  /* Sensitivities will be computed */
+  cv_mem->cv_sensi = TRUE;
+  cv_mem->cv_sensMallocDone = TRUE;
+
+  /* Sensitivity initialization was successfull */
+  return(CV_SUCCESS);
+}
+
+/*-----------------------------------------------------------------*/
+
+#define Ns (cv_mem->cv_Ns)
+
+/*-----------------------------------------------------------------*/
+
+/*
+ * CVodeSensReInit
+ *
+ * CVodeSensReInit re-initializes CVODES's sensitivity related memory 
+ * for a problem, assuming it has already been allocated in prior 
+ * calls to CVodeMalloc and CVodeSensMalloc. 
+ * All problem specification inputs are checked for errors.
+ * The number of sensitivities Ns is assumed to be unchanged since
+ * the previous call to CVodeSensMalloc.
+ * If any error occurs during initialization, it is reported to the
+ * file whose file pointer is errfp.
+ * The return value is CV_SUCCESS = 0 if no errors occurred, or
+ * a negative value otherwise.
+ */ 
+
+int CVodeSensReInit(void *cvode_mem, int ism, N_Vector *yS0)
+{
+  CVodeMem    cv_mem;
+  int is;  
+
+  /* Check cvode_mem */
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSensReInit", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;
+
+  /* Was sensitivity initialized? */
+  if (cv_mem->cv_sensMallocDone == FALSE) {
+    CVProcessError(cv_mem, CV_NO_SENS, "CVODES", "CVodeSensReInit", MSGCV_NO_SENSI);
+    return(CV_NO_SENS);
+  } 
+
+  /* Check if ism is legal */
+  if ((ism!=CV_SIMULTANEOUS) && (ism!=CV_STAGGERED) && (ism!=CV_STAGGERED1)) {
+    CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSensReInit", MSGCV_BAD_ISM);
+    return(CV_ILL_INPUT);
+  }
+  cv_mem->cv_ism = ism;
+  
+  /* Check if yS0 is non-null */
+  if (yS0 == NULL) {
+    CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSensReInit", MSGCV_NULL_YS0);
+    return(CV_ILL_INPUT);
+  }  
+  
+  /* Allocate ncfS1, ncfnS1, and nniS1 if needed */
+  if ( (ism==CV_STAGGERED1) && (stgr1alloc==FALSE) ) {
+    stgr1alloc = TRUE;
+    ncfS1 = NULL;
+    ncfS1 = (int*)malloc(Ns*sizeof(int));
+    ncfnS1 = NULL;
+    ncfnS1 = (long int*)malloc(Ns*sizeof(long int));
+    nniS1 = NULL;
+    nniS1 = (long int*)malloc(Ns*sizeof(long int));
+    if ( (ncfS1==NULL) || (ncfnS1==NULL) || (nniS1==NULL) ) {
+      CVProcessError(cv_mem, CV_MEM_FAIL, "CVODES", "CVodeSensReInit", MSGCV_MEM_FAIL);
+      return(CV_MEM_FAIL);
+    }
+  }
+
+  /*---------------------------------------------- 
+    All error checking is complete at this point 
+    -----------------------------------------------*/
+
+  /* Initialize znS[0] in the history array */
+  for (is=0; is<Ns; is++) 
+    N_VScale(ONE, yS0[is], cv_mem->cv_znS[0][is]);
+
+  /* Initialize all sensitivity related counters */
+  cv_mem->cv_nfSe     = 0;
+  cv_mem->cv_nfeS     = 0;
+  cv_mem->cv_ncfnS    = 0;
+  cv_mem->cv_netfS    = 0;
+  cv_mem->cv_nniS     = 0;
+  cv_mem->cv_nsetupsS = 0;
+  if (ism==CV_STAGGERED1)
+    for (is=0; is<Ns; is++) {
+      ncfnS1[is] = 0;
+      nniS1[is] = 0;
+    }
+
+  /* Problem has been successfully re-initialized */
+  cv_mem->cv_sensi = TRUE;
+  return(CV_SUCCESS);
+}
+
+/*
+ * CVodeSensToggleOff
+ *
+ * CVodeSensToggleOff deactivates sensitivity calculations.
+ * It does NOT deallocate sensitivity-related memory.
+ */
+
+int CVodeSensToggleOff(void *cvode_mem)
+{
+  CVodeMem cv_mem;
+
+  /* Check cvode_mem */
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSensToggleOff", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;
+
+  /* Disable sensitivities */
+  cv_mem->cv_sensi = FALSE;
+
+  return(CV_SUCCESS);
+}
+
+/* 
+ * -----------------------------------------------------------------
+ * Readibility Constants
+ * -----------------------------------------------------------------
+ */
+
+#define f              (cv_mem->cv_f)      
+#define f_data         (cv_mem->cv_f_data) 
+#define efun           (cv_mem->cv_efun)
+#define e_data         (cv_mem->cv_e_data) 
+#define qmax           (cv_mem->cv_qmax)
+#define mxstep         (cv_mem->cv_mxstep)
+#define mxhnil         (cv_mem->cv_mxhnil)
+#define sldeton        (cv_mem->cv_sldeton)
+#define hin            (cv_mem->cv_hin)
+#define hmin           (cv_mem->cv_hmin)
+#define hmax_inv       (cv_mem->cv_hmax_inv)
+#define istop          (cv_mem->cv_istop)
+#define tstop          (cv_mem->cv_tstop)
+#define tstopset       (cv_mem->cv_tstopset)
+#define maxnef         (cv_mem->cv_maxnef)
+#define maxncf         (cv_mem->cv_maxncf)
+#define maxcor         (cv_mem->cv_maxcor)
+#define nlscoef        (cv_mem->cv_nlscoef)
+#define itol           (cv_mem->cv_itol)         
+#define reltol         (cv_mem->cv_reltol)       
+#define Sabstol        (cv_mem->cv_Sabstol) 
+#define Vabstol        (cv_mem->cv_Vabstol) 
+
+#define fQ             (cv_mem->cv_fQ)
+#define fQ_data        (cv_mem->cv_fQ_data)
+#define errconQ        (cv_mem->cv_errconQ)
+#define itolQ          (cv_mem->cv_itolQ)
+#define reltolQ        (cv_mem->cv_reltolQ)
+#define SabstolQ       (cv_mem->cv_SabstolQ)
+#define VabstolQ       (cv_mem->cv_VabstolQ)
+
+#define fS             (cv_mem->cv_fS)
+#define fS1            (cv_mem->cv_fS1)
+#define fS_data        (cv_mem->cv_fS_data)
+#define DQtype         (cv_mem->cv_DQtype)
+#define DQrhomax       (cv_mem->cv_DQrhomax)
+#define pbar           (cv_mem->cv_pbar)
+#define errconS        (cv_mem->cv_errconS)
+#define maxcorS        (cv_mem->cv_maxcorS)
+#define itolS          (cv_mem->cv_itolS)
+#define reltolS        (cv_mem->cv_reltolS)
+#define SabstolS       (cv_mem->cv_SabstolS)
+#define VabstolS       (cv_mem->cv_VabstolS)
+#define ism            (cv_mem->cv_ism)
+#define p              (cv_mem->cv_p)
+#define plist          (cv_mem->cv_plist)
+
+#define uround         (cv_mem->cv_uround)  
+#define zn             (cv_mem->cv_zn) 
+#define ewt            (cv_mem->cv_ewt)  
+#define y              (cv_mem->cv_y)
+#define acor           (cv_mem->cv_acor)
+#define tempv          (cv_mem->cv_tempv)
+#define ftemp          (cv_mem->cv_ftemp) 
+#define q              (cv_mem->cv_q)
+#define qprime         (cv_mem->cv_qprime)
+#define next_q         (cv_mem->cv_next_q)
+#define qwait          (cv_mem->cv_qwait)
+#define L              (cv_mem->cv_L)
+#define h              (cv_mem->cv_h)
+#define hprime         (cv_mem->cv_hprime)
+#define next_h         (cv_mem->cv_next_h)
+#define eta            (cv_mem->cv_eta) 
+#define etaqm1         (cv_mem->cv_etaqm1) 
+#define etaq           (cv_mem->cv_etaq) 
+#define etaqp1         (cv_mem->cv_etaqp1) 
+#define nscon          (cv_mem->cv_nscon)
+#define hscale         (cv_mem->cv_hscale)
+#define tn             (cv_mem->cv_tn)
+#define tau            (cv_mem->cv_tau)
+#define tq             (cv_mem->cv_tq)
+#define l              (cv_mem->cv_l)
+#define rl1            (cv_mem->cv_rl1)
+#define gamma          (cv_mem->cv_gamma) 
+#define gammap         (cv_mem->cv_gammap) 
+#define gamrat         (cv_mem->cv_gamrat)
+#define crate          (cv_mem->cv_crate)
+#define acnrm          (cv_mem->cv_acnrm)
+#define mnewt          (cv_mem->cv_mnewt)
+#define etamax         (cv_mem->cv_etamax)
+#define nst            (cv_mem->cv_nst)
+#define nfe            (cv_mem->cv_nfe)
+#define ncfn           (cv_mem->cv_ncfn)
+#define netf           (cv_mem->cv_netf)
+#define nni            (cv_mem->cv_nni)
+#define nsetups        (cv_mem->cv_nsetups)
+#define nhnil          (cv_mem->cv_nhnil)
+#define linit          (cv_mem->cv_linit)
+#define lsetup         (cv_mem->cv_lsetup)
+#define lsolve         (cv_mem->cv_lsolve) 
+#define lfree          (cv_mem->cv_lfree) 
+#define lmem           (cv_mem->cv_lmem) 
+#define qu             (cv_mem->cv_qu)          
+#define nstlp          (cv_mem->cv_nstlp)  
+#define h0u            (cv_mem->cv_h0u)
+#define hu             (cv_mem->cv_hu)         
+#define saved_tq5      (cv_mem->cv_saved_tq5)  
+#define indx_acor      (cv_mem->cv_indx_acor)
+#define jcur           (cv_mem->cv_jcur)         
+#define tolsf          (cv_mem->cv_tolsf)      
+#define setupNonNull   (cv_mem->cv_setupNonNull) 
+#define forceSetup     (cv_mem->cv_forceSetup)
+#define nor            (cv_mem->cv_nor)
+#define ssdat          (cv_mem->cv_ssdat)
+
+#define nrtfn          (cv_mem->cv_nrtfn)
+#define tlo            (cv_mem->cv_tlo)
+#define thi            (cv_mem->cv_thi)
+#define tretlast       (cv_mem->cv_tretlast)
+#define toutc          (cv_mem->cv_toutc)
+#define trout          (cv_mem->cv_trout)
+#define ttol           (cv_mem->cv_ttol)
+#define taskc          (cv_mem->cv_taskc)
+#define irfnd          (cv_mem->cv_irfnd)
+#define nge            (cv_mem->cv_nge)
+
+#define sensi          (cv_mem->cv_sensi)
+#define znS            (cv_mem->cv_znS)
+#define ewtS           (cv_mem->cv_ewtS)
+#define acorS          (cv_mem->cv_acorS)
+#define yS             (cv_mem->cv_yS)
+#define tempvS         (cv_mem->cv_tempvS)
+#define ftempS         (cv_mem->cv_ftempS)
+#define crateS         (cv_mem->cv_crateS)
+#define acnrmS         (cv_mem->cv_acnrmS)
+#define nfSe           (cv_mem->cv_nfSe)
+#define nfeS           (cv_mem->cv_nfeS)
+#define nniS           (cv_mem->cv_nniS)
+#define ncfnS          (cv_mem->cv_ncfnS)
+#define netfS          (cv_mem->cv_netfS)
+#define nsetupsS       (cv_mem->cv_nsetupsS)
+#define stgr1alloc     (cv_mem->cv_stgr1alloc)
+#define sensMallocDone (cv_mem->cv_sensMallocDone)
+
+#define quadr          (cv_mem->cv_quadr)
+#define znQ            (cv_mem->cv_znQ)
+#define ewtQ           (cv_mem->cv_ewtQ)
+#define acorQ          (cv_mem->cv_acorQ)
+#define yQ             (cv_mem->cv_yQ)
+#define tempvQ         (cv_mem->cv_tempvQ)
+#define acnrmQ         (cv_mem->cv_acnrmQ)
+#define nfQe           (cv_mem->cv_nfQe)
+#define netfQ          (cv_mem->cv_netfQ)
+#define quadMallocDone (cv_mem->cv_quadMallocDone)
+
+/* 
+ * -----------------------------------------------------------------
+ * Main solver function
+ * -----------------------------------------------------------------
+ */
+
+/*
+ * CVode
+ *
+ * This routine is the main driver of the CVODES package. 
+ *
+ * It integrates over a time interval defined by the user, by calling
+ * CVStep to do internal time steps.
+ *
+ * The first time that CVode is called for a successfully initialized
+ * problem, it computes a tentative initial step size h.
+ *
+ * CVode supports four modes, specified by itask: CV_NORMAL, CV_ONE_STEP,
+ * CV_NORMAL_TSTOP, and CV_ONE_STEP_TSTOP.
+ * In the CV_NORMAL mode, the solver steps until it reaches or passes tout
+ * and then interpolates to obtain y(tout).
+ * In the CV_ONE_STEP mode, it takes one internal step and returns.
+ * CV_NORMAL_TSTOP and CV_ONE_STEP_TSTOP are similar to CV_NORMAL and CV_ONE_STEP,
+ * respectively, but the integration never proceeds past tstop (which
+ * must have been defined through a call to CVodeSetStopTime).
+ */
+
+int CVode(void *cvode_mem, realtype tout, N_Vector yout, 
+          realtype *tret, int itask)
+{
+  CVodeMem cv_mem;
+  long int nstloc; 
+  int retval, hflag, kflag, istate, is, ier, task, irfndp;
+  realtype troundoff, rh, nrm;
+
+  /*
+   * -------------------------------------
+   * 1. Check and process inputs
+   * -------------------------------------
+   */
+
+  /* Check if cvode_mem exists */
+  if (cvode_mem == NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVode", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;
+
+  /* Check if cvode_mem was allocated */
+  if (cv_mem->cv_MallocDone == FALSE) {
+    CVProcessError(cv_mem, CV_NO_MALLOC, "CVODES", "CVode", MSGCV_NO_MALLOC);
+    return(CV_NO_MALLOC);
+  }
+  
+  /* Check for yout != NULL */
+  if ((y = yout) == NULL) {
+    CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVode", MSGCV_YOUT_NULL);
+    return(CV_ILL_INPUT);
+  }
+  
+  /* Check for tret != NULL */
+  if (tret == NULL) {
+    CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVode", MSGCV_TRET_NULL);
+    return(CV_ILL_INPUT);
+  }
+
+  /* Check for valid itask */
+  if ((itask != CV_NORMAL)       && 
+      (itask != CV_ONE_STEP)     &&
+      (itask != CV_NORMAL_TSTOP) &&
+      (itask != CV_ONE_STEP_TSTOP) ) {
+    CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVode", MSGCV_BAD_ITASK);
+    return(CV_ILL_INPUT);
+  }
+
+  /* Split itask into task and istop */
+  if ((itask == CV_NORMAL_TSTOP) || (itask == CV_ONE_STEP_TSTOP)) {
+    if ( tstopset == FALSE ) {
+      CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVode", MSGCV_NO_TSTOP);
+      return(CV_ILL_INPUT);
+    }
+    istop = TRUE;
+  } else {
+    istop = FALSE;
+  }
+  if ((itask == CV_NORMAL) || (itask == CV_NORMAL_TSTOP)) {
+    task = CV_NORMAL; toutc = tout;
+  } else {
+    task = CV_ONE_STEP;
+  }
+  taskc = task;
+
+
+  /* Sensitivity-specific tests */
+
+  if (sensi && fSDQ) {
+
+    /* If using internal DQ function for sensitivity RHS */
+
+    /* Set internal DQ functions */
+    fS  = CVSensRhsDQ;
+    fS1 = CVSensRhs1DQ;
+
+    /* Make sure we have the right 'user data' */
+    fS_data = cvode_mem;
+    
+    /* Test if we have the problem parameters */
+    if(p == NULL) {
+      CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVode", MSGCV_NULL_P);
+      return(CV_ILL_INPUT);
+    }
+
+    /* Set ifS to CV_ONESENS so that any method can be used */
+    ifS = CV_ONESENS;
+    
+  }
+
+  /*
+   * ----------------------------------------
+   * 2. Initializations performed only at
+   *    the first step (nst=0):
+   *    - initial setup
+   *    - initialize Nordsieck history array
+   *    - compute initial step size
+   *    - check for approach to tstop
+   *    - check for approach to a root
+   * ----------------------------------------
+   */
+
+  if (nst == 0) {
+
+    /* Check inputs for corectness */
+
+    ier = CVInitialSetup(cv_mem);
+    if (ier!= CV_SUCCESS) return(ier);
+
+    /* 
+       Call f at (t0,y0), set zn[1] = y'(t0). 
+       If computing any quadratures, call fQ at (t0,y0), set znQ[1] = yQ'(t0)
+       If computing sensitivities, call fS at (t0,y0,yS0), set znS[1][is] = yS'(t0), is=1,...,Ns.
+    */
+
+    retval = f(tn, zn[0], zn[1], f_data); 
+    nfe++;
+    if (retval < 0) {
+      CVProcessError(cv_mem, CV_RHSFUNC_FAIL, "CVODES", "CVode", MSGCV_RHSFUNC_FAILED, tn);
+      return(CV_RHSFUNC_FAIL);
+    }
+    if (retval > 0) {
+      CVProcessError(cv_mem, CV_FIRST_RHSFUNC_ERR, "CVODES", "CVode", MSGCV_RHSFUNC_FIRST);
+      return(CV_FIRST_RHSFUNC_ERR);
+    }
+
+    if (quadr) {
+      retval = fQ(tn, zn[0], znQ[1], fQ_data);
+      nfQe++;
+      if (retval < 0) {
+        CVProcessError(cv_mem, CV_QRHSFUNC_FAIL, "CVODES", "CVode", MSGCV_QRHSFUNC_FAILED, tn);
+        return(CV_QRHSFUNC_FAIL);
+      }
+      if (retval > 0) {
+        CVProcessError(cv_mem, CV_FIRST_QRHSFUNC_ERR, "CVODES", "CVode", MSGCV_QRHSFUNC_FIRST);
+        return(CV_FIRST_QRHSFUNC_ERR);
+      }
+    }
+
+    if (sensi) {
+      retval = CVSensRhs(cv_mem, tn, zn[0], zn[1], znS[0], znS[1], tempv, ftemp);
+      if (retval < 0) {
+        CVProcessError(cv_mem, CV_SRHSFUNC_FAIL, "CVODES", "CVSensRhs", MSGCV_SRHSFUNC_FAILED, tn);
+        return(CV_SRHSFUNC_FAIL);
+      } 
+      if (retval > 0) {
+        CVProcessError(cv_mem, CV_FIRST_SRHSFUNC_ERR, "CVODES", "CVSensRhs", MSGCV_SRHSFUNC_FIRST);
+        return(CV_FIRST_SRHSFUNC_ERR);
+      }
+    }
+
+    /* Set initial h (from H0 or CVHin). */
+    
+    h = hin;
+    if ( (h != ZERO) && ((tout-tn)*h < ZERO) ) {
+      CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVode", MSGCV_BAD_H0);
+      return(CV_ILL_INPUT);
+    }
+    if (h == ZERO) {
+      hflag = CVHin(cv_mem, tout);
+      if (hflag != CV_SUCCESS) {
+        istate = CVHandleFailure(cv_mem, hflag);
+        return(istate);
+      }
+    }
+    rh = ABS(h)*hmax_inv;
+    if (rh > ONE) h /= rh;
+    if (ABS(h) < hmin) h *= hmin/ABS(h);
+
+    /* Check for approach to tstop */
+
+    if (istop) {
+      if ( (tstop - tn)*h < ZERO ) {
+        CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVode", MSGCV_BAD_TSTOP, tn);
+        return(CV_ILL_INPUT);
+      }
+      if ( (tn + h - tstop)*h > ZERO ) 
+        h = (tstop - tn)*(ONE-FOUR*uround);
+    }
+
+    /* 
+       Scale zn[1] by h.
+       If computing any quadratures, scale znQ[1] by h.
+       If computing sensitivities,  scale znS[1][is] by h. 
+    */
+
+    hscale = h;
+    h0u    = h;
+    hprime = h;
+
+    N_VScale(h, zn[1], zn[1]);
+    
+    if (sensi)
+      for (is=0; is<Ns; is++) 
+        N_VScale(h, znS[1][is], znS[1][is]);
+    
+    if (quadr)
+      N_VScale(h, znQ[1], znQ[1]);
+
+    /* Check for zeros of root function g at and near t0. */
+
+    if (nrtfn > 0) {
+
+      retval = CVRcheck1(cv_mem);
+
+      if (retval == INITROOT) {
+        CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVRcheck1", MSGCV_BAD_INIT_ROOT);
+        return(CV_ILL_INPUT);
+      } else if (retval == CV_RTFUNC_FAIL) {
+        CVProcessError(cv_mem, CV_RTFUNC_FAIL, "CVODES", "CVRcheck1", MSGCV_RTFUNC_FAILED, tn);
+        return(CV_RTFUNC_FAIL);
+      }
+
+    }
+
+  } /* end first call block */
+
+  /*
+   * ------------------------------------------------------
+   * 3. At following steps, perform stop tests:
+   *    - check for root in last step
+   *    - check if we passed tstop
+   *    - check if we passed tout (NORMAL mode)
+   *    - check if current tn was returned (ONE_STEP mode)
+   *    - check if we are close to tstop
+   *      (adjust step size if needed)
+   * -------------------------------------------------------
+   */
+
+  if (nst > 0) {
+
+    /* Estimate an infinitesimal time interval to be used as
+       a roundoff for time quantities (based on current time 
+       and step size) */
+    troundoff = FUZZ_FACTOR*uround*(ABS(tn) + ABS(h));
+
+    /* First check for a root in the last step taken, other than the
+       last root found, if any.  If task = CV_ONE_STEP and y(tn) was not
+       returned because of an intervening root, return y(tn) now.     */
+    if (nrtfn > 0) {
+      
+      irfndp = irfnd;
+      
+      retval = CVRcheck2(cv_mem);
+
+      if (retval == CLOSERT) {
+        CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVRcheck2", MSGCV_CLOSE_ROOTS, tlo);
+        return(CV_ILL_INPUT);
+      } else if (retval == CV_RTFUNC_FAIL) {
+        CVProcessError(cv_mem, CV_RTFUNC_FAIL, "CVODES", "CVRcheck2", MSGCV_RTFUNC_FAILED, tlo);
+        return(CV_RTFUNC_FAIL);
+      } else if (retval == RTFOUND) {
+        tretlast = *tret = tlo;
+        return(CV_ROOT_RETURN);
+      }
+      
+      /* If tn is distinct from tretlast (within roundoff),
+         check remaining interval for roots */
+      if ( ABS(tn - tretlast) > troundoff ) {
+
+        retval = CVRcheck3(cv_mem);
+
+        if (retval == CV_SUCCESS) {     /* no root found */
+          irfnd = 0;
+          if ((irfndp == 1) && (task == CV_ONE_STEP)) {
+            tretlast = *tret = tn;
+            N_VScale(ONE, zn[0], yout);
+            return(CV_SUCCESS);
+          }
+        } else if (retval == RTFOUND) {  /* a new root was found */
+          irfnd = 1;
+          tretlast = *tret = tlo;
+          return(CV_ROOT_RETURN);
+        } else if (retval == CV_RTFUNC_FAIL) {  /* g failed */
+          CVProcessError(cv_mem, CV_RTFUNC_FAIL, "CVODES", "CVRcheck3", MSGCV_RTFUNC_FAILED, tlo);
+          return(CV_RTFUNC_FAIL);
+        }
+
+      }
+      
+    } /* end of root stop check */
+    
+    /* Test for tn past tstop */
+    if ( istop && ((tstop - tn)*h < ZERO) ) {
+      CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVode", MSGCV_BAD_TSTOP, tn);
+      return(CV_ILL_INPUT);
+    }
+    
+    /* In CV_NORMAL mode, test if tout was reached */
+    if ( (task == CV_NORMAL) && ((tn-tout)*h >= ZERO) ) {
+      tretlast = *tret = tout;
+      ier =  CVodeGetDky(cv_mem, tout, 0, yout);
+      if (ier != CV_SUCCESS) {
+        CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVode", MSGCV_BAD_TOUT, tout);
+        return(CV_ILL_INPUT);
+      }
+      return(CV_SUCCESS);
+    }
+    
+    /* In CV_ONE_STEP mode, test if tn was returned */
+    if ( task == CV_ONE_STEP && ABS(tn - tretlast) > troundoff ) {
+      tretlast = *tret = tn;
+      N_VScale(ONE, zn[0], yout);
+      return(CV_SUCCESS);
+    }
+    
+    /* Test for tn at tstop or near tstop */
+    if ( istop ) {
+      
+      if ( ABS(tn - tstop) <= troundoff ) {
+        ier =  CVodeGetDky(cv_mem, tstop, 0, yout);
+        if (ier != CV_SUCCESS) {
+          CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVode", MSGCV_BAD_TSTOP, tn);
+          return(CV_ILL_INPUT);
+        }
+        tretlast = *tret = tstop;
+        return(CV_TSTOP_RETURN);
+      }
+      
+      /* If next step would overtake tstop, adjust stepsize */
+      if ( (tn + hprime - tstop)*h > ZERO ) {
+        hprime = (tstop - tn)*(ONE-FOUR*uround);
+        eta = hprime/h;
+      }
+      
+    } /* end of istop tests block */
+    
+  } /* end stopping tests block at nst>0 */  
+  
+  /*
+   * --------------------------------------------------
+   * 4. Looping point for internal steps
+   *
+   *    4.1. check for errors (too many steps, too much
+   *         accuracy requested, step size too small)
+   *    4.2. take a new step (call CVStep)
+   *    4.3. stop on error 
+   *    4.4. perform stop tests:
+   *         - check for root in last step
+   *         - check if tout was passed
+   *         - check if close to tstop
+   *         - check if in ONE_STEP mode (must return)
+   * --------------------------------------------------
+   */  
+  
+  nstloc = 0;
+  loop {
+   
+    next_h = h;
+    next_q = q;
+    
+    /* Reset and check ewt, ewtQ, ewtS */   
+    if (nst > 0) {
+
+      ier = efun(zn[0], ewt, e_data);
+      if(ier != 0) {
+        if (itol == CV_WF) CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVode", MSGCV_EWT_NOW_FAIL, tn);
+        else               CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVode", MSGCV_EWT_NOW_BAD, tn);
+        istate = CV_ILL_INPUT;
+        tretlast = *tret = tn;
+        N_VScale(ONE, zn[0], yout);
+        break;
+      }
+
+      if (quadr && errconQ) {
+        ier = CVQuadEwtSet(cv_mem, znQ[0], ewtQ);
+        if(ier != 0) {
+          CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVode", MSGCV_EWTQ_NOW_BAD, tn);
+          istate = CV_ILL_INPUT;
+          tretlast = *tret = tn;
+          N_VScale(ONE, zn[0], yout);
+          break;
+        }
+      }
+
+      if (sensi) {
+        ier = CVSensEwtSet(cv_mem, znS[0], ewtS);
+        if (ier != 0) {
+          CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVode", MSGCV_EWTS_NOW_BAD, tn);
+          istate = CV_ILL_INPUT;
+          tretlast = *tret = tn;
+          N_VScale(ONE, zn[0], yout);
+          break;
+        }
+      }
+
+    }
+
+    /* Check for too many steps */
+    if (nstloc >= mxstep) {
+      CVProcessError(cv_mem, CV_TOO_MUCH_WORK, "CVODES", "CVode", MSGCV_MAX_STEPS, tn);
+      istate = CV_TOO_MUCH_WORK;
+      tretlast = *tret = tn;
+      N_VScale(ONE, zn[0], yout);
+      break;
+    }
+
+    /* Check for too much accuracy requested */
+    nrm = N_VWrmsNorm(zn[0], ewt);
+    if (quadr && errconQ) {
+      nrm = CVQuadUpdateNorm(cv_mem, nrm, znQ[0], ewtQ); 
+    }
+    if (sensi && errconS) {
+      nrm = CVSensUpdateNorm(cv_mem, nrm, znS[0], ewtS);
+    }
+    tolsf = uround * nrm;
+    if (tolsf > ONE) {
+      CVProcessError(cv_mem, CV_TOO_MUCH_ACC, "CVODES", "CVode", MSGCV_TOO_MUCH_ACC, tn);
+      istate = CV_TOO_MUCH_ACC;
+      tretlast = *tret = tn;
+      N_VScale(ONE, zn[0], yout);
+      tolsf *= TWO;
+      break;
+    } else {
+      tolsf = ONE;
+    }
+    
+    /* Check for h below roundoff level in tn */
+    if (tn + h == tn) {
+      nhnil++;
+      if (nhnil <= mxhnil) 
+        CVProcessError(cv_mem, CV_WARNING, "CVODES", "CVode", MSGCV_HNIL, tn, h);
+      if (nhnil == mxhnil) 
+        CVProcessError(cv_mem, CV_WARNING, "CVODES", "CVode", MSGCV_HNIL_DONE);
+    }
+
+    /* Call CVStep to take a step */
+    kflag = CVStep(cv_mem);
+
+    /* Process failed step cases, and exit loop */
+    if (kflag != CV_SUCCESS) {
+      istate = CVHandleFailure(cv_mem, kflag);
+      tretlast = *tret = tn;
+      N_VScale(ONE, zn[0], yout);
+      break;
+    }
+    
+    nstloc++;
+
+    /* Check for root in last step taken. */    
+    if (nrtfn > 0) {
+      
+      retval = CVRcheck3(cv_mem);
+      
+      if (retval == RTFOUND) {  /* A new root was found */
+        irfnd = 1;
+        istate = CV_ROOT_RETURN;
+        tretlast = *tret = tlo;
+        break;
+      } else if (retval == CV_RTFUNC_FAIL) { /* g failed */
+        CVProcessError(cv_mem, CV_RTFUNC_FAIL, "CVODES", "CVRcheck3", MSGCV_RTFUNC_FAILED, tlo);
+        istate = CV_RTFUNC_FAIL;
+        break;
+      }
+
+    }
+
+    /* In NORMAL mode, check if tout reached */
+    if ( (task == CV_NORMAL) &&  (tn-tout)*h >= ZERO ) {
+      istate = CV_SUCCESS;
+      tretlast = *tret = tout;
+      (void) CVodeGetDky(cv_mem, tout, 0, yout);
+      next_q = qprime;
+      next_h = hprime;
+      break;
+    }
+
+    /* Check if tn is at tstop or near tstop */
+    if ( istop ) {
+
+      troundoff = FUZZ_FACTOR*uround*(ABS(tn) + ABS(h));
+      if ( ABS(tn - tstop) <= troundoff) {
+        (void) CVodeGetDky(cv_mem, tstop, 0, yout);
+        tretlast = *tret = tstop;
+        istate = CV_TSTOP_RETURN;
+        break;
+      }
+
+      if ( (tn + hprime - tstop)*h > ZERO ) {
+        hprime = (tstop - tn)*(ONE-FOUR*uround);
+        eta = hprime/h;
+      }
+
+    }
+
+    /* In ONE_STEP mode, copy y and exit loop */
+    if (task == CV_ONE_STEP) {
+      istate = CV_SUCCESS;
+      tretlast = *tret = tn;
+      N_VScale(ONE, zn[0], yout);
+      next_q = qprime;
+      next_h = hprime;
+      break;
+    }
+
+  } /* end looping for internal steps */
+  
+  /* Load optional output */
+  if (sensi && (ism==CV_STAGGERED1)) { 
+    nniS  = 0;
+    ncfnS = 0;
+    for (is=0; is<Ns; is++) {
+      nniS  += nniS1[is];
+      ncfnS += ncfnS1[is];
+    }
+  }
+  
+  return(istate);
+
+}
+
+/* 
+ * -----------------------------------------------------------------
+ * Interpolated output and extraction functions
+ * -----------------------------------------------------------------
+ */
+
+/*
+ * CVodeGetDky
+ *
+ * This routine computes the k-th derivative of the interpolating
+ * polynomial at the time t and stores the result in the vector dky.
+ * The formula is:
+ *         q 
+ *  dky = SUM c(j,k) * (t - tn)^(j-k) * h^(-j) * zn[j] , 
+ *        j=k 
+ * where c(j,k) = j*(j-1)*...*(j-k+1), q is the current order, and
+ * zn[j] is the j-th column of the Nordsieck history array.
+ *
+ * This function is called by CVode with k = 0 and t = tout, but
+ * may also be called directly by the user.
+ */
+
+int CVodeGetDky(void *cvode_mem, realtype t, int k, N_Vector dky)
+{
+  realtype s, c, r;
+  realtype tfuzz, tp, tn1;
+  int i, j;
+  CVodeMem cv_mem;
+  
+  /* Check all inputs for legality */
+ 
+  if (cvode_mem == NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetDky", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (dky == NULL) {
+    CVProcessError(cv_mem, CV_BAD_DKY, "CVODES", "CVodeGetDky", MSGCV_NULL_DKY);
+    return(CV_BAD_DKY);
+  }
+
+  if ((k < 0) || (k > q)) {
+    CVProcessError(cv_mem, CV_BAD_K, "CVODES", "CVodeGetDky", MSGCV_BAD_K);
+    return(CV_BAD_K);
+  }
+  
+  /* Allow for some slack */
+  tfuzz = FUZZ_FACTOR * uround * (ABS(tn) + ABS(hu));
+  if (hu < ZERO) tfuzz = -tfuzz;
+  tp = tn - hu - tfuzz;
+  tn1 = tn + tfuzz;
+  if ((t-tp)*(t-tn1) > ZERO) {
+    CVProcessError(cv_mem, CV_BAD_T, "CVODES", "CVodeGetDky", MSGCV_BAD_T, t, tn-hu, tn);
+    return(CV_BAD_T);
+  }
+
+  /* Sum the differentiated interpolating polynomial */
+
+  s = (t - tn) / h;
+  for (j=q; j >= k; j--) {
+    c = ONE;
+    for (i=j; i >= j-k+1; i--) c *= i;
+    if (j == q) {
+      N_VScale(c, zn[q], dky);
+    } else {
+      N_VLinearSum(c, zn[j], s, dky, dky);
+    }
+  }
+  if (k == 0) return(CV_SUCCESS);
+  r = RPowerI(h,-k);
+  N_VScale(r, dky, dky);
+  return(CV_SUCCESS);
+}
+
+/* 
+ * CVodeGetQuad
+ *
+ * This routine extracts quadrature solution into yQout.
+ * This is just a wrapper that calls CVodeGetQuadDky with k=0                    
+ */
+ 
+int CVodeGetQuad(void *cvode_mem, realtype t, N_Vector yQout)
+{
+  return(CVodeGetQuadDky(cvode_mem,t,0,yQout));
+}
+
+/*
+ * CVodeGetQuadDky
+ *
+ * CVodeQuadDky computes the kth derivative of the yQ function at
+ * time t, where tn-hu <= t <= tn, tn denotes the current         
+ * internal time reached, and hu is the last internal step size   
+ * successfully used by the solver. The user may request 
+ * k=0, 1, ..., qu, where qu is the current order. 
+ * The derivative vector is returned in dky. This vector 
+ * must be allocated by the caller. It is only legal to call this         
+ * function after a successful return from CVode with quadrature
+ * computation enabled.
+ */
+
+int CVodeGetQuadDky(void *cvode_mem, realtype t, int k, N_Vector dkyQ)
+{ 
+  realtype s, c, r;
+  realtype tfuzz, tp, tn1;
+  int i, j;
+  CVodeMem cv_mem;
+  
+  /* Check all inputs for legality */
+  
+  if (cvode_mem == NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetQuadDky", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;  
+
+  if(quadr != TRUE) {
+    CVProcessError(cv_mem, CV_NO_QUAD, "CVODES", "CVodeGetQuadDky", MSGCV_NO_QUAD);
+    return(CV_NO_QUAD);
+  }
+
+  if (dkyQ == NULL) {
+    CVProcessError(cv_mem, CV_BAD_DKY, "CVODES", "CVodeGetQuadDky", MSGCV_NULL_DKY);
+    return(CV_BAD_DKY);
+  }
+  
+  if ((k < 0) || (k > q)) {
+    CVProcessError(cv_mem, CV_BAD_K, "CVODES", "CVodeGetQuadDky", MSGCV_BAD_K);
+    return(CV_BAD_K);
+  }
+  
+  /* Allow for some slack */
+  tfuzz = FUZZ_FACTOR * uround * (ABS(tn) + ABS(hu));
+  if (hu < ZERO) tfuzz = -tfuzz;
+  tp = tn - hu - tfuzz;
+  tn1 = tn + tfuzz;
+  if ((t-tp)*(t-tn1) > ZERO) {
+    CVProcessError(cv_mem, CV_BAD_T, "CVODES", "CVodeGetQuadDky", MSGCV_BAD_T);
+    return(CV_BAD_T);
+  }
+  
+  /* Sum the differentiated interpolating polynomial */
+  
+  s = (t - tn) / h;
+  for (j=q; j >= k; j--) {
+    c = ONE;
+    for (i=j; i >= j-k+1; i--) c *= i;
+    if (j == q) {
+      N_VScale(c, znQ[q], dkyQ);
+    } else {
+      N_VLinearSum(c, znQ[j], s, dkyQ, dkyQ);
+    }
+  }
+  if (k == 0) return(CV_SUCCESS);
+  r = RPowerI(h,-k);
+  N_VScale(r, dkyQ, dkyQ);
+  return(CV_SUCCESS);
+  
+}
+
+/* 
+ * CVodeGetSens
+ *
+ * This routine extracts sensitivity solution into ySout.
+ * This is just a wrapper that calls CVodeSensDky with k=0                    
+ */
+ 
+int CVodeGetSens(void *cvode_mem, realtype t, N_Vector *ySout)
+{
+  return(CVodeGetSensDky(cvode_mem,t,0,ySout));
+}
+    
+/* 
+ * CVodeGetSens1
+ *
+ * This routine extracts the is-th sensitivity solution into ySout.
+ * This is just a wrapper that calls CVodeSensDky1 with k=0                    
+ */
+ 
+int CVodeGetSens1(void *cvode_mem, realtype t, int is, N_Vector ySout)
+{
+  return(CVodeGetSensDky1(cvode_mem,t,0,is,ySout));
+}
+    
+/*
+ * CVodeGetSensDky
+ *
+ * If the user calls directly CVodeSensDky then s must be allocated
+ * prior to this call. When CVodeSensDky is called by 
+ * CVodeGetSens, only ier=CV_SUCCESS, ier=CV_NO_SENS, or 
+ * ier=CV_BAD_T are possible.
+ */
+
+int CVodeGetSensDky(void *cvode_mem, realtype t, int k, N_Vector *dkyS)
+{
+  int ier=CV_SUCCESS;
+  int is;
+  CVodeMem cv_mem;
+  
+  if (cvode_mem == NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetSensDky", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;  
+  
+  if (dkyS == NULL) {
+    CVProcessError(cv_mem, CV_BAD_DKY, "CVODES", "CVodeGetSensDky", MSGCV_NULL_DKYA);
+    return(CV_BAD_DKY);
+  }
+  
+  for (is=0; is<Ns; is++) {
+    ier = CVodeGetSensDky1(cvode_mem,t,k,is,dkyS[is]);
+    if (ier!=CV_SUCCESS) break;
+  }
+  
+  return(ier);
+}
+    
+/*
+ * CVodeGetSensDky1
+ *
+ * CVodeSensDky1 computes the kth derivative of the yS[is] function at
+ * time t, where tn-hu <= t <= tn, tn denotes the current         
+ * internal time reached, and hu is the last internal step size   
+ * successfully used by the solver. The user may request 
+ * is=0, 1, ..., Ns-1 and k=0, 1, ..., qu, where qu is the current
+ * order. The derivative vector is returned in dky. This vector 
+ * must be allocated by the caller. It is only legal to call this         
+ * function after a successful return from CVode with sensitivity 
+ * computation enabled.
+ */
+
+int CVodeGetSensDky1(void *cvode_mem, realtype t, int k, int is, N_Vector dkyS)
+{ 
+  realtype s, c, r;
+  realtype tfuzz, tp, tn1;
+  int i, j;
+  CVodeMem cv_mem;
+  
+  /* Check all inputs for legality */
+  
+  if (cvode_mem == NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetSensDky1", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;  
+  
+  if(sensi != TRUE) {
+    CVProcessError(cv_mem, CV_NO_SENS, "CVODES", "CVodeGetSensDky1", MSGCV_NO_SENSI);
+    return(CV_NO_SENS);
+  }
+
+  if (dkyS == NULL) {
+    CVProcessError(cv_mem, CV_BAD_DKY, "CVODES", "CVodeGetSensDky1", MSGCV_NULL_DKY);
+    return(CV_BAD_DKY);
+  }
+  
+  if ((k < 0) || (k > q)) {
+    CVProcessError(cv_mem, CV_BAD_K, "CVODES", "CVodeGetSensDky1", MSGCV_BAD_K);
+    return(CV_BAD_K);
+  }
+  
+  if ((is < 0) || (is > Ns-1)) {
+    CVProcessError(cv_mem, CV_BAD_IS, "CVODES", "CVodeGetSensDky1", MSGCV_BAD_IS);
+    return(CV_BAD_IS);
+  }
+  
+  /* Allow for some slack */
+  tfuzz = FUZZ_FACTOR * uround * (ABS(tn) + ABS(hu));
+  if (hu < ZERO) tfuzz = -tfuzz;
+  tp = tn - hu - tfuzz;
+  tn1 = tn + tfuzz;
+  if ((t-tp)*(t-tn1) > ZERO) {
+    CVProcessError(cv_mem, CV_BAD_T, "CVODES", "CVodeGetSensDky1", MSGCV_BAD_T);
+    return(CV_BAD_T);
+  }
+  
+  /* Sum the differentiated interpolating polynomial */
+  
+  s = (t - tn) / h;
+  for (j=q; j >= k; j--) {
+    c = ONE;
+    for (i=j; i >= j-k+1; i--) c *= i;
+    if (j == q) {
+      N_VScale(c, znS[q][is], dkyS);
+    } else {
+      N_VLinearSum(c, znS[j][is], s, dkyS, dkyS);
+    }
+  }
+  if (k == 0) return(CV_SUCCESS);
+  r = RPowerI(h,-k);
+  N_VScale(r, dkyS, dkyS);
+  return(CV_SUCCESS);
+  
+}
+
+/* 
+ * -----------------------------------------------------------------
+ * Deallocation functions
+ * -----------------------------------------------------------------
+ */
+
+/*
+ * CVodeFree
+ *
+ * This routine frees the problem memory allocated by CVodeMalloc.
+ * Such memory includes all the vectors allocated by CVAllocVectors,
+ * and the memory lmem for the linear solver (deallocated by a call
+ * to lfree), as well as (if Ns!=0) all memory allocated for 
+ * sensitivity computations by CVodeSensMalloc.
+ */
+
+void CVodeFree(void **cvode_mem)
+{
+  CVodeMem cv_mem;
+
+  if (*cvode_mem == NULL) return;
+
+  cv_mem = (CVodeMem) (*cvode_mem);
+  
+  CVFreeVectors(cv_mem);
+
+  CVodeQuadFree(cv_mem);
+
+  CVodeSensFree(cv_mem);
+
+  if (iter == CV_NEWTON && lfree != NULL) lfree(cv_mem);
+
+  if (nrtfn > 0) {
+    free(glo); glo = NULL; 
+    free(ghi);  ghi = NULL;
+    free(grout);  grout = NULL;
+    free(iroots); iroots = NULL;
+  }
+
+  free(*cvode_mem);
+  *cvode_mem = NULL;
+}
+
+/*
+ * CVodeQuadFree
+ *
+ * CVodeQuadFree frees the problem memory in cvode_mem allocated
+ * for quadrature integration. Its only argument is the pointer
+ * cvode_mem returned by CVodeCreate. 
+ */
+
+void CVodeQuadFree(void *cvode_mem)
+{
+  CVodeMem cv_mem;
+  
+  if (cvode_mem == NULL) return;
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if(quadMallocDone) {
+    CVQuadFreeVectors(cv_mem);
+    quadMallocDone = FALSE;
+    quadr = FALSE;
+  }
+}
+
+/*
+ * CVodeSensFree
+ *
+ * CVodeSensFree frees the problem memory in cvode_mem allocated
+ * for sensitivity analysis. Its only argument is the pointer
+ * cvode_mem returned by CVodeCreate. 
+ */
+
+void CVodeSensFree(void *cvode_mem)
+{
+  CVodeMem cv_mem;
+  
+  if (cvode_mem == NULL) return;
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if(sensMallocDone) {
+    if (stgr1alloc) {
+      free(ncfS1); ncfS1 = NULL;
+      free(ncfnS1); ncfnS1 = NULL;
+      free(nniS1); nniS1 = NULL;
+      stgr1alloc = FALSE;
+    }
+    CVSensFreeVectors(cv_mem);
+    sensMallocDone = FALSE;
+    sensi = FALSE;
+  }
+}
+
+/* 
+ * =================================================================
+ * PRIVATE FUNCTIONS
+ * =================================================================
+ */
+
+/*
+ * CVCheckNvector
+ * This routine checks if all required vector operations are present.
+ * If any of them is missing it returns FALSE.
+ */
+
+static booleantype CVCheckNvector(N_Vector tmpl)
+{
+  if((tmpl->ops->nvclone     == NULL) ||
+     (tmpl->ops->nvdestroy   == NULL) ||
+     (tmpl->ops->nvlinearsum == NULL) ||
+     (tmpl->ops->nvconst     == NULL) ||
+     (tmpl->ops->nvprod      == NULL) ||
+     (tmpl->ops->nvdiv       == NULL) ||
+     (tmpl->ops->nvscale     == NULL) ||
+     (tmpl->ops->nvabs       == NULL) ||
+     (tmpl->ops->nvinv       == NULL) ||
+     (tmpl->ops->nvaddconst  == NULL) ||
+     (tmpl->ops->nvmaxnorm   == NULL) ||
+     (tmpl->ops->nvwrmsnorm  == NULL) ||
+     (tmpl->ops->nvmin       == NULL))
+    return(FALSE);
+  else
+    return(TRUE);
+}
+
+/* 
+ * -----------------------------------------------------------------
+ * Memory allocation/deallocation
+ * -----------------------------------------------------------------
+ */
+
+/*
+ * CVAllocVectors
+ *
+ * This routine allocates the CVODES vectors ewt, acor, tempv, ftemp, and
+ * zn[0], ..., zn[maxord]. If itol=CV_SV, it also allocates space for Vabstol.
+ * If all memory allocations are successful, CVAllocVectors returns TRUE. 
+ * Otherwise all allocated memory is freed and CVAllocVectors returns FALSE.
+ * This routine also sets the optional outputs lrw and liw, which are
+ * (respectively) the lengths of the real and integer work spaces
+ * allocated here.
+ */
+
+static booleantype CVAllocVectors(CVodeMem cv_mem, N_Vector tmpl, int tol)
+{
+  int i, j;
+
+  /* Allocate ewt, acor, tempv, ftemp */
+  
+  ewt = NULL;
+  ewt = N_VClone(tmpl);
+  if (ewt == NULL) return(FALSE);
+
+  acor = NULL;
+  acor = N_VClone(tmpl);
+  if (acor == NULL) {
+    N_VDestroy(ewt);
+    return(FALSE);
+  }
+
+  tempv = NULL;
+  tempv = N_VClone(tmpl);
+  if (tempv == NULL) {
+    N_VDestroy(ewt);
+    N_VDestroy(acor);
+    return(FALSE);
+  }
+
+  ftemp = NULL;
+  ftemp = N_VClone(tmpl);
+  if (ftemp == NULL) {
+    N_VDestroy(tempv);
+    N_VDestroy(ewt);
+    N_VDestroy(acor);
+    return(FALSE);
+  }
+
+  /* Allocate zn[0] ... zn[qmax] */
+
+  for (j=0; j <= qmax; j++) {
+    zn[j] = NULL;
+    zn[j] = N_VClone(tmpl);
+    if (zn[j] == NULL) {
+      N_VDestroy(ewt);
+      N_VDestroy(acor);
+      N_VDestroy(tempv);
+      N_VDestroy(ftemp);
+      for (i=0; i < j; i++) N_VDestroy(zn[i]);
+      return(FALSE);
+    }
+  }
+
+  /* Update solver workspace lengths  */
+  lrw += (qmax + 5)*lrw1;
+  liw += (qmax + 5)*liw1;
+
+  if (tol == CV_SV) {
+    Vabstol = NULL;
+    Vabstol = N_VClone(tmpl);
+    if (Vabstol == NULL) {
+      N_VDestroy(ewt);
+      N_VDestroy(acor);
+      N_VDestroy(tempv);
+      N_VDestroy(ftemp);
+      for (i=0; i <= qmax; i++) N_VDestroy(zn[i]);
+      return(FALSE);
+    }
+    lrw += lrw1;
+    liw += liw1;
+    cv_mem->cv_VabstolMallocDone = TRUE;
+  }  
+
+  /* Store the value of qmax used here */
+  cv_mem->cv_qmax_alloc = qmax;
+
+  return(TRUE);
+}
+
+/*  
+ * CVFreeVectors
+ *
+ * This routine frees the CVODES vectors allocated in CVAllocVectors.
+ */
+
+static void CVFreeVectors(CVodeMem cv_mem)
+{
+  int j, maxord;
+  
+  maxord = cv_mem->cv_qmax_alloc;
+
+  N_VDestroy(ewt);
+  N_VDestroy(acor);
+  N_VDestroy(tempv);
+  N_VDestroy(ftemp);
+  for (j=0; j <= maxord; j++) 
+    N_VDestroy(zn[j]);
+
+  lrw -= (maxord + 5)*lrw1;
+  liw -= (maxord + 5)*liw1;
+
+  if (cv_mem->cv_VabstolMallocDone) {
+    N_VDestroy(Vabstol);
+    lrw -= lrw1;
+    liw -= liw1;
+  }
+}
+
+/*
+ * CVodeQuadAllocVectors
+ *
+ * NOTE: Space for ewtQ is allocated even when errconQ=FALSE, 
+ * although in this case, ewtQ is never used. The reason for this
+ * decision is to allow the user to re-initialize the quadrature
+ * computation with errconQ=TRUE, after an initialization with
+ * errconQ=FALSE, without new memory allocation within 
+ * CVodeQuadReInit.
+ */
+
+static booleantype CVQuadAllocVectors(CVodeMem cv_mem, N_Vector tmpl) 
+{
+  int i, j;
+
+  /* Allocate ewtQ */
+  ewtQ = NULL;
+  ewtQ = N_VClone(tmpl);
+  if (ewtQ == NULL) {
+    return(FALSE);
+  }
+  
+  /* Allocate acorQ */
+  acorQ = NULL;
+  acorQ = N_VClone(tmpl);
+  if (acorQ == NULL) {
+    N_VDestroy(ewtQ);
+    return(FALSE);
+  }
+
+  /* Allocate yQ */
+  yQ = NULL;
+  yQ = N_VClone(tmpl);
+  if (yQ == NULL) {
+    N_VDestroy(ewtQ);
+    N_VDestroy(acorQ);
+    return(FALSE);
+  }
+
+  /* Allocate tempvQ */
+  tempvQ = NULL;
+  tempvQ = N_VClone(tmpl);
+  if (tempvQ == NULL) {
+    N_VDestroy(ewtQ);
+    N_VDestroy(acorQ);
+    N_VDestroy(yQ);
+    return(FALSE);
+  }
+
+  /* Allocate zQn[0] ... zQn[maxord] */
+
+  for (j=0; j <= qmax; j++) {
+    znQ[j] = NULL;
+    znQ[j] = N_VClone(tmpl);
+    if (znQ[j] == NULL) {
+      N_VDestroy(ewtQ);
+      N_VDestroy(acorQ);
+      N_VDestroy(yQ);
+      N_VDestroy(tempvQ);
+      for (i=0; i < j; i++) N_VDestroy(znQ[i]);
+      return(FALSE);
+    }
+  }
+
+  /* Store the value of qmax used here */
+  cv_mem->cv_qmax_allocQ = qmax;
+
+  /* Update solver workspace lengths */
+  lrw += (qmax + 5)*lrw1Q;
+  liw += (qmax + 5)*liw1Q;
+
+  return(TRUE);
+}
+
+/*
+ * CVQuadFreeVectors
+ *
+ * This routine frees the CVODES vectors allocated in CVQuadAllocVectors.
+ */
+
+static void CVQuadFreeVectors(CVodeMem cv_mem)
+{
+  int j, maxord;
+  
+  maxord = cv_mem->cv_qmax_allocQ;
+
+  N_VDestroy(ewtQ);
+  N_VDestroy(acorQ);
+  N_VDestroy(yQ);
+  N_VDestroy(tempvQ);
+  
+  for (j=0; j<=maxord; j++) N_VDestroy(znQ[j]);
+
+  lrw -= (maxord + 5)*lrw1Q;
+  liw -= (maxord + 5)*liw1Q;
+
+  if (cv_mem->cv_VabstolQMallocDone) {
+    N_VDestroy(VabstolQ);
+    lrw -= lrw1Q;
+    liw -= liw1Q;
+  }
+
+  cv_mem->cv_VabstolQMallocDone = FALSE;
+}
+
+/*
+ * CVSensAllocVectors
+ *
+ * Create (through duplication) N_Vectors used for sensitivity analysis, 
+ * using the N_Vector 'tmpl' as a template.
+ */
+
+static booleantype CVSensAllocVectors(CVodeMem cv_mem, N_Vector tmpl) 
+{
+  int i, j;
+  
+  /* Allocate yS */
+  yS = NULL;
+  yS = N_VCloneVectorArray(Ns, tmpl);
+  if (yS == NULL) {
+    return(FALSE);
+  }
+
+  /* Allocate ewtS */
+  ewtS = NULL;
+  ewtS = N_VCloneVectorArray(Ns, tmpl);
+  if (ewtS == NULL) {
+    N_VDestroyVectorArray(yS, Ns);
+    return(FALSE);
+  }
+  
+  /* Allocate acorS */
+  acorS = NULL;
+  acorS = N_VCloneVectorArray(Ns, tmpl);
+  if (acorS == NULL) {
+    N_VDestroyVectorArray(yS, Ns);
+    N_VDestroyVectorArray(ewtS, Ns);
+    return(FALSE);
+  }
+  
+  /* Allocate tempvS */
+  tempvS = NULL;
+  tempvS = N_VCloneVectorArray(Ns, tmpl);
+  if (tempvS == NULL) {
+    N_VDestroyVectorArray(yS, Ns);
+    N_VDestroyVectorArray(ewtS, Ns);
+    N_VDestroyVectorArray(acorS, Ns);
+    return(FALSE);
+  }
+    
+  /* Allocate ftempS */
+  ftempS = NULL;
+  ftempS = N_VCloneVectorArray(Ns, tmpl);
+  if (ftempS == NULL) {
+    N_VDestroyVectorArray(yS, Ns);
+    N_VDestroyVectorArray(ewtS, Ns);
+    N_VDestroyVectorArray(acorS, Ns);
+    N_VDestroyVectorArray(tempvS, Ns);
+    return(FALSE);
+  }
+  
+  /* Allocate znS */
+  for (j=0; j<=qmax; j++) {
+    znS[j] = NULL;
+    znS[j] = N_VCloneVectorArray(Ns, tmpl);
+    if (znS[j] == NULL) {
+      N_VDestroyVectorArray(yS, Ns);
+      N_VDestroyVectorArray(ewtS, Ns);
+      N_VDestroyVectorArray(acorS, Ns);
+      N_VDestroyVectorArray(tempvS, Ns);
+      N_VDestroyVectorArray(ftempS, Ns);
+      for (i=0; i<j; i++) N_VDestroyVectorArray(znS[i], Ns);
+      return(FALSE);
+    }
+  }
+  
+  /* Allocate space for pbar and plist */
+  pbar = NULL;
+  pbar = (realtype *)malloc(Ns*sizeof(realtype));
+  if (pbar == NULL) {
+    N_VDestroyVectorArray(yS, Ns);
+    N_VDestroyVectorArray(ewtS, Ns);
+    N_VDestroyVectorArray(acorS, Ns);
+    N_VDestroyVectorArray(tempvS, Ns);
+    N_VDestroyVectorArray(ftempS, Ns);
+    for (i=0; i<=qmax; i++) N_VDestroyVectorArray(znS[i], Ns);
+    return(FALSE);
+  }
+
+  plist = NULL;
+  plist = (int *)malloc(Ns*sizeof(int));
+  if (plist == NULL) {
+    N_VDestroyVectorArray(yS, Ns);
+    N_VDestroyVectorArray(ewtS, Ns);
+    N_VDestroyVectorArray(acorS, Ns);
+    N_VDestroyVectorArray(tempvS, Ns);
+    N_VDestroyVectorArray(ftempS, Ns);
+    for (i=0; i<=qmax; i++) N_VDestroyVectorArray(znS[i], Ns);
+    free(pbar); pbar = NULL;
+    return(FALSE);
+  }
+
+  /* Update solver workspace lengths */
+  lrw += (qmax + 6)*Ns*lrw1 + Ns;
+  liw += (qmax + 6)*Ns*liw1 + Ns;
+  
+  /* Store the value of qmax used here */
+  cv_mem->cv_qmax_allocS = qmax;
+
+  return(TRUE);
+}
+
+/*
+ * CVSensFreeVectors
+ *
+ * This routine frees the CVODES vectors allocated in CVSensAllocVectors.
+ */
+
+static void CVSensFreeVectors(CVodeMem cv_mem) 
+{
+  int j, maxord;
+  
+  maxord = cv_mem->cv_qmax_allocS;
+
+  N_VDestroyVectorArray(yS, Ns);
+  N_VDestroyVectorArray(ewtS, Ns);
+  N_VDestroyVectorArray(acorS, Ns);
+  N_VDestroyVectorArray(tempvS, Ns);
+  N_VDestroyVectorArray(ftempS, Ns);
+  
+  for (j=0; j<=maxord; j++) N_VDestroyVectorArray(znS[j], Ns);  
+
+  free(pbar); pbar = NULL;
+  free(plist); plist = NULL;
+
+  lrw -= (maxord + 6)*Ns*lrw1 + Ns;
+  liw -= (maxord + 6)*Ns*liw1 + Ns;
+
+  if (cv_mem->cv_VabstolSMallocDone) {
+    N_VDestroyVectorArray(VabstolS, Ns);
+    lrw -= Ns*lrw1;
+    liw -= Ns*liw1;
+  }
+  if (cv_mem->cv_SabstolSMallocDone) {
+    free(SabstolS); SabstolS = NULL;
+    lrw -= Ns;
+  }
+  cv_mem->cv_VabstolSMallocDone = FALSE;
+  cv_mem->cv_SabstolSMallocDone = FALSE;
+}
+
+/* 
+ * -----------------------------------------------------------------
+ * Initial stepsize calculation
+ * -----------------------------------------------------------------
+ */
+
+/*
+ * CVHin
+ *
+ * This routine computes a tentative initial step size h0. 
+ * If tout is too close to tn (= t0), then CVHin returns CV_TOO_CLOSE
+ * and h remains uninitialized. 
+ * If any RHS function fails unrecoverably, CVHin returns CV_*RHSFUNC_FAIL.
+ * If any RHS function fails recoverably too many times and recovery is
+ * not possible, CVHin returns CV_REPTD_*RHSFUNC_ERR.
+ * Otherwise, CVHin sets h to the chosen value h0 and returns CV_SUCCESS.
+ *
+ * The algorithm used seeks to find h0 as a solution of
+ *       (WRMS norm of (h0^2 ydd / 2)) = 1, 
+ * where ydd = estimated second derivative of y. Here, y includes
+ * all variables considered in the error test.
+ *
+ * We start with an initial estimate equal to the geometric mean of the
+ * lower and upper bounds on the step size.
+ *
+ * Loop up to MAX_ITERS times to find h0.
+ * Stop if new and previous values differ by a factor < 2.
+ * Stop if hnew/hg > 2 after one iteration, as this probably means
+ * that the ydd value is bad because of cancellation error.        
+ *  
+ * For each new proposed hg, we allow MAX_ITERS attempts to
+ * resolve a possible recoverable failure from f() by reducing
+ * the proposed stepsize by a factor of 0.2. If a legal stepsize
+ * still cannot be found, fall back on a previous value if possible,
+ * or else return CV_REPTD_RHSFUNC_ERR.
+ *
+ * Finally, we apply a bias (0.5) and verify that h0 is within bounds.
+ */
+
+static int CVHin(CVodeMem cv_mem, realtype tout)
+{
+  int retval, sign, count1, count2;
+  realtype tdiff, tdist, tround, hlb, hub;
+  realtype hg, hgs, hs, hnew, hrat, h0, yddnrm;
+  booleantype hgOK, hnewOK;
+
+  /* If tout is too close to tn, give up */
+  
+  if ((tdiff = tout-tn) == ZERO) return(CV_TOO_CLOSE);
+  
+  sign = (tdiff > ZERO) ? 1 : -1;
+  tdist = ABS(tdiff);
+  tround = uround * MAX(ABS(tn), ABS(tout));
+
+  if (tdist < TWO*tround) return(CV_TOO_CLOSE);
+  
+  /* 
+     Set lower and upper bounds on h0, and take geometric mean 
+     as first trial value.
+     Exit with this value if the bounds cross each other.
+  */
+
+  hlb = HLB_FACTOR * tround;
+  hub = CVUpperBoundH0(cv_mem, tdist);
+
+  hg  = RSqrt(hlb*hub);
+
+  if (hub < hlb) {
+    if (sign == -1) h = -hg;
+    else            h =  hg;
+    return(CV_SUCCESS);
+  }
+  
+  /* Outer loop */
+
+  hnewOK = FALSE;
+  hs = hg;         /* safeguard against 'uninitialized variable' warning */
+
+  for(count1 = 1; count1 <= MAX_ITERS; count1++) {
+
+    /* Attempts to estimate ydd */
+
+    hgOK = FALSE;
+
+    for (count2 = 1; count2 <= MAX_ITERS; count2++) {
+      hgs = hg*sign;
+      retval = CVYddNorm(cv_mem, hgs, &yddnrm);
+      /* If a RHS function failed unrecoverably, give up */
+      if (retval < 0) return(retval);
+      /* If successful, we can use ydd */
+      if (retval == CV_SUCCESS) {hgOK = TRUE; break;}
+      /* A RHS function failed recoverably; cut step size and test it again */
+      hg *= POINT2;
+    }
+
+    /* If a RHS function failed recoverably MAX_ITERS times */
+
+    if (!hgOK) {
+      /* Exit if this is the first or second pass. No recovery possible */
+      if (count1 <= 2) 
+        if (retval == RHSFUNC_RECVR)  return(CV_REPTD_RHSFUNC_ERR);
+        if (retval == QRHSFUNC_RECVR) return(CV_REPTD_QRHSFUNC_ERR);
+        if (retval == SRHSFUNC_RECVR) return(CV_REPTD_SRHSFUNC_ERR);
+      /* We have a fall-back option. The value hs is a previous hnew which
+         passed through f(). Use it and break */
+      hnew = hs;
+      break;
+    }
+
+    /* The proposed step size is feasible. Save it. */
+    hs = hg;
+
+    /* If the stopping criteria was met, or if this is the last pass, stop */
+    if ( (hnewOK) || (count1 == MAX_ITERS))  {hnew = hg; break;}
+
+    /* Propose new step size */
+    hnew = (yddnrm*hub*hub > TWO) ? RSqrt(TWO/yddnrm) : RSqrt(hg*hub);
+    hrat = hnew/hg;
+    
+    /* Accept hnew if it does not differ from hg by more than a factor of 2 */
+    if ((hrat > HALF) && (hrat < TWO)) {
+      hnewOK = TRUE;
+    }
+
+    /* After one pass, if ydd seems to be bad, use fall-back value. */
+    if ((count1 > 1) && (hrat > TWO)) {
+      hnew = hg;
+      hnewOK = TRUE;
+    }
+
+    /* Send this value back through f() */
+    hg = hnew;
+
+  }
+
+  /* Apply bounds, bias factor, and attach sign */
+
+  h0 = H_BIAS*hnew;
+  if (h0 < hlb) h0 = hlb;
+  if (h0 > hub) h0 = hub;
+  if (sign == -1) h0 = -h0;
+  h = h0;
+
+  return(CV_SUCCESS);
+}
+
+/*
+ * CVUpperBoundH0
+ *
+ * This routine sets an upper bound on abs(h0) based on
+ * tdist = tn - t0 and the values of y[i]/y'[i].
+ */
+
+static realtype CVUpperBoundH0(CVodeMem cv_mem, realtype tdist)
+{
+  realtype hub_inv, hubQ_inv, hubS_inv, hub;
+  N_Vector temp1, temp2;
+  N_Vector tempQ1, tempQ2;
+  N_Vector *tempS1;
+  int is;
+
+  /* 
+   * Bound based on |y|/|y'| -- allow at most an increase of
+   * HUB_FACTOR in y0 (based on a forward Euler step). The weight 
+   * factor is used as a safeguard against zero components in y0. 
+   */
+
+  temp1 = tempv;
+  temp2 = acor;
+
+  N_VAbs(zn[0], temp2);
+  efun(zn[0], temp1, e_data);
+  N_VInv(temp1, temp1);
+  N_VLinearSum(HUB_FACTOR, temp2, ONE, temp1, temp1);
+
+  N_VAbs(zn[1], temp2);
+
+  N_VDiv(temp2, temp1, temp1);
+  hub_inv = N_VMaxNorm(temp1);
+
+  /* Bound based on |yQ|/|yQ'| */
+  
+  if (quadr && errconQ) {
+
+    tempQ1 = tempvQ;
+    tempQ2 = acorQ;
+
+    N_VAbs(znQ[0], tempQ2);
+    CVQuadEwtSet(cv_mem, znQ[0], tempQ1);
+    N_VInv(tempQ1, tempQ1);
+    N_VLinearSum(HUB_FACTOR, tempQ2, ONE, tempQ1, tempQ1);
+    
+    N_VAbs(znQ[1], tempQ2);
+    
+    N_VDiv(tempQ2, tempQ1, tempQ1);
+    hubQ_inv = N_VMaxNorm(tempQ1);
+
+    if (hubQ_inv > hub_inv) hub_inv = hubQ_inv;
+
+  }
+
+  /* Bound based on |yS|/|yS'| */
+
+  if (sensi && errconS) {
+
+    tempS1 = acorS;
+    CVSensEwtSet(cv_mem, znS[0], tempS1);
+
+    for (is=0; is<Ns; is++) {
+
+      N_VAbs(znS[0][is], temp2);
+      N_VInv(tempS1[is], temp1);
+      N_VLinearSum(HUB_FACTOR, temp2, ONE, temp1, temp1);
+      
+      N_VAbs(znS[1][is], temp2);
+      
+      N_VDiv(temp2, temp1, temp1);
+      hubS_inv = N_VMaxNorm(temp1);
+
+      if (hubS_inv > hub_inv) hub_inv = hubS_inv;
+
+    }
+
+  }
+
+  /*
+   * bound based on tdist -- allow at most a step of magnitude
+   * HUB_FACTOR * tdist
+   */
+  
+  hub = HUB_FACTOR*tdist;
+
+  /* Use the smaler of the two */
+
+  if (hub*hub_inv > ONE) hub = ONE/hub_inv;
+
+  return(hub);
+}
+
+/*
+ * CVYddNorm
+ *
+ * This routine computes an estimate of the second derivative of Y
+ * using a difference quotient, and returns its WRMS norm.
+ *
+ * Y contains all variables included in the error test. 
+ */
+
+static int CVYddNorm(CVodeMem cv_mem, realtype hg, realtype *yddnrm)
+{
+  int retval, is;
+  N_Vector wrk1, wrk2;
+  
+  /* y     <- h*y'(t) + y(t) */
+  
+  N_VLinearSum(hg, zn[1], ONE, zn[0], y);
+  
+  if (sensi && errconS) 
+    for (is=0; is<Ns; is++)
+      N_VLinearSum(hg, znS[1][is], ONE, znS[0][is], yS[is]);
+  
+  /* tempv <- f(t+h, h*y'(t)+y(t)) */
+
+  retval = f(tn+hg, y, tempv, f_data);
+  nfe++;
+  if (retval < 0) return(CV_RHSFUNC_FAIL);
+  if (retval > 0) return(RHSFUNC_RECVR);
+
+  if (quadr && errconQ) {
+    retval = fQ(tn+hg, y, tempvQ, fQ_data);
+    nfQe++;
+    if (retval < 0) return(CV_QRHSFUNC_FAIL);
+    if (retval > 0) return(QRHSFUNC_RECVR);
+  }
+
+  if (sensi && errconS) {
+    wrk1 = ftemp;
+    wrk2 = acor;
+    retval = CVSensRhs(cv_mem, tn+hg, y, tempv, yS, tempvS, wrk1, wrk2);
+    if (retval < 0) return(CV_SRHSFUNC_FAIL);
+    if (retval > 0) return(SRHSFUNC_RECVR);
+  }  
+
+  /* tempv <- f(t+h, h*y'(t)+y(t)) - y'(t) */
+  /* tempv <- ydd */
+  
+  N_VLinearSum(ONE, tempv, -ONE, zn[1], tempv);
+  N_VScale(ONE/hg, tempv, tempv);
+  
+  if (quadr && errconQ) {
+    N_VLinearSum(ONE, tempvQ, -ONE, znQ[1], tempvQ);
+    N_VScale(ONE/hg, tempvQ, tempvQ);
+  }
+
+  if (sensi && errconS)
+    for (is=0; is<Ns; is++) {
+      N_VLinearSum(ONE, tempvS[is], -ONE, znS[1][is], tempvS[is]);
+      N_VScale(ONE/hg, tempvS[is], tempvS[is]);
+    }
+
+  /* Estimate ||y''|| */
+  
+  *yddnrm = N_VWrmsNorm(tempv, ewt);
+  if (quadr && errconQ) {
+    *yddnrm = CVQuadUpdateNorm(cv_mem, *yddnrm, tempvQ, ewtQ);
+  }
+  if (sensi && errconS) {
+    *yddnrm = CVSensUpdateNorm(cv_mem, *yddnrm, tempvS, ewtS);
+  }
+
+  return(CV_SUCCESS);
+}
+
+/* 
+ * -----------------------------------------------------------------
+ * Initial setup
+ * -----------------------------------------------------------------
+ */
+
+/*  
+ * CVInitialSetup
+ *
+ * This routine performs input consistency checks at the first step.
+ * If needed, it also checks the linear solver module and calls the
+ * linear solver initialization routine.
+ */
+
+static int CVInitialSetup(CVodeMem cv_mem)
+{
+  int ier;
+
+  /* Did the user provide efun? */
+
+  if (itol != CV_WF) {
+    efun = CVEwtSet;
+    e_data = (void *)cv_mem;
+  } else {
+    if (efun == NULL) {
+      CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVInitialSetup", MSGCV_NO_EFUN);
+      return(CV_ILL_INPUT);
+    }
+  }
+
+  ier = efun(zn[0], ewt, e_data);
+  if (ier != 0) {
+
+    if (itol == CV_WF) 
+      CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVInitialSetup", MSGCV_EWT_FAIL);
+    else
+      CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVInitialSetup", MSGCV_BAD_EWT);
+
+    return(CV_ILL_INPUT);
+  }
+  
+  /* Quadrature initial setup */
+
+  if (quadr && errconQ) {
+
+    /* Load ewtQ */
+    ier = CVQuadEwtSet(cv_mem, znQ[0], ewtQ);
+    if (ier != 0) {
+      CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVInitialSetup", MSGCV_BAD_EWTQ);
+      return(CV_ILL_INPUT);
+    }
+
+  }
+
+  if (!quadr) errconQ = FALSE;
+
+  /* Forward sensitivity initial setup */
+
+  if (sensi) {
+
+    /* Check if ism and ifS agree */
+    if ((ism==CV_STAGGERED1) && (ifS==CV_ALLSENS)) {
+      CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVInitialSetup", MSGCV_BAD_ISM_IFS);
+      return(CV_ILL_INPUT);
+    }    
+
+    /* Load ewtS */
+    ier = CVSensEwtSet(cv_mem, znS[0], ewtS);
+    if (ier != 0) {
+      CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVInitialSetup", MSGCV_BAD_EWTS);
+      return(CV_ILL_INPUT);
+    }
+
+  }
+
+  /* Check if lsolve function exists (if needed)
+     and call linit function (if it exists) */
+
+  if (iter == CV_NEWTON) {
+    if (lsolve == NULL) {
+      CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVInitialSetup", MSGCV_LSOLVE_NULL);
+      return(CV_ILL_INPUT);
+    }
+    if (linit != NULL) {
+      ier = linit(cv_mem);
+      if (ier != 0) {
+        CVProcessError(cv_mem, CV_LINIT_FAIL, "CVODES", "CVInitialSetup", MSGCV_LINIT_FAIL);
+        return(CV_LINIT_FAIL);
+      }
+    }
+  }
+    
+  return(CV_SUCCESS);
+}
+
+/*
+ * CVEwtSet
+ *
+ * This routine is responsible for setting the error weight vector ewt,
+ * according to tol_type, as follows:
+ *
+ * (1) ewt[i] = 1 / (reltol * ABS(ycur[i]) + *abstol), i=0,...,neq-1
+ *     if tol_type = CV_SS
+ * (2) ewt[i] = 1 / (reltol * ABS(ycur[i]) + abstol[i]), i=0,...,neq-1
+ *     if tol_type = CV_SV
+ *
+ * CVEwtSet returns 0 if ewt is successfully set as above to a
+ * positive vector and -1 otherwise. In the latter case, ewt is
+ * considered undefined.
+ *
+ * All the real work is done in the routines CVEwtSetSS, CVEwtSetSV.
+ */
+
+int CVEwtSet(N_Vector ycur, N_Vector weight, void *data)
+{
+  CVodeMem cv_mem;
+  int flag = 0;
+
+  /* data points to cv_mem here */
+
+  cv_mem = (CVodeMem) data;
+
+  switch(itol) {
+  case CV_SS: 
+    flag = CVEwtSetSS(cv_mem, ycur, weight);
+    break;
+  case CV_SV: 
+    flag = CVEwtSetSV(cv_mem, ycur, weight);
+    break;
+  }
+
+  return(flag);
+}
+
+/*
+ * CVEwtSetSS
+ *
+ * This routine sets ewt as decribed above in the case tol_type = CV_SS.
+ * It tests for non-positive components before inverting. CVEwtSetSS
+ * returns 0 if ewt is successfully set to a positive vector
+ * and -1 otherwise. In the latter case, ewt is considered undefined.
+ */
+
+static int CVEwtSetSS(CVodeMem cv_mem, N_Vector ycur, N_Vector weight)
+{
+  N_VAbs(ycur, tempv);
+  N_VScale(reltol, tempv, tempv);
+  N_VAddConst(tempv, Sabstol, tempv);
+  if (N_VMin(tempv) <= ZERO) return(-1);
+  N_VInv(tempv, weight);
+
+  return(0);
+}
+
+/*
+ * CVEwtSetSV
+ *
+ * This routine sets ewt as decribed above in the case tol_type = CV_SV.
+ * It tests for non-positive components before inverting. CVEwtSetSV
+ * returns 0 if ewt is successfully set to a positive vector
+ * and -1 otherwise. In the latter case, ewt is considered undefined.
+ */
+
+static int CVEwtSetSV(CVodeMem cv_mem, N_Vector ycur, N_Vector weight)
+{
+  N_VAbs(ycur, tempv);
+  N_VLinearSum(reltol, tempv, ONE, Vabstol, tempv);
+  if (N_VMin(tempv) <= ZERO) return(-1);
+  N_VInv(tempv, weight);
+  return(0);
+}
+
+/*
+ * CVQuadEwtSet
+ *
+ */
+
+static int CVQuadEwtSet(CVodeMem cv_mem, N_Vector qcur, N_Vector weightQ)
+{
+  int flag=0;
+
+  switch (itolQ) {
+  case CV_SS: 
+    flag = CVQuadEwtSetSS(cv_mem, qcur, weightQ);
+    break;
+  case CV_SV: 
+    flag = CVQuadEwtSetSV(cv_mem, qcur, weightQ);
+    break;
+  }
+
+  return(flag);
+
+}
+
+/*
+ * CVQuadEwtSetSS
+ *
+ */
+
+static int CVQuadEwtSetSS(CVodeMem cv_mem, N_Vector qcur, N_Vector weightQ)
+{
+  N_VAbs(qcur, tempvQ);
+  N_VScale(reltolQ, tempvQ, tempvQ);
+  N_VAddConst(tempvQ, SabstolQ, tempvQ);
+  if (N_VMin(tempvQ) <= ZERO) return(-1);
+  N_VInv(tempvQ, weightQ);
+
+  return(0);
+}
+
+/*
+ * CVQuadEwtSetSV
+ *
+ */
+
+static int CVQuadEwtSetSV(CVodeMem cv_mem, N_Vector qcur, N_Vector weightQ)
+{
+  N_VAbs(qcur, tempvQ);
+  N_VLinearSum(reltolQ, tempvQ, ONE, VabstolQ, tempvQ);
+  if (N_VMin(tempvQ) <= ZERO) return(-1);
+  N_VInv(tempvQ, weightQ);
+
+  return(0);
+}
+
+/*
+ * CVSensEwtSet
+ *
+ */
+
+static int CVSensEwtSet(CVodeMem cv_mem, N_Vector *yScur, N_Vector *weightS)
+{
+  int flag=0;
+
+  switch (itolS) {
+  case CV_EE:
+    flag = CVSensEwtSetEE(cv_mem, yScur, weightS);
+    break;
+  case CV_SS: 
+    flag = CVSensEwtSetSS(cv_mem, yScur, weightS);
+    break;
+  case CV_SV: 
+    flag = CVSensEwtSetSV(cv_mem, yScur, weightS);
+    break;
+  }
+
+  return(flag);
+
+}
+
+/*
+ * CVSensEwtSetEE
+ *
+ * In this case, the error weight vector for the i-th sensitivity is set to
+ *
+ * ewtS_i = pbar_i * efun(pbar_i*yS_i)
+ *
+ * In other words, the scaled sensitivity pbar_i * yS_i has the same error
+ * weight vector calculation as the solution vector.
+ *
+ */
+
+static int CVSensEwtSetEE(CVodeMem cv_mem, N_Vector *yScur, N_Vector *weightS)
+{
+  int is;
+  N_Vector pyS;
+  int flag;
+
+  /* Use tempvS[0] as temporary storage for the scaled sensitivity */
+  pyS = tempvS[0];
+
+  for (is=0; is<Ns; is++) {
+    N_VScale(pbar[is], yScur[is], pyS);
+    flag = efun(pyS, weightS[is], e_data);
+    if (flag != 0) return(-1);
+    N_VScale(pbar[is], weightS[is], weightS[is]);
+  }
+
+  return(0);
+}
+
+/*
+ * CVSensEwtSetSS
+ *
+ */
+
+static int CVSensEwtSetSS(CVodeMem cv_mem, N_Vector *yScur, N_Vector *weightS)
+{
+  int is;
+  
+  for (is=0; is<Ns; is++) {
+    N_VAbs(yScur[is], tempv);
+    N_VScale(reltolS, tempv, tempv);
+    N_VAddConst(tempv, SabstolS[is], tempv);
+    if (N_VMin(tempv) <= ZERO) return(-1);
+    N_VInv(tempv, weightS[is]);
+  }
+  return(0);
+}
+
+/*
+ * CVSensEwtSetSV
+ *
+ */
+
+static int CVSensEwtSetSV(CVodeMem cv_mem, N_Vector *yScur, N_Vector *weightS)
+{
+  int is;
+  
+  for (is=0; is<Ns; is++) {
+    N_VAbs(yScur[is], tempv);
+    N_VLinearSum(reltolS, tempv, ONE, VabstolS[is], tempv);
+    if (N_VMin(tempv) <= ZERO) return(-1);
+    N_VInv(tempv, weightS[is]);
+  }
+
+  return(0);
+}
+
+/* 
+ * -----------------------------------------------------------------
+ * Main CVStep function
+ * -----------------------------------------------------------------
+ */
+
+/* 
+ * CVStep
+ *
+ * This routine performs one internal cvode step, from tn to tn + h.
+ * It calls other routines to do all the work.
+ *
+ * The main operations done here are as follows:
+ * - preliminary adjustments if a new step size was chosen;
+ * - prediction of the Nordsieck history array zn at tn + h;
+ * - setting of multistep method coefficients and test quantities;
+ * - solution of the nonlinear system;
+ * - testing the local error;
+ * - updating zn and other state data if successful;
+ * - resetting stepsize and order for the next step.
+ * - if SLDET is on, check for stability, reduce order if necessary.
+ * On a failure in the nonlinear system solution or error test, the
+ * step may be reattempted, depending on the nature of the failure.
+ */
+
+static int CVStep(CVodeMem cv_mem)
+{
+  realtype saved_t, dsm, dsmS, dsmQ;
+  booleantype do_sensi_stg, do_sensi_stg1;
+  int ncf, nef, ncfS, nefS, nefQ;
+  int nflag, kflag, eflag;
+  int retval, is;
+
+  /* Are we computing sensitivities with a staggered approach? */
+
+  do_sensi_stg  = (sensi && (ism==CV_STAGGERED));
+  do_sensi_stg1 = (sensi && (ism==CV_STAGGERED1));
+
+  /* Initialize local counters for convergence and error test failures */
+
+  ncf  = nef  = 0;
+  nefQ = 0;
+  ncfS = nefS = 0;
+  if (do_sensi_stg1)
+    for (is=0; is<Ns; is++) ncfS1[is] = 0;
+
+  /* If needed, adjust method parameters */
+
+  if ((nst > 0) && (hprime != h)) CVAdjustParams(cv_mem);
+
+  /* Looping point for attempts to take a step */
+
+  saved_t = tn;
+  nflag = FIRST_CALL;
+
+  loop {  
+
+    CVPredict(cv_mem);  
+    CVSet(cv_mem);
+
+    /* ------ Correct state variables ------ */
+    
+    nflag = CVNls(cv_mem, nflag);
+    kflag = CVHandleNFlag(cv_mem, &nflag, saved_t, &ncf, &ncfn);
+
+    /* Go back in loop if we need to predict again (nflag=PREV_CONV_FAIL) */
+    if (kflag == PREDICT_AGAIN) continue;
+
+    /* Return if nonlinear solve failed and recovery not possible. */
+    if (kflag != DO_ERROR_TEST) return(kflag);
+
+    /* Perform error test (nflag=CV_SUCCESS) */
+    eflag = CVDoErrorTest(cv_mem, &nflag, saved_t, acnrm, &nef, &netf, &dsm);
+
+    /* Go back in loop if we need to predict again (nflag=PREV_ERR_FAIL) */
+    if (eflag == TRY_AGAIN) continue;
+
+    /* Return if error test failed and recovery not possible. */
+    if (eflag != CV_SUCCESS) return(eflag);
+
+    /* Error test passed (eflag=CV_SUCCESS, nflag=CV_SUCCESS), go on */
+
+    /* ------ Correct the quadrature variables ------ */
+
+    if (quadr) {
+
+      ncf = nef = 0; /* reset counters for states */
+
+      nflag = CVQuadNls(cv_mem);
+      kflag = CVHandleNFlag(cv_mem, &nflag, saved_t, &ncf, &ncfn);
+
+      if (kflag == PREDICT_AGAIN) continue;
+      if (kflag != DO_ERROR_TEST) return(kflag);
+
+      /* Error test on quadratures */
+      if (errconQ) {
+        acnrmQ = N_VWrmsNorm(acorQ, ewtQ);
+        eflag = CVDoErrorTest(cv_mem, &nflag, saved_t, acnrmQ, &nefQ, &netfQ, &dsmQ);
+
+        if (eflag == TRY_AGAIN)  continue;
+        if (eflag != CV_SUCCESS) return(eflag);
+
+        /* update 'dsm' with 'dsmQ' (to be used in CVPrepareNextStep) */
+        dsm = CVQuadUpdateDsm(cv_mem, dsm, dsmQ);
+      }
+
+    }
+
+    /* ------ Correct the sensitivity variables (STAGGERED or STAGGERED1) ------- */
+
+    if (do_sensi_stg || do_sensi_stg1) {
+
+      ncf = nef = 0;        /* reset counters for states     */
+      if (quadr) nefQ = 0;  /* reset counter for quadratures */
+
+      /* Evaluate f at converged y, needed for future evaluations of sens. RHS 
+         If f() fails recoverably, treat it as a convergence failure and 
+         attempt the step again */
+
+      retval = f(tn, y, ftemp, f_data);
+      nfe++;
+      if (retval < 0) return(CV_RHSFUNC_FAIL);
+      if (retval > 0) {
+        nflag = PREV_CONV_FAIL;
+        continue;
+      }
+
+      if (do_sensi_stg) {
+        /* Nonlinear solve for sensitivities (all-at-once) */
+        nflag = CVStgrNls(cv_mem);
+        kflag = CVHandleNFlag(cv_mem, &nflag, saved_t, &ncfS, &ncfnS);
+      } else {
+        /* Nonlinear solve for sensitivities (one-by-one) */
+        for (is=0; is<Ns; is++) { 
+          nflag = CVStgr1Nls(cv_mem, is); 
+          kflag = CVHandleNFlag(cv_mem, &nflag, saved_t, &ncfS1[is], &ncfnS1[is]);
+          if (kflag != DO_ERROR_TEST) break; 
+        }
+      }
+
+      if (kflag == PREDICT_AGAIN) continue;
+      if (kflag != DO_ERROR_TEST) return(kflag);
+
+      /* Error test on sensitivities */
+      if (errconS) {
+
+        if (do_sensi_stg1) acnrmS = CVSensNorm(cv_mem, acorS, ewtS);
+
+        eflag = CVDoErrorTest(cv_mem, &nflag, saved_t, acnrmS, &nefS, &netfS, &dsmS);
+
+        if (eflag == TRY_AGAIN)  continue;
+        if (eflag != CV_SUCCESS) return(eflag);
+
+        /* update 'dsm' with 'dsmS' (to be used in CVPrepareNextStep) */
+        dsm = CVStgrUpdateDsm(cv_mem, dsm, dsmS);
+      }
+
+    }
+
+    /* Everything went fine; exit loop */ 
+    break;
+
+  }
+
+  /* Nonlinear system solve and error test were both successful.
+     Update data, and consider change of step and/or order.       */
+
+  CVCompleteStep(cv_mem); 
+
+  CVPrepareNextStep(cv_mem, dsm); 
+
+  /* If Stablilty Limit Detection is turned on, call stability limit
+     detection routine for possible order reduction. */
+
+  if (sldeton) CVBDFStab(cv_mem);
+
+  etamax = (nst <= SMALL_NST) ? ETAMX2 : ETAMX3;
+
+  /*  Finally, we rescale the acor array to be the 
+      estimated local error vector. */
+
+  N_VScale(ONE/tq[2], acor, acor);
+
+  if (quadr)
+    N_VScale(ONE/tq[2], acorQ, acorQ);
+
+  if (sensi)
+    for (is=0; is<Ns; is++)
+      N_VScale(ONE/tq[2], acorS[is], acorS[is]);
+
+  return(CV_SUCCESS);
+      
+}
+
+/* 
+ * -----------------------------------------------------------------
+ * Function called at beginning of step
+ * -----------------------------------------------------------------
+ */
+
+/*
+ * CVAdjustParams
+ *
+ * This routine is called when a change in step size was decided upon,
+ * and it handles the required adjustments to the history array zn.
+ * If there is to be a change in order, we call CVAdjustOrder and reset
+ * q, L = q+1, and qwait.  Then in any case, we call CVRescale, which
+ * resets h and rescales the Nordsieck array.
+ */
+
+static void CVAdjustParams(CVodeMem cv_mem)
+{
+  if (qprime != q) {
+    CVAdjustOrder(cv_mem, qprime-q);
+    q = qprime;
+    L = q+1;
+    qwait = L;
+  }
+  CVRescale(cv_mem);
+}
+
+/*
+ * CVAdjustOrder
+ *
+ * This routine is a high level routine which handles an order
+ * change by an amount deltaq (= +1 or -1). If a decrease in order
+ * is requested and q==2, then the routine returns immediately.
+ * Otherwise CVAdjustAdams or CVAdjustBDF is called to handle the
+ * order change (depending on the value of lmm).
+ */
+
+static void CVAdjustOrder(CVodeMem cv_mem, int deltaq)
+{
+  if ((q==2) && (deltaq != 1)) return;
+  
+  switch(lmm){
+  case CV_ADAMS: 
+    CVAdjustAdams(cv_mem, deltaq);
+    break;
+  case CV_BDF:   
+    CVAdjustBDF(cv_mem, deltaq);
+    break;
+  }
+}
+
+/*
+ * CVAdjustAdams
+ *
+ * This routine adjusts the history array on a change of order q by
+ * deltaq, in the case that lmm == CV_ADAMS.
+ */
+
+static void CVAdjustAdams(CVodeMem cv_mem, int deltaq)
+{
+  int i, j;
+  int is;
+  realtype xi, hsum;
+
+  /* On an order increase, set new column of zn to zero and return */
+  
+  if (deltaq==1) {
+    N_VConst(ZERO, zn[L]);
+    if (quadr)
+      N_VConst(ZERO, znQ[L]);
+    if (sensi)
+      for (is=0; is<Ns; is++)
+        N_VConst(ZERO, znS[L][is]);
+    return;
+  }
+
+  /*
+   * On an order decrease, each zn[j] is adjusted by a multiple of zn[q].
+   * The coeffs. in the adjustment are the coeffs. of the polynomial:
+   *        x
+   * q * INT { u * ( u + xi_1 ) * ... * ( u + xi_{q-2} ) } du 
+   *        0
+   * where xi_j = [t_n - t_(n-j)]/h => xi_0 = 0
+   */
+
+  for (i=0; i <= qmax; i++) l[i] = ZERO;
+  l[1] = ONE;
+  hsum = ZERO;
+  for (j=1; j <= q-2; j++) {
+    hsum += tau[j];
+    xi = hsum / hscale;
+    for (i=j+1; i >= 1; i--) l[i] = l[i]*xi + l[i-1];
+  }
+  
+  for (j=1; j <= q-2; j++) l[j+1] = q * (l[j] / (j+1));
+  
+  for (j=2; j < q; j++)
+    N_VLinearSum(-l[j], zn[q], ONE, zn[j], zn[j]);
+
+  if (quadr)
+    for (j=2; j < q; j++)
+      N_VLinearSum(-l[j], znQ[q], ONE, znQ[j], znQ[j]);
+
+  if (sensi)
+    for (is=0; is<Ns; is++)
+      for (j=2; j < q; j++)
+        N_VLinearSum(-l[j], znS[q][is], ONE, znS[j][is], znS[j][is]);
+
+}
+
+/*
+ * CVAdjustBDF
+ *
+ * This is a high level routine which handles adjustments to the
+ * history array on a change of order by deltaq in the case that 
+ * lmm == CV_BDF.  CVAdjustBDF calls CVIncreaseBDF if deltaq = +1 and 
+ * CVDecreaseBDF if deltaq = -1 to do the actual work.
+ */
+
+static void CVAdjustBDF(CVodeMem cv_mem, int deltaq)
+{
+  switch(deltaq) {
+  case 1: 
+    CVIncreaseBDF(cv_mem);
+    return;
+  case -1: 
+    CVDecreaseBDF(cv_mem);
+    return;
+  }
+}
+
+/*
+ * CVIncreaseBDF
+ *
+ * This routine adjusts the history array on an increase in the 
+ * order q in the case that lmm == CV_BDF.  
+ * A new column zn[q+1] is set equal to a multiple of the saved 
+ * vector (= acor) in zn[indx_acor].  Then each zn[j] is adjusted by
+ * a multiple of zn[q+1].  The coefficients in the adjustment are the 
+ * coefficients of the polynomial x*x*(x+xi_1)*...*(x+xi_j),
+ * where xi_j = [t_n - t_(n-j)]/h.
+ */
+
+static void CVIncreaseBDF(CVodeMem cv_mem)
+{
+  realtype alpha0, alpha1, prod, xi, xiold, hsum, A1;
+  int i, j;
+  int is;
+
+  for (i=0; i <= qmax; i++) l[i] = ZERO;
+  l[2] = alpha1 = prod = xiold = ONE;
+  alpha0 = -ONE;
+  hsum = hscale;
+  if (q > 1) {
+    for (j=1; j < q; j++) {
+      hsum += tau[j+1];
+      xi = hsum / hscale;
+      prod *= xi;
+      alpha0 -= ONE / (j+1);
+      alpha1 += ONE / xi;
+      for (i=j+2; i >= 2; i--) l[i] = l[i]*xiold + l[i-1];
+      xiold = xi;
+    }
+  }
+  A1 = (-alpha0 - alpha1) / prod;
+
+  /* 
+     zn[indx_acor] contains the value Delta_n = y_n - y_n(0) 
+     This value was stored there at the previous successful
+     step (in CVCompleteStep) 
+     
+     A1 contains dbar = (1/xi* - 1/xi_q)/prod(xi_j)
+  */
+  
+  N_VScale(A1, zn[indx_acor], zn[L]);
+  for (j=2; j <= q; j++)
+    N_VLinearSum(l[j], zn[L], ONE, zn[j], zn[j]);
+
+  if (quadr) {
+    N_VScale(A1, znQ[indx_acor], znQ[L]);
+    for (j=2; j <= q; j++)
+      N_VLinearSum(l[j], znQ[L], ONE, znQ[j], znQ[j]);
+  }
+
+  if (sensi) {
+    for (is=0; is<Ns; is++) {
+      N_VScale(A1, znS[indx_acor][is], znS[L][is]);
+      for (j=2; j <= q; j++)
+        N_VLinearSum(l[j], znS[L][is], ONE, znS[j][is], znS[j][is]);
+    }
+  }
+
+}
+
+/*
+ * CVDecreaseBDF
+ *
+ * This routine adjusts the history array on a decrease in the 
+ * order q in the case that lmm == CV_BDF.  
+ * Each zn[j] is adjusted by a multiple of zn[q].  The coefficients
+ * in the adjustment are the coefficients of the polynomial
+ *   x*x*(x+xi_1)*...*(x+xi_j), where xi_j = [t_n - t_(n-j)]/h.
+ */
+
+static void CVDecreaseBDF(CVodeMem cv_mem)
+{
+  realtype hsum, xi;
+  int i, j;
+  int is;
+  
+  for (i=0; i <= qmax; i++) l[i] = ZERO;
+  l[2] = ONE;
+  hsum = ZERO;
+  for (j=1; j <= q-2; j++) {
+    hsum += tau[j];
+    xi = hsum /hscale;
+    for (i=j+2; i >= 2; i--) l[i] = l[i]*xi + l[i-1];
+  }
+  
+  for (j=2; j < q; j++)
+    N_VLinearSum(-l[j], zn[q], ONE, zn[j], zn[j]);
+
+  if (quadr) {
+    for (j=2; j < q; j++)
+      N_VLinearSum(-l[j], znQ[q], ONE, znQ[j], znQ[j]);
+  }
+
+  if (sensi) {
+    for (is=0; is<Ns; is++) 
+      for (j=2; j < q; j++)
+        N_VLinearSum(-l[j], znS[q][is], ONE, znS[j][is], znS[j][is]);
+  }
+}
+
+/*
+ * CVRescale
+ *
+ * This routine rescales the Nordsieck array by multiplying the
+ * jth column zn[j] by eta^j, j = 1, ..., q.  Then the value of
+ * h is rescaled by eta, and hscale is reset to h.
+ */
+
+static void CVRescale(CVodeMem cv_mem)
+{
+  int j;
+  int is;
+  realtype factor;
+
+  factor = eta;
+  for (j=1; j <= q; j++) {
+
+    N_VScale(factor, zn[j], zn[j]);
+
+    if (quadr)
+      N_VScale(factor, znQ[j], znQ[j]);
+
+    if (sensi)
+      for (is=0; is<Ns; is++)
+        N_VScale(factor, znS[j][is], znS[j][is]);
+
+    factor *= eta;
+
+  }
+  h = hscale * eta;
+  next_h = h;
+  hscale = h;
+  nscon = 0;
+}
+
+/*
+ * CVPredict
+ *
+ * This routine advances tn by the tentative step size h, and computes
+ * the predicted array z_n(0), which is overwritten on zn.  The
+ * prediction of zn is done by repeated additions.
+ * In TSTOP mode, it is possible for tn + h to be past tstop by roundoff,
+ * and in that case, we reset tn (after incrementing by h) to tstop.
+ */
+
+static void CVPredict(CVodeMem cv_mem)
+{
+  int j, k;
+  int is;
+
+  tn += h;
+  if (istop) {
+    if ((tn - tstop)*h > ZERO) tn = tstop;
+  }
+
+  for (k = 1; k <= q; k++)
+    for (j = q; j >= k; j--) 
+      N_VLinearSum(ONE, zn[j-1], ONE, zn[j], zn[j-1]); 
+
+  if (quadr) {
+    for (k = 1; k <= q; k++)
+      for (j = q; j >= k; j--) 
+        N_VLinearSum(ONE, znQ[j-1], ONE, znQ[j], znQ[j-1]);
+  }
+
+  if (sensi) {
+    for (is=0; is<Ns; is++) {
+      for (k = 1; k <= q; k++)
+        for (j = q; j >= k; j--) 
+          N_VLinearSum(ONE, znS[j-1][is], ONE, znS[j][is], znS[j-1][is]);
+    }
+  }
+}
+
+/*
+ * CVSet
+ *
+ * This routine is a high level routine which calls CVSetAdams or
+ * CVSetBDF to set the polynomial l, the test quantity array tq, 
+ * and the related variables  rl1, gamma, and gamrat.
+ */
+
+static void CVSet(CVodeMem cv_mem)
+{
+  switch(lmm) {
+  case CV_ADAMS: 
+    CVSetAdams(cv_mem);
+    break;
+  case CV_BDF: 
+    CVSetBDF(cv_mem);
+    break;
+  }
+  rl1 = ONE / l[1];
+  gamma = h * rl1;
+  if (nst == 0) gammap = gamma;
+  gamrat = (nst > 0) ? gamma / gammap : ONE;  /* protect x / x != 1.0 */
+}
+
+/*
+ * CVSetAdams
+ *
+ * This routine handles the computation of l and tq for the
+ * case lmm == CV_ADAMS.
+ *
+ * The components of the array l are the coefficients of a
+ * polynomial Lambda(x) = l_0 + l_1 x + ... + l_q x^q, given by
+ *                          q-1
+ * (d/dx) Lambda(x) = c * PRODUCT (1 + x / xi_i) , where
+ *                          i=1
+ *  Lambda(-1) = 0, Lambda(0) = 1, and c is a normalization factor.
+ * Here xi_i = [t_n - t_(n-i)] / h.
+ *
+ * The array tq is set to test quantities used in the convergence
+ * test, the error test, and the selection of h at a new order.
+ */
+
+static void CVSetAdams(CVodeMem cv_mem)
+{
+  realtype m[L_MAX], M[3], hsum;
+  
+  if (q == 1) {
+    l[0] = l[1] = tq[1] = tq[5] = ONE;
+    tq[2] = TWO;
+    tq[3] = TWELVE;
+    tq[4] = nlscoef * tq[2];       /* = 0.1 * tq[2] */
+    return;
+  }
+  
+  hsum = CVAdamsStart(cv_mem, m);
+  
+  M[0] = CVAltSum(q-1, m, 1);
+  M[1] = CVAltSum(q-1, m, 2);
+  
+  CVAdamsFinish(cv_mem, m, M, hsum);
+}
+
+/*
+ * CVAdamsStart
+ *
+ * This routine generates in m[] the coefficients of the product
+ * polynomial needed for the Adams l and tq coefficients for q > 1.
+ */
+
+static realtype CVAdamsStart(CVodeMem cv_mem, realtype m[])
+{
+  realtype hsum, xi_inv, sum;
+  int i, j;
+  
+  hsum = h;
+  m[0] = ONE;
+  for (i=1; i <= q; i++) m[i] = ZERO;
+  for (j=1; j < q; j++) {
+    if ((j==q-1) && (qwait == 1)) {
+      sum = CVAltSum(q-2, m, 2);
+      tq[1] = m[q-2] / (q * sum);
+    }
+    xi_inv = h / hsum;
+    for (i=j; i >= 1; i--) m[i] += m[i-1] * xi_inv;
+    hsum += tau[j];
+    /* The m[i] are coefficients of product(1 to j) (1 + x/xi_i) */
+  }
+  return(hsum);
+}
+
+/*
+ * CVAdamsFinish
+ *
+ * This routine completes the calculation of the Adams l and tq.
+ */
+
+static void CVAdamsFinish(CVodeMem cv_mem, realtype m[], realtype M[], realtype hsum)
+{
+  int i;
+  realtype M0_inv, xi, xi_inv;
+  
+  M0_inv = ONE / M[0];
+  
+  l[0] = ONE;
+  for (i=1; i <= q; i++) l[i] = M0_inv * (m[i-1] / i);
+  xi = hsum / h;
+  xi_inv = ONE / xi;
+  
+  tq[2] = xi * M[0] / M[1];
+  tq[5] = xi / l[q];
+
+  if (qwait == 1) {
+    for (i=q; i >= 1; i--) m[i] += m[i-1] * xi_inv;
+    M[2] = CVAltSum(q, m, 2);
+    tq[3] = L * M[0] / M[2];
+  }
+
+  tq[4] = nlscoef * tq[2];
+}
+
+/*  
+ * CVAltSum
+ *
+ * CVAltSum returns the value of the alternating sum
+ *   sum (i= 0 ... iend) [ (-1)^i * (a[i] / (i + k)) ].
+ * If iend < 0 then CVAltSum returns 0.
+ * This operation is needed to compute the integral, from -1 to 0,
+ * of a polynomial x^(k-1) M(x) given the coefficients of M(x).
+ */
+
+static realtype CVAltSum(int iend, realtype a[], int k)
+{
+  int i, sign;
+  realtype sum;
+  
+  if (iend < 0) return(ZERO);
+  
+  sum = ZERO;
+  sign = 1;
+  for (i=0; i <= iend; i++) {
+    sum += sign * (a[i] / (i+k));
+    sign = -sign;
+  }
+  return(sum);
+}
+
+/*
+ * CVSetBDF
+ *
+ * This routine computes the coefficients l and tq in the case
+ * lmm == CV_BDF.  CVSetBDF calls CVSetTqBDF to set the test
+ * quantity array tq. 
+ * 
+ * The components of the array l are the coefficients of a
+ * polynomial Lambda(x) = l_0 + l_1 x + ... + l_q x^q, given by
+ *                                 q-1
+ * Lambda(x) = (1 + x / xi*_q) * PRODUCT (1 + x / xi_i) , where
+ *                                 i=1
+ *  xi_i = [t_n - t_(n-i)] / h.
+ *
+ * The array tq is set to test quantities used in the convergence
+ * test, the error test, and the selection of h at a new order.
+ */
+
+static void CVSetBDF(CVodeMem cv_mem)
+{
+  realtype alpha0, alpha0_hat, xi_inv, xistar_inv, hsum;
+  int i,j;
+  
+  l[0] = l[1] = xi_inv = xistar_inv = ONE;
+  for (i=2; i <= q; i++) l[i] = ZERO;
+  alpha0 = alpha0_hat = -ONE;
+  hsum = h;
+  if (q > 1) {
+    for (j=2; j < q; j++) {
+      hsum += tau[j-1];
+      xi_inv = h / hsum;
+      alpha0 -= ONE / j;
+      for (i=j; i >= 1; i--) l[i] += l[i-1]*xi_inv;
+      /* The l[i] are coefficients of product(1 to j) (1 + x/xi_i) */
+    }
+    
+    /* j = q */
+    alpha0 -= ONE / q;
+    xistar_inv = -l[1] - alpha0;
+    hsum += tau[q-1];
+    xi_inv = h / hsum;
+    alpha0_hat = -l[1] - xi_inv;
+    for (i=q; i >= 1; i--) l[i] += l[i-1]*xistar_inv;
+  }
+
+  CVSetTqBDF(cv_mem, hsum, alpha0, alpha0_hat, xi_inv, xistar_inv);
+}
+
+/*
+ * CVSetTqBDF
+ *
+ * This routine sets the test quantity array tq in the case
+ * lmm == CV_BDF.
+ */
+
+static void CVSetTqBDF(CVodeMem cv_mem, realtype hsum, realtype alpha0,
+                       realtype alpha0_hat, realtype xi_inv, realtype xistar_inv)
+{
+  realtype A1, A2, A3, A4, A5, A6;
+  realtype C, CPrime, CPrimePrime;
+  
+  A1 = ONE - alpha0_hat + alpha0;
+  A2 = ONE + q * A1;
+  tq[2] = ABS(alpha0 * (A2 / A1));
+  tq[5] = ABS((A2) / (l[q] * xi_inv/xistar_inv));
+  if (qwait == 1) {
+    C = xistar_inv / l[q];
+    A3 = alpha0 + ONE / q;
+    A4 = alpha0_hat + xi_inv;
+    CPrime = A3 / (ONE - A4 + A3);
+    tq[1] = ABS(CPrime / C);
+    hsum += tau[q];
+    xi_inv = h / hsum;
+    A5 = alpha0 - (ONE / (q+1));
+    A6 = alpha0_hat - xi_inv;
+    CPrimePrime = A2 / (ONE - A6 + A5);
+    tq[3] = ABS(CPrimePrime * xi_inv * (q+2) * A5);
+  }
+  tq[4] = nlscoef * tq[2];
+}
+
+/* 
+ * -----------------------------------------------------------------
+ * Nonlinear solver functions
+ * -----------------------------------------------------------------
+ */
+
+/*
+ * CVNls
+ *
+ * This routine attempts to solve the nonlinear system associated
+ * with a single implicit step of the linear multistep method.
+ * Depending on iter, it calls CVNlsFunctional or CVNlsNewton
+ * to do the work.
+ */
+
+static int CVNls(CVodeMem cv_mem, int nflag)
+{
+  int flag=CV_SUCCESS;
+
+  switch(iter) {
+  case CV_FUNCTIONAL: 
+    flag = CVNlsFunctional(cv_mem);
+    break;
+  case CV_NEWTON: 
+    flag = CVNlsNewton(cv_mem, nflag);
+    break;
+  }
+  
+  return(flag);
+
+}
+
+/*
+ * CVNlsFunctional
+ *
+ * This routine attempts to solve the nonlinear system using 
+ * functional iteration (no matrices involved).
+ * 
+ * This routine also handles the functional iteration of the
+ * combined system (states + sensitivities) when sensitivities are 
+ * computed using the CV_SIMULTANEOUS approach.
+ *
+ * Possible return values are:
+ *
+ *   CV_SUCCESS       ---> continue with error test
+ *
+ *   CV_RHSFUNC_FAIL  -+   
+ *   CV_SRHSFUNC_FAIL -+-> halt the integration 
+ *
+ *   CONV_FAIL        -+
+ *   RHSFUNC_RECVR     |-> predict again or stop if too many
+ *   SRHSFUNC_RECVR   -+
+ *
+ */
+
+static int CVNlsFunctional(CVodeMem cv_mem)
+{
+  int m;
+  realtype del, delS, Del, Delp, dcon;
+  int retval, is;
+  booleantype do_sensi_sim;
+  N_Vector wrk1, wrk2;
+
+  /* Are we computing sensitivities with the CV_SIMULTANEOUS approach? */
+  do_sensi_sim = (sensi && (ism==CV_SIMULTANEOUS));
+
+  /* Initialize counter and evaluate f at predicted y */
+  crate = ONE;
+  m = 0;
+
+  /* Initialize delS and Delp to avoid compiler warning message */
+  delS = Delp = ZERO;
+
+  retval = f(tn, zn[0], tempv, f_data);
+  nfe++;
+  if (retval < 0) return(CV_RHSFUNC_FAIL);
+  if (retval > 0) return(RHSFUNC_RECVR);
+
+  if (do_sensi_sim) {
+    wrk1 = ftemp;
+    wrk2 = ftempS[0];
+    retval = CVSensRhs(cv_mem, tn, zn[0], tempv, znS[0], tempvS, wrk1, wrk2);
+    if (retval < 0) return(CV_SRHSFUNC_FAIL);
+    if (retval > 0) return(SRHSFUNC_RECVR);
+  }
+
+  /* Initialize correction to zero */
+
+  N_VConst(ZERO, acor);
+  if (do_sensi_sim) {
+    for (is=0; is<Ns; is++)
+      N_VConst(ZERO,acorS[is]);
+  }
+
+  /* Loop until convergence; accumulate corrections in acor */
+
+  loop {
+
+    nni++;
+
+    /* Correct y directly from the last f value */
+
+    N_VLinearSum(h, tempv, -ONE, zn[1], tempv);
+    N_VScale(rl1, tempv, tempv);
+    N_VLinearSum(ONE, zn[0], ONE, tempv, y);
+
+    if (do_sensi_sim)
+      for (is=0; is<Ns; is++) {
+        N_VLinearSum(h, tempvS[is], -ONE, znS[1][is], tempvS[is]);
+        N_VScale(rl1, tempvS[is], tempvS[is]);
+        N_VLinearSum(ONE, znS[0][is], ONE, tempvS[is], yS[is]);
+      }
+    
+    /* Get WRMS norm of current correction to use in convergence test */
+
+    N_VLinearSum(ONE, tempv, -ONE, acor, acor);
+    if (do_sensi_sim)
+      for (is=0; is<Ns; is++)
+        N_VLinearSum(ONE, tempvS[is], -ONE, acorS[is], acorS[is]);
+
+    del = N_VWrmsNorm(acor, ewt);
+    if (do_sensi_sim)
+      delS = CVSensUpdateNorm(cv_mem, del, acorS, ewtS);
+
+    N_VScale(ONE, tempv, acor);
+    if (do_sensi_sim) 
+      for (is=0; is<Ns; is++)
+        N_VScale(ONE, tempvS[is], acorS[is]);
+    
+    /* Test for convergence.  If m > 0, an estimate of the convergence
+       rate constant is stored in crate, and used in the test. 
+
+       Recall that, even when errconS=FALSE, all variables are used in the
+       convergence test. Hence, we use Del (and not del). However, acnrm
+       is used in the error test and thus it has different forms
+       depending on errconS (and this explains why we have to carry around
+       del and delS)
+    */
+    
+    Del = (do_sensi_sim) ? delS : del;
+    if (m > 0) crate = MAX(CRDOWN * crate, Del / Delp);
+    dcon = Del * MIN(ONE, crate) / tq[4];
+
+    if (dcon <= ONE) {
+      if (m == 0)
+        if (do_sensi_sim && errconS) acnrm = delS;
+        else                         acnrm = del;
+      else {
+        acnrm = N_VWrmsNorm(acor, ewt);
+        if (do_sensi_sim && errconS)
+          acnrm = CVSensUpdateNorm(cv_mem, acnrm, acorS, ewtS);
+      }
+      return(CV_SUCCESS);  /* Convergence achieved */
+    }
+
+    /* Stop at maxcor iterations or if iter. seems to be diverging */
+
+    m++;
+    if ((m==maxcor) || ((m >= 2) && (Del > RDIV * Delp))) return(CONV_FAIL);
+
+    /* Save norm of correction, evaluate f, and loop again */
+
+    Delp = Del;
+
+    retval = f(tn, y, tempv, f_data);
+    nfe++;
+    if (retval < 0) return(CV_RHSFUNC_FAIL);
+    if (retval > 0) return(RHSFUNC_RECVR);
+
+    if (do_sensi_sim) {
+      wrk1 = ftemp;
+      wrk2 = ftempS[0];
+      retval = CVSensRhs(cv_mem, tn, y, tempv, yS, tempvS, wrk1, wrk2);
+      if (retval < 0) return(CV_SRHSFUNC_FAIL);
+      if (retval > 0) return(SRHSFUNC_RECVR);
+    }      
+
+  } /* end loop */
+
+}
+
+/*
+ * CVNlsNewton
+ *
+ * This routine handles the Newton iteration. It calls lsetup if 
+ * indicated, calls CVNewtonIteration to perform the iteration, and 
+ * retries a failed attempt at Newton iteration if that is indicated.
+ * See return values at top of this file.
+ *
+ * This routine also handles the Newton iteration of the combined 
+ * system when sensitivities are computed using the CV_SIMULTANEOUS
+ * approach. Since in that case we use a quasi-Newton on the 
+ * combined system (by approximating the Jacobian matrix by its
+ * block diagonal) and thus only solve linear systems with 
+ * multiple right hand sides (all sharing the same coefficient
+ * matrix - whatever iteration matrix we decide on) we set-up
+ * the linear solver to handle N equations at a time.
+ *
+ * Possible return values:
+ *
+ *   CV_SUCCESS       ---> continue with error test
+ *
+ *   CV_RHSFUNC_FAIL  -+  
+ *   CV_LSETUP_FAIL    |
+ *   CV_LSOLVE_FAIL    |-> halt the integration 
+ *   CV_SRHSFUNC_FAIL -+
+ *
+ *   CONV_FAIL        -+
+ *   RHSFUNC_RECVR     |-> predict again or stop if too many
+ *   SRHSFUNC_RECVR   -+
+ *
+ */
+
+static int CVNlsNewton(CVodeMem cv_mem, int nflag)
+{
+  N_Vector vtemp1, vtemp2, vtemp3, wrk1, wrk2;
+  int convfail, ier;
+  booleantype callSetup, do_sensi_sim;
+  int retval, is;
+  
+  /* Are we computing sensitivities with the CV_SIMULTANEOUS approach? */
+  do_sensi_sim = (sensi && (ism==CV_SIMULTANEOUS));
+
+  vtemp1 = acor;  /* rename acor as vtemp1 for readability  */
+  vtemp2 = y;     /* rename y as vtemp2 for readability     */
+  vtemp3 = tempv; /* rename tempv as vtemp3 for readability */
+  
+  /* Set flag convfail, input to lsetup for its evaluation decision */
+  convfail = ((nflag == FIRST_CALL) || (nflag == PREV_ERR_FAIL)) ?
+    CV_NO_FAILURES : CV_FAIL_OTHER;
+
+  /* Decide whether or not to call setup routine (if one exists) */
+  if (setupNonNull) {      
+    callSetup = (nflag == PREV_CONV_FAIL) || (nflag == PREV_ERR_FAIL) ||
+      (nst == 0) || (nst >= nstlp + MSBP) || (ABS(gamrat-ONE) > DGMAX);
+
+    /* Decide whether to force a call to setup */
+    if (forceSetup) {
+      callSetup = TRUE;
+      convfail = CV_FAIL_OTHER;
+    }
+
+  } else {  
+    crate = ONE;
+    crateS = ONE;  /* if NO lsetup all conv. rates are set to ONE */
+    callSetup = FALSE;
+  }
+  
+  /* Looping point for the solution of the nonlinear system.
+     Evaluate f at the predicted y, call lsetup if indicated, and
+     call CVNewtonIteration for the Newton iteration itself.      */
+
+  loop {
+
+    retval = f(tn, zn[0], ftemp, f_data);
+    nfe++; 
+    if (retval < 0) return(CV_RHSFUNC_FAIL);
+    if (retval > 0) return(RHSFUNC_RECVR);
+
+    if (do_sensi_sim) {
+      wrk1 = tempv;
+      wrk2 = tempvS[0];
+      retval = CVSensRhs(cv_mem, tn, zn[0], ftemp, znS[0], ftempS, wrk1, wrk2);
+      if (retval < 0) return(CV_SRHSFUNC_FAIL);
+      if (retval > 0) return(SRHSFUNC_RECVR);
+    }
+
+    if (callSetup) {
+      ier = lsetup(cv_mem, convfail, zn[0], ftemp, &jcur, 
+                   vtemp1, vtemp2, vtemp3);
+      nsetups++;
+      callSetup = FALSE;
+      forceSetup = FALSE;
+      gamrat = ONE; 
+      gammap = gamma;
+      crate = ONE;
+      crateS = ONE; /* after lsetup all conv. rates are reset to ONE */
+      nstlp = nst;
+      /* Return if lsetup failed */
+      if (ier < 0) return(CV_LSETUP_FAIL);
+      if (ier > 0) return(CONV_FAIL);
+    }
+
+    /* Set acor to zero and load prediction into y vector */
+    N_VConst(ZERO, acor);
+    N_VScale(ONE, zn[0], y);
+
+    if (do_sensi_sim)
+      for (is=0; is<Ns; is++) {
+        N_VConst(ZERO, acorS[is]);
+        N_VScale(ONE, znS[0][is], yS[is]);
+      }
+
+    /* Do the Newton iteration */
+    ier = CVNewtonIteration(cv_mem);
+
+    /* If there is a convergence failure and the Jacobian-related 
+       data appears not to be current, loop again with a call to lsetup
+       in which convfail=CV_FAIL_BAD_J.  Otherwise return.                 */
+    if (ier != TRY_AGAIN) return(ier);
+    
+    callSetup = TRUE;
+    convfail = CV_FAIL_BAD_J;
+  }
+}
+
+/*
+ * CVNewtonIteration
+ *
+ * This routine performs the Newton iteration. If the iteration succeeds,
+ * it returns the value CV_SUCCESS. If not, it may signal the CVNlsNewton 
+ * routine to call lsetup again and reattempt the iteration, by
+ * returning the value TRY_AGAIN. (In this case, CVNlsNewton must set 
+ * convfail to CV_FAIL_BAD_J before calling setup again). 
+ * Otherwise, this routine returns one of the appropriate values 
+ * CV_LSOLVE_FAIL, CV_RHSFUNC_FAIL, CV_SRHSFUNC_FAIL, CONV_FAIL,
+ * RHSFUNC_RECVR, or SRHSFUNC_RECVR back to CVNlsNewton.
+ *
+ * If sensitivities are computed using the CV_SIMULTANEOUS approach, this
+ * routine performs a quasi-Newton on the combined nonlinear system.
+ * The iteration matrix of the combined system is block diagonal with
+ * each block being the iteration matrix of the original system. Thus
+ * we solve linear systems with the same matrix but different right
+ * hand sides.
+ */
+
+static int CVNewtonIteration(CVodeMem cv_mem)
+{
+  int m;
+  realtype del, delS, Del, Delp, dcon;
+  N_Vector b, *bS=NULL, wrk1, wrk2;
+  booleantype do_sensi_sim;
+  int retval, is;
+  
+  /* Are we computing sensitivities with the CV_SIMULTANEOUS approach? */
+  do_sensi_sim = (sensi && (ism==CV_SIMULTANEOUS));
+
+  mnewt = m = 0;
+
+  /* Initialize delS and Delp to avoid compiler warning message */
+  delS = Delp = ZERO;
+
+  /* At this point, ftemp  <- f(t_n, y_n(0))
+     ftempS <- fS(t_n, y_n(0), s_n(0))
+     acor   <- 0
+     acorS  <- 0
+     y      <- y_n(0)
+     yS     <- yS_n(0)                 */
+
+  /* Looping point for Newton iteration */
+  loop {
+    
+    /* Evaluate the residual of the nonlinear system */
+    N_VLinearSum(rl1, zn[1], ONE, acor, tempv);
+    N_VLinearSum(gamma, ftemp, -ONE, tempv, tempv);
+
+    /* Call the lsolve function */
+    b = tempv;
+
+    retval = lsolve(cv_mem, b, ewt, y, ftemp); 
+    nni++;
+
+    if (retval < 0) return(CV_LSOLVE_FAIL);
+    
+    /* If lsolve had a recoverable failure and Jacobian data is
+       not current, signal to try the solution again            */
+    if (retval > 0) { 
+      if ((!jcur) && (setupNonNull)) return(TRY_AGAIN);
+      else                           return(CONV_FAIL);
+    }
+
+    /* Solve the sensitivity linear systems and do the same 
+       tests on the return value of lsolve. */
+ 
+    if (do_sensi_sim) {
+
+      for (is=0; is<Ns; is++) {
+        N_VLinearSum(rl1, znS[1][is], ONE, acorS[is], tempvS[is]);
+        N_VLinearSum(gamma, ftempS[is], -ONE, tempvS[is], tempvS[is]);
+      }
+      bS = tempvS;
+      for (is=0; is<Ns; is++) {
+        retval = lsolve(cv_mem, bS[is], ewtS[is], y, ftemp);
+        if (retval < 0) return(CV_LSOLVE_FAIL);
+        if (retval > 0) { 
+          if ((!jcur) && (setupNonNull)) return(TRY_AGAIN);
+          else                           return(CONV_FAIL);
+        }
+      }
+    }
+    
+    /* Get WRMS norm of correction; add correction to acor and y */
+
+    del = N_VWrmsNorm(b, ewt);
+    N_VLinearSum(ONE, acor, ONE, b, acor);
+    N_VLinearSum(ONE, zn[0], ONE, acor, y);
+
+    if (do_sensi_sim) {
+      delS = CVSensUpdateNorm(cv_mem, del, bS, ewtS);
+      for (is=0; is<Ns; is++) {
+        N_VLinearSum(ONE, acorS[is], ONE, bS[is], acorS[is]);
+        N_VLinearSum(ONE, znS[0][is], ONE, acorS[is], yS[is]);
+      }
+    }
+
+    /* Test for convergence.  If m > 0, an estimate of the convergence
+       rate constant is stored in crate, and used in the test.        */
+
+    Del = (do_sensi_sim) ? delS : del;
+    if (m > 0) crate = MAX(CRDOWN * crate, Del/Delp);
+    dcon = Del * MIN(ONE, crate) / tq[4];
+    
+    if (dcon <= ONE) {
+      if (m == 0)
+        if (do_sensi_sim && errconS) acnrm = delS;
+        else                         acnrm = del;
+      else {
+        acnrm = N_VWrmsNorm(acor, ewt);
+        if (do_sensi_sim && errconS)
+          acnrm = CVSensUpdateNorm(cv_mem, acnrm, acorS, ewtS);
+      }
+      jcur = FALSE;
+      return(CV_SUCCESS);  /* Convergence achieved */
+    }
+
+    mnewt = ++m;
+    
+    /* Stop at maxcor iterations or if iter. seems to be diverging.
+       If still not converged and Jacobian data is not current, 
+       signal to try the solution again                            */
+    if ((m == maxcor) || ((m >= 2) && (Del > RDIV * Delp))) {
+      if ((!jcur) && (setupNonNull)) return(TRY_AGAIN);
+      else                           return(CONV_FAIL);
+    }
+    
+    /* Save norm of correction, evaluate f, and loop again */
+    Delp = Del;
+    retval = f(tn, y, ftemp, f_data);
+    nfe++;
+    if (retval < 0) return(CV_RHSFUNC_FAIL);
+    if (retval > 0) {
+      if ((!jcur) && (setupNonNull)) return(TRY_AGAIN);
+      else                           return(RHSFUNC_RECVR);
+    }
+
+    if (do_sensi_sim) {
+      wrk1 = tempv;
+      wrk2 = tempvS[0];
+      retval = CVSensRhs(cv_mem, tn, y, ftemp, yS, ftempS, wrk1, wrk2);
+      if (retval < 0) return(CV_SRHSFUNC_FAIL);
+      if (retval > 0) {
+        if ((!jcur) && (setupNonNull)) return(TRY_AGAIN);
+        else                           return(SRHSFUNC_RECVR);
+      }
+    }
+
+  } /* end loop */
+
+}
+
+/*
+ * CVQuadNls
+ * 
+ * This routine solves for the quadrature variables at the new step.
+ * It does not solve a nonlinear system, but rather updates the
+ * quadrature variables. The name for this function is just for 
+ * uniformity purposes.
+ *
+ * Possible return values (interpreted by CVHandleNFlag)
+ *
+ *   CV_SUCCESS       -> continue with error test
+ *   CV_QRHSFUNC_FAIL -> halt the integration 
+ *   QRHSFUNC_RECVR   -> predict again or stop if too many
+ *   
+ */
+
+static int CVQuadNls(CVodeMem cv_mem)
+{
+  int retval;
+
+  /* Save quadrature correction in acorQ */
+  retval = fQ(tn, y, acorQ, fQ_data);
+  nfQe++;
+  if (retval < 0) return(CV_QRHSFUNC_FAIL);
+  if (retval > 0) return(QRHSFUNC_RECVR);
+
+  N_VLinearSum(h, acorQ, -ONE, znQ[1], acorQ);
+  N_VScale(rl1, acorQ, acorQ);
+
+  /* Apply correction to quadrature variables */
+  N_VLinearSum(ONE, znQ[0], ONE, acorQ, yQ);
+
+  return(CV_SUCCESS);
+}
+
+/*
+ * CVStgrNls
+ *
+ * This is a high-level routine that attempts to solve the 
+ * sensitivity linear systems using nonlinear iterations (CV_FUNCTIONAL
+ * or CV_NEWTON - depending on the value of iter) once the states y_n
+ * were obtained and passed the error test.
+ */
+
+static int CVStgrNls(CVodeMem cv_mem)
+{
+  int flag=CV_SUCCESS;
+
+  switch(iter) {
+  case CV_FUNCTIONAL: 
+    flag = CVStgrNlsFunctional(cv_mem);
+    break;
+  case CV_NEWTON:     
+    flag = CVStgrNlsNewton(cv_mem);
+    break;
+  }
+
+  return(flag);
+
+}
+
+/*
+ * CVStgrNlsfunctional
+ *
+ * This routine attempts to solve the sensitivity linear systems 
+ * using functional iteration (no matrices involved).
+ *
+ * Possible return values:
+ *  CV_SUCCESS,
+ *  CV_SRHSFUNC_FAIL,
+ *  CONV_FAIL, SRHSFUNC_RECVR
+ */
+
+static int CVStgrNlsFunctional(CVodeMem cv_mem)
+{
+  int m;
+  int retval, is;
+  realtype Del, Delp, dcon;
+  N_Vector wrk1, wrk2;
+
+  /* Initialize estimated conv. rate and counter */
+  crateS = ONE;
+  m = 0;
+
+  /* Initialize Delp to avoid compiler warning message */
+  Delp = ZERO;
+
+  /* Evaluate fS at predicted yS but with converged y (and corresponding f) */
+  wrk1 = tempv;
+  wrk2 = ftempS[0];
+  retval = CVSensRhs(cv_mem, tn, y, ftemp, znS[0], tempvS, wrk1, wrk2);
+  if (retval < 0) return(CV_SRHSFUNC_FAIL);
+  if (retval > 0) return(SRHSFUNC_RECVR);
+
+  /* Initialize correction to zero */
+  for (is=0; is<Ns; is++)
+    N_VConst(ZERO,acorS[is]);
+
+  /* Loop until convergence; accumulate corrections in acorS */
+
+  loop {
+    
+    nniS++;
+    
+    /* Correct yS from last fS value */
+    for (is=0; is<Ns; is++) {
+      N_VLinearSum(h, tempvS[is], -ONE, znS[1][is], tempvS[is]);
+      N_VScale(rl1, tempvS[is], tempvS[is]);
+      N_VLinearSum(ONE, znS[0][is], ONE, tempvS[is], yS[is]);
+    }
+    /* Get norm of current correction to use in convergence test */
+    for (is=0; is<Ns; is++)
+      N_VLinearSum(ONE, tempvS[is], -ONE, acorS[is], acorS[is]);
+    Del = CVSensNorm(cv_mem, acorS, ewtS);
+    for (is=0; is<Ns; is++)
+      N_VScale(ONE, tempvS[is], acorS[is]);
+
+    /* Test for convergence.  If m > 0, an estimate of the convergence
+       rate constant is stored in crateS, and used in the test. 
+       acnrmS contains the norm of the corrections (yS_n-yS_n(0)) and
+       will be used in the error test (if errconS==TRUE)              */
+    if (m > 0) crateS = MAX(CRDOWN * crateS, Del / Delp);
+    dcon = Del * MIN(ONE, crateS) / tq[4];
+    
+    if (dcon <= ONE) {
+      if (errconS)
+        acnrmS = (m==0)? Del : CVSensNorm(cv_mem, acorS, ewtS);
+      return(CV_SUCCESS);  /* Convergence achieved */
+    }
+
+    /* Stop at maxcor iterations or if iter. seems to be diverging */
+    m++;
+    if ((m==maxcorS) || ((m >= 2) && (Del > RDIV * Delp))) return(CONV_FAIL);
+
+    /* Save norm of correction, evaluate f, and loop again */
+    Delp = Del;
+
+    wrk1 = tempv;
+    wrk2 = ftempS[0];
+    retval = CVSensRhs(cv_mem, tn, y, ftemp, yS, tempvS, wrk1, wrk2);
+    if (retval < 0) return(CV_SRHSFUNC_FAIL);
+    if (retval > 0) return(SRHSFUNC_RECVR);
+
+  } /* end loop */
+  
+}
+
+/*
+ * CVStgrNlsNewton
+ *
+ * This routine attempts to solve the sensitivity linear systems using 
+ * Newton iteration. It calls CVStgrNlsNewton to perform the actual 
+ * iteration. If the Newton iteration fails with out-of-date Jacobian 
+ * data (ier=TRY_AGAIN), it calls lsetup and retries the Newton iteration. 
+ * This second try is unlikely to happen when using a Krylov linear solver.
+ *
+ * Possible return values:
+ *
+ *   CV_SUCCESS
+ *
+ *   CV_LSOLVE_FAIL   -+
+ *   CV_LSETUP_FAIL    |
+ *   CV_SRHSFUNC_FAIL -+
+ *
+ *   CONV_FAIL        -+
+ *   SRHSFUNC_RECVR   -+
+ */
+
+static int CVStgrNlsNewton(CVodeMem cv_mem)
+{
+  int retval, is;
+  int convfail, ier;
+  N_Vector vtemp1, vtemp2, vtemp3, wrk1, wrk2;
+
+  loop {
+
+    /* Set acorS to zero and load prediction into yS vector */
+    for (is=0; is<Ns; is++) {
+      N_VConst(ZERO, acorS[is]);
+      N_VScale(ONE, znS[0][is], yS[is]);
+    }
+ 
+    /* Evaluate fS at predicted yS but with converged y (and corresponding f) */
+    wrk1 = tempv;
+    wrk2 = tempvS[0];
+    retval = CVSensRhs(cv_mem, tn, y, ftemp, yS, ftempS, wrk1, wrk2);
+    if (retval < 0) return(CV_SRHSFUNC_FAIL);
+    if (retval > 0) return(SRHSFUNC_RECVR);
+
+    /* Do the Newton iteration */
+    ier = CVStgrNewtonIteration(cv_mem);
+
+    /* If the solve was successful (ier=CV_SUCCESS) or if an error 
+       that cannot be fixed by a call to lsetup occured
+       (ier = CV_LSOLVE_FAIL or CONV_FAIL) return */
+    if (ier != TRY_AGAIN) return(ier);
+
+    /* There was a convergence failure and the Jacobian-related data
+       appears not to be current. Call lsetup with convfail=CV_FAIL_BAD_J
+       and then loop again */
+    convfail = CV_FAIL_BAD_J;
+
+    /* Rename some vectors for readibility */
+    vtemp1 = tempv;
+    vtemp2 = yS[0];
+    vtemp3 = ftempS[0];
+
+    /* Call linear solver setup at converged y */
+    ier = lsetup(cv_mem, convfail, y, ftemp, &jcur, 
+                 vtemp1, vtemp2, vtemp3);
+    nsetups++;
+    nsetupsS++;
+    gamrat = ONE;
+    gammap = gamma;
+    crate = ONE;
+    crateS = ONE; /* after lsetup all conv. rates are reset to ONE */
+    nstlp = nst;
+
+    /* Return if lsetup failed */
+    if (ier < 0) return(CV_LSETUP_FAIL);
+    if (ier > 0) return(CONV_FAIL);
+
+  } /* end loop */
+
+}
+
+/*
+ * CVstgrNewtonIteration
+ *
+ * This routine performs the Newton iteration for all sensitivities. 
+ * If the iteration succeeds, it returns the value CV_SUCCESS. 
+ * If not, it may signal the CVStgrNlsNewton routine to call lsetup and 
+ * reattempt the iteration, by returning the value TRY_AGAIN. (In this case, 
+ * CVStgrNlsNewton must set convfail to CV_FAIL_BAD_J before calling setup again). 
+ * Otherwise, this routine returns one of the appropriate values 
+ * CV_LSOLVE_FAIL or CONV_FAIL back to CVStgrNlsNewton.
+ */
+
+static int CVStgrNewtonIteration(CVodeMem cv_mem)
+{
+  int m, retval;
+  realtype Del, Delp, dcon;
+  N_Vector *bS, wrk1, wrk2;
+  int is;
+
+  m = 0;
+
+  /* Initialize Delp to avoid compiler warning message */
+  Delp = ZERO;
+
+  /* ftemp  <- f(t_n, y_n)
+     y      <- y_n
+     ftempS <- fS(t_n, y_n(0), s_n(0))
+     acorS  <- 0
+     yS     <- yS_n(0)                   */
+
+  loop {
+
+    /* Evaluate the residual of the nonlinear systems */
+    for (is=0; is<Ns; is++) {
+      N_VLinearSum(rl1, znS[1][is], ONE, acorS[is], tempvS[is]);
+      N_VLinearSum(gamma, ftempS[is], -ONE, tempvS[is], tempvS[is]);
+    }
+
+    /* Call the lsolve function */
+    bS = tempvS;
+    nniS++;
+    for (is=0; is<Ns; is++) {
+
+      retval = lsolve(cv_mem, bS[is], ewtS[is], y, ftemp);
+
+      /* Unrecoverable error in lsolve */
+      if (retval < 0) return(CV_LSOLVE_FAIL);
+
+      /* Recoverable error in lsolve and Jacobian data not current */
+      if (retval > 0) { 
+        if ((!jcur) && (setupNonNull)) return(TRY_AGAIN);
+        else                           return(CONV_FAIL);
+      }
+
+    }
+ 
+    /* Get norm of correction; add correction to acorS and yS */
+    Del = CVSensNorm(cv_mem, bS, ewtS);
+    for (is=0; is<Ns; is++) {
+      N_VLinearSum(ONE, acorS[is], ONE, bS[is], acorS[is]);
+      N_VLinearSum(ONE, znS[0][is], ONE, acorS[is], yS[is]);
+    }
+
+    /* Test for convergence.  If m > 0, an estimate of the convergence
+       rate constant is stored in crateS, and used in the test.        */
+    if (m > 0) crateS = MAX(CRDOWN * crateS, Del/Delp);
+    dcon = Del * MIN(ONE, crateS) / tq[4];
+    if (dcon <= ONE) {
+      if (errconS)
+        acnrmS = (m==0) ? Del : CVSensNorm(cv_mem, acorS, ewtS);
+      jcur = FALSE;
+      return(CV_SUCCESS);  /* Convergence achieved */
+    }
+
+    m++;
+
+    /* Stop at maxcor iterations or if iter. seems to be diverging.
+       If still not converged and Jacobian data is not current, 
+       signal to try the solution again                            */
+    if ((m == maxcorS) || ((m >= 2) && (Del > RDIV * Delp))) {
+      if ((!jcur) && (setupNonNull)) return(TRY_AGAIN);
+      else                           return(CONV_FAIL);
+    }
+    
+    /* Save norm of correction, evaluate fS, and loop again */
+    Delp = Del;
+    
+    wrk1 = tempv;
+    wrk2 = tempvS[0];
+    retval = CVSensRhs(cv_mem, tn, y, ftemp, yS, ftempS, wrk1, wrk2);
+    if (retval < 0) return(CV_SRHSFUNC_FAIL);
+    if (retval > 0) {
+      if ((!jcur) && (setupNonNull)) return(TRY_AGAIN);
+      else                           return(SRHSFUNC_RECVR);
+    }
+
+  } /* end loop */
+
+}
+
+/*
+ * CVStgr1Nls
+ *
+ * This is a high-level routine that attempts to solve the i-th 
+ * sensitivity linear system using nonlinear iterations (CV_FUNCTIONAL
+ * or CV_NEWTON - depending on the value of iter) once the states y_n
+ * were obtained and passed the error test.
+ */
+
+static int CVStgr1Nls(CVodeMem cv_mem, int is)
+{
+  int flag=CV_SUCCESS;
+
+  switch(iter) {
+  case CV_FUNCTIONAL: 
+    flag = CVStgr1NlsFunctional(cv_mem,is);
+    break;
+  case CV_NEWTON:     
+    flag = CVStgr1NlsNewton(cv_mem,is);
+    break;
+  }
+
+  return(flag);
+
+}
+
+/*
+ * CVStgr1NlsFunctional
+ *
+ * This routine attempts to solve the i-th sensitivity linear system
+ * using functional iteration (no matrices involved).
+ *
+ * Possible return values:
+ *   CV_SUCCESS,
+ *   CV_SRHSFUNC_FAIL,
+ *   CONV_FAIL, SRHSFUNC_RECVR
+ */
+
+static int CVStgr1NlsFunctional(CVodeMem cv_mem, int is)
+{
+  int retval, m;
+  realtype Del, Delp, dcon;
+  N_Vector wrk1, wrk2;
+
+  /* Initialize estimated conv. rate and counter */
+  crateS = ONE;
+  m = 0;
+
+  /* Initialize Delp to avoid compiler warning message */
+  Delp = ZERO;
+
+  /* Evaluate fS at predicted yS but with converged y (and corresponding f) */
+  wrk1 = tempv;
+  wrk2 = ftempS[0];
+  retval = CVSensRhs1(cv_mem, tn, y, ftemp, is, znS[0][is], tempvS[is], wrk1, wrk2);
+  if (retval < 0) return(CV_SRHSFUNC_FAIL);
+  if (retval > 0) return(SRHSFUNC_RECVR);
+
+  /* Initialize correction to zero */
+  N_VConst(ZERO,acorS[is]);
+
+  /* Loop until convergence; accumulate corrections in acorS */
+
+  loop {
+
+    nniS1[is]++;
+
+    /* Correct yS from last fS value */
+    N_VLinearSum(h, tempvS[is], -ONE, znS[1][is], tempvS[is]);
+    N_VScale(rl1, tempvS[is], tempvS[is]);
+    N_VLinearSum(ONE, znS[0][is], ONE, tempvS[is], yS[is]);
+
+    /* Get WRMS norm of current correction to use in convergence test */
+    N_VLinearSum(ONE, tempvS[is], -ONE, acorS[is], acorS[is]);
+    Del = N_VWrmsNorm(acorS[is], ewtS[is]);
+    N_VScale(ONE, tempvS[is], acorS[is]);
+
+    /* Test for convergence.  If m > 0, an estimate of the convergence
+       rate constant is stored in crateS, and used in the test. */
+
+    if (m > 0) crateS = MAX(CRDOWN * crateS, Del / Delp);
+    dcon = Del * MIN(ONE, crateS) / tq[4];
+
+    if (dcon <= ONE) {
+      return(CV_SUCCESS);  /* Convergence achieved */
+    }
+
+    /* Stop at maxcor iterations or if iter. seems to be diverging */
+    m++;
+    if ((m==maxcorS) || ((m >= 2) && (Del > RDIV * Delp))) return(CONV_FAIL);
+
+    /* Save norm of correction, evaluate f, and loop again */
+    Delp = Del;
+
+    wrk1 = tempv;
+    wrk2 = ftempS[0];
+
+    retval = CVSensRhs1(cv_mem, tn, y, ftemp, is, yS[is], tempvS[is], wrk1, wrk2);
+    if (retval < 0) return(CV_SRHSFUNC_FAIL);
+    if (retval > 0) return(SRHSFUNC_RECVR);
+
+  } /* end loop */
+  
+}
+
+/*
+ * CVStgr1NlsNewton
+ *
+ * This routine attempts to solve the i-th sensitivity linear system 
+ * using Newton iteration. It calls CVStgr1NlsNewton to perform the 
+ * actual iteration. If the Newton iteration fails with out-of-date 
+ * Jacobian data (ier=TRY_AGAIN), it calls lsetup and retries the 
+ * Newton iteration. This second try is unlikely to happen when 
+ * using a Krylov linear solver.
+ *
+ * Possible return values:
+ *
+ *   CV_SUCCESS
+ *
+ *   CV_LSOLVE_FAIL
+ *   CV_LSETUP_FAIL
+ *   CV_SRHSFUNC_FAIL
+ *
+ *   CONV_FAIL
+ *   SRHSFUNC_RECVR
+ */
+
+static int CVStgr1NlsNewton(CVodeMem cv_mem, int is)
+{
+  int convfail, retval, ier;
+  N_Vector vtemp1, vtemp2, vtemp3, wrk1, wrk2;
+
+  loop {
+
+    /* Set acorS to zero and load prediction into yS vector */
+    N_VConst(ZERO, acorS[is]);
+    N_VScale(ONE, znS[0][is], yS[is]);
+ 
+    /* Evaluate fS at predicted yS but with converged y (and corresponding f) */
+    wrk1 = tempv;
+    wrk2 = tempvS[0];
+    retval = CVSensRhs1(cv_mem, tn, y, ftemp, is, yS[is], ftempS[is], wrk1, wrk2);
+    if (retval < 0) return(CV_SRHSFUNC_FAIL);
+    if (retval > 0) return(SRHSFUNC_RECVR);
+  
+    /* Do the Newton iteration */
+    ier = CVStgr1NewtonIteration(cv_mem, is);
+
+    /* If the solve was successful (ier=CV_SUCCESS) or if an error 
+       that cannot be fixed by a call to lsetup occured
+       (ier = CV_LSOLVE_FAIL or CONV_FAIL) return */
+    if (ier != TRY_AGAIN) return(ier);
+
+    /* There was a convergence failure and the Jacobian-related data
+       appears not to be current. Call lsetup with convfail=CV_FAIL_BAD_J
+       and then loop again */
+    convfail = CV_FAIL_BAD_J;
+
+    /* Rename some vectors for readibility */
+    vtemp1 = tempv;
+    vtemp2 = yS[0];
+    vtemp3 = ftempS[0];
+
+    /* Call linear solver setup at converged y */
+    ier = lsetup(cv_mem, convfail, y, ftemp, &jcur, 
+                 vtemp1, vtemp2, vtemp3);
+    nsetups++;
+    nsetupsS++;
+    gamrat = ONE;
+    crate = ONE;
+    crateS = ONE; /* after lsetup all conv. rates are reset to ONE */
+    gammap = gamma;
+    nstlp = nst;
+
+    /* Return if lsetup failed */
+    if (ier < 0) return(CV_LSETUP_FAIL);
+    if (ier > 0) return(CONV_FAIL);
+
+  } /* end loop */
+
+}
+
+/*
+ * CVStgr1NewtonIteration
+ *
+ * This routine performs the Newton iteration for the i-th sensitivity. 
+ * If the iteration succeeds, it returns the value CV_SUCCESS. 
+ * If not, it may signal the CVStgr1NlsNewton routine to call lsetup 
+ * and reattempt the iteration, by returning the value TRY_AGAIN. 
+ * (In this case, CVStgr1NlsNewton must set convfail to CV_FAIL_BAD_J 
+ * before calling setup again). Otherwise, this routine returns one 
+ * of the appropriate values CV_LSOLVE_FAIL or CONV_FAIL back to 
+ * CVStgr1NlsNewton.
+ */
+
+static int CVStgr1NewtonIteration(CVodeMem cv_mem, int is)
+{
+  int m, retval;
+  realtype Del, Delp, dcon;
+  N_Vector *bS, wrk1, wrk2;
+
+  m = 0;
+
+  /* Initialize Delp to avoid compiler warning message */
+  Delp = ZERO;
+
+  /* ftemp      <- f(t_n, y_n)
+     y          <- y_n
+     ftempS[is] <- fS(is, t_n, y_n(0), s_n(0))
+     acorS[is]  <- 0
+     yS[is]     <- yS_n(0)[is]                 */
+
+  loop {
+
+    /* Evaluate the residual of the nonlinear systems */
+    N_VLinearSum(rl1, znS[1][is], ONE, acorS[is], tempvS[is]);
+    N_VLinearSum(gamma, ftempS[is], -ONE, tempvS[is], tempvS[is]);
+
+    /* Call the lsolve function */
+    bS = tempvS;
+
+    nniS1[is]++;
+
+    retval = lsolve(cv_mem, bS[is], ewtS[is], y, ftemp);
+
+    /* Unrecoverable error in lsolve */
+    if (retval < 0) return(CV_LSOLVE_FAIL);
+
+    /* Recoverable error in lsolve and Jacobian data not current */
+    if (retval > 0) { 
+      if ((!jcur) && (setupNonNull)) return(TRY_AGAIN);
+      else                           return(CONV_FAIL);
+    }
+
+    /* Get norm of correction; add correction to acorS and yS */
+    Del = N_VWrmsNorm(bS[is], ewtS[is]);
+    N_VLinearSum(ONE, acorS[is], ONE, bS[is], acorS[is]);
+    N_VLinearSum(ONE, znS[0][is], ONE, acorS[is], yS[is]);
+
+    /* Test for convergence.  If m > 0, an estimate of the convergence
+       rate constant is stored in crateS, and used in the test.        */
+    if (m > 0) crateS = MAX(CRDOWN * crateS, Del/Delp);
+    dcon = Del * MIN(ONE, crateS) / tq[4];
+    if (dcon <= ONE) {
+      jcur = FALSE;
+      return(CV_SUCCESS);  /* Convergence achieved */
+    }
+
+    m++;
+
+    /* Stop at maxcor iterations or if iter. seems to be diverging.
+       If still not converged and Jacobian data is not current, 
+       signal to try the solution again                            */
+    if ((m == maxcorS) || ((m >= 2) && (Del > RDIV * Delp))) {
+      if ((!jcur) && (setupNonNull)) return(TRY_AGAIN);
+      else                           return(CONV_FAIL);
+    }
+
+    /* Save norm of correction, evaluate fS, and loop again */
+    Delp = Del;
+
+    wrk1 = tempv;
+    wrk2 = tempvS[0];
+    retval = CVSensRhs1(cv_mem, tn, y, ftemp, is, yS[is], ftempS[is], wrk1, wrk2);
+    if (retval < 0) return(CV_SRHSFUNC_FAIL);
+    if (retval > 0) {
+      if ((!jcur) && (setupNonNull)) return(TRY_AGAIN);
+      else                           return(SRHSFUNC_RECVR);
+    }
+
+  } /* end loop */
+
+}
+
+/*
+ * CVHandleNFlag
+ *
+ * This routine takes action on the return value nflag = *nflagPtr
+ * returned by CVNls, as follows:
+ *
+ * If CVNls succeeded in solving the nonlinear system, then
+ * CVHandleNFlag returns the constant DO_ERROR_TEST, which tells CVStep
+ * to perform the error test.
+ *
+ * If the nonlinear system was not solved successfully, then ncfn and
+ * ncf = *ncfPtr are incremented and Nordsieck array zn is restored.
+ *
+ * If the solution of the nonlinear system failed due to an
+ * unrecoverable failure by setup, we return the value CV_LSETUP_FAIL.
+ * 
+ * If it failed due to an unrecoverable failure in solve, then we return
+ * the value CV_LSOLVE_FAIL.
+ *
+ * If it failed due to an unrecoverable failure in rhs, then we return
+ * the value CV_RHSFUNC_FAIL.
+ *
+ * If it failed due to an unrecoverable failure in quad rhs, then we return
+ * the value CV_QRHSFUNC_FAIL.
+ *
+ * If it failed due to an unrecoverable failure in sensi rhs, then we return
+ * the value CV_SRHSFUNC_FAIL.
+ *
+ * Otherwise, a recoverable failure occurred when solving the 
+ * nonlinear system (CVNls returned nflag = CONV_FAIL, RHSFUNC_RECVR, or
+ * SRHSFUNC_RECVR). 
+ * In this case, if ncf is now equal to maxncf or |h| = hmin, 
+ * we return the value CV_CONV_FAILURE (if nflag=CONV_FAIL), or
+ * CV_REPTD_RHSFUNC_ERR (if nflag=RHSFUNC_RECVR), or CV_REPTD_SRHSFUNC_ERR
+ * (if nflag=SRHSFUNC_RECVR).
+ * If not, we set *nflagPtr = PREV_CONV_FAIL and return the value
+ * PREDICT_AGAIN, telling CVStep to reattempt the step.
+ *
+ */
+
+static int CVHandleNFlag(CVodeMem cv_mem, int *nflagPtr, realtype saved_t,
+                         int *ncfPtr, long int *ncfnPtr)
+{
+  int nflag;
+  
+  nflag = *nflagPtr;
+  
+  if (nflag == CV_SUCCESS) return(DO_ERROR_TEST);
+
+  /* The nonlinear soln. failed; increment ncfn and restore zn */
+  (*ncfnPtr)++;
+  CVRestore(cv_mem, saved_t);
+  
+  /* Return if lsetup, lsolve, or some rhs failed unrecoverably */
+  if (nflag == CV_LSETUP_FAIL)   return(CV_LSETUP_FAIL);
+  if (nflag == CV_LSOLVE_FAIL)   return(CV_LSOLVE_FAIL);
+  if (nflag == CV_RHSFUNC_FAIL)  return(CV_RHSFUNC_FAIL);
+  if (nflag == CV_QRHSFUNC_FAIL) return(CV_QRHSFUNC_FAIL);
+  if (nflag == CV_SRHSFUNC_FAIL) return(CV_SRHSFUNC_FAIL);
+
+  /* At this point, nflag = CONV_FAIL, RHSFUNC_RECVR, or SRHSFUNC_RECVR; 
+     increment ncf */
+  
+  (*ncfPtr)++;
+  etamax = ONE;
+
+  /* If we had maxncf failures or |h| = hmin, 
+     return CV_CONV_FAILURE, CV_REPTD_RHSFUNC_ERR, 
+     CV_REPTD_QRHSFUNC_ERR, or CV_REPTD_SRHSFUNC_ERR */
+
+  if ((ABS(h) <= hmin*ONEPSM) || (*ncfPtr == maxncf)) {
+    if (nflag == CONV_FAIL)      return(CV_CONV_FAILURE);
+    if (nflag == RHSFUNC_RECVR)  return(CV_REPTD_RHSFUNC_ERR);    
+    if (nflag == QRHSFUNC_RECVR) return(CV_REPTD_QRHSFUNC_ERR);    
+    if (nflag == SRHSFUNC_RECVR) return(CV_REPTD_SRHSFUNC_ERR);    
+  }
+
+  /* Reduce step size; return to reattempt the step */
+
+  eta = MAX(ETACF, hmin / ABS(h));
+  *nflagPtr = PREV_CONV_FAIL;
+  CVRescale(cv_mem);
+
+  return(PREDICT_AGAIN);
+}
+
+/*
+ * CVRestore
+ *
+ * This routine restores the value of tn to saved_t and undoes the
+ * prediction.  After execution of CVRestore, the Nordsieck array zn has
+ * the same values as before the call to CVPredict.
+ */
+
+static void CVRestore(CVodeMem cv_mem, realtype saved_t)
+{
+  int j, k;
+  int is;
+
+  tn = saved_t;
+  for (k = 1; k <= q; k++)
+    for (j = q; j >= k; j--)
+      N_VLinearSum(ONE, zn[j-1], -ONE, zn[j], zn[j-1]);
+
+  if (quadr) {
+    for (k = 1; k <= q; k++)
+      for (j = q; j >= k; j--)
+        N_VLinearSum(ONE, znQ[j-1], -ONE, znQ[j], znQ[j-1]);
+  }
+
+  if (sensi) {
+    for (is=0; is<Ns; is++) {
+      for (k = 1; k <= q; k++)
+        for (j = q; j >= k; j--)
+          N_VLinearSum(ONE, znS[j-1][is], -ONE, znS[j][is], znS[j-1][is]);
+    }
+  }
+}
+
+/* 
+ * -----------------------------------------------------------------
+ * Error Test
+ * -----------------------------------------------------------------
+ */
+
+/*
+ * CVDoErrorTest
+ *
+ * This routine performs the local error test, for the state, quadrature, 
+ * or sensitivity variables. Its last three arguments change depending
+ * on which variables the error test is to be performed on.
+ * 
+ * The weighted local error norm dsm is loaded into *dsmPtr, and 
+ * the test dsm ?<= 1 is made.
+ *
+ * If the test passes, CVDoErrorTest returns CV_SUCCESS. 
+ *
+ * If the test fails, we undo the step just taken (call CVRestore) and 
+ *
+ *   - if maxnef error test failures have occurred or if ABS(h) = hmin,
+ *     we return CV_ERR_FAILURE.
+ *
+ *   - if more than MXNEF1 error test failures have occurred, an order
+ *     reduction is forced. If already at order 1, restart by reloading 
+ *     zn from scratch (also znQ and znS if appropriate).
+ *     If f() fails, we return CV_RHSFUNC_FAIL or CV_UNREC_RHSFUNC_ERR;
+ *     if fQ() fails, we return CV_QRHSFUNC_FAIL or CV_UNREC_QRHSFUNC_ERR;
+ *     if CVSensRhs() fails, we return CV_SRHSFUNC_FAIL or CV_UNREC_SRHSFUNC_ERR;
+ *     (no recovery is possible at this stage).
+ *
+ *   - otherwise, set *nflagPtr to PREV_ERR_FAIL, and return TRY_AGAIN. 
+ *
+ */
+
+static int CVDoErrorTest(CVodeMem cv_mem, int *nflagPtr, realtype saved_t, 
+                         realtype acor_nrm,
+                         int *nefPtr, long int *netfPtr, realtype *dsmPtr)
+{
+  realtype dsm;
+  int retval, is;
+  N_Vector wrk1, wrk2;
+
+  dsm = acor_nrm / tq[2];
+
+  /* If est. local error norm dsm passes test, return CV_SUCCESS */  
+  *dsmPtr = dsm; 
+  if (dsm <= ONE) return(CV_SUCCESS);
+  
+  /* Test failed; increment counters, set nflag, and restore zn array */
+  (*nefPtr)++;
+  (*netfPtr)++;
+  *nflagPtr = PREV_ERR_FAIL;
+  CVRestore(cv_mem, saved_t);
+
+  /* At maxnef failures or |h| = hmin, return CV_ERR_FAILURE */
+  if ((ABS(h) <= hmin*ONEPSM) || (*nefPtr == maxnef)) return(CV_ERR_FAILURE);
+
+  /* Set etamax = 1 to prevent step size increase at end of this step */
+  etamax = ONE;
+
+  /* Set h ratio eta from dsm, rescale, and return for retry of step */
+  if (*nefPtr <= MXNEF1) {
+    eta = ONE / (RPowerR(BIAS2*dsm,ONE/L) + ADDON);
+    eta = MAX(ETAMIN, MAX(eta, hmin / ABS(h)));
+    if (*nefPtr >= SMALL_NEF) eta = MIN(eta, ETAMXF);
+    CVRescale(cv_mem);
+    return(TRY_AGAIN);
+  }
+  
+  /* After MXNEF1 failures, force an order reduction and retry step */
+  if (q > 1) {
+    eta = MAX(ETAMIN, hmin / ABS(h));
+    CVAdjustOrder(cv_mem,-1);
+    L = q;
+    q--;
+    qwait = L;
+    CVRescale(cv_mem);
+    return(TRY_AGAIN);
+  }
+
+  /* If already at order 1, restart: reload zn, znQ, znS from scratch */
+  eta = MAX(ETAMIN, hmin / ABS(h));
+  h *= eta;
+  next_h = h;
+  hscale = h;
+  qwait = LONG_WAIT;
+  nscon = 0;
+
+  retval = f(tn, zn[0], tempv, f_data);
+  nfe++;
+  if (retval < 0) return(CV_RHSFUNC_FAIL);
+  if (retval > 0) return(CV_UNREC_RHSFUNC_ERR);
+
+  N_VScale(h, tempv, zn[1]);
+
+  if (quadr) {
+
+    retval = fQ(tn, zn[0], tempvQ, fQ_data);
+    nfQe++;
+    if (retval < 0) return(CV_QRHSFUNC_FAIL);
+    if (retval > 0) return(CV_UNREC_QRHSFUNC_ERR);
+
+    N_VScale(h, tempvQ, znQ[1]);
+
+  }
+
+  if (sensi) {
+
+    wrk1 = ftemp;
+    wrk2 = ftempS[0];
+
+    retval = CVSensRhs(cv_mem, tn, zn[0], tempv, znS[0], tempvS, wrk1, wrk2);
+    if (retval < 0) return(CV_SRHSFUNC_FAIL);
+    if (retval > 0) return(CV_UNREC_SRHSFUNC_ERR);
+
+    for (is=0; is<Ns; is++) 
+      N_VScale(h, tempvS[is], znS[1][is]);
+
+  }
+  
+  return(TRY_AGAIN);
+}
+
+/* 
+ * -----------------------------------------------------------------
+ * Functions called after a successful step
+ * -----------------------------------------------------------------
+ */
+
+/*
+ * CVCompleteStep
+ *
+ * This routine performs various update operations when the solution
+ * to the nonlinear system has passed the local error test. 
+ * We increment the step counter nst, record the values hu and qu,
+ * update the tau array, and apply the corrections to the zn array.
+ * The tau[i] are the last q values of h, with tau[1] the most recent.
+ * The counter qwait is decremented, and if qwait == 1 (and q < qmax)
+ * we save acor and tq[5] for a possible order increase.
+ */
+
+static void CVCompleteStep(CVodeMem cv_mem)
+{
+  int i, j;
+  int is;
+  
+  nst++;
+  nscon++;
+  hu = h;
+  qu = q;
+
+  for (i=q; i >= 2; i--)  tau[i] = tau[i-1];
+  if ((q==1) && (nst > 1)) tau[2] = tau[1];
+  tau[1] = h;
+
+  /* Apply correction to column j of zn: l_j * Delta_n */
+
+  for (j=0; j <= q; j++) 
+    N_VLinearSum(l[j], acor, ONE, zn[j], zn[j]);
+
+  if (quadr) {
+    for (j=0; j <= q; j++) 
+      N_VLinearSum(l[j], acorQ, ONE, znQ[j], znQ[j]);
+  }
+
+  if (sensi) {
+    for (is=0; is<Ns; is++)
+      for (j=0; j <= q; j++) 
+        N_VLinearSum(l[j], acorS[is], ONE, znS[j][is], znS[j][is]);
+  }
+
+  /* If necessary, store Delta_n in zn[qmax] to be used in order increase
+  
+  This actually will be Delta_{n-1} in the ELTE at q+1 since it happens at
+  the next to last step of order q before a possible one at order q+1
+  */
+
+  qwait--;
+  if ((qwait == 1) && (q != qmax)) {
+    
+    N_VScale(ONE, acor, zn[qmax]);
+    
+    if (quadr)
+      N_VScale(ONE, acorQ, znQ[qmax]);
+
+    if (sensi)
+      for (is=0; is<Ns; is++)
+        N_VScale(ONE, acorS[is], znS[qmax][is]);
+    
+    saved_tq5 = tq[5];
+    indx_acor = qmax;
+  }
+
+}
+
+/*
+ * CVprepareNextStep
+ *
+ * This routine handles the setting of stepsize and order for the
+ * next step -- hprime and qprime.  Along with hprime, it sets the
+ * ratio eta = hprime/h.  It also updates other state variables 
+ * related to a change of step size or order. 
+ */
+
+static void CVPrepareNextStep(CVodeMem cv_mem, realtype dsm)
+{
+  /* If etamax = 1, defer step size or order changes */
+  if (etamax == ONE) {
+    qwait = MAX(qwait, 2);
+    qprime = q;
+    hprime = h;
+    eta = ONE;
+    return;
+  }
+
+  /* etaq is the ratio of new to old h at the current order */  
+  etaq = ONE /(RPowerR(BIAS2*dsm,ONE/L) + ADDON);
+  
+  /* If no order change, adjust eta and acor in CVSetEta and return */
+  if (qwait != 0) {
+    eta = etaq;
+    qprime = q;
+    CVSetEta(cv_mem);
+    return;
+  }
+  
+  /* If qwait = 0, consider an order change.   etaqm1 and etaqp1 are 
+     the ratios of new to old h at orders q-1 and q+1, respectively.
+     CVChooseEta selects the largest; CVSetEta adjusts eta and acor */
+  qwait = 2;
+  etaqm1 = CVComputeEtaqm1(cv_mem);
+  etaqp1 = CVComputeEtaqp1(cv_mem);  
+  CVChooseEta(cv_mem); 
+  CVSetEta(cv_mem);
+}
+
+/*
+ * CVsetEta
+ *
+ * This routine adjusts the value of eta according to the various
+ * heuristic limits and the optional input hmax.  It also resets
+ * etamax to be the estimated local error vector.
+ */
+
+static void CVSetEta(CVodeMem cv_mem)
+{
+
+  /* If eta below the threshhold THRESH, reject a change of step size */
+  if (eta < THRESH) {
+    eta = ONE;
+    hprime = h;
+  } else {
+    /* Limit eta by etamax and hmax, then set hprime */
+    eta = MIN(eta, etamax);
+    eta /= MAX(ONE, ABS(h)*hmax_inv*eta);
+    hprime = h * eta;
+    if (qprime < q) nscon = 0;
+  }
+
+  /* Reset etamx for the next step size change, and scale acor */
+}
+
+/*
+ * CVComputeEtaqm1
+ *
+ * This routine computes and returns the value of etaqm1 for a
+ * possible decrease in order by 1.
+ */
+
+static realtype CVComputeEtaqm1(CVodeMem cv_mem)
+{
+  realtype ddn;
+  
+  etaqm1 = ZERO;
+
+  if (q > 1) {
+
+    ddn = N_VWrmsNorm(zn[q], ewt);
+
+    if ( quadr && errconQ) {
+      ddn = CVQuadUpdateNorm(cv_mem, ddn, znQ[q], ewtQ);
+    }
+
+    if ( sensi && errconS ) {
+      ddn = CVSensUpdateNorm(cv_mem, ddn, znS[q], ewtS);
+    }
+
+    ddn = ddn/tq[1];
+
+    etaqm1 = ONE/(RPowerR(BIAS1*ddn, ONE/q) + ADDON);
+
+  }
+
+  return(etaqm1);
+}
+
+/*
+ * CVComputeEtaqp1
+ *
+ * This routine computes and returns the value of etaqp1 for a
+ * possible increase in order by 1.
+ */
+
+static realtype CVComputeEtaqp1(CVodeMem cv_mem)
+{
+  realtype dup, cquot;
+  int is;
+  
+  etaqp1 = ZERO;
+
+  if (q != qmax) {
+
+    cquot = (tq[5] / saved_tq5) * RPowerI(h/tau[2], L);
+
+    N_VLinearSum(-cquot, zn[qmax], ONE, acor, tempv);
+
+    dup = N_VWrmsNorm(tempv, ewt);
+
+    if ( quadr && errconQ ) {
+      N_VLinearSum(-cquot, znQ[qmax], ONE, acorQ, tempvQ);
+      dup = CVQuadUpdateNorm(cv_mem, dup, tempvQ, ewtQ);
+    }
+
+    if ( sensi && errconS ) {
+      for (is=0; is<Ns; is++) 
+        N_VLinearSum(-cquot, znS[qmax][is], ONE, acorS[is], tempvS[is]);
+      dup = CVSensUpdateNorm(cv_mem, dup, tempvS, ewtS);
+    }
+
+    dup = dup / tq[3];
+
+    etaqp1 = ONE / (RPowerR(BIAS3*dup, ONE/(L+1)) + ADDON);
+
+  }
+
+  return(etaqp1);
+}
+
+/*
+ * CVChooseEta
+ * Given etaqm1, etaq, etaqp1 (the values of eta for qprime =
+ * q - 1, q, or q + 1, respectively), this routine chooses the 
+ * maximum eta value, sets eta to that value, and sets qprime to the
+ * corresponding value of q.  If there is a tie, the preference
+ * order is to (1) keep the same order, then (2) decrease the order,
+ * and finally (3) increase the order.  If the maximum eta value
+ * is below the threshhold THRESH, the order is kept unchanged and
+ * eta is set to 1.
+ */
+
+static void CVChooseEta(CVodeMem cv_mem)
+{
+  realtype etam;
+  int is;
+  
+  etam = MAX(etaqm1, MAX(etaq, etaqp1));
+  
+  if (etam < THRESH) {
+    eta = ONE;
+    qprime = q;
+    return;
+  }
+
+  if (etam == etaq) {
+
+    eta = etaq;
+    qprime = q;
+
+  } else if (etam == etaqm1) {
+
+    eta = etaqm1;
+    qprime = q - 1;
+
+  } else {
+
+    eta = etaqp1;
+    qprime = q + 1;
+
+    if (lmm == CV_BDF) {
+
+      /* 
+       * Store Delta_n in zn[qmax] to be used in order increase 
+       *
+       * This happens at the last step of order q before an increase
+       * to order q+1, so it represents Delta_n in the ELTE at q+1
+       */
+      
+      N_VScale(ONE, acor, zn[qmax]);
+      
+      if (quadr && errconQ)
+        N_VScale(ONE, acorQ, znQ[qmax]);
+      
+      if (sensi && errconS)
+        for (is=0; is<Ns; is++)
+          N_VScale(ONE, acorS[is], znS[qmax][is]);
+    }
+
+  }
+
+}
+
+/* 
+ * -----------------------------------------------------------------
+ * Function to handle failures
+ * -----------------------------------------------------------------
+ */
+
+/*
+ * CVHandleFailure
+ *
+ * This routine prints error messages for all cases of failure by
+ * CVHin or CVStep. 
+ * It returns to CVode the value that CVode is to return to the user.
+ */
+
+static int CVHandleFailure(CVodeMem cv_mem, int flag)
+{
+
+  /* Set vector of  absolute weighted local errors */
+  /*
+  N_VProd(acor, ewt, tempv);
+  N_VAbs(tempv, tempv);
+  */  
+
+  /* Depending on flag, print error message and return error flag */
+  switch (flag) {
+  case CV_ERR_FAILURE:  
+    CVProcessError(cv_mem, CV_ERR_FAILURE, "CVODES", "CVode", MSGCV_ERR_FAILS, tn, h);
+    break;
+  case CV_CONV_FAILURE: 
+    CVProcessError(cv_mem, CV_CONV_FAILURE, "CVODES", "CVode", MSGCV_CONV_FAILS, tn, h);
+    break;
+  case CV_LSETUP_FAIL:  
+    CVProcessError(cv_mem, CV_LSETUP_FAIL, "CVODES", "CVode", MSGCV_SETUP_FAILED, tn);
+    break;
+  case CV_LSOLVE_FAIL:  
+    CVProcessError(cv_mem, CV_LSOLVE_FAIL, "CVODES", "CVode", MSGCV_SOLVE_FAILED, tn);
+    break;
+  case CV_RHSFUNC_FAIL:
+    CVProcessError(cv_mem, CV_RHSFUNC_FAIL, "CVODES", "CVode", MSGCV_RHSFUNC_FAILED, tn);
+    break;
+  case CV_UNREC_RHSFUNC_ERR:
+    CVProcessError(cv_mem, CV_UNREC_RHSFUNC_ERR, "CVODES", "CVode", MSGCV_RHSFUNC_UNREC, tn);
+    break;
+  case CV_REPTD_RHSFUNC_ERR:
+    CVProcessError(cv_mem, CV_REPTD_RHSFUNC_ERR, "CVODES", "CVode", MSGCV_RHSFUNC_REPTD, tn);
+    break;
+  case CV_RTFUNC_FAIL:    
+    CVProcessError(cv_mem, CV_RTFUNC_FAIL, "CVODES", "CVode", MSGCV_RTFUNC_FAILED, tn);
+    break;
+  case CV_QRHSFUNC_FAIL:
+    CVProcessError(cv_mem, CV_QRHSFUNC_FAIL, "CVODES", "CVode", MSGCV_QRHSFUNC_FAILED, tn);
+    break;
+  case CV_UNREC_QRHSFUNC_ERR:
+    CVProcessError(cv_mem, CV_UNREC_QRHSFUNC_ERR, "CVODES", "CVode", MSGCV_QRHSFUNC_UNREC, tn);
+    break;
+  case CV_REPTD_QRHSFUNC_ERR:
+    CVProcessError(cv_mem, CV_REPTD_QRHSFUNC_ERR, "CVODES", "CVode", MSGCV_QRHSFUNC_REPTD, tn);
+    break;
+  case CV_SRHSFUNC_FAIL:
+    CVProcessError(cv_mem, CV_SRHSFUNC_FAIL, "CVODES", "CVode", MSGCV_SRHSFUNC_FAILED, tn);
+    break;
+  case CV_UNREC_SRHSFUNC_ERR:
+    CVProcessError(cv_mem, CV_UNREC_SRHSFUNC_ERR, "CVODES", "CVode", MSGCV_SRHSFUNC_UNREC, tn);
+    break;
+  case CV_REPTD_SRHSFUNC_ERR:
+    CVProcessError(cv_mem, CV_REPTD_SRHSFUNC_ERR, "CVODES", "CVode", MSGCV_SRHSFUNC_REPTD, tn);
+    break;
+  case CV_TOO_CLOSE:
+    CVProcessError(cv_mem, CV_TOO_CLOSE, "CVODES", "CVode", MSGCV_TOO_CLOSE);
+  default:
+    return(CV_SUCCESS);
+  }
+
+  return(flag);
+
+}
+
+/* 
+ * -----------------------------------------------------------------
+ * Functions for BDF Stability Limit Detection   
+ * -----------------------------------------------------------------
+ */
+
+/*
+ * CVBDFStab
+ *
+ * This routine handles the BDF Stability Limit Detection Algorithm
+ * STALD.  It is called if lmm = CV_BDF and the SLDET option is on.
+ * If the order is 3 or more, the required norm data is saved.
+ * If a decision to reduce order has not already been made, and
+ * enough data has been saved, CVsldet is called.  If it signals
+ * a stability limit violation, the order is reduced, and the step
+ * size is reset accordingly.
+ */
+
+static void CVBDFStab(CVodeMem cv_mem)
+{
+  int i,k, ldflag, factorial;
+  realtype sq, sqm1, sqm2;
+      
+  /* If order is 3 or greater, then save scaled derivative data,
+     push old data down in i, then add current values to top.    */
+
+  if (q >= 3) {
+    for (k = 1; k <= 3; k++)
+      for (i = 5; i >= 2; i--) 
+        ssdat[i][k] = ssdat[i-1][k]; 
+    factorial = 1;
+    for (i = 1; i <= q-1; i++) factorial *= i;
+    sq = factorial*q*(q+1)*acnrm/tq[5];
+    sqm1 = factorial*q*N_VWrmsNorm(zn[q], ewt);
+    sqm2 = factorial*N_VWrmsNorm(zn[q-1], ewt);
+    ssdat[1][1] = sqm2*sqm2;
+    ssdat[1][2] = sqm1*sqm1;
+    ssdat[1][3] = sq*sq;
+  }  
+
+  if (qprime >= q) {
+
+    /* If order is 3 or greater, and enough ssdat has been saved,
+       nscon >= q+5, then call stability limit detection routine.  */
+
+    if ( (q >= 3) && (nscon >= q+5) ) {
+      ldflag = CVsldet(cv_mem);
+      if (ldflag > 3) {
+        /* A stability limit violation is indicated by
+           a return flag of 4, 5, or 6.
+           Reduce new order.                     */
+        qprime = q-1;
+        eta = etaqm1; 
+        eta = MIN(eta,etamax);
+        eta = eta/MAX(ONE,ABS(h)*hmax_inv*eta);
+        hprime = h*eta;
+        nor = nor + 1;
+      }
+    }
+  }
+  else {
+    /* Otherwise, let order increase happen, and 
+       reset stability limit counter, nscon.     */
+    nscon = 0;
+  }
+}
+
+/*
+ * CVsldet
+ *
+ * This routine detects stability limitation using stored scaled 
+ * derivatives data. CVsldet returns the magnitude of the
+ * dominate characteristic root, rr. The presents of a stability
+ * limit is indicated by rr > "something a little less then 1.0",  
+ * and a positive kflag. This routine should only be called if
+ * order is greater than or equal to 3, and data has been collected
+ * for 5 time steps. 
+ * 
+ * Returned values:
+ *    kflag = 1 -> Found stable characteristic root, normal matrix case
+ *    kflag = 2 -> Found stable characteristic root, quartic solution
+ *    kflag = 3 -> Found stable characteristic root, quartic solution,
+ *                 with Newton correction
+ *    kflag = 4 -> Found stability violation, normal matrix case
+ *    kflag = 5 -> Found stability violation, quartic solution
+ *    kflag = 6 -> Found stability violation, quartic solution,
+ *                 with Newton correction
+ *
+ *    kflag < 0 -> No stability limitation, 
+ *                 or could not compute limitation.
+ *
+ *    kflag = -1 -> Min/max ratio of ssdat too small.
+ *    kflag = -2 -> For normal matrix case, vmax > vrrt2*vrrt2
+ *    kflag = -3 -> For normal matrix case, The three ratios
+ *                  are inconsistent.
+ *    kflag = -4 -> Small coefficient prevents elimination of quartics.  
+ *    kflag = -5 -> R value from quartics not consistent.
+ *    kflag = -6 -> No corrected root passes test on qk values
+ *    kflag = -7 -> Trouble solving for sigsq.
+ *    kflag = -8 -> Trouble solving for B, or R via B.
+ *    kflag = -9 -> R via sigsq[k] disagrees with R from data.
+ */
+
+static int CVsldet(CVodeMem cv_mem)
+{
+  int i, k, j, it, kmin=0, kflag=0;
+  realtype rat[5][4], rav[4], qkr[4], sigsq[4], smax[4], ssmax[4];
+  realtype drr[4], rrc[4],sqmx[4], qjk[4][4], vrat[5], qc[6][4], qco[6][4];
+  realtype rr, rrcut, vrrtol, vrrt2, sqtol, rrtol;
+  realtype smink, smaxk, sumrat, sumrsq, vmin, vmax, drrmax, adrr;
+  realtype tem, sqmax, saqk, qp, s, sqmaxk, saqj, sqmin;
+  realtype rsa, rsb, rsc, rsd, rd1a, rd1b, rd1c;
+  realtype rd2a, rd2b, rd3a, cest1, corr1; 
+  realtype ratp, ratm, qfac1, qfac2, bb, rrb;
+
+  /* The following are cutoffs and tolerances used by this routine */
+
+  rrcut  = RCONST(0.98);
+  vrrtol = RCONST(1.0e-4);
+  vrrt2  = RCONST(5.0e-4);
+  sqtol  = RCONST(1.0e-3);
+  rrtol  = RCONST(1.0e-2);
+
+  rr = ZERO;
+
+  /*  Index k corresponds to the degree of the interpolating polynomial. */
+  /*      k = 1 -> q-1          */
+  /*      k = 2 -> q            */
+  /*      k = 3 -> q+1          */
+
+  /*  Index i is a backward-in-time index, i = 1 -> current time, */
+  /*      i = 2 -> previous step, etc    */
+
+  /* get maxima, minima, and variances, and form quartic coefficients  */
+
+  for (k=1; k<=3; k++) {
+    smink = ssdat[1][k];
+    smaxk = ZERO;
+    
+    for (i=1; i<=5; i++) {
+      smink = MIN(smink,ssdat[i][k]);
+      smaxk = MAX(smaxk,ssdat[i][k]);
+    }
+    
+    if (smink < TINY*smaxk) {
+      kflag = -1;  
+      return(kflag);
+    }
+    smax[k] = smaxk;
+    ssmax[k] = smaxk*smaxk;
+    
+    sumrat = ZERO;
+    sumrsq = ZERO;
+    for (i=1; i<=4; i++) {
+      rat[i][k] = ssdat[i][k]/ssdat[i+1][k];
+      sumrat = sumrat + rat[i][k];
+      sumrsq = sumrsq + rat[i][k]*rat[i][k];
+    } 
+    rav[k] = FOURTH*sumrat;
+    vrat[k] = ABS(FOURTH*sumrsq - rav[k]*rav[k]);
+      
+    qc[5][k] = ssdat[1][k]*ssdat[3][k] - ssdat[2][k]*ssdat[2][k];
+    qc[4][k] = ssdat[2][k]*ssdat[3][k] - ssdat[1][k]*ssdat[4][k];
+    qc[3][k] = ZERO;
+    qc[2][k] = ssdat[2][k]*ssdat[5][k] - ssdat[3][k]*ssdat[4][k];
+    qc[1][k] = ssdat[4][k]*ssdat[4][k] - ssdat[3][k]*ssdat[5][k];
+    
+    for (i=1; i<=5; i++) {
+      qco[i][k] = qc[i][k];
+    }
+  }                            /* End of k loop */
+  
+  /* Isolate normal or nearly-normal matrix case. Three quartic will
+     have common or nearly-common roots in this case. 
+     Return a kflag = 1 if this procedure works. If three root 
+     differ more than vrrt2, return error kflag = -3.    */
+  
+  vmin = MIN(vrat[1],MIN(vrat[2],vrat[3]));
+  vmax = MAX(vrat[1],MAX(vrat[2],vrat[3]));
+  
+  if (vmin < vrrtol*vrrtol) {
+
+    if (vmax > vrrt2*vrrt2) {
+      kflag = -2;  
+      return(kflag);
+    } else {
+      rr = (rav[1] + rav[2] + rav[3])/THREE;
+      drrmax = ZERO;
+      for (k = 1;k<=3;k++) {
+        adrr = ABS(rav[k] - rr);
+        drrmax = MAX(drrmax, adrr);
+      }
+      if (drrmax > vrrt2)
+        kflag = -3;    
+      kflag = 1;
+      /*  can compute charactistic root, drop to next section   */
+    }
+
+  } else {
+      
+    /* use the quartics to get rr. */
+      
+    if (ABS(qco[1][1]) < TINY*ssmax[1]) {
+      kflag = -4;    
+      return(kflag);
+    }
+      
+    tem = qco[1][2]/qco[1][1];
+    for (i=2; i<=5; i++) {
+      qco[i][2] = qco[i][2] - tem*qco[i][1];
+    }
+      
+    qco[1][2] = ZERO;
+    tem = qco[1][3]/qco[1][1];
+    for (i=2; i<=5; i++) {
+      qco[i][3] = qco[i][3] - tem*qco[i][1];
+    }
+    qco[1][3] = ZERO;
+      
+    if (ABS(qco[2][2]) < TINY*ssmax[2]) {
+      kflag = -4;    
+      return(kflag);
+    }
+      
+    tem = qco[2][3]/qco[2][2];
+    for (i=3; i<=5; i++) {
+      qco[i][3] = qco[i][3] - tem*qco[i][2];
+    }
+      
+    if (ABS(qco[4][3]) < TINY*ssmax[3]) {
+      kflag = -4;    
+      return(kflag);
+    }
+      
+    rr = -qco[5][3]/qco[4][3];
+      
+    if (rr < TINY || rr > HUN) {
+      kflag = -5;   
+      return(kflag);
+    }
+      
+    for (k=1; k<=3; k++) {
+      qkr[k] = qc[5][k] + rr*(qc[4][k] + rr*rr*(qc[2][k] + rr*qc[1][k]));
+    }  
+      
+    sqmax = ZERO;
+    for (k=1; k<=3; k++) {
+      saqk = ABS(qkr[k])/ssmax[k];
+      if (saqk > sqmax) sqmax = saqk;
+    } 
+      
+    if (sqmax < sqtol) {
+      kflag = 2;
+        
+      /*  can compute charactistic root, drop to "given rr,etc"   */
+        
+    } else {
+          
+      /* do Newton corrections to improve rr.  */
+        
+      for (it=1; it<=3; it++) {
+        for (k=1; k<=3; k++) {
+          qp = qc[4][k] + rr*rr*(THREE*qc[2][k] + rr*FOUR*qc[1][k]);
+          drr[k] = ZERO;
+          if (ABS(qp) > TINY*ssmax[k]) drr[k] = -qkr[k]/qp;
+          rrc[k] = rr + drr[k];
+        } 
+          
+        for (k=1; k<=3; k++) {
+          s = rrc[k];
+          sqmaxk = ZERO;
+          for (j=1; j<=3; j++) {
+            qjk[j][k] = qc[5][j] + s*(qc[4][j] + 
+                                      s*s*(qc[2][j] + s*qc[1][j]));
+            saqj = ABS(qjk[j][k])/ssmax[j];
+            if (saqj > sqmaxk) sqmaxk = saqj;
+          } 
+          sqmx[k] = sqmaxk;
+        } 
+              
+        sqmin = sqmx[1] + ONE;
+        for (k=1; k<=3; k++) {
+          if (sqmx[k] < sqmin) {
+            kmin = k;
+            sqmin = sqmx[k];
+          }
+        } 
+        rr = rrc[kmin];
+              
+        if (sqmin < sqtol) {
+          kflag = 3;
+          /*  can compute charactistic root   */
+          /*  break out of Newton correction loop and drop to "given rr,etc" */ 
+          break;
+        } else {
+          for (j=1; j<=3; j++) {
+            qkr[j] = qjk[j][kmin];
+          }
+        }     
+      } /*  end of Newton correction loop  */ 
+          
+      if (sqmin > sqtol) {
+        kflag = -6;
+        return(kflag);
+      }
+    } /*  end of if (sqmax < sqtol) else   */
+  } /*  end of if (vmin < vrrtol*vrrtol) else, quartics to get rr. */
+  
+  /* given rr, find sigsq[k] and verify rr.  */
+  /* All positive kflag drop to this section  */
+  
+  for (k=1; k<=3; k++) {
+    rsa = ssdat[1][k];
+    rsb = ssdat[2][k]*rr;
+    rsc = ssdat[3][k]*rr*rr;
+    rsd = ssdat[4][k]*rr*rr*rr;
+    rd1a = rsa - rsb;
+    rd1b = rsb - rsc;
+    rd1c = rsc - rsd;
+    rd2a = rd1a - rd1b;
+    rd2b = rd1b - rd1c;
+    rd3a = rd2a - rd2b;
+    
+    if (ABS(rd1b) < TINY*smax[k]) {
+      kflag = -7;
+      return(kflag);
+    }
+    
+    cest1 = -rd3a/rd1b;
+    if (cest1 < TINY || cest1 > FOUR) {
+      kflag = -7;
+      return(kflag);
+    }
+    corr1 = (rd2b/cest1)/(rr*rr);
+    sigsq[k] = ssdat[3][k] + corr1;
+  }
+  
+  if (sigsq[2] < TINY) {
+    kflag = -8;
+    return(kflag);
+  }
+  
+  ratp = sigsq[3]/sigsq[2];
+  ratm = sigsq[1]/sigsq[2];
+  qfac1 = FOURTH*(q*q - ONE);
+  qfac2 = TWO/(q - ONE);
+  bb = ratp*ratm - ONE - qfac1*ratp;
+  tem = ONE - qfac2*bb;
+  
+  if (ABS(tem) < TINY) {
+    kflag = -8;
+    return(kflag);
+  }
+  
+  rrb = ONE/tem;
+  
+  if (ABS(rrb - rr) > rrtol) {
+    kflag = -9;
+    return(kflag);
+  }
+  
+  /* Check to see if rr is above cutoff rrcut  */
+  if (rr > rrcut) {
+    if (kflag == 1) kflag = 4;
+    if (kflag == 2) kflag = 5;
+    if (kflag == 3) kflag = 6;
+  }
+  
+  /* All positive kflag returned at this point  */
+  
+  return(kflag);
+  
+}
+
+/* 
+ * -----------------------------------------------------------------
+ * Functions for rootfinding
+ * -----------------------------------------------------------------
+ */
+
+/* 
+ * CVRcheck1
+ *
+ * This routine completes the initialization of rootfinding memory
+ * information, and checks whether g has a zero both at and very near
+ * the initial point of the IVP.
+ *
+ * This routine returns an int equal to:
+ *  INITROOT = -1 if a close pair of zeros was found, and
+ *  CV_SUCCESS     =  0 otherwise.
+ */
+
+static int CVRcheck1(CVodeMem cv_mem)
+{
+  int i, retval;
+  realtype smallh, hratio;
+  booleantype zroot;
+
+  for (i = 0; i < nrtfn; i++) iroots[i] = 0;
+  tlo = tn;
+  ttol = (ABS(tn) + ABS(h))*uround*HUN;
+
+  /* Evaluate g at initial t and check for zero values. */
+  retval = gfun(tlo, zn[0], glo, g_data);
+  nge = 1;
+  if (retval != 0) return(CV_RTFUNC_FAIL);
+  
+  zroot = FALSE;
+  for (i = 0; i < nrtfn; i++) {
+    if (ABS(glo[i]) == ZERO) zroot = TRUE;
+  }
+  if (!zroot) return(CV_SUCCESS);
+
+  /* Some g_i is zero at t0; look at g at t0+(small increment). */
+  hratio = MAX(ttol/ABS(h), TENTH);
+  smallh = hratio*h;
+  tlo += smallh;
+  N_VLinearSum(ONE, zn[0], hratio, zn[1], y);
+  retval = gfun(tlo, y, glo, g_data);
+  nge++;
+  if (retval != 0) return(CV_RTFUNC_FAIL);
+
+  zroot = FALSE;
+  for (i = 0; i < nrtfn; i++) {
+    if (ABS(glo[i]) == ZERO) {
+      zroot = TRUE;
+      iroots[i] = 1;
+    }
+  }
+  if (zroot) return(INITROOT);
+  return(CV_SUCCESS);
+
+}
+
+/*
+ * CVRcheck2
+ *
+ * This routine checks for exact zeros of g at the last root found,
+ * if the last return was a root.  It then checks for a close
+ * pair of zeros (an error condition), and for a new root at a
+ * nearby point.  The left endpoint (tlo) of the search interval
+ * is adjusted if necessary to assure that all g_i are nonzero
+ * there, before returning to do a root search in the interval.
+ *
+ * On entry, tlo = tretlast is the last value of tret returned by
+ * CVode.  This may be the previous tn, the previous tout value, or
+ * the last root location.
+ *
+ * This routine returns an int equal to:
+ *      CLOSERT = -2 if a close pair of zeros was found,
+ *      RTFOUND =  1 if a new zero of g was found near tlo, or
+ *      CV_SUCCESS    =  0 otherwise.
+ */
+
+static int CVRcheck2(CVodeMem cv_mem)
+{
+  int i, retval;
+  realtype smallh, hratio;
+  booleantype zroot;
+
+  if (irfnd == 0) return(CV_SUCCESS);
+
+  (void) CVodeGetDky(cv_mem, tlo, 0, y);
+  retval = gfun(tlo, y, glo, g_data);
+  nge++;
+  if (retval != 0) return(CV_RTFUNC_FAIL);
+
+  zroot = FALSE;
+  for (i = 0; i < nrtfn; i++) iroots[i] = 0;
+  for (i = 0; i < nrtfn; i++) {
+    if (ABS(glo[i]) == ZERO) {
+      zroot = TRUE;
+      iroots[i] = 1;
+    }
+  }
+  if (!zroot) return(CV_SUCCESS);
+
+  /* One or more g_i has a zero at tlo.  Check g at tlo+smallh. */
+  ttol = (ABS(tn) + ABS(h))*uround*HUN;
+  smallh = (h > ZERO) ? ttol : -ttol;
+  tlo += smallh;
+  if ( (tlo - tn)*h >= ZERO) {
+    hratio = smallh/h;
+    N_VLinearSum(ONE, y, hratio, zn[1], y);
+  } else {
+    (void) CVodeGetDky(cv_mem, tlo, 0, y);
+  }
+  retval = gfun(tlo, y, glo, g_data);
+  nge++;
+  if (retval != 0) return(CV_RTFUNC_FAIL);
+
+  zroot = FALSE;
+  for (i = 0; i < nrtfn; i++) {
+    if (ABS(glo[i]) == ZERO) {
+      if (iroots[i] == 1) return(CLOSERT);
+      zroot = TRUE;
+      iroots[i] = 1;
+    }
+  }
+  if (zroot) return(RTFOUND);
+  return(CV_SUCCESS);
+
+}
+
+/*
+ * CVRcheck3
+ *
+ * This routine interfaces to CVRootfind to look for a root of g
+ * between tlo and either tn or tout, whichever comes first.
+ * Only roots beyond tlo in the direction of integration are sought.
+ *
+ * This routine returns an int equal to:
+ *      RTFOUND =  1 if a root of g was found, or
+ *      CV_SUCCESS    =  0 otherwise.
+ */
+
+static int CVRcheck3(CVodeMem cv_mem)
+{
+  int i, retval, ier;
+
+  /* Set thi = tn or tout, whichever comes first; set y = y(thi). */
+  if (taskc == CV_ONE_STEP) {
+    thi = tn;
+    N_VScale(ONE, zn[0], y);
+  }
+  if (taskc == CV_NORMAL) {
+    if ( (toutc - tn)*h >= ZERO) {
+      thi = tn; 
+      N_VScale(ONE, zn[0], y);
+    } else {
+      thi = toutc;
+      (void) CVodeGetDky(cv_mem, thi, 0, y);
+    }
+  }
+
+  /* Set ghi = g(thi) and call CVRootfind to search (tlo,thi) for roots. */
+  retval = gfun(thi, y, ghi, g_data);
+  nge++;
+  if (retval != 0) return(CV_RTFUNC_FAIL);
+
+  ttol = (ABS(tn) + ABS(h))*uround*HUN;
+  ier = CVRootfind(cv_mem);
+  tlo = trout;
+  for (i = 0; i < nrtfn; i++) glo[i] = grout[i];
+
+  /* If no root found, return CV_SUCCESS. */  
+  if (ier == CV_SUCCESS) return(CV_SUCCESS);
+
+  /* If a root was found, interpolate to get y(trout) and return.  */
+  (void) CVodeGetDky(cv_mem, trout, 0, y);
+  return(RTFOUND);
+
+}
+
+/*
+ * CVRootFind
+ *
+ * This routine solves for a root of g(t) between tlo and thi, if
+ * one exists.  Only roots of odd multiplicity (i.e. with a change
+ * of sign in one of the g_i), or exact zeros, are found.
+ * Here the sign of tlo - thi is arbitrary, but if multiple roots
+ * are found, the one closest to tlo is returned.
+ *
+ * The method used is the Illinois algorithm, a modified secant method.
+ * Reference: Kathie L. Hiebert and Lawrence F. Shampine, Implicitly
+ * Defined Output Points for Solutions of ODEs, Sandia National
+ * Laboratory Report SAND80-0180, February 1980.
+ *
+ * This routine uses the following parameters for communication:
+ *
+ * nrtfn    = number of functions g_i, or number of components of
+ *            the vector-valued function g(t).  Input only.
+ *
+ * gfun     = user-defined function for g(t).  Its form is
+ *            (void) gfun(t, y, gt, g_data)
+ *
+ * nge      = cumulative counter for gfun calls.
+ *
+ * ttol     = a convergence tolerance for trout.  Input only.
+ *            When a root at trout is found, it is located only to
+ *            within a tolerance of ttol.  Typically, ttol should
+ *            be set to a value on the order of
+ *               100 * UROUND * max (ABS(tlo), ABS(thi))
+ *            where UROUND is the unit roundoff of the machine.
+ *
+ * tlo, thi = endpoints of the interval in which roots are sought.
+ *            On input, and must be distinct, but tlo - thi may
+ *            be of either sign.  The direction of integration is
+ *            assumed to be from tlo to thi.  On return, tlo and thi
+ *            are the endpoints of the final relevant interval.
+ *
+ * glo, ghi = arrays of length nrtfn containing the vectors g(tlo)
+ *            and g(thi) respectively.  Input and output.  On input,
+ *            none of the glo[i] should be zero.
+ *
+ * trout    = root location, if a root was found, or thi if not.
+ *            Output only.  If a root was found other than an exact
+ *            zero of g, trout is the endpoint thi of the final
+ *            interval bracketing the root, with size at most ttol.
+ *
+ * grout    = array of length nrtfn containing g(trout) on return.
+ *
+ * iroots   = int array of length nrtfn with root information.
+ *            Output only.  If a root was found, iroots indicates
+ *            which components g_i have a root at trout.  For
+ *            i = 0, ..., nrtfn-1, iroots[i] = 1 if g_i has a root
+ *            and iroots[i] = 0 otherwise.
+ *
+ * This routine returns an int equal to:
+ *      RTFOUND =  1 if a root of g was found, or
+ *      CV_SUCCESS    =  0 otherwise.
+ */
+
+static int CVRootfind(CVodeMem cv_mem)
+{
+  realtype alpha, tmid, gfrac, maxfrac, fracint, fracsub;
+  int i, retval, imax, side, sideprev;
+  booleantype zroot, sgnchg;
+
+  imax = 0;
+
+  /* First check for change in sign in ghi or for a zero in ghi. */
+  maxfrac = ZERO;
+  zroot = FALSE;
+  sgnchg = FALSE;
+  for (i = 0;  i < nrtfn; i++) {
+    if (ABS(ghi[i]) == ZERO) {
+      zroot = TRUE;
+    } else {
+      if (glo[i]*ghi[i] < ZERO) {
+        gfrac = ABS(ghi[i]/(ghi[i] - glo[i]));
+        if (gfrac > maxfrac) {
+          sgnchg = TRUE;
+          maxfrac = gfrac;
+          imax = i;
+        }
+      }
+    }
+  }
+
+  /* If no sign change was found, reset trout and grout.  Then return
+     CV_SUCCESS if no zero was found, or set iroots and return RTFOUND.  */ 
+  if (!sgnchg) {
+    trout = thi;
+    for (i = 0; i < nrtfn; i++) grout[i] = ghi[i];
+    if (!zroot) return(CV_SUCCESS);
+    for (i = 0; i < nrtfn; i++) {
+      iroots[i] = 0;
+      if (ABS(ghi[i]) == ZERO) iroots[i] = 1;
+    }
+    return(RTFOUND);
+  }
+
+  /* Initialize alpha to avoid compiler warning */
+
+  alpha = ONE;
+
+  /* A sign change was found.  Loop to locate nearest root. */
+
+  side = 0;  sideprev = -1;
+  loop {                                    /* Looping point */
+
+    /* Set weight alpha.
+       On the first two passes, set alpha = 1.  Thereafter, reset alpha
+       according to the side (low vs high) of the subinterval in which
+       the sign change was found in the previous two passes.
+       If the sides were opposite, set alpha = 1.
+       If the sides were the same, then double alpha (if high side),
+       or halve alpha (if low side).
+       The next guess tmid is the secant method value if alpha = 1, but
+       is closer to tlo if alpha < 1, and closer to thi if alpha > 1.    */
+
+    if (sideprev == side) {
+      alpha = (side == 2) ? alpha*TWO : alpha*HALF;
+    } else {
+      alpha = ONE;
+    }
+
+    /* Set next root approximation tmid and get g(tmid).
+       If tmid is too close to tlo or thi, adjust it inward,
+       by a fractional distance that is between 0.1 and 0.5.  */
+    tmid = thi - (thi - tlo)*ghi[imax]/(ghi[imax] - alpha*glo[imax]);
+    if (ABS(tmid - tlo) < HALF*ttol) {
+      fracint = ABS(thi - tlo)/ttol;
+      fracsub = (fracint > FIVE) ? TENTH : HALF/fracint;
+      tmid = tlo + fracsub*(thi - tlo);
+    }
+    if (ABS(thi - tmid) < HALF*ttol) {
+      fracint = ABS(thi - tlo)/ttol;
+      fracsub = (fracint > FIVE) ? TENTH : HALF/fracint;
+      tmid = thi - fracsub*(thi - tlo);
+    }
+
+    (void) CVodeGetDky(cv_mem, tmid, 0, y);
+    retval = gfun(tmid, y, grout, g_data);
+    nge++;
+    if (retval != 0) return(CV_RTFUNC_FAIL);
+
+    /* Check to see in which subinterval g changes sign, and reset imax.
+       Set side = 1 if sign change is on low side, or 2 if on high side.  */  
+    maxfrac = ZERO;
+    zroot = FALSE;
+    sgnchg = FALSE;
+    sideprev = side;
+    for (i = 0;  i < nrtfn; i++) {
+      if (ABS(grout[i]) == ZERO) {
+        zroot = TRUE;
+      } else {
+        if (glo[i]*grout[i] < ZERO) {
+          gfrac = ABS(grout[i]/(grout[i] - glo[i]));
+          if (gfrac > maxfrac) {
+            sgnchg = TRUE;
+            maxfrac = gfrac;
+            imax = i;
+          }
+        }
+      }
+    }
+    if (sgnchg) {
+      /* Sign change found in (tlo,tmid); replace thi with tmid. */
+      thi = tmid;
+      for (i = 0; i < nrtfn; i++) ghi[i] = grout[i];
+      side = 1;
+      /* Stop at root thi if converged; otherwise loop. */
+      if (ABS(thi - tlo) <= ttol) break;
+      continue;  /* Return to looping point. */
+    }
+
+    if (zroot) {
+      /* No sign change in (tlo,tmid), but g = 0 at tmid; return root tmid. */
+      thi = tmid;
+      for (i = 0; i < nrtfn; i++) ghi[i] = grout[i];
+      break;
+    }
+
+    /* No sign change in (tlo,tmid), and no zero at tmid.
+       Sign change must be in (tmid,thi).  Replace tlo with tmid. */
+    tlo = tmid;
+    for (i = 0; i < nrtfn; i++) glo[i] = grout[i];
+    side = 2;
+    /* Stop at root thi if converged; otherwise loop back. */
+    if (ABS(thi - tlo) <= ttol) break;
+
+  } /* End of root-search loop */
+
+  /* Reset trout and grout, set iroots, and return RTFOUND. */
+  trout = thi;
+  for (i = 0; i < nrtfn; i++) {
+    grout[i] = ghi[i];
+    iroots[i] = 0;
+    if (ABS(ghi[i]) == ZERO) iroots[i] = 1;
+    if (glo[i]*ghi[i] < ZERO) iroots[i] = 1;
+  }
+  return(RTFOUND);
+}
+
+/* 
+ * -----------------------------------------------------------------
+ * Functions for combined norms
+ * -----------------------------------------------------------------
+ */
+
+/*
+ * CVQuadUpdateNorm
+ *
+ * Updates the norm old_nrm to account for all quadratures.
+ */
+
+static realtype CVQuadUpdateNorm(CVodeMem cv_mem, realtype old_nrm,
+                                 N_Vector xQ, N_Vector wQ)
+{
+  realtype qnrm;
+
+  qnrm = N_VWrmsNorm(xQ, wQ);
+  if (old_nrm > qnrm) return(old_nrm);
+  else                return(qnrm);
+}
+
+/*
+ * CVQuadUpdateDsm
+ *
+ *  Usage    : dms = CVQuadUpdateDsm(cv_mem, dsm, dsmQ);
+ *
+ * This routine updates the local error norm dsm with quadrature
+ * related information. Used only if quadratures are computed
+ * with FULL error control.
+ *
+ * Returns the maximum over the wheighted local error norms.
+ */
+
+static realtype CVQuadUpdateDsm(CVodeMem cv_mem, realtype old_dsm, 
+                                realtype dsmQ)
+{
+  if ( old_dsm > dsmQ ) return(old_dsm);
+  else                  return(dsmQ);
+}
+
+/*
+ * CVSensNorm
+ *
+ * This routine returns the maximum over the weighted root mean 
+ * square norm of xS with weight vectors wS:
+ *
+ *  max { wrms(xS[0],wS[0]) ... wrms(xS[Ns-1],wS[Ns-1]) }    
+ *
+ * Called by CVSensUpdateNorm or directly in the CV_STAGGERED approach 
+ * during the NLS solution and before the error test.
+ */
+
+static realtype CVSensNorm(CVodeMem cv_mem, N_Vector *xS, N_Vector *wS)
+{
+  int is;
+  realtype nrm, snrm;
+
+  nrm = N_VWrmsNorm(xS[0],wS[0]);
+  for (is=1; is<Ns; is++) {
+    snrm = N_VWrmsNorm(xS[is],wS[is]);
+    if ( snrm > nrm ) nrm = snrm;
+  }
+
+  return(nrm);
+
+}
+
+/*
+ * CVSensUpdateNorm
+ *
+ * Updates the norm old_nrm to account for all sensitivities.
+ */
+
+static realtype CVSensUpdateNorm(CVodeMem cv_mem, realtype old_nrm,
+                                 N_Vector *xS, N_Vector *wS)
+{
+  realtype snrm;
+  
+  snrm = CVSensNorm(cv_mem, xS, wS);
+  if (old_nrm > snrm) return(old_nrm);
+  else                return(snrm);
+}
+
+/*
+ * CVStgrUpdateNorm
+ *
+ *  Usage    : dms = CVStgrUpdateDsm(cv_mem, old_dsm, dsmS);
+ *
+ * This routine updates the local error norm old_dsm with sensitivity 
+ * related information. Used only in the CV_STAGGERED or CV_STAGGERED1 
+ * approach with FULL error control.This value is consistent with 
+ * the one computed in CVDoErrorTest when ism=CV_SIMULTANEOUS and 
+ * errconS=TRUE.
+ *
+ * Returns the maximum over the wheighted local error norms.
+ */
+
+static realtype CVStgrUpdateDsm(CVodeMem cv_mem, realtype old_dsm, 
+                                realtype dsmS)
+{
+  if ( old_dsm > dsmS ) return(old_dsm);
+  else                  return(dsmS);
+}
+
+/* 
+ * -----------------------------------------------------------------
+ * Wrappers for sensitivity RHS
+ * -----------------------------------------------------------------
+ */
+
+/*
+ * CVSensRhs
+ *
+ * CVSensRhs is a high level routine that returns right hand side 
+ * of sensitivity equations. Depending on the 'ifS' flag, it either 
+ * calls directly the fS routine (ifS=CV_ALLSENS) or (if ifS=CV_ONESENS) 
+ * calls the fS1 routine in a loop over all sensitivities.
+ *
+ * CVSensRhs is called:
+ *  (*) by CVode at the first step
+ *  (*) by CVYddNorm if errcon=TRUE
+ *  (*) by CVNlsFunctional, CVNlsNewton, and CVNewtonIteration
+ *      if ism=CV_SIMULTANEOUS
+ *  (*) by CVDoErrorTest when restarting from scratch
+ *  (*) in the corrector loop if ism=CV_STAGGERED
+ *  (*) by CVStgrDoErrorTest when restarting from scratch 
+ *
+ * The return value is that of the sensitivity RHS function fS,
+ *
+ */
+
+static int CVSensRhs(CVodeMem cv_mem, realtype time, 
+                     N_Vector ycur, N_Vector fcur, 
+                     N_Vector *yScur, N_Vector *fScur,
+                     N_Vector temp1, N_Vector temp2)
+{
+  int retval=0, is;
+
+  if (ifS==CV_ALLSENS) {
+    retval = fS(Ns, time, ycur, fcur, yScur, fScur, 
+                fS_data, temp1, temp2);
+    nfSe++;
+  } else {
+    for (is=0; is<Ns; is++) {
+      retval = fS1(Ns, time, ycur, fcur, is, yScur[is], fScur[is], 
+                   fS_data, temp1, temp2);
+      nfSe++;
+      if (retval != 0) break;
+    }
+  }
+
+  return(retval);
+}
+
+/*
+ * CVSensRhs1
+ *
+ * CVSensRhs1 is a high level routine that returns right hand side 
+ * of the is-th sensitivity equation. 
+ *
+ * CVSensRhs1 is called only during the CV_STAGGERED1 corrector loop
+ * (ifS must be CV_ONESENS, otherwise CVodeSensMalloc would have 
+ * issued an error message).
+ *
+ * The return value is that of the sensitivity RHS function fS1,
+ */
+
+static int CVSensRhs1(CVodeMem cv_mem, realtype time, 
+                      N_Vector ycur, N_Vector fcur, 
+                      int is, N_Vector yScur, N_Vector fScur,
+                      N_Vector temp1, N_Vector temp2)
+{
+  int retval;
+
+  retval = fS1(Ns, time, ycur, fcur, is, yScur, fScur, 
+               fS_data, temp1, temp2);
+  nfSe++;
+
+  return(retval);
+}
+
+/* 
+ * -----------------------------------------------------------------
+ * Internal DQ approximations for sensitivity RHS
+ * -----------------------------------------------------------------
+ */
+
+/* Undefine Readibility Constants */
+
+#undef Ns
+#undef y
+#undef yS
+#undef fS_data
+#undef ftemp
+
+/*
+ * CVSensRhsDQ   - internal CVSensRhsFn
+ *
+ * CVSensRhsDQ computes right hand side of all sensitivity equations
+ * by finite differences
+ */
+
+int CVSensRhsDQ(int Ns, realtype t, 
+                N_Vector y, N_Vector ydot, 
+                N_Vector *yS, N_Vector *ySdot, 
+                void *fS_data,  
+                N_Vector ytemp, N_Vector ftemp)
+{
+  int is, retval;
+  
+  for (is=0; is<Ns; is++) {
+    retval = CVSensRhs1DQ(Ns, t, y, ydot, is, yS[is], ySdot[is],
+                          fS_data, ytemp, ftemp);
+    if (retval!=0) return(retval);
+  }
+
+  return(0);
+}
+
+/*
+ * CVSensRhs1DQ   - internal CVSensRhs1Fn
+ *
+ * CVSensRhs1DQ computes the right hand side of the is-th sensitivity 
+ * equation by finite differences
+ *
+ * CVSensRhs1DQ returns 0 if successful. Otherwise it returns the 
+ * non-zero return value from f().
+ */
+
+int CVSensRhs1DQ(int Ns, realtype t, 
+                 N_Vector y, N_Vector ydot, 
+                 int is, N_Vector yS, N_Vector ySdot, 
+                 void *fS_data,
+                 N_Vector ytemp, N_Vector ftemp)
+{
+  CVodeMem cv_mem;
+  int retval, method;
+  int nfel = 0, which;
+  realtype psave, pbari;
+  realtype delta , rdelta;
+  realtype Deltap, rDeltap, r2Deltap;
+  realtype Deltay, rDeltay, r2Deltay;
+  realtype Delta , rDelta , r2Delta ;
+  realtype norms, ratio;
+  
+  /* fS_data points to cv_mem */
+  cv_mem = (CVodeMem) fS_data;
+
+  delta = RSqrt(MAX(reltol, uround));
+  rdelta = ONE/delta;
+  
+  pbari = pbar[is];
+
+  which = plist[is];
+
+  psave = p[which];
+  
+  Deltap  = pbari * delta;
+  rDeltap = ONE/Deltap;
+  norms   = N_VWrmsNorm(yS, ewt) * pbari;
+  rDeltay = MAX(norms, rdelta) / pbari;
+  Deltay  = ONE/rDeltay;
+  
+  if (DQrhomax == ZERO) {
+    /* No switching */
+    method = (DQtype==CV_CENTERED) ? CENTERED1 : FORWARD1;
+  } else {
+    /* switch between simultaneous/separate DQ */
+    ratio = Deltay * rDeltap;
+    if ( MAX(ONE/ratio, ratio) <= DQrhomax ) 
+      method = (DQtype==CV_CENTERED) ? CENTERED1 : FORWARD1;
+    else
+      method = (DQtype==CV_CENTERED) ? CENTERED2 : FORWARD2;
+  }
+
+  switch(method) {
+    
+  case CENTERED1:
+    
+    Delta = MIN(Deltay, Deltap);
+    r2Delta = HALF/Delta;
+    
+    N_VLinearSum(ONE,y,Delta,yS,ytemp);
+    p[which] = psave + Delta;
+
+    retval = f(t, ytemp, ySdot, f_data);
+    nfel++;
+    if (retval != 0) return(retval);
+    
+    N_VLinearSum(ONE,y,-Delta,yS,ytemp);
+    p[which] = psave - Delta;
+
+    retval = f(t, ytemp, ftemp, f_data);
+    nfel++;
+    if (retval != 0) return(retval);
+
+    N_VLinearSum(r2Delta,ySdot,-r2Delta,ftemp,ySdot);
+    
+    break;
+    
+  case CENTERED2:
+    
+    r2Deltap = HALF/Deltap;
+    r2Deltay = HALF/Deltay;
+    
+    N_VLinearSum(ONE,y,Deltay,yS,ytemp);
+
+    retval = f(t, ytemp, ySdot, f_data);
+    nfel++;
+    if (retval != 0) return(retval);
+
+    N_VLinearSum(ONE,y,-Deltay,yS,ytemp);
+
+    retval = f(t, ytemp, ftemp, f_data);
+    nfel++;
+    if (retval != 0) return(retval);
+
+    N_VLinearSum(r2Deltay, ySdot, -r2Deltay, ftemp, ySdot);
+    
+    p[which] = psave + Deltap;
+    retval = f(t, y, ytemp, f_data);
+    nfel++;
+    if (retval != 0) return(retval);
+
+    p[which] = psave - Deltap;
+    retval = f(t, y, ftemp, f_data);
+    nfel++;
+    if (retval != 0) return(retval);
+
+    N_VLinearSum(r2Deltap,ytemp,-r2Deltap,ftemp,ftemp);
+    
+    N_VLinearSum(ONE,ySdot,ONE,ftemp,ySdot);
+    
+    break;
+    
+  case FORWARD1:
+    
+    Delta = MIN(Deltay, Deltap);
+    rDelta = ONE/Delta;
+    
+    N_VLinearSum(ONE,y,Delta,yS,ytemp);
+    p[which] = psave + Delta;
+
+    retval = f(t, ytemp, ySdot, f_data);
+    nfel++;
+    if (retval != 0) return(retval);
+    
+    N_VLinearSum(rDelta,ySdot,-rDelta,ydot,ySdot);
+    
+    break;
+    
+  case FORWARD2:
+    
+    N_VLinearSum(ONE,y,Deltay,yS,ytemp);
+
+    retval = f(t, ytemp, ySdot, f_data);
+    nfel++;
+    if (retval != 0) return(retval);
+
+    N_VLinearSum(rDeltay, ySdot, -rDeltay, ydot, ySdot);
+    
+    p[which] = psave + Deltap;
+    retval = f(t, y, ytemp, f_data);
+    nfel++;
+    if (retval != 0) return(retval);
+
+    N_VLinearSum(rDeltap,ytemp,-rDeltap,ydot,ftemp);
+      
+    N_VLinearSum(ONE,ySdot,ONE,ftemp,ySdot);
+    
+    break;
+    
+  }
+  
+  p[which] = psave;
+  
+  /* Increment counter nfeS */
+  nfeS += nfel;
+  
+  return(0);
+}
+
+/* 
+ * -----------------------------------------------------------------
+ * Error message handling functions
+ * -----------------------------------------------------------------
+ */
+
+/* 
+ * CVProcessError is a high level error handling function
+ * - if cv_mem==NULL it prints the error message to stderr
+ * - otherwise, it sets-up and calls the error hadling function 
+ *   pointed to by cv_ehfun
+ */
+
+#define ehfun    (cv_mem->cv_ehfun)
+#define eh_data  (cv_mem->cv_eh_data)
+
+void CVProcessError(CVodeMem cv_mem, 
+                    int error_code, const char *module, const char *fname, 
+                    const char *msgfmt, ...)
+{
+  va_list ap;
+  char msg[256];
+
+  /* Initialize the argument pointer variable 
+     (msgfmt is the last required argument to CVProcessError) */
+
+  va_start(ap, msgfmt);
+
+  if (cv_mem == NULL) {    /* We write to stderr */
+
+#ifndef NO_FPRINTF_OUTPUT
+    fprintf(stderr, "\n[%s ERROR]  %s\n  ", module, fname);
+    fprintf(stderr, msgfmt);
+    fprintf(stderr, "\n\n");
+#endif
+
+  } else {                 /* We can call ehfun */
+
+    /* Compose the message */
+
+    vsprintf(msg, msgfmt, ap);
+
+    /* Call ehfun */
+
+    ehfun(error_code, module, fname, msg, eh_data);
+
+  }
+
+  /* Finalize argument processing */
+  
+  va_end(ap);
+
+  return;
+
+}
+
+/* 
+ * CVErrHandler is the default error handling function.
+ * It sends the error message to the stream pointed to by cv_errfp 
+ */
+
+#define errfp    (cv_mem->cv_errfp)
+
+void CVErrHandler(int error_code, const char *module,
+                  const char *function, char *msg, void *data)
+{
+  CVodeMem cv_mem;
+  char err_type[10];
+
+  /* data points to cv_mem here */
+
+  cv_mem = (CVodeMem) data;
+
+  if (error_code == CV_WARNING)
+    sprintf(err_type,"WARNING");
+  else
+    sprintf(err_type,"ERROR");
+
+#ifndef NO_FPRINTF_OUTPUT
+  if (errfp!=NULL) {
+    fprintf(errfp,"\n[%s %s]  %s\n",module,err_type,function);
+    fprintf(errfp,"  %s\n\n",msg);
+  }
+#endif
+
+  return;
+}
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_band.c b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_band.c
new file mode 100644
index 0000000000000000000000000000000000000000..c53cb786c8adcc5656403738c082a381dc6ebb02
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_band.c	
@@ -0,0 +1,805 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * ----------------------------------------------------------------- 
+ * Programmer(s): Radu Serban @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2005, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This is the implementation file for the CVBAND linear solver.
+ * -----------------------------------------------------------------
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "cvodes_band_impl.h"
+#include "cvodes_impl.h"
+
+#include <sundials/sundials_math.h>
+
+/* Other Constants */
+
+#define MIN_INC_MULT RCONST(1000.0)
+#define ZERO         RCONST(0.0)
+#define ONE          RCONST(1.0)
+#define TWO          RCONST(2.0)
+
+/* CVBAND linit, lsetup, lsolve, and lfree routines */
+
+static int CVBandInit(CVodeMem cv_mem);
+
+static int CVBandSetup(CVodeMem cv_mem, int convfail, N_Vector ypred,
+                       N_Vector fpred, booleantype *jcurPtr, N_Vector vtemp1,
+                       N_Vector vtemp2, N_Vector vtemp3);
+
+static int CVBandSolve(CVodeMem cv_mem, N_Vector b, N_Vector weight,
+                       N_Vector ycur, N_Vector fcur);
+
+static void CVBandFree(CVodeMem cv_mem);
+
+/* CVBAND lfreeB function */
+
+static void CVBandFreeB(CVadjMem ca_mem);
+
+/* Wrapper function for adjoint code */
+
+static int CVAbandJac(long int nB, long int mupperB, 
+                      long int mlowerB, BandMat JB, realtype t, 
+                      N_Vector yB, N_Vector fyB, void *cvadj_mem, 
+                      N_Vector tmp1B, N_Vector tmp2B, N_Vector tmp3B);
+
+/* CVBAND DQJac routine */
+
+static int CVBandDQJac(long int n, long int mupper, long int mlower,
+                       BandMat J, realtype t,
+                       N_Vector y, N_Vector fy, void *jac_data,
+                       N_Vector tmp1, N_Vector tmp2, N_Vector tmp3);
+
+
+/* 
+ * ================================================================
+ *
+ *                   PART I - forward problems
+ *
+ * ================================================================
+ */
+
+
+/* Readability Replacements */
+
+#define lmm       (cv_mem->cv_lmm)
+#define f         (cv_mem->cv_f)
+#define f_data    (cv_mem->cv_f_data)
+#define uround    (cv_mem->cv_uround)
+#define nst       (cv_mem->cv_nst)
+#define tn        (cv_mem->cv_tn)
+#define h         (cv_mem->cv_h)
+#define gamma     (cv_mem->cv_gamma)
+#define gammap    (cv_mem->cv_gammap)
+#define gamrat    (cv_mem->cv_gamrat)
+#define ewt       (cv_mem->cv_ewt)
+#define nfe       (cv_mem->cv_nfe)
+#define linit     (cv_mem->cv_linit)
+#define lsetup    (cv_mem->cv_lsetup)
+#define lsolve    (cv_mem->cv_lsolve)
+#define lfree     (cv_mem->cv_lfree)
+#define lmem      (cv_mem->cv_lmem)
+#define vec_tmpl      (cv_mem->cv_tempv)
+#define setupNonNull  (cv_mem->cv_setupNonNull)
+
+#define n          (cvband_mem->b_n)
+#define jac        (cvband_mem->b_jac)
+#define M          (cvband_mem->b_M)
+#define mu         (cvband_mem->b_mu)
+#define ml         (cvband_mem->b_ml)
+#define storage_mu (cvband_mem->b_storage_mu)
+#define pivots     (cvband_mem->b_pivots)
+#define savedJ     (cvband_mem->b_savedJ)
+#define nstlj      (cvband_mem->b_nstlj)
+#define nje        (cvband_mem->b_nje)
+#define nfeB       (cvband_mem->b_nfeB)
+#define J_data     (cvband_mem->b_J_data)
+#define last_flag  (cvband_mem->b_last_flag)
+
+
+/*
+ * -----------------------------------------------------------------
+ * CVBand
+ * -----------------------------------------------------------------
+ * This routine initializes the memory record and sets various function
+ * fields specific to the band linear solver module.  CVBand first calls
+ * the existing lfree routine if this is not NULL.  It then sets the
+ * cv_linit, cv_lsetup, cv_lsolve, and cv_lfree fields in (*cvode_mem)
+ * to be CVBandInit, CVBandSetup, CVBandSolve, and CVBandFree,
+ * respectively.  It allocates memory for a structure of type
+ * CVBandMemRec and sets the cv_lmem field in (*cvode_mem) to the
+ * address of this structure.  It sets setupNonNull in (*cvode_mem) to be
+ * TRUE, b_mu to be mupper, b_ml to be mlower, and the b_jac field to be 
+ * CVBandDQJac.
+ * Finally, it allocates memory for M, savedJ, and pivot.  The CVBand
+ * return value is SUCCESS = 0, LMEM_FAIL = -1, or LIN_ILL_INPUT = -2.
+ *
+ * NOTE: The band linear solver assumes a serial implementation
+ *       of the NVECTOR package. Therefore, CVBand will first 
+ *       test for compatible a compatible N_Vector internal
+ *       representation by checking that the function 
+ *       N_VGetArrayPointer exists.
+ * -----------------------------------------------------------------
+ */
+                  
+int CVBand(void *cvode_mem, long int N,
+           long int mupper, long int mlower)
+{
+  CVodeMem cv_mem;
+  CVBandMem cvband_mem;
+
+  /* Return immediately if cvode_mem is NULL */
+  if (cvode_mem == NULL) {
+    CVProcessError(NULL, CVBAND_MEM_NULL, "CVBAND", "CVBand", MSGB_CVMEM_NULL);
+    return(CVBAND_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;
+
+  /* Test if the NVECTOR package is compatible with the BAND solver */
+  if (vec_tmpl->ops->nvgetarraypointer == NULL) {
+    CVProcessError(cv_mem, CVBAND_ILL_INPUT, "CVBAND", "CVBand", MSGB_BAD_NVECTOR);
+    return(CVBAND_ILL_INPUT);
+  }
+
+  if (lfree != NULL) lfree(cv_mem);
+
+  /* Set four main function fields in cv_mem */  
+  linit  = CVBandInit;
+  lsetup = CVBandSetup;
+  lsolve = CVBandSolve;
+  lfree  = CVBandFree;
+  
+  /* Get memory for CVBandMemRec */
+  cvband_mem = NULL;
+  cvband_mem = (CVBandMem) malloc(sizeof(CVBandMemRec));
+  if (cvband_mem == NULL) {
+    CVProcessError(cv_mem, CVBAND_MEM_FAIL, "CVBAND", "CVBand", MSGB_MEM_FAIL);
+    return(CVBAND_MEM_FAIL);
+  }
+  
+  /* Set default Jacobian routine and Jacobian data */
+  jac = CVBandDQJac;
+  J_data = cvode_mem;
+  last_flag = CVBAND_SUCCESS;
+
+  setupNonNull = TRUE;
+  
+  /* Load problem dimension */
+  n = N;
+
+  /* Load half-bandwiths in cvband_mem */
+  ml = mlower;
+  mu = mupper;
+
+  /* Test ml and mu for legality */
+  if ((ml < 0) || (mu < 0) || (ml >= N) || (mu >= N)) {
+    CVProcessError(cv_mem, CVBAND_ILL_INPUT, "CVBAND", "CVBand", MSGB_BAD_SIZES);
+    return(CVBAND_ILL_INPUT);
+  }
+
+  /* Set extended upper half-bandwith for M (required for pivoting) */
+  storage_mu = MIN(N-1, mu + ml);
+
+  /* Allocate memory for M, savedJ, and pivot arrays */
+  M = NULL;
+  M = BandAllocMat(N, mu, ml, storage_mu);
+  if (M == NULL) {
+    CVProcessError(cv_mem, CVBAND_MEM_FAIL, "CVBAND", "CVBand", MSGB_MEM_FAIL);
+    free(cvband_mem); cvband_mem = NULL;
+    return(CVBAND_MEM_FAIL);
+  }
+  savedJ = NULL;
+  savedJ = BandAllocMat(N, mu, ml, mu);
+  if (savedJ == NULL) {
+    CVProcessError(cv_mem, CVBAND_MEM_FAIL, "CVBAND", "CVBand", MSGB_MEM_FAIL);
+    BandFreeMat(M);
+    free(cvband_mem); cvband_mem = NULL;
+    return(CVBAND_MEM_FAIL);
+  }
+  pivots = NULL;
+  pivots = BandAllocPiv(N);
+  if (pivots == NULL) {
+    CVProcessError(cv_mem, CVBAND_MEM_FAIL, "CVBAND", "CVBand", MSGB_MEM_FAIL);
+    BandFreeMat(M);
+    BandFreeMat(savedJ);
+    free(cvband_mem); cvband_mem = NULL;
+    return(CVBAND_MEM_FAIL);
+  }
+
+  /* Attach linear solver memory to integrator memory */
+  lmem = cvband_mem;
+
+  return(CVBAND_SUCCESS);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVBandSetJacFn
+ * -----------------------------------------------------------------
+ */
+
+int CVBandSetJacFn(void *cvode_mem, CVBandJacFn bjac, void *jac_data)
+{
+  CVodeMem cv_mem;
+  CVBandMem cvband_mem;
+
+  /* Return immediately if cvode_mem is NULL */
+  if (cvode_mem == NULL) {
+    CVProcessError(NULL, CVBAND_MEM_NULL, "CVBAND", "CVBandSetJacFn", MSGB_CVMEM_NULL);
+    return(CVBAND_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (lmem == NULL) {
+    CVProcessError(cv_mem, CVBAND_LMEM_NULL, "CVBAND", "CVBandSetJacFn", MSGB_LMEM_NULL);
+    return(CVBAND_LMEM_NULL);
+  }
+  cvband_mem = (CVBandMem) lmem;
+
+  jac = bjac;
+  if (bjac != NULL) J_data = jac_data;
+
+  return(CVBAND_SUCCESS);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVBandGetWorkSpace
+ * -----------------------------------------------------------------
+ */
+
+int CVBandGetWorkSpace(void *cvode_mem, long int *lenrwLS, long int *leniwLS)
+{
+  CVodeMem cv_mem;
+  CVBandMem cvband_mem;
+
+  /* Return immediately if cvode_mem is NULL */
+  if (cvode_mem == NULL) {
+    CVProcessError(NULL, CVBAND_MEM_NULL, "CVBAND", "CVBandGetWorkSpace", MSGB_CVMEM_NULL);
+    return(CVBAND_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (lmem == NULL) {
+    CVProcessError(cv_mem, CVBAND_LMEM_NULL, "CVBAND", "CVBandGetWorkSpace", MSGB_LMEM_NULL);
+    return(CVBAND_LMEM_NULL);
+  }
+  cvband_mem = (CVBandMem) lmem;
+
+  *lenrwLS = n*(storage_mu + mu + 2*ml + 2);
+  *leniwLS = n;
+
+  return(CVBAND_SUCCESS);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVBandGetNumJacEvals
+ * -----------------------------------------------------------------
+ */
+
+int CVBandGetNumJacEvals(void *cvode_mem, long int *njevals)
+{
+  CVodeMem cv_mem;
+  CVBandMem cvband_mem;
+
+  /* Return immediately if cvode_mem is NULL */
+  if (cvode_mem == NULL) {
+    CVProcessError(NULL, CVBAND_MEM_NULL, "CVBAND", "CVBandGetNumJacEvals", MSGB_CVMEM_NULL);
+    return(CVBAND_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (lmem == NULL) {
+    CVProcessError(cv_mem, CVBAND_LMEM_NULL, "CVBAND", "CVBandGetNumJacEvals", MSGB_LMEM_NULL);
+    return(CVBAND_LMEM_NULL);
+  }
+  cvband_mem = (CVBandMem) lmem;
+
+  *njevals = nje;
+
+  return(CVBAND_SUCCESS);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVBandGetNumRhsEvals
+ * -----------------------------------------------------------------
+ */
+
+int CVBandGetNumRhsEvals(void *cvode_mem, long int *nfevalsLS)
+{
+  CVodeMem cv_mem;
+  CVBandMem cvband_mem;
+
+  /* Return immediately if cvode_mem is NULL */
+  if (cvode_mem == NULL) {
+    CVProcessError(NULL, CVBAND_MEM_NULL, "CVBAND", "CVBandGetNumRhsEvals", MSGB_CVMEM_NULL);
+    return(CVBAND_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (lmem == NULL) {
+    CVProcessError(cv_mem, CVBAND_LMEM_NULL, "CVBAND", "CVBandGetNumRhsEvals", MSGB_LMEM_NULL);
+    return(CVBAND_LMEM_NULL);
+  }
+  cvband_mem = (CVBandMem) lmem;
+
+  *nfevalsLS = nfeB;
+
+  return(CVBAND_SUCCESS);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVBandGetLastFlag
+ * -----------------------------------------------------------------
+ */
+
+int CVBandGetLastFlag(void *cvode_mem, int *flag)
+{
+  CVodeMem cv_mem;
+  CVBandMem cvband_mem;
+
+  /* Return immediately if cvode_mem is NULL */
+  if (cvode_mem == NULL) {
+    CVProcessError(NULL, CVBAND_MEM_NULL, "CVBAND", "CVBandGetLastFlag", MSGB_CVMEM_NULL);
+    return(CVBAND_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (lmem == NULL) {
+    CVProcessError(cv_mem, CVBAND_LMEM_NULL, "CVBAND", "CVBandGetLastFlag", MSGB_LMEM_NULL);
+    return(CVBAND_LMEM_NULL);
+  }
+  cvband_mem = (CVBandMem) lmem;
+
+  *flag = last_flag;
+
+  return(CVBAND_SUCCESS);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVBandGetReturnFlagName
+ * -----------------------------------------------------------------
+ */
+
+char *CVBandGetReturnFlagName(int flag)
+{
+  char *name;
+
+  name = (char *)malloc(30*sizeof(char));
+
+  switch(flag) {
+  case CVBAND_SUCCESS:
+    sprintf(name,"CVBAND_SUCCESS");
+    break;  
+  case CVBAND_MEM_NULL:
+    sprintf(name,"CVBAND_MEM_NULL");
+    break;
+  case CVBAND_LMEM_NULL:
+    sprintf(name,"CVBAND_LMEM_NULL");
+    break;
+  case CVBAND_ILL_INPUT:
+    sprintf(name,"CVBAND_ILL_INPUT");
+    break;
+  case CVBAND_MEM_FAIL:
+    sprintf(name,"CVBAND_MEM_FAIL");
+    break;
+  case CVBAND_JACFUNC_UNRECVR:
+    sprintf(name,"CVBAND_JACFUNC_UNRECVR");
+    break;
+  case CVBAND_JACFUNC_RECVR:
+    sprintf(name,"CVBAND_JACFUNC_RECVR");
+    break;
+  case CVBAND_ADJMEM_NULL:
+    sprintf(name,"CVBAND_ADJMEM_NULL");
+    break;
+  case CVBAND_LMEMB_NULL:
+    sprintf(name,"CVBAND_LMEMB_NULL");
+    break;
+  default:
+    sprintf(name,"NONE");
+  }
+
+  return(name);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVBandInit
+ * -----------------------------------------------------------------
+ * This routine does remaining initializations specific to the band
+ * linear solver.
+ * -----------------------------------------------------------------
+ */
+
+static int CVBandInit(CVodeMem cv_mem)
+{
+  CVBandMem cvband_mem;
+
+  cvband_mem = (CVBandMem) lmem;
+
+  nje   = 0;
+  nfeB  = 0;
+  nstlj = 0;
+
+  if (jac == NULL) {
+    jac = CVBandDQJac;
+    J_data = cv_mem;
+  }
+
+  last_flag = CVBAND_SUCCESS;
+  return(0);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVBandSetup
+ * -----------------------------------------------------------------
+ * This routine does the setup operations for the band linear solver.
+ * It makes a decision whether or not to call the Jacobian evaluation
+ * routine based on various state variables, and if not it uses the 
+ * saved copy.  In any case, it constructs the Newton matrix 
+ * M = I - gamma*J, updates counters, and calls the band LU 
+ * factorization routine.
+ * -----------------------------------------------------------------
+ */
+
+static int CVBandSetup(CVodeMem cv_mem, int convfail, N_Vector ypred,
+                       N_Vector fpred, booleantype *jcurPtr, N_Vector vtemp1,
+                       N_Vector vtemp2, N_Vector vtemp3)
+{
+  booleantype jbad, jok;
+  realtype dgamma;
+  long int ier;
+  CVBandMem cvband_mem;
+  int retval;
+
+  cvband_mem = (CVBandMem) lmem;
+
+  /* Use nst, gamma/gammap, and convfail to set J eval. flag jok */
+
+  dgamma = ABS((gamma/gammap) - ONE);
+  jbad = (nst == 0) || (nst > nstlj + CVB_MSBJ) ||
+         ((convfail == CV_FAIL_BAD_J) && (dgamma < CVB_DGMAX)) ||
+         (convfail == CV_FAIL_OTHER);
+  jok = !jbad;
+  
+  if (jok) {
+
+    /* If jok = TRUE, use saved copy of J */
+    *jcurPtr = FALSE;
+    BandCopy(savedJ, M, mu, ml);
+
+  } else {
+
+    /* If jok = FALSE, call jac routine for new J value */
+    nje++;
+    nstlj = nst;
+    *jcurPtr = TRUE;
+    BandZero(M); 
+
+    retval = jac(n, mu, ml, M, tn, ypred, fpred, J_data, vtemp1, vtemp2, vtemp3);
+    if (retval < 0) {
+      CVProcessError(cv_mem, CVBAND_JACFUNC_UNRECVR, "CVBAND", "CVBandSetup", MSGB_JACFUNC_FAILED);
+      last_flag = CVBAND_JACFUNC_UNRECVR;
+      return(-1);
+    }
+    if (retval > 0) {
+      last_flag = CVBAND_JACFUNC_RECVR;
+      return(1);
+    }
+
+    BandCopy(M, savedJ, mu, ml);
+
+  }
+  
+  /* Scale and add I to get M = I - gamma*J */
+  BandScale(-gamma, M);
+  BandAddI(M);
+
+  /* Do LU factorization of M */
+  ier = BandGBTRF(M, pivots);
+
+  /* Return 0 if the LU was complete; otherwise return 1 */
+  if (ier > 0) {
+    last_flag = ier;
+    return(1);
+  }
+  last_flag = CVBAND_SUCCESS;
+  return(0);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVBandSolve
+ * -----------------------------------------------------------------
+ * This routine handles the solve operation for the band linear solver
+ * by calling the band backsolve routine.  The return value is 0.
+ * -----------------------------------------------------------------
+ */
+
+static int CVBandSolve(CVodeMem cv_mem, N_Vector b, N_Vector weight,
+                       N_Vector ycur, N_Vector fcur)
+{
+  CVBandMem cvband_mem;
+  realtype *bd;
+
+  cvband_mem = (CVBandMem) lmem;
+
+  bd = N_VGetArrayPointer(b);
+
+  BandGBTRS(M, pivots, bd);
+
+  /* If CV_BDF, scale the correction to account for change in gamma */
+  if ((lmm == CV_BDF) && (gamrat != ONE)) {
+    N_VScale(TWO/(ONE + gamrat), b, b);
+  }
+
+  last_flag = CVBAND_SUCCESS;
+  return(0);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVBandFree
+ * -----------------------------------------------------------------
+ * This routine frees memory specific to the band linear solver.
+ * -----------------------------------------------------------------
+ */
+
+static void CVBandFree(CVodeMem cv_mem)
+{
+  CVBandMem cvband_mem;
+
+  cvband_mem = (CVBandMem) lmem;
+
+  BandFreeMat(M);
+  BandFreeMat(savedJ);
+  BandFreePiv(pivots);
+  free(cvband_mem); cvband_mem = NULL;
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVBandDQJac
+ * -----------------------------------------------------------------
+ * This routine generates a banded difference quotient approximation to
+ * the Jacobian of f(t,y).  It assumes that a band matrix of type
+ * BandMat is stored column-wise, and that elements within each column
+ * are contiguous. This makes it possible to get the address of a column
+ * of J via the macro BAND_COL and to write a simple for loop to set
+ * each of the elements of a column in succession.
+ * -----------------------------------------------------------------
+ */
+
+static int CVBandDQJac(long int N, long int mupper, long int mlower,
+                       BandMat J, realtype t,
+                       N_Vector y, N_Vector fy, void *jac_data,
+                       N_Vector tmp1, N_Vector tmp2, N_Vector tmp3)
+{
+  N_Vector ftemp, ytemp;
+  realtype fnorm, minInc, inc, inc_inv, srur;
+  realtype *col_j, *ewt_data, *fy_data, *ftemp_data, *y_data, *ytemp_data;
+  long int group, i, j, width, ngroups, i1, i2;
+  int retval = 0;
+
+  CVodeMem cv_mem;
+  CVBandMem cvband_mem;
+
+  /* jac_dat points to cvode_mem */
+  cv_mem = (CVodeMem) jac_data;
+  cvband_mem = (CVBandMem) lmem;
+
+  /* Rename work vectors for use as temporary values of y and f */
+  ftemp = tmp1;
+  ytemp = tmp2;
+
+  /* Obtain pointers to the data for ewt, fy, ftemp, y, ytemp */
+  ewt_data   = N_VGetArrayPointer(ewt);
+  fy_data    = N_VGetArrayPointer(fy);
+  ftemp_data = N_VGetArrayPointer(ftemp);
+  y_data     = N_VGetArrayPointer(y);
+  ytemp_data = N_VGetArrayPointer(ytemp);
+
+  /* Load ytemp with y = predicted y vector */
+  N_VScale(ONE, y, ytemp);
+
+  /* Set minimum increment based on uround and norm of f */
+  srur = RSqrt(uround);
+  fnorm = N_VWrmsNorm(fy, ewt);
+  minInc = (fnorm != ZERO) ?
+           (MIN_INC_MULT * ABS(h) * uround * N * fnorm) : ONE;
+
+  /* Set bandwidth and number of column groups for band differencing */
+  width = mlower + mupper + 1;
+  ngroups = MIN(width, N);
+  
+  for (group=1; group <= ngroups; group++) {
+    
+    /* Increment all y_j in group */
+    for(j=group-1; j < N; j+=width) {
+      inc = MAX(srur*ABS(y_data[j]), minInc/ewt_data[j]);
+      ytemp_data[j] += inc;
+    }
+
+    /* Evaluate f with incremented y */
+
+    retval = f(tn, ytemp, ftemp, f_data);
+    nfeB++;
+    if (retval != 0) break;
+
+    /* Restore ytemp, then form and load difference quotients */
+    for (j=group-1; j < N; j+=width) {
+      ytemp_data[j] = y_data[j];
+      col_j = BAND_COL(J,j);
+      inc = MAX(srur*ABS(y_data[j]), minInc/ewt_data[j]);
+      inc_inv = ONE/inc;
+      i1 = MAX(0, j-mupper);
+      i2 = MIN(j+mlower, N-1);
+      for (i=i1; i <= i2; i++)
+        BAND_COL_ELEM(col_j,i,j) =
+          inc_inv * (ftemp_data[i] - fy_data[i]);
+    }
+  }
+  
+  return(retval);
+}
+
+
+/* 
+ * ================================================================
+ *
+ *                   PART II - backward problems
+ *
+ * ================================================================
+ */
+
+
+/* Additional readability replacements */
+
+#define ytmp        (ca_mem->ca_ytmp)
+#define getY        (ca_mem->ca_getY)
+#define lmemB       (ca_mem->ca_lmemB)
+#define lfreeB      (ca_mem->ca_lfreeB)
+
+#define bjac_B      (cvbandB_mem->b_bjacB)
+#define jac_data_B  (cvbandB_mem->b_jac_dataB)
+
+/*
+ * CVBandB and CVBandSet*B
+ *
+ * Wrappers for the backward phase around the corresponding 
+ * CVODES functions
+ */
+
+int CVBandB(void *cvadj_mem, long int nB, 
+            long int mupperB, long int mlowerB)
+{
+  CVadjMem ca_mem;
+  CVBandMemB cvbandB_mem;
+  CVodeMem cvB_mem;
+  int flag;
+
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CVBAND_ADJMEM_NULL, "CVBAND", "CVBandB", MSGB_CAMEM_NULL);
+    return(CVBAND_ADJMEM_NULL);
+  }
+  ca_mem = (CVadjMem) cvadj_mem;
+
+  cvB_mem = ca_mem->cvb_mem;
+
+  /* Get memory for CVBandMemRecB */
+  cvbandB_mem = (CVBandMemB) malloc(sizeof(CVBandMemRecB));
+  if (cvbandB_mem == NULL) {
+    CVProcessError(cvB_mem, CVBAND_MEM_FAIL, "CVBAND", "CVBandB", MSGB_MEM_FAIL);
+    return(CVBAND_MEM_FAIL);
+  }
+
+  bjac_B = NULL;
+  jac_data_B = NULL;
+
+  /* attach lmemB and lfreeB */
+  lmemB = cvbandB_mem;
+  lfreeB = CVBandFreeB;
+
+  flag = CVBand(cvB_mem, nB, mupperB, mlowerB);
+
+  if (flag != CVBAND_SUCCESS) {
+    free(cvbandB_mem);
+    cvbandB_mem = NULL;
+  }
+
+  return(flag);
+}
+
+int CVBandSetJacFnB(void *cvadj_mem, CVBandJacFnB bjacB, void *jac_dataB)
+{
+  CVadjMem ca_mem;
+  CVBandMemB cvbandB_mem;
+  CVodeMem cvB_mem;
+  int flag;
+
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CVBAND_ADJMEM_NULL, "CVBAND", "CVBandSetJacFnB", MSGB_CAMEM_NULL);
+    return(CVBAND_ADJMEM_NULL);
+  }
+  ca_mem = (CVadjMem) cvadj_mem;
+
+  cvB_mem = ca_mem->cvb_mem;
+
+  if (lmemB == NULL) {
+    CVProcessError(cvB_mem, CVBAND_LMEMB_NULL, "CVBAND", "CVBandSetJacFnB", MSGB_LMEMB_NULL);
+    return(CVBAND_LMEMB_NULL);
+  }
+  cvbandB_mem = (CVBandMemB) lmemB;
+
+  bjac_B     = bjacB;
+  jac_data_B = jac_dataB;
+
+  flag = CVBandSetJacFn(cvB_mem, CVAbandJac, cvadj_mem);
+
+  return(flag);
+}
+
+/*
+ * CVBandFreeB 
+ */
+
+static void CVBandFreeB(CVadjMem ca_mem)
+{
+  CVBandMemB cvbandB_mem;
+
+  cvbandB_mem = (CVBandMemB) lmemB;
+
+  free(cvbandB_mem);
+}
+
+/*
+ * CVAbandJac
+ *
+ * This routine interfaces to the CVBandJacFnB routine provided 
+ * by the user.
+ * NOTE: jac_data actually contains cvadj_mem
+ */
+
+static int CVAbandJac(long int nB, long int mupperB, 
+                      long int mlowerB, BandMat JB, realtype t, 
+                      N_Vector yB, N_Vector fyB, void *cvadj_mem, 
+                      N_Vector tmp1B, N_Vector tmp2B, N_Vector tmp3B)
+{
+  CVadjMem ca_mem;
+  CVodeMem cvB_mem;
+  CVBandMemB cvbandB_mem;
+  int retval, flag;
+
+  ca_mem = (CVadjMem) cvadj_mem;
+  cvB_mem = ca_mem->cvb_mem;
+  cvbandB_mem = (CVBandMemB) lmemB;
+
+  /* Forward solution from interpolation */
+  flag = getY(ca_mem, t, ytmp);
+  if (flag != CV_SUCCESS) {
+    CVProcessError(cvB_mem, -1, "CVBAND", "CVAbandJac", MSGB_BAD_T);
+    return(-1);
+  }
+
+  /* Call user's adjoint band bjacB routine */
+  retval = bjac_B(nB, mupperB, mlowerB, JB, t, ytmp, yB, fyB, jac_data_B,
+                  tmp1B, tmp2B, tmp3B);
+
+  return(retval);
+}
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_band_impl.h b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_band_impl.h
new file mode 100644
index 0000000000000000000000000000000000000000..e6c2f93177f6a5ac3ff39aa83381eb3a075d465d
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_band_impl.h	
@@ -0,0 +1,106 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * ----------------------------------------------------------------- 
+ * Programmer(s): Radu Serban @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2005, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * Implementation header file for the band linear solver, CVBAND.
+ * -----------------------------------------------------------------
+ */
+
+#ifndef _CVSBAND_IMPL_H
+#define _CVSBAND_IMPL_H
+
+#ifdef __cplusplus  /* wrapper to enable C++ usage */
+extern "C" {
+#endif
+
+#include <cvodes/cvodes_band.h>
+
+  /*
+   * -----------------------------------------------------------------
+   * Types: CVBandMemRec, CVBandMem                                
+   * -----------------------------------------------------------------
+   * The type CVBandMem is pointer to a CVBandMemRec.
+   * This structure contains CVBand solver-specific data.                
+   *
+   * CVBand attaches such a structure to the lmem field of CVodeMem
+   * -----------------------------------------------------------------
+   */                                                                
+
+  typedef struct {
+
+    long int b_n;           /* N = problem dimension                    */
+
+    CVBandJacFn b_jac;      /* jac = Jacobian routine to be called      */
+
+    long int b_ml;          /* b_ml = lower bandwidth of savedJ         */
+  
+    long int b_mu;          /* b_mu = upper bandwidth of savedJ         */ 
+  
+    long int b_storage_mu;  /* upper bandwith of M = MIN(N-1,b_mu+b_ml) */
+  
+    BandMat b_M;            /* M = I - gamma J, gamma = h / l1          */
+  
+    long int *b_pivots;     /* pivots = pivot array for PM = LU         */
+  
+    BandMat b_savedJ;       /* savedJ = old Jacobian                    */
+  
+    long int b_nstlj;       /* nstlj = nst at last Jacobian eval.       */
+  
+    long int b_nje;         /* nje = no. of calls to jac                */
+  
+    long int b_nfeB;        /* nfeB = no. of calls to f due to difference
+                               quotient band Jacobian approximation     */
+
+    void *b_J_data;         /* J_data is passed to jac                  */
+
+    int b_last_flag;        /* last error return flag                   */
+  
+  } CVBandMemRec, *CVBandMem;
+
+
+  /*
+   * -----------------------------------------------------------------
+   * Types : CVBandMemRecB, CVBandMemB       
+   * -----------------------------------------------------------------
+   * CVBandB attaches such a structure to the lmemB filed of CVadjMem
+   * -----------------------------------------------------------------
+   */
+
+  typedef struct {
+
+    CVBandJacFnB b_bjacB;
+    void *b_jac_dataB;
+
+  } CVBandMemRecB, *CVBandMemB;
+
+
+  /*
+   * -----------------------------------------------------------------
+   * Error Messages 
+   * -----------------------------------------------------------------
+   */
+
+#define MSGB_CVMEM_NULL "Integrator memory is NULL."
+#define MSGB_MEM_FAIL "A memory request failed."
+#define MSGB_BAD_SIZES "Illegal bandwidth parameter(s). Must have 0 <=  ml, mu <= N-1."
+#define MSGB_BAD_NVECTOR "A required vector operation is not implemented."
+#define MSGB_LMEM_NULL "CVBAND memory is NULL."
+#define MSGB_JACFUNC_FAILED "The Jacobian routine failed in an unrecoverable manner."
+
+#define MSGB_CAMEM_NULL "cvadj_mem = NULL illegal."
+#define MSGB_LMEMB_NULL "CVBAND memory is NULL for the backward integration."
+#define MSGB_BAD_T "Bad t for interpolation."
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_bandpre.c b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_bandpre.c
new file mode 100644
index 0000000000000000000000000000000000000000..737a36bc055992aca66a2167f4f7bb1dfb8fd6e5
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_bandpre.c	
@@ -0,0 +1,647 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * ----------------------------------------------------------------- 
+ * Programmer(s): Radu Serban and Aaron Collier @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2005, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This file contains implementations of the banded difference
+ * quotient Jacobian-based preconditioner and solver routines for
+ * use with the CVSPILS linear solvers.
+ * -----------------------------------------------------------------
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "cvodes_impl.h"
+#include "cvodes_bandpre_impl.h"
+
+#include <cvodes/cvodes_sptfqmr.h>
+#include <cvodes/cvodes_spbcgs.h>
+#include <cvodes/cvodes_spgmr.h>
+
+#include <sundials/sundials_math.h>
+
+#define MIN_INC_MULT RCONST(1000.0)
+#define ZERO         RCONST(0.0)
+#define ONE          RCONST(1.0)
+
+/* Prototypes of CVBandPrecSetup and CVBandPrecSolve */
+  
+static int CVBandPrecSetup(realtype t, N_Vector y, N_Vector fy, 
+                           booleantype jok, booleantype *jcurPtr, 
+                           realtype gamma, void *bp_data,
+                           N_Vector tmp1, N_Vector tmp2, N_Vector tmp3);
+
+static int CVBandPrecSolve(realtype t, N_Vector y, N_Vector fy, 
+                           N_Vector r, N_Vector z, 
+                           realtype gamma, realtype delta,
+                           int lr, void *bp_data, N_Vector tmp);
+
+/* Prototype for difference quotient Jacobian calculation routine */
+
+static int CVBandPDQJac(CVBandPrecData pdata, 
+                        realtype t, N_Vector y, N_Vector fy, 
+                        N_Vector ftemp, N_Vector ytemp);
+
+/* 
+ * ================================================================
+ *
+ *                   PART I - forward problems
+ *
+ * ================================================================
+ */
+
+/* Redability replacements */
+
+#define vec_tmpl (cv_mem->cv_tempv)
+
+/*
+ * -----------------------------------------------------------------
+ * Malloc, Free, and Get Functions
+ * NOTE: The band linear solver assumes a serial implementation
+ *       of the NVECTOR package. Therefore, CVBandPrecAlloc will
+ *       first test for a compatible N_Vector internal representation
+ *       by checking that the function N_VGetArrayPointer exists.
+ * -----------------------------------------------------------------
+ */
+
+void *CVBandPrecAlloc(void *cvode_mem, long int N, 
+                      long int mu, long int ml)
+{
+  CVodeMem cv_mem;
+  CVBandPrecData pdata;
+  long int mup, mlp, storagemu;
+
+  if (cvode_mem == NULL) {
+    CVProcessError(NULL, 0, "CVBANDPRE", "CVBandPrecAlloc", MSGBP_CVMEM_NULL);
+    return(NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;
+
+  /* Test if the NVECTOR package is compatible with the BAND preconditioner */
+  if(vec_tmpl->ops->nvgetarraypointer == NULL) {
+    CVProcessError(cv_mem, 0, "CVBANDPRE", "CVBandPrecAlloc", MSGBP_BAD_NVECTOR);
+    return(NULL);
+  }
+
+  pdata = NULL;
+  pdata = (CVBandPrecData) malloc(sizeof *pdata);  /* Allocate data memory */
+  if (pdata == NULL) {
+    CVProcessError(cv_mem, 0, "CVBANDPRE", "CVBandPrecAlloc", MSGBP_MEM_FAIL);
+    return(NULL);
+  }
+
+  /* Load pointers and bandwidths into pdata block. */
+  pdata->cvode_mem = cvode_mem;
+  pdata->N = N;
+  pdata->mu = mup = MIN(N-1, MAX(0,mu));
+  pdata->ml = mlp = MIN(N-1, MAX(0,ml));
+
+  /* Initialize nfeBP counter */
+  pdata->nfeBP = 0;
+
+  /* Allocate memory for saved banded Jacobian approximation. */
+  pdata->savedJ = NULL;
+  pdata->savedJ = BandAllocMat(N, mup, mlp, mup);
+  if (pdata->savedJ == NULL) {
+    free(pdata); pdata = NULL;
+    CVProcessError(cv_mem, 0, "CVBANDPRE", "CVBandPrecAlloc", MSGBP_MEM_FAIL);
+    return(NULL);
+  }
+
+  /* Allocate memory for banded preconditioner. */
+  storagemu = MIN(N-1, mup+mlp);
+  pdata->savedP = NULL;
+  pdata->savedP = BandAllocMat(N, mup, mlp, storagemu);
+  if (pdata->savedP == NULL) {
+    BandFreeMat(pdata->savedJ);
+    free(pdata); pdata = NULL;
+    CVProcessError(cv_mem, 0, "CVBANDPRE", "CVBandPrecAlloc", MSGBP_MEM_FAIL);
+    return(NULL);
+  }
+
+  /* Allocate memory for pivot array. */
+  pdata->pivots = NULL;
+  pdata->pivots = BandAllocPiv(N);
+  if (pdata->savedJ == NULL) {
+    BandFreeMat(pdata->savedP);
+    BandFreeMat(pdata->savedJ);
+    free(pdata); pdata = NULL;
+    CVProcessError(cv_mem, 0, "CVBANDPRE", "CVBandPrecAlloc", MSGBP_MEM_FAIL);
+    return(NULL);
+  }
+
+  return((void *) pdata);
+}
+
+int CVBPSptfqmr(void *cvode_mem, int pretype, int maxl, void *p_data)
+{
+  CVodeMem cv_mem;
+  int flag;
+
+  flag = CVSptfqmr(cvode_mem, pretype, maxl);
+  if(flag != CVSPILS_SUCCESS) return(flag);
+  
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if ( p_data == NULL ) {
+    CVProcessError(cv_mem, CVBANDPRE_PDATA_NULL, "CVBANDPRE", "CVBPSptfqmr", MSGBP_PDATA_NULL);
+    return(CVBANDPRE_PDATA_NULL);
+  } 
+
+  flag = CVSpilsSetPreconditioner(cvode_mem, CVBandPrecSetup, CVBandPrecSolve, p_data);
+  if(flag != CVSPILS_SUCCESS) return(flag);
+
+  return(CVSPILS_SUCCESS);
+}
+
+int CVBPSpbcg(void *cvode_mem, int pretype, int maxl, void *p_data)
+{
+  CVodeMem cv_mem;
+  int flag;
+
+  flag = CVSpbcg(cvode_mem, pretype, maxl);
+  if(flag != CVSPILS_SUCCESS) return(flag);
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if ( p_data == NULL ) {
+    CVProcessError(cv_mem, CVBANDPRE_PDATA_NULL, "CVBANDPRE", "CVBPSpbcg", MSGBP_PDATA_NULL);
+    return(CVBANDPRE_PDATA_NULL);
+  } 
+
+  flag = CVSpilsSetPreconditioner(cvode_mem, CVBandPrecSetup, CVBandPrecSolve, p_data);
+  if(flag != CVSPILS_SUCCESS) return(flag);
+
+  return(CVSPILS_SUCCESS);
+}
+
+int CVBPSpgmr(void *cvode_mem, int pretype, int maxl, void *p_data)
+{
+  CVodeMem cv_mem;
+  int flag;
+
+  flag = CVSpgmr(cvode_mem, pretype, maxl);
+  if(flag != CVSPILS_SUCCESS) return(flag);
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if ( p_data == NULL ) {
+    CVProcessError(cv_mem, CVBANDPRE_PDATA_NULL, "CVBANDPRE", "CVBPSpgmr", MSGBP_PDATA_NULL);
+    return(CVBANDPRE_PDATA_NULL);
+  }
+
+  flag = CVSpilsSetPreconditioner(cvode_mem, CVBandPrecSetup, CVBandPrecSolve, p_data);
+  if(flag != CVSPILS_SUCCESS) return(flag);
+
+  return(CVSPILS_SUCCESS);
+}
+
+void CVBandPrecFree(void **bp_data)
+{
+  CVBandPrecData pdata;
+
+  if (*bp_data == NULL) return;
+
+  pdata = (CVBandPrecData) (*bp_data);
+  BandFreeMat(pdata->savedJ);
+  BandFreeMat(pdata->savedP);
+  BandFreePiv(pdata->pivots);
+
+  free(*bp_data);
+  *bp_data = NULL;
+
+}
+
+int CVBandPrecGetWorkSpace(void *bp_data, long int *lenrwBP, long int *leniwBP)
+{
+  CVBandPrecData pdata;
+  long int N, ml, mu, smu;
+
+  if ( bp_data == NULL ) {
+    CVProcessError(NULL, CVBANDPRE_PDATA_NULL, "CVBANDPRE", "CVBandPrecGetWorkSpace", MSGBP_PDATA_NULL);
+    return(CVBANDPRE_PDATA_NULL);
+  } 
+
+  pdata = (CVBandPrecData) bp_data;
+
+  N   = pdata->N;
+  mu  = pdata->mu;
+  ml  = pdata->ml;
+  smu = MIN( N-1, mu + ml);
+
+  *leniwBP = pdata->N;
+  *lenrwBP = N * ( 2*ml + smu + mu + 2 );
+
+  return(CVBANDPRE_SUCCESS);
+}
+
+int CVBandPrecGetNumRhsEvals(void *bp_data, long int *nfevalsBP)
+{
+  CVBandPrecData pdata;
+
+  if (bp_data == NULL) {
+    CVProcessError(NULL, CVBANDPRE_PDATA_NULL, "CVBANDPRE", "CVBandPrecGetNumRhsEvals", MSGBP_PDATA_NULL);
+    return(CVBANDPRE_PDATA_NULL);
+  } 
+
+  pdata = (CVBandPrecData) bp_data;
+
+  *nfevalsBP = pdata->nfeBP;
+
+  return(CVBANDPRE_SUCCESS);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVBandPrecGetReturnFlagName
+ * -----------------------------------------------------------------
+ */
+
+char *CVBandPrecGetReturnFlagName(int flag)
+{
+  char *name;
+
+  name = (char *)malloc(30*sizeof(char));
+
+  switch(flag) {
+  case CVBANDPRE_SUCCESS:
+    sprintf(name,"CVBANDPRE_SUCCESS");
+    break;    
+  case CVBANDPRE_PDATA_NULL:
+    sprintf(name,"CVBANDPRE_PDATA_NULL");
+    break;
+  case CVBANDPRE_RHSFUNC_UNRECVR:
+    sprintf(name,"CVBANDPRE_RHSFUNC_UNRECVR");
+    break;
+  case CVBANDPRE_ADJMEM_NULL:
+    sprintf(name,"CVBANDPRE_ADJMEM_NULL");
+    break;
+  case CVBANDPRE_MEM_FAIL:
+    sprintf(name,"CVBANDPRE_MEM_FAIL");
+    break;
+  default:
+    sprintf(name,"NONE");
+  }
+
+  return(name);
+}
+
+/* Readability Replacements */
+
+#define N      (pdata->N)
+#define mu     (pdata->mu)
+#define ml     (pdata->ml)
+#define pivots (pdata->pivots)
+#define savedJ (pdata->savedJ)
+#define savedP (pdata->savedP)
+#define nfeBP  (pdata->nfeBP)
+
+/*
+ * -----------------------------------------------------------------
+ * CVBandPrecSetup
+ * -----------------------------------------------------------------
+ * Together CVBandPrecSetup and CVBandPrecSolve use a banded
+ * difference quotient Jacobian to create a preconditioner.
+ * CVBandPrecSetup calculates a new J, if necessary, then
+ * calculates P = I - gamma*J, and does an LU factorization of P.
+ *
+ * The parameters of CVBandPrecSetup are as follows:
+ *
+ * t       is the current value of the independent variable.
+ *
+ * y       is the current value of the dependent variable vector,
+ *         namely the predicted value of y(t).
+ *
+ * fy      is the vector f(t,y).
+ *
+ * jok     is an input flag indicating whether Jacobian-related
+ *         data needs to be recomputed, as follows:
+ *           jok == FALSE means recompute Jacobian-related data
+ *                  from scratch.
+ *           jok == TRUE means that Jacobian data from the
+ *                  previous PrecSetup call will be reused
+ *                  (with the current value of gamma).
+ *         A CVBandPrecSetup call with jok == TRUE should only
+ *         occur after a call with jok == FALSE.
+ *
+ * *jcurPtr is a pointer to an output integer flag which is
+ *          set by CVBandPrecond as follows:
+ *            *jcurPtr = TRUE if Jacobian data was recomputed.
+ *            *jcurPtr = FALSE if Jacobian data was not recomputed,
+ *                       but saved data was reused.
+ *
+ * gamma   is the scalar appearing in the Newton matrix.
+ *
+ * bp_data is a pointer to preconditoner data - the same as the
+ *         bp_data parameter passed to CVSp*.
+ *
+ * tmp1, tmp2, and tmp3 are pointers to memory allocated
+ *           for vectors of length N for work space. This
+ *           routine uses only tmp1 and tmp2.
+ *
+ * The value to be returned by the CVBandPrecSetup function is
+ *   0  if successful, or
+ *   1  if the band factorization failed.
+ * -----------------------------------------------------------------
+ */
+
+static int CVBandPrecSetup(realtype t, N_Vector y, N_Vector fy, 
+                           booleantype jok, booleantype *jcurPtr, 
+                           realtype gamma, void *bp_data,
+                           N_Vector tmp1, N_Vector tmp2, N_Vector tmp3)
+{
+  long int ier;
+  CVBandPrecData pdata;
+  CVodeMem cv_mem;
+  int retval;
+
+  /* Assume matrix and pivots have already been allocated. */
+  pdata = (CVBandPrecData) bp_data;
+
+  cv_mem = (CVodeMem) pdata->cvode_mem;
+
+  if (jok) {
+
+    /* If jok = TRUE, use saved copy of J. */
+    *jcurPtr = FALSE;
+    BandCopy(savedJ, savedP, mu, ml);
+
+  } else {
+
+    /* If jok = FALSE, call CVBandPDQJac for new J value. */
+    *jcurPtr = TRUE;
+    BandZero(savedJ);
+
+    retval = CVBandPDQJac(pdata, t, y, fy, tmp1, tmp2);
+    if (retval < 0) {
+      CVProcessError(cv_mem, CVBANDPRE_RHSFUNC_UNRECVR, "CVBANDPRE", "CVBandPrecSetup", MSGBP_RHSFUNC_FAILED);
+      return(-1);
+    }
+    if (retval > 0) {
+      return(1);
+    }
+
+    BandCopy(savedJ, savedP, mu, ml);
+
+  }
+  
+  /* Scale and add I to get savedP = I - gamma*J. */
+  BandScale(-gamma, savedP);
+  BandAddI(savedP);
+ 
+  /* Do LU factorization of matrix. */
+  ier = BandGBTRF(savedP, pivots);
+ 
+  /* Return 0 if the LU was complete; otherwise return 1. */
+  if (ier > 0) return(1);
+  return(0);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVBandPrecSolve
+ * -----------------------------------------------------------------
+ * CVBandPrecSolve solves a linear system P z = r, where P is the
+ * matrix computed by CVBandPrecond.
+ *
+ * The parameters of CVBandPrecSolve used here are as follows:
+ *
+ * r       is the right-hand side vector of the linear system.
+ *
+ * bp_data is a pointer to preconditioner data - the same as the
+ *         bp_data parameter passed to CVSp*.
+ *
+ * z       is the output vector computed by CVBandPrecSolve.
+ *
+ * The value returned by the CVBandPrecSolve function is always 0,
+ * indicating success.
+ * -----------------------------------------------------------------
+ */ 
+
+static int CVBandPrecSolve(realtype t, N_Vector y, N_Vector fy, 
+                           N_Vector r, N_Vector z, 
+                           realtype gamma, realtype delta,
+                           int lr, void *bp_data, N_Vector tmp)
+{
+  CVBandPrecData pdata;
+  realtype *zd;
+
+  /* Assume matrix and pivots have already been allocated. */
+  pdata = (CVBandPrecData) bp_data;
+
+  /* Copy r to z. */
+  N_VScale(ONE, r, z);
+
+  /* Do band backsolve on the vector z. */
+  zd = N_VGetArrayPointer(z);
+
+  BandGBTRS(savedP, pivots, zd);
+
+  return(0);
+}
+
+#define ewt    (cv_mem->cv_ewt)
+#define uround (cv_mem->cv_uround)
+#define h      (cv_mem->cv_h)
+#define f      (cv_mem->cv_f)
+#define f_data (cv_mem->cv_f_data)
+
+/*
+ * -----------------------------------------------------------------
+ * CVBandPDQJac
+ * -----------------------------------------------------------------
+ * This routine generates a banded difference quotient approximation to
+ * the Jacobian of f(t,y). It assumes that a band matrix of type
+ * BandMat is stored column-wise, and that elements within each column
+ * are contiguous. This makes it possible to get the address of a column
+ * of J via the macro BAND_COL and to write a simple for loop to set
+ * each of the elements of a column in succession.
+ * -----------------------------------------------------------------
+ */
+
+static int CVBandPDQJac(CVBandPrecData pdata, 
+                        realtype t, N_Vector y, N_Vector fy, 
+                        N_Vector ftemp, N_Vector ytemp)
+{
+  CVodeMem cv_mem;
+  realtype fnorm, minInc, inc, inc_inv, srur;
+  long int group, i, j, width, ngroups, i1, i2;
+  realtype *col_j, *ewt_data, *fy_data, *ftemp_data, *y_data, *ytemp_data;
+  int retval;
+
+  cv_mem = (CVodeMem) pdata->cvode_mem;
+
+  /* Obtain pointers to the data for ewt, fy, ftemp, y, ytemp. */
+  ewt_data   = N_VGetArrayPointer(ewt);
+  fy_data    = N_VGetArrayPointer(fy);
+  ftemp_data = N_VGetArrayPointer(ftemp);
+  y_data     = N_VGetArrayPointer(y);
+  ytemp_data = N_VGetArrayPointer(ytemp);
+
+  /* Load ytemp with y = predicted y vector. */
+  N_VScale(ONE, y, ytemp);
+
+  /* Set minimum increment based on uround and norm of f. */
+  srur = RSqrt(uround);
+  fnorm = N_VWrmsNorm(fy, ewt);
+  minInc = (fnorm != ZERO) ?
+           (MIN_INC_MULT * ABS(h) * uround * N * fnorm) : ONE;
+
+  /* Set bandwidth and number of column groups for band differencing. */
+  width = ml + mu + 1;
+  ngroups = MIN(width, N);
+  
+  for (group = 1; group <= ngroups; group++) {
+    
+    /* Increment all y_j in group. */
+    for(j = group-1; j < N; j += width) {
+      inc = MAX(srur*ABS(y_data[j]), minInc/ewt_data[j]);
+      ytemp_data[j] += inc;
+    }
+
+    /* Evaluate f with incremented y. */
+
+    retval = f(t, ytemp, ftemp, f_data);
+    nfeBP++;
+    if (retval != 0) return(retval);
+
+    /* Restore ytemp, then form and load difference quotients. */
+    for (j = group-1; j < N; j += width) {
+      ytemp_data[j] = y_data[j];
+      col_j = BAND_COL(savedJ,j);
+      inc = MAX(srur*ABS(y_data[j]), minInc/ewt_data[j]);
+      inc_inv = ONE/inc;
+      i1 = MAX(0, j-mu);
+      i2 = MIN(j+ml, N-1);
+      for (i=i1; i <= i2; i++)
+        BAND_COL_ELEM(col_j,i,j) =
+          inc_inv * (ftemp_data[i] - fy_data[i]);
+    }
+  }
+
+  return(0);
+}
+
+/* 
+ * ================================================================
+ *
+ *                   PART II - backward problems
+ *
+ * ================================================================
+ */
+
+/* Additional readability replacements */
+
+#define bp_data_B   (ca_mem->ca_pmemB)
+
+/*
+ * CVBandPrecAllocB, CVBPSp*B
+ *
+ * Wrappers for the backward phase around the corresponding 
+ * CVODES functions
+ */
+
+int CVBandPrecAllocB(void *cvadj_mem, long int nB, 
+                     long int muB, long int mlB)
+{
+  CVadjMem ca_mem;
+  CVodeMem cvB_mem;
+  void *bp_dataB;
+
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CVBANDPRE_ADJMEM_NULL, "CVBANDPRE", "CVBandPrecAlloc", MSGBP_CAMEM_NULL);
+    return(CVBANDPRE_ADJMEM_NULL);
+  }
+  ca_mem = (CVadjMem) cvadj_mem;
+
+  cvB_mem = ca_mem->cvb_mem;
+
+  bp_dataB = CVBandPrecAlloc(cvB_mem, nB, muB, mlB);
+  if (bp_dataB == NULL) {
+    CVProcessError(cvB_mem, CVBANDPRE_MEM_FAIL, "CVBANDPRE", "CVBandPrecAlloc", MSGBP_MEM_FAIL);
+    return(CVBANDPRE_MEM_FAIL);
+  }
+
+  bp_data_B = bp_dataB;
+
+  return(CVBANDPRE_SUCCESS);
+
+}
+
+int CVBPSptfqmrB(void *cvadj_mem, int pretypeB, int maxlB)
+{
+  CVadjMem ca_mem;
+  CVodeMem cvB_mem;
+  int flag;
+
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CVBANDPRE_ADJMEM_NULL, "CVBANDPRE", "CVBPSptfqmrAlloc", MSGBP_CAMEM_NULL);
+    return(CVBANDPRE_ADJMEM_NULL);
+  }
+  ca_mem = (CVadjMem) cvadj_mem;
+
+  cvB_mem = ca_mem->cvb_mem;
+  
+  flag = CVBPSptfqmr(cvB_mem, pretypeB, maxlB, bp_data_B);
+
+  return(flag);
+}
+
+int CVBPSpbcgB(void *cvadj_mem, int pretypeB, int maxlB)
+{
+  CVadjMem ca_mem;
+  CVodeMem cvB_mem;
+  int flag;
+
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CVBANDPRE_ADJMEM_NULL, "CVBANDPRE", "CVBPSptbcgAlloc", MSGBP_CAMEM_NULL);
+    return(CVBANDPRE_ADJMEM_NULL);
+  }
+  ca_mem = (CVadjMem) cvadj_mem;
+
+  cvB_mem = ca_mem->cvb_mem;
+  
+  flag = CVBPSpbcg(cvB_mem, pretypeB, maxlB, bp_data_B);
+
+  return(flag);
+}
+
+int CVBPSpgmrB(void *cvadj_mem, int pretypeB, int maxlB)
+{
+  CVadjMem ca_mem;
+  CVodeMem cvB_mem;
+  int flag;
+
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CVBANDPRE_ADJMEM_NULL, "CVBANDPRE", "CVBPSpgmrAlloc", MSGBP_CAMEM_NULL);
+    return(CVBANDPRE_ADJMEM_NULL);
+  }
+  ca_mem = (CVadjMem) cvadj_mem;
+
+  cvB_mem = ca_mem->cvb_mem;
+  
+  flag = CVBPSpgmr(cvB_mem, pretypeB, maxlB, bp_data_B);
+
+  return(flag);
+}
+
+
+void CVBandPrecFreeB(void *cvadj_mem)
+{
+  CVadjMem ca_mem;
+
+  if (cvadj_mem == NULL) return;
+  ca_mem = (CVadjMem) cvadj_mem;
+
+  CVBandPrecFree(&bp_data_B);
+}
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_bandpre_impl.h b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_bandpre_impl.h
new file mode 100644
index 0000000000000000000000000000000000000000..8cfed9b0436a2d49a6cace9f1fded05f4191ba64
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_bandpre_impl.h	
@@ -0,0 +1,74 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * ----------------------------------------------------------------- 
+ * Programmer(s): Radu Serban @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2005, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * Implementation header file for the CVBANDPRE module.
+ * -----------------------------------------------------------------
+ */
+
+#ifndef _CVSBANDPRE_IMPL_H
+#define _CVSBANDPRE_IMPL_H
+
+#ifdef __cplusplus  /* wrapper to enable C++ usage */
+extern "C" {
+#endif
+
+#include <cvodes/cvodes_bandpre.h>
+#include <sundials/sundials_band.h>
+
+  /*
+   * -----------------------------------------------------------------
+   * Type: CVBandPrecData
+   * -----------------------------------------------------------------
+   */
+
+  typedef struct {
+
+    /* Data set by user in CVBandPrecAlloc */
+
+    long int N;
+    long int ml, mu;
+
+    /* Data set by CVBandPrecSetup */
+
+    BandMat savedJ;
+    BandMat savedP;
+    long int *pivots;
+
+    /* Rhs calls */
+
+    long int nfeBP;
+
+    /* Pointer to cvode_mem */
+
+    void *cvode_mem;
+
+  } *CVBandPrecData;
+
+  /*
+   * -----------------------------------------------------------------
+   * CVBANDPRE error messages
+   * -----------------------------------------------------------------
+   */
+
+#define MSGBP_CVMEM_NULL "Integrator memory is NULL."
+#define MSGBP_MEM_FAIL "A memory request failed."
+#define MSGBP_BAD_NVECTOR "A required vector operation is not implemented."
+#define MSGBP_PDATA_NULL "CVBANDPRE memory is NULL."
+#define MSGBP_RHSFUNC_FAILED "The right-hand side routine failed in an unrecoverable manner."
+
+#define MSGBP_CAMEM_NULL "cvadj_mem = NULL illegal."
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_bbdpre.c b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_bbdpre.c
new file mode 100644
index 0000000000000000000000000000000000000000..cb1f705d9754232887411ff6495924641f001372
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_bbdpre.c	
@@ -0,0 +1,883 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * ----------------------------------------------------------------- 
+ * Programmer(s): Radu Serban and Aaron Collier @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2005, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This file contains implementations of routines for a
+ * band-block-diagonal preconditioner, i.e. a block-diagonal
+ * matrix with banded blocks, for use with CVODE, a CVSPILS linear
+ * solver, and the parallel implementation of NVECTOR.
+ * -----------------------------------------------------------------
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "cvodes_impl.h"
+#include "cvodes_bbdpre_impl.h"
+
+#include <cvodes/cvodes_sptfqmr.h>
+#include <cvodes/cvodes_spbcgs.h>
+#include <cvodes/cvodes_spgmr.h>
+
+#include <sundials/sundials_math.h>
+
+#define MIN_INC_MULT RCONST(1000.0)
+#define ZERO         RCONST(0.0)
+#define ONE          RCONST(1.0)
+
+/* Prototypes of functions CVBBDPrecSetup and CVBBDPrecSolve */
+
+static int CVBBDPrecSetup(realtype t, N_Vector y, N_Vector fy, 
+                          booleantype jok, booleantype *jcurPtr, 
+                          realtype gamma, void *bbd_data, 
+                          N_Vector tmp1, N_Vector tmp2, N_Vector tmp3);
+
+static int CVBBDPrecSolve(realtype t, N_Vector y, N_Vector fy, 
+                          N_Vector r, N_Vector z, 
+                          realtype gamma, realtype delta,
+                          int lr, void *bbd_data, N_Vector tmp);
+
+/* Wrapper functions for adjoint code */
+
+static int CVAgloc(long int NlocalB, realtype t, N_Vector yB, N_Vector gB, 
+                   void *cvadj_mem);
+
+static int CVAcfn(long int NlocalB, realtype t, N_Vector yB,
+                  void *cvadj_mem);
+
+/* Prototype for difference quotient Jacobian calculation routine */
+
+static int CVBBDDQJac(CVBBDPrecData pdata, realtype t, 
+                      N_Vector y, N_Vector gy, 
+                      N_Vector ytemp, N_Vector gtemp);
+
+
+/* 
+ * ================================================================
+ *
+ *                   PART I - forward problems
+ *
+ * ================================================================
+ */
+
+/* Redability replacements */
+
+#define uround   (cv_mem->cv_uround)
+#define vec_tmpl (cv_mem->cv_tempv)
+
+/*
+ * -----------------------------------------------------------------
+ * User-Callable Functions: malloc, reinit and free
+ * -----------------------------------------------------------------
+ */
+
+void *CVBBDPrecAlloc(void *cvode_mem, long int Nlocal, 
+                     long int mudq, long int mldq,
+                     long int mukeep, long int mlkeep, 
+                     realtype dqrely, 
+                     CVLocalFn gloc, CVCommFn cfn)
+{
+  CVodeMem cv_mem;
+  CVBBDPrecData pdata;
+  long int muk, mlk, storage_mu;
+
+  if (cvode_mem == NULL) {
+    CVProcessError(NULL, 0, "CVBBDPRE", "CVBBDPrecAlloc", MSGBBDP_CVMEM_NULL);
+    return(NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;
+
+  /* Test if the NVECTOR package is compatible with the BLOCK BAND preconditioner */
+  if(vec_tmpl->ops->nvgetarraypointer == NULL) {
+    CVProcessError(cv_mem, 0, "CVBBDPRE", "CVBBDPrecAlloc", MSGBBDP_BAD_NVECTOR);
+    return(NULL);
+  }
+
+  /* Allocate data memory */
+  pdata = NULL;
+  pdata = (CVBBDPrecData) malloc(sizeof *pdata);  
+  if (pdata == NULL) {
+    CVProcessError(cv_mem, 0, "CVBBDPRE", "CVBBDPrecAlloc", MSGBBDP_MEM_FAIL);
+    return(NULL);
+  }
+
+  /* Set pointers to gloc and cfn; load half-bandwidths */
+  pdata->cvode_mem = cvode_mem;
+  pdata->gloc = gloc;
+  pdata->cfn = cfn;
+  pdata->mudq = MIN(Nlocal-1, MAX(0,mudq));
+  pdata->mldq = MIN(Nlocal-1, MAX(0,mldq));
+  muk = MIN(Nlocal-1, MAX(0,mukeep));
+  mlk = MIN(Nlocal-1, MAX(0,mlkeep));
+  pdata->mukeep = muk;
+  pdata->mlkeep = mlk;
+
+  /* Allocate memory for saved Jacobian */
+  pdata->savedJ = BandAllocMat(Nlocal, muk, mlk, muk);
+  if (pdata->savedJ == NULL) { 
+    free(pdata); pdata = NULL; 
+    CVProcessError(cv_mem, 0, "CVBBDPRE", "CVBBDPrecAlloc", MSGBBDP_MEM_FAIL);
+    return(NULL); 
+  }
+
+  /* Allocate memory for preconditioner matrix */
+  storage_mu = MIN(Nlocal-1, muk + mlk);
+  pdata->savedP = NULL;
+  pdata->savedP = BandAllocMat(Nlocal, muk, mlk, storage_mu);
+  if (pdata->savedP == NULL) {
+    BandFreeMat(pdata->savedJ);
+    free(pdata); pdata = NULL;
+    CVProcessError(cv_mem, 0, "CVBBDPRE", "CVBBDPrecAlloc", MSGBBDP_MEM_FAIL);
+    return(NULL);
+  }
+  /* Allocate memory for pivots */
+  pdata->pivots = NULL;
+  pdata->pivots = BandAllocPiv(Nlocal);
+  if (pdata->savedJ == NULL) {
+    BandFreeMat(pdata->savedP);
+    BandFreeMat(pdata->savedJ);
+    free(pdata); pdata = NULL;
+    CVProcessError(cv_mem, 0, "CVBBDPRE", "CVBBDPrecAlloc", MSGBBDP_MEM_FAIL);
+    return(NULL);
+  }
+
+  /* Set pdata->dqrely based on input dqrely (0 implies default). */
+  pdata->dqrely = (dqrely > ZERO) ? dqrely : RSqrt(uround);
+
+  /* Store Nlocal to be used in CVBBDPrecSetup */
+  pdata->n_local = Nlocal;
+
+  /* Set work space sizes and initialize nge */
+  pdata->rpwsize = Nlocal*(muk + 2*mlk + storage_mu + 2);
+  pdata->ipwsize = Nlocal;
+  pdata->nge = 0;
+
+  return((void *)pdata);
+}
+
+int CVBBDSptfqmr(void *cvode_mem, int pretype, int maxl, void *bbd_data)
+{
+  CVodeMem cv_mem;
+  int flag;
+
+  flag = CVSptfqmr(cvode_mem, pretype, maxl);
+  if(flag != CVSPILS_SUCCESS) return(flag);
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (bbd_data == NULL) {
+    CVProcessError(cv_mem, CVBBDPRE_PDATA_NULL, "CVBBDPRE", "CVBBDSptfqmr", MSGBBDP_PDATA_NULL);
+    return(CVBBDPRE_PDATA_NULL);
+  } 
+
+  flag = CVSpilsSetPreconditioner(cvode_mem, CVBBDPrecSetup, CVBBDPrecSolve, bbd_data);
+  if(flag != CVSPILS_SUCCESS) return(flag);
+
+  return(CVSPILS_SUCCESS);
+}
+
+int CVBBDSpbcg(void *cvode_mem, int pretype, int maxl, void *bbd_data)
+{
+  CVodeMem cv_mem;
+  int flag;
+
+  flag = CVSpbcg(cvode_mem, pretype, maxl);
+  if(flag != CVSPILS_SUCCESS) return(flag);
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (bbd_data == NULL) {
+    CVProcessError(cv_mem, CVBBDPRE_PDATA_NULL, "CVBBDPRE", "CVBBDSpbcg", MSGBBDP_PDATA_NULL);
+    return(CVBBDPRE_PDATA_NULL);
+  } 
+
+  flag = CVSpilsSetPreconditioner(cvode_mem, CVBBDPrecSetup, CVBBDPrecSolve, bbd_data);
+  if(flag != CVSPILS_SUCCESS) return(flag);
+
+  return(CVSPILS_SUCCESS);
+}
+
+int CVBBDSpgmr(void *cvode_mem, int pretype, int maxl, void *bbd_data)
+{
+  CVodeMem cv_mem;
+  int flag;
+
+  flag = CVSpgmr(cvode_mem, pretype, maxl);
+  if(flag != CVSPILS_SUCCESS) return(flag);
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (bbd_data == NULL) {
+    CVProcessError(cv_mem, CVBBDPRE_PDATA_NULL, "CVBBDPRE", "CVBBDSpgmr", MSGBBDP_PDATA_NULL);
+    return(CVBBDPRE_PDATA_NULL);
+  } 
+
+  flag = CVSpilsSetPreconditioner(cvode_mem, CVBBDPrecSetup, CVBBDPrecSolve, bbd_data);
+  if(flag != CVSPILS_SUCCESS) return(flag);
+
+  return(CVSPILS_SUCCESS);
+}
+
+int CVBBDPrecReInit(void *bbd_data, 
+                    long int mudq, long int mldq, 
+                    realtype dqrely, 
+                    CVLocalFn gloc, CVCommFn cfn)
+{
+  CVBBDPrecData pdata;
+  CVodeMem cv_mem;
+  long int Nlocal;
+
+  if (bbd_data == NULL) {
+    CVProcessError(NULL, CVBBDPRE_PDATA_NULL, "CVBBDPRE", "CVBBDPrecReInit", MSGBBDP_PDATA_NULL);
+    return(CVBBDPRE_PDATA_NULL);
+  } 
+
+  pdata  = (CVBBDPrecData) bbd_data;
+  cv_mem = (CVodeMem) pdata->cvode_mem;
+
+  /* Set pointers to gloc and cfn; load half-bandwidths */
+  pdata->gloc = gloc;
+  pdata->cfn = cfn;
+  Nlocal = pdata->n_local;
+  pdata->mudq = MIN(Nlocal-1, MAX(0,mudq));
+  pdata->mldq = MIN(Nlocal-1, MAX(0,mldq));
+
+  /* Set pdata->dqrely based on input dqrely (0 implies default). */
+  pdata->dqrely = (dqrely > ZERO) ? dqrely : RSqrt(uround);
+
+  /* Re-initialize nge */
+  pdata->nge = 0;
+
+  return(CVBBDPRE_SUCCESS);
+}
+
+void CVBBDPrecFree(void **bbd_data)
+{
+  CVBBDPrecData pdata;
+  
+  if (*bbd_data == NULL) return;
+
+  pdata = (CVBBDPrecData) (*bbd_data);
+  BandFreeMat(pdata->savedJ);
+  BandFreeMat(pdata->savedP);
+  BandFreePiv(pdata->pivots);
+
+  free(*bbd_data);
+  *bbd_data = NULL;
+
+}
+
+int CVBBDPrecGetWorkSpace(void *bbd_data, long int *lenrwBBDP, long int *leniwBBDP)
+{
+  CVBBDPrecData pdata;
+
+  if (bbd_data == NULL) {
+    CVProcessError(NULL, CVBBDPRE_PDATA_NULL, "CVBBDPRE", "CVBBDPrecGetWorkSpace", MSGBBDP_PDATA_NULL);    
+    return(CVBBDPRE_PDATA_NULL);
+  } 
+
+  pdata = (CVBBDPrecData) bbd_data;
+
+  *lenrwBBDP = pdata->rpwsize;
+  *leniwBBDP = pdata->ipwsize;
+
+  return(CVBBDPRE_SUCCESS);
+}
+
+int CVBBDPrecGetNumGfnEvals(void *bbd_data, long int *ngevalsBBDP)
+{
+  CVBBDPrecData pdata;
+
+  if (bbd_data == NULL) {
+    CVProcessError(NULL, CVBBDPRE_PDATA_NULL, "CVBBDPRE", "CVBBDPrecGetNumGfnEvals", MSGBBDP_PDATA_NULL);
+    return(CVBBDPRE_PDATA_NULL);
+  } 
+
+  pdata = (CVBBDPrecData) bbd_data;
+
+  *ngevalsBBDP = pdata->nge;
+
+  return(CVBBDPRE_SUCCESS);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVBBDPrecGetReturnFlagName
+ * -----------------------------------------------------------------
+ */
+
+char *CVBBDPrecGetReturnFlagName(int flag)
+{
+  char *name;
+
+  name = (char *)malloc(30*sizeof(char));
+
+  switch(flag) {
+  case CVBBDPRE_SUCCESS:
+    sprintf(name,"CVBBDPRE_SUCCESS");
+    break; 
+  case CVBBDPRE_PDATA_NULL:
+    sprintf(name,"CVBBDPRE_PDATA_NULL");
+    break;
+  case CVBBDPRE_FUNC_UNRECVR:
+    sprintf(name,"CVBBDPRE_FUNC_UNRECVR");
+    break;
+  case CVBBDPRE_ADJMEM_NULL:
+    sprintf(name,"CVBBDPRE_ADJMEM_NULL");
+    break;
+  case CVBBDPRE_PDATAB_NULL:
+    sprintf(name,"CVBBDPRE_PDATAB_NULL");
+    break;
+  case CVBBDPRE_MEM_FAIL:
+    sprintf(name,"CVBBDPRE_MEM_FAIL");
+    break;
+  default:
+    sprintf(name,"NONE");
+  }
+
+  return(name);
+}
+
+/* Readability Replacements */
+
+#define Nlocal (pdata->n_local)
+#define mudq   (pdata->mudq)
+#define mldq   (pdata->mldq)
+#define mukeep (pdata->mukeep)
+#define mlkeep (pdata->mlkeep)
+#define dqrely (pdata->dqrely)
+#define gloc   (pdata->gloc)
+#define cfn    (pdata->cfn)
+#define savedJ (pdata->savedJ)
+#define savedP (pdata->savedP)
+#define pivots (pdata->pivots)
+#define nge    (pdata->nge)
+
+/*
+ * -----------------------------------------------------------------
+ * Function : CVBBDPrecSetup                                      
+ * -----------------------------------------------------------------
+ * CVBBDPrecSetup generates and factors a banded block of the
+ * preconditioner matrix on each processor, via calls to the
+ * user-supplied gloc and cfn functions. It uses difference
+ * quotient approximations to the Jacobian elements.
+ *
+ * CVBBDPrecSetup calculates a new J,if necessary, then calculates
+ * P = I - gamma*J, and does an LU factorization of P.
+ *
+ * The parameters of CVBBDPrecSetup used here are as follows:
+ *
+ * t       is the current value of the independent variable.
+ *
+ * y       is the current value of the dependent variable vector,
+ *         namely the predicted value of y(t).
+ *
+ * fy      is the vector f(t,y).
+ *
+ * jok     is an input flag indicating whether Jacobian-related
+ *         data needs to be recomputed, as follows:
+ *           jok == FALSE means recompute Jacobian-related data
+ *                  from scratch.
+ *           jok == TRUE  means that Jacobian data from the
+ *                  previous CVBBDPrecon call can be reused
+ *                  (with the current value of gamma).
+ *         A CVBBDPrecon call with jok == TRUE should only occur
+ *         after a call with jok == FALSE.
+ *
+ * jcurPtr is a pointer to an output integer flag which is
+ *         set by CVBBDPrecon as follows:
+ *           *jcurPtr = TRUE if Jacobian data was recomputed.
+ *           *jcurPtr = FALSE if Jacobian data was not recomputed,
+ *                      but saved data was reused.
+ *
+ * gamma   is the scalar appearing in the Newton matrix.
+ *
+ * bbd_data  is a pointer to user data - the same as the P_data
+ *           parameter passed to CVSp*. For CVBBDPrecon,
+ *           this should be of type CVBBDData.
+ *
+ * tmp1, tmp2, and tmp3 are pointers to memory allocated
+ *           for NVectors which are be used by CVBBDPrecSetup
+ *           as temporary storage or work space.
+ *
+ * Return value:
+ * The value returned by this CVBBDPrecSetup function is the int
+ *   0  if successful,
+ *   1  for a recoverable error (step will be retried).
+ * -----------------------------------------------------------------
+ */
+
+static int CVBBDPrecSetup(realtype t, N_Vector y, N_Vector fy, 
+                          booleantype jok, booleantype *jcurPtr, 
+                          realtype gamma, void *bbd_data, 
+                          N_Vector tmp1, N_Vector tmp2, N_Vector tmp3)
+{
+  long int ier;
+  CVBBDPrecData pdata;
+  CVodeMem cv_mem;
+  int retval;
+
+  pdata = (CVBBDPrecData) bbd_data;
+
+  cv_mem = (CVodeMem) pdata->cvode_mem;
+
+  if (jok) {
+
+    /* If jok = TRUE, use saved copy of J */
+    *jcurPtr = FALSE;
+    BandCopy(savedJ, savedP, mukeep, mlkeep);
+
+  } else {
+
+    /* Otherwise call CVBBDDQJac for new J value */
+    *jcurPtr = TRUE;
+    BandZero(savedJ);
+
+    retval = CVBBDDQJac(pdata, t, y, tmp1, tmp2, tmp3);
+    if (retval < 0) {
+      CVProcessError(cv_mem, CVBBDPRE_FUNC_UNRECVR, "CVBBDPRE", "CVBBDPrecSetup", MSGBBDP_FUNC_FAILED);
+      return(-1);
+    }
+    if (retval > 0) {
+      return(1);
+    }
+
+    BandCopy(savedJ, savedP, mukeep, mlkeep);
+
+  }
+  
+  /* Scale and add I to get P = I - gamma*J */
+  BandScale(-gamma, savedP);
+  BandAddI(savedP);
+ 
+  /* Do LU factorization of P in place */
+  ier = BandGBTRF(savedP, pivots);
+ 
+  /* Return 0 if the LU was complete; otherwise return 1 */
+  if (ier > 0) return(1);
+  return(0);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * Function : CVBBDPrecSolve
+ * -----------------------------------------------------------------
+ * CVBBDPrecSolve solves a linear system P z = r, with the
+ * band-block-diagonal preconditioner matrix P generated and
+ * factored by CVBBDPrecSetup.
+ *
+ * The parameters of CVBBDPrecSolve used here are as follows:
+ *
+ * r      is the right-hand side vector of the linear system.
+ *
+ * bbd_data is a pointer to the preconditioner data returned by
+ *          CVBBDPrecAlloc.
+ *
+ * z      is the output vector computed by CVBBDPrecSolve.
+ *
+ * The value returned by the CVBBDPrecSolve function is always 0,
+ * indicating success.
+ * -----------------------------------------------------------------
+ */
+
+static int CVBBDPrecSolve(realtype t, N_Vector y, N_Vector fy, 
+                          N_Vector r, N_Vector z, 
+                          realtype gamma, realtype delta,
+                          int lr, void *bbd_data, N_Vector tmp)
+{
+  CVBBDPrecData pdata;
+  realtype *zd;
+
+  pdata = (CVBBDPrecData) bbd_data;
+
+  /* Copy r to z, then do backsolve and return */
+  N_VScale(ONE, r, z);
+  
+  zd = N_VGetArrayPointer(z);
+
+  BandGBTRS(savedP, pivots, zd);
+
+  return(0);
+}
+
+#define ewt    (cv_mem->cv_ewt)
+#define h      (cv_mem->cv_h)
+#define f_data (cv_mem->cv_f_data)
+
+/*
+ * -----------------------------------------------------------------
+ * Function : CVBBDDQJac
+ * -----------------------------------------------------------------
+ * This routine generates a banded difference quotient approximation
+ * to the local block of the Jacobian of g(t,y). It assumes that a
+ * band matrix of type BandMat is stored columnwise, and that elements
+ * within each column are contiguous. All matrix elements are generated
+ * as difference quotients, by way of calls to the user routine gloc.
+ * By virtue of the band structure, the number of these calls is
+ * bandwidth + 1, where bandwidth = mldq + mudq + 1.
+ * But the band matrix kept has bandwidth = mlkeep + mukeep + 1.
+ * This routine also assumes that the local elements of a vector are
+ * stored contiguously.
+ * -----------------------------------------------------------------
+ */
+
+static int CVBBDDQJac(CVBBDPrecData pdata, realtype t, 
+                      N_Vector y, N_Vector gy, 
+                      N_Vector ytemp, N_Vector gtemp)
+{
+  CVodeMem cv_mem;
+  realtype gnorm, minInc, inc, inc_inv;
+  long int group, i, j, width, ngroups, i1, i2;
+  realtype *y_data, *ewt_data, *gy_data, *gtemp_data, *ytemp_data, *col_j;
+  int retval;
+
+  cv_mem = (CVodeMem) pdata->cvode_mem;
+
+  /* Load ytemp with y = predicted solution vector */
+  N_VScale(ONE, y, ytemp);
+
+  /* Call cfn and gloc to get base value of g(t,y) */
+  if (cfn != NULL) {
+    retval = cfn(Nlocal, t, y, f_data);
+    if (retval != 0) return(retval);
+  }
+
+  retval = gloc(Nlocal, t, ytemp, gy, f_data);
+  nge++;
+  if (retval != 0) return(retval);
+
+  /* Obtain pointers to the data for various vectors */
+  y_data     =  N_VGetArrayPointer(y);
+  gy_data    =  N_VGetArrayPointer(gy);
+  ewt_data   =  N_VGetArrayPointer(ewt);
+  ytemp_data =  N_VGetArrayPointer(ytemp);
+  gtemp_data =  N_VGetArrayPointer(gtemp);
+
+  /* Set minimum increment based on uround and norm of g */
+  gnorm = N_VWrmsNorm(gy, ewt);
+  minInc = (gnorm != ZERO) ?
+           (MIN_INC_MULT * ABS(h) * uround * Nlocal * gnorm) : ONE;
+
+  /* Set bandwidth and number of column groups for band differencing */
+  width = mldq + mudq + 1;
+  ngroups = MIN(width, Nlocal);
+
+  /* Loop over groups */  
+  for (group=1; group <= ngroups; group++) {
+    
+    /* Increment all y_j in group */
+    for(j=group-1; j < Nlocal; j+=width) {
+      inc = MAX(dqrely*ABS(y_data[j]), minInc/ewt_data[j]);
+      ytemp_data[j] += inc;
+    }
+
+    /* Evaluate g with incremented y */
+    retval = gloc(Nlocal, t, ytemp, gtemp, f_data);
+    nge++;
+    if (retval != 0) return(retval);
+
+    /* Restore ytemp, then form and load difference quotients */
+    for (j=group-1; j < Nlocal; j+=width) {
+      ytemp_data[j] = y_data[j];
+      col_j = BAND_COL(savedJ,j);
+      inc = MAX(dqrely*ABS(y_data[j]), minInc/ewt_data[j]);
+      inc_inv = ONE/inc;
+      i1 = MAX(0, j-mukeep);
+      i2 = MIN(j+mlkeep, Nlocal-1);
+      for (i=i1; i <= i2; i++)
+        BAND_COL_ELEM(col_j,i,j) =
+          inc_inv * (gtemp_data[i] - gy_data[i]);
+    }
+  }
+
+  return(0);
+}
+
+
+/* 
+ * ================================================================
+ *
+ *                   PART II - backward problems
+ *
+ * ================================================================
+ */
+
+
+/* Additional readability replacements */
+
+#define ytmp        (ca_mem->ca_ytmp)
+#define f_data_B    (ca_mem->ca_f_dataB)
+#define getY        (ca_mem->ca_getY)
+#define pmemB       (ca_mem->ca_pmemB)
+
+#define bbd_data_B  (cvbbdB_mem->bbd_dataB)
+#define gloc_B      (cvbbdB_mem->glocB)
+#define cfn_B       (cvbbdB_mem->cfnB)
+
+
+/*
+ * CVBBDPrecAllocB, CVBPSp*B
+ *
+ * Wrappers for the backward phase around the corresponding 
+ * CVODES functions
+ */
+
+int CVBBDPrecAllocB(void *cvadj_mem, long int NlocalB, 
+                    long int mudqB, long int mldqB, 
+                    long int mukeepB, long int mlkeepB, 
+                    realtype dqrelyB,
+                    CVLocalFnB glocB, CVCommFnB cfnB)
+{
+  CVadjMem ca_mem;
+  CVBBDPrecDataB cvbbdB_mem;
+  CVodeMem cvB_mem;
+  void *bbd_dataB;
+
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CVBBDPRE_ADJMEM_NULL, "CVBBDPRE", "CVBBDPrecAllocB", MSGBBDP_CAMEM_NULL);
+    return(CVBBDPRE_ADJMEM_NULL);
+  }
+  ca_mem = (CVadjMem) cvadj_mem;
+
+  cvB_mem = ca_mem->cvb_mem;
+
+  /* Get memory for CVBBDPrecDataB */
+  cvbbdB_mem = NULL;
+  cvbbdB_mem = (CVBBDPrecDataB) malloc(sizeof(* cvbbdB_mem));
+  if (cvbbdB_mem == NULL) {
+    CVProcessError(cvB_mem, CVBBDPRE_MEM_FAIL, "CVBBDPRE", "CVBBDPrecAllocB", MSGBBDP_MEM_FAIL);
+    return(CVBBDPRE_MEM_FAIL);
+  }
+
+  gloc_B = glocB;
+  cfn_B  = cfnB;
+
+  bbd_dataB = CVBBDPrecAlloc(cvB_mem, NlocalB, 
+                             mudqB, mldqB,
+                             mukeepB, mlkeepB, 
+                             dqrelyB, 
+                             CVAgloc, CVAcfn);
+  if (bbd_dataB == NULL) {
+    free(cvbbdB_mem); cvbbdB_mem = NULL;
+
+    return(CVBBDPRE_MEM_FAIL);
+  }
+
+  bbd_data_B = bbd_dataB;
+
+  /* attach pmemB */
+  pmemB = cvbbdB_mem;
+
+  return(CVBBDPRE_SUCCESS);
+
+}
+
+int CVBBDSptfqmrB(void *cvadj_mem, int pretypeB, int maxlB)
+{
+
+  CVadjMem ca_mem;
+  CVBBDPrecDataB cvbbdB_mem;
+  CVodeMem cvB_mem;
+  int flag;
+  
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CVBBDPRE_ADJMEM_NULL, "CVBBDPRE", "CVBBDSptfqmrB", MSGBBDP_CAMEM_NULL);
+    return(CVBBDPRE_ADJMEM_NULL);
+  }
+  ca_mem = (CVadjMem) cvadj_mem;
+  
+  cvB_mem = ca_mem->cvb_mem;
+  
+  if (pmemB == NULL) {
+    CVProcessError(cvB_mem, CVBBDPRE_PDATAB_NULL, "CVBBDPRE", "CVBBDSptfqmrB", MSGBBDP_PDATAB_NULL);
+    return(CVBBDPRE_PDATAB_NULL);
+  }
+  cvbbdB_mem = (CVBBDPrecDataB) pmemB;
+
+  flag = CVBBDSptfqmr(cvB_mem, pretypeB, maxlB, bbd_data_B);
+
+  return(flag);
+
+}
+
+int CVBBDSpbcgB(void *cvadj_mem, int pretypeB, int maxlB)
+{
+
+  CVadjMem ca_mem;
+  CVBBDPrecDataB cvbbdB_mem;
+  CVodeMem cvB_mem;
+  int flag;
+  
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CVBBDPRE_ADJMEM_NULL, "CVBBDPRE", "CVBBDSpbcgB", MSGBBDP_CAMEM_NULL);
+    return(CVBBDPRE_ADJMEM_NULL);
+  }
+  ca_mem = (CVadjMem) cvadj_mem;
+  
+  cvB_mem = ca_mem->cvb_mem;
+  
+  if (pmemB == NULL) {
+    CVProcessError(cvB_mem, CVBBDPRE_PDATAB_NULL, "CVBBDPRE", "CVBBDSpbcgB", MSGBBDP_PDATAB_NULL);
+    return(CVBBDPRE_PDATAB_NULL);
+  }
+  cvbbdB_mem = (CVBBDPrecDataB) pmemB;
+
+  flag = CVBBDSpbcg(cvB_mem, pretypeB, maxlB, bbd_data_B);
+
+  return(flag);
+
+}
+
+int CVBBDSpgmrB(void *cvadj_mem, int pretypeB, int maxlB)
+{
+
+  CVadjMem ca_mem;
+  CVBBDPrecDataB cvbbdB_mem;
+  CVodeMem cvB_mem;
+  int flag;
+  
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CVBBDPRE_ADJMEM_NULL, "CVBBDPRE", "CVBBDSpgmrB", MSGBBDP_CAMEM_NULL);
+    return(CV_ADJMEM_NULL);
+  }
+  ca_mem = (CVadjMem) cvadj_mem;
+  
+  cvB_mem = ca_mem->cvb_mem;
+  
+  if (pmemB == NULL) {
+    CVProcessError(cvB_mem, CVBBDPRE_PDATAB_NULL, "CVBBDPRE", "CVBBDSpgmrB", MSGBBDP_PDATAB_NULL);
+    return(CVBBDPRE_PDATAB_NULL);
+  }
+  cvbbdB_mem = (CVBBDPrecDataB) pmemB;
+
+  flag = CVBBDSpgmr(cvB_mem, pretypeB, maxlB, bbd_data_B);
+
+  return(flag);
+
+}
+
+int CVBBDPrecReInitB(void *cvadj_mem, long int mudqB, long int mldqB,
+                     realtype dqrelyB, CVLocalFnB glocB, CVCommFnB cfnB)
+{
+  CVadjMem ca_mem;
+  CVodeMem cvB_mem;
+  CVBBDPrecDataB cvbbdB_mem;
+  int flag;
+
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CVBBDPRE_ADJMEM_NULL, "CVBBDPRE", "CVBBDPrecReInitB", MSGBBDP_CAMEM_NULL);
+    return(CVBBDPRE_ADJMEM_NULL);
+  }
+  ca_mem = (CVadjMem) cvadj_mem;
+  
+  cvB_mem = ca_mem->cvb_mem;
+
+  if (pmemB == NULL) {
+    CVProcessError(cvB_mem, CVBBDPRE_PDATAB_NULL, "CVBBDPRE", "CVBBDPrecReInitB", MSGBBDP_PDATAB_NULL);
+    return(CVBBDPRE_PDATAB_NULL);
+  }
+  cvbbdB_mem = (CVBBDPrecDataB) pmemB;
+
+  gloc_B = glocB;
+  cfn_B  = cfnB;
+
+  flag = CVBBDPrecReInit(bbd_data_B, mudqB, mldqB,
+                         dqrelyB, CVAgloc, CVAcfn);
+
+  return(flag);
+}
+
+
+void CVBBDPrecFreeB(void *cvadj_mem)
+{
+  CVadjMem ca_mem;
+  CVBBDPrecDataB cvbbdB_mem;
+
+  if (cvadj_mem == NULL) return;
+  ca_mem = (CVadjMem) cvadj_mem;
+  
+  if (pmemB == NULL) return;
+  cvbbdB_mem = (CVBBDPrecDataB) pmemB;
+
+  CVBBDPrecFree(&bbd_data_B);
+  
+  free(pmemB); pmemB = NULL;
+}
+
+
+/*
+ * CVAgloc
+ *
+ * This routine interfaces to the CVLocalFnB routine 
+ * provided by the user.
+ * NOTE: f_data actually contains cvadj_mem
+ */
+
+static int CVAgloc(long int NlocalB, realtype t, N_Vector yB, N_Vector gB, 
+                   void *cvadj_mem)
+{
+  CVadjMem ca_mem;
+  CVodeMem cvB_mem;
+  CVBBDPrecDataB cvbbdB_mem;
+  int retval, flag;
+
+  ca_mem = (CVadjMem) cvadj_mem;
+  cvB_mem = ca_mem->cvb_mem;
+  cvbbdB_mem = (CVBBDPrecDataB) pmemB;
+
+  /* Forward solution from interpolation */
+  flag = getY(ca_mem, t, ytmp);
+  if (flag != CV_SUCCESS) {
+    CVProcessError(cvB_mem, -1, "CVBBDPRE", "CVAgloc", MSGBBDP_BAD_T);
+    return(-1);
+  } 
+
+  /* Call user's adjoint glocB routine */
+  retval = gloc_B(NlocalB, t, ytmp, yB, gB, f_data_B);
+
+  return(retval);
+}
+
+/*
+ * CVAcfn
+ *
+ * This routine interfaces to the CVCommFnB routine 
+ * provided by the user.
+ * NOTE: f_data actually contains cvadj_mem
+ */
+
+static int CVAcfn(long int NlocalB, realtype t, N_Vector yB,
+                  void *cvadj_mem)
+{
+  CVadjMem ca_mem;
+  CVodeMem cvB_mem;
+  CVBBDPrecDataB cvbbdB_mem;
+  int retval, flag;
+
+  ca_mem = (CVadjMem) cvadj_mem;
+  cvB_mem = ca_mem->cvb_mem;
+  cvbbdB_mem = (CVBBDPrecDataB) pmemB;
+
+  if (cfn_B == NULL) return(0);
+
+  /* Forward solution from interpolation */
+  flag = getY(ca_mem, t, ytmp);
+  if (flag != CV_SUCCESS) {
+    CVProcessError(cvB_mem, -1, "CVBBDPRE", "CVAcfn", MSGBBDP_BAD_T);
+    return(-1);
+  } 
+
+  /* Call user's adjoint cfnB routine */
+  retval = cfn_B(NlocalB, t, ytmp, yB, f_data_B);
+
+  return(retval);
+}
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_bbdpre_impl.h b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_bbdpre_impl.h
new file mode 100644
index 0000000000000000000000000000000000000000..028cd29da0fa3ea178d1e516042354c0e9207e07
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_bbdpre_impl.h	
@@ -0,0 +1,103 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * ----------------------------------------------------------------- 
+ * Programmer(s): Radu Serban @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2005, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * Implementation header file for the CVBBDPRE module.
+ * -----------------------------------------------------------------
+ */
+
+#ifndef _CVSBBDPRE_IMPL_H
+#define _CVSBBDPRE_IMPL_H
+
+#ifdef __cplusplus  /* wrapper to enable C++ usage */
+extern "C" {
+#endif
+
+#include <cvodes/cvodes_bbdpre.h>
+#include <sundials/sundials_band.h>
+
+  /*
+   * -----------------------------------------------------------------
+   * Type: CVBBDPrecData
+   * -----------------------------------------------------------------
+   */
+
+  typedef struct {
+
+    /* passed by user to CVBBDPrecAlloc and used by PrecSetup/PrecSolve */
+
+    long int mudq, mldq, mukeep, mlkeep;
+    realtype dqrely;
+    CVLocalFn gloc;
+    CVCommFn cfn;
+
+    /* set by CVBBDPrecSetup and used by CVBBDPrecSolve */
+
+    BandMat savedJ;
+    BandMat savedP;
+    long int *pivots;
+
+    /* set by CVBBDPrecAlloc and used by CVBBDPrecSetup */
+
+    long int n_local;
+
+    /* available for optional output */
+
+    long int rpwsize;
+    long int ipwsize;
+    long int nge;
+
+    /* pointer to cvode_mem */
+
+    void *cvode_mem;
+
+  } *CVBBDPrecData;
+
+
+  /*
+   * -----------------------------------------------------------------
+   * Type: CVBBDPrecDataB
+   * -----------------------------------------------------------------
+   */
+
+  typedef struct {
+
+    /* BBD user functions (glocB and cfnB) for backward run */
+    CVLocalFnB glocB;
+    CVCommFnB  cfnB;
+    
+    /* BBD prec data */
+    void *bbd_dataB;
+
+  } *CVBBDPrecDataB;
+
+  /*
+   * -----------------------------------------------------------------
+   * CVBBDPRE error messages
+   * -----------------------------------------------------------------
+   */
+
+#define MSGBBDP_CVMEM_NULL  "Integrator memory is NULL."
+#define MSGBBDP_MEM_FAIL    "A memory request failed."
+#define MSGBBDP_BAD_NVECTOR "A required vector operation is not implemented."
+#define MSGBBDP_PDATA_NULL  "CVBBDPRE memory is NULL."
+#define MSGBBDP_FUNC_FAILED "The gloc or cfn routine failed in an unrecoverable manner."
+
+#define MSGBBDP_CAMEM_NULL  "cvadj_mem = NULL illegal."
+#define MSGBBDP_PDATAB_NULL "CVBBDPRE memory is NULL for the backward integration."
+#define MSGBBDP_BAD_T       "Bad t for interpolation."
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_dense.c b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_dense.c
new file mode 100644
index 0000000000000000000000000000000000000000..98ff34aca0be8a67d7c6614b313985a721bc1de8
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_dense.c	
@@ -0,0 +1,778 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * ----------------------------------------------------------------- 
+ * Programmer(s): Radu Serban @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2005, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This is the implementation file for the CVDENSE linear solver.
+ * -----------------------------------------------------------------
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "cvodes_dense_impl.h"
+#include "cvodes_impl.h"
+
+#include <sundials/sundials_math.h>
+
+/* Other Constants */
+
+#define MIN_INC_MULT RCONST(1000.0)
+#define ZERO         RCONST(0.0)
+#define ONE          RCONST(1.0)
+#define TWO          RCONST(2.0)
+
+/* CVDENSE linit, lsetup, lsolve, and lfree routines */
+ 
+static int CVDenseInit(CVodeMem cv_mem);
+
+static int CVDenseSetup(CVodeMem cv_mem, int convfail, N_Vector ypred,
+                        N_Vector fpred, booleantype *jcurPtr, 
+                        N_Vector vtemp1, N_Vector vtemp2, N_Vector vtemp3);
+
+static int CVDenseSolve(CVodeMem cv_mem, N_Vector b, N_Vector weight,
+                        N_Vector ycur, N_Vector fcur);
+
+static void CVDenseFree(CVodeMem cv_mem);
+
+/* CVDENSE lfreeB function */
+
+static void CVDenseFreeB(CVadjMem ca_mem);
+
+/* Wrapper function for adjoint code */
+
+static int CVAdenseJac(long int nB, DenseMat JB, realtype t, 
+                       N_Vector yB, N_Vector fyB, void *cvadj_mem,
+                       N_Vector tmp1B, N_Vector tmp2B, N_Vector tmp3B);
+
+
+/* CVDENSE DQJac routine */
+
+static int CVDenseDQJac(long int n, DenseMat J, realtype t, 
+                        N_Vector y, N_Vector fy, void *jac_data,
+                        N_Vector tmp1, N_Vector tmp2, N_Vector tmp3);
+
+
+/* 
+ * ================================================================
+ *
+ *                   PART I - forward problems
+ *
+ * ================================================================
+ */
+
+
+/* Readability Replacements */
+
+#define lmm       (cv_mem->cv_lmm)
+#define f         (cv_mem->cv_f)
+#define f_data    (cv_mem->cv_f_data)
+#define uround    (cv_mem->cv_uround)
+#define nst       (cv_mem->cv_nst)
+#define tn        (cv_mem->cv_tn)
+#define h         (cv_mem->cv_h)
+#define gamma     (cv_mem->cv_gamma)
+#define gammap    (cv_mem->cv_gammap)
+#define gamrat    (cv_mem->cv_gamrat)
+#define ewt       (cv_mem->cv_ewt)
+#define linit     (cv_mem->cv_linit)
+#define lsetup    (cv_mem->cv_lsetup)
+#define lsolve    (cv_mem->cv_lsolve)
+#define lfree     (cv_mem->cv_lfree)
+#define lmem      (cv_mem->cv_lmem)
+#define vec_tmpl     (cv_mem->cv_tempv)
+#define setupNonNull (cv_mem->cv_setupNonNull)
+
+#define n         (cvdense_mem->d_n)
+#define jac       (cvdense_mem->d_jac)
+#define M         (cvdense_mem->d_M)
+#define pivots    (cvdense_mem->d_pivots)
+#define savedJ    (cvdense_mem->d_savedJ)
+#define nstlj     (cvdense_mem->d_nstlj)
+#define nje       (cvdense_mem->d_nje)
+#define nfeD      (cvdense_mem->d_nfeD)
+#define J_data    (cvdense_mem->d_J_data)
+#define last_flag (cvdense_mem->d_last_flag)
+
+/*
+ * -----------------------------------------------------------------
+ * CVDense
+ * -----------------------------------------------------------------
+ * This routine initializes the memory record and sets various function
+ * fields specific to the dense linear solver module.  CVDense first
+ * calls the existing lfree routine if this is not NULL.  Then it sets
+ * the cv_linit, cv_lsetup, cv_lsolve, cv_lfree fields in (*cvode_mem)
+ * to be CVDenseInit, CVDenseSetup, CVDenseSolve, and CVDenseFree,
+ * respectively.  It allocates memory for a structure of type
+ * CVDenseMemRec and sets the cv_lmem field in (*cvode_mem) to the
+ * address of this structure.  It sets setupNonNull in (*cvode_mem) to
+ * TRUE, and the d_jac field to the default CVDenseDQJac.
+ * Finally, it allocates memory for M, savedJ, and pivots.
+ * The return value is SUCCESS = 0, or LMEM_FAIL = -1.
+ *
+ * NOTE: The dense linear solver assumes a serial implementation
+ *       of the NVECTOR package. Therefore, CVDense will first 
+ *       test for compatible a compatible N_Vector internal
+ *       representation by checking that N_VGetArrayPointer and
+ *       N_VSetArrayPointer exist.
+ * -----------------------------------------------------------------
+ */
+
+int CVDense(void *cvode_mem, long int N)
+{
+  CVodeMem cv_mem;
+  CVDenseMem cvdense_mem;
+
+  /* Return immediately if cvode_mem is NULL */
+  if (cvode_mem == NULL) {
+    CVProcessError(NULL, CVDENSE_MEM_NULL, "CVDENSE", "CVDense", MSGDS_CVMEM_NULL);
+    return(CVDENSE_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;
+
+  /* Test if the NVECTOR package is compatible with the DENSE solver */
+  if (vec_tmpl->ops->nvgetarraypointer == NULL ||
+      vec_tmpl->ops->nvsetarraypointer == NULL) {
+    CVProcessError(cv_mem, CVDENSE_ILL_INPUT, "CVDENSE", "CVDense", MSGDS_BAD_NVECTOR);
+    return(CVDENSE_ILL_INPUT);
+  }
+
+  if (lfree !=NULL) lfree(cv_mem);
+
+  /* Set four main function fields in cv_mem */
+  linit  = CVDenseInit;
+  lsetup = CVDenseSetup;
+  lsolve = CVDenseSolve;
+  lfree  = CVDenseFree;
+
+  /* Get memory for CVDenseMemRec */
+  cvdense_mem = NULL;
+  cvdense_mem = (CVDenseMem) malloc(sizeof(CVDenseMemRec));
+  if (cvdense_mem == NULL) {
+    CVProcessError(cv_mem, CVDENSE_MEM_FAIL, "CVDENSE", "CVDense", MSGDS_MEM_FAIL);
+    return(CVDENSE_MEM_FAIL);
+  }
+
+  /* Set default Jacobian routine and Jacobian data */
+  jac = CVDenseDQJac;
+  J_data = cvode_mem;
+  last_flag = CVDENSE_SUCCESS;
+
+  setupNonNull = TRUE;
+
+  /* Set problem dimension */
+  n = N;
+
+  /* Allocate memory for M, savedJ, and pivot array */
+
+  M = NULL;
+  M = DenseAllocMat(N, N);
+  if (M == NULL) {
+    CVProcessError(cv_mem, CVDENSE_MEM_FAIL, "CVDENSE", "CVDense", MSGDS_MEM_FAIL);
+    free(cvdense_mem); cvdense_mem = NULL;
+    return(CVDENSE_MEM_FAIL);
+  }
+  savedJ = NULL;
+  savedJ = DenseAllocMat(N, N);
+  if (savedJ == NULL) {
+    CVProcessError(cv_mem, CVDENSE_MEM_FAIL, "CVDENSE", "CVDense", MSGDS_MEM_FAIL);
+    DenseFreeMat(M);
+    free(cvdense_mem); cvdense_mem = NULL;
+    return(CVDENSE_MEM_FAIL);
+  }
+  pivots = NULL;
+  pivots = DenseAllocPiv(N);
+  if (pivots == NULL) {
+    CVProcessError(cv_mem, CVDENSE_MEM_FAIL, "CVDENSE", "CVDense", MSGDS_MEM_FAIL);
+    DenseFreeMat(M);
+    DenseFreeMat(savedJ);
+    free(cvdense_mem); cvdense_mem = NULL;
+    return(CVDENSE_MEM_FAIL);
+  }
+
+  /* Attach linear solver memory to integrator memory */
+  lmem = cvdense_mem;
+
+  return(CVDENSE_SUCCESS);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVDenseSetJacFn
+ * -----------------------------------------------------------------
+ */
+
+int CVDenseSetJacFn(void *cvode_mem, CVDenseJacFn djac, void *jac_data)
+{
+  CVodeMem cv_mem;
+  CVDenseMem cvdense_mem;
+
+  /* Return immediately if cvode_mem is NULL */
+  if (cvode_mem == NULL) {
+    CVProcessError(NULL, CVDENSE_MEM_NULL, "CVDENSE", "CVDenseSetJacFn", MSGDS_CVMEM_NULL);
+    return(CVDENSE_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (lmem == NULL) {
+    CVProcessError(cv_mem, CVDENSE_LMEM_NULL, "CVDENSE", "CVDenseSetJacFn", MSGDS_LMEM_NULL);
+    return(CVDENSE_LMEM_NULL);
+  }
+  cvdense_mem = (CVDenseMem) lmem;
+
+  jac = djac;
+  if (djac != NULL) J_data = jac_data;
+
+  return(CVDENSE_SUCCESS);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVDenseGetWorkSpace
+ * -----------------------------------------------------------------
+ */
+
+int CVDenseGetWorkSpace(void *cvode_mem, long int *lenrwLS, long int *leniwLS)
+{
+  CVodeMem cv_mem;
+  CVDenseMem cvdense_mem;
+
+  /* Return immediately if cvode_mem is NULL */
+  if (cvode_mem == NULL) {
+    CVProcessError(NULL, CVDENSE_MEM_NULL, "CVDENSE", "CVDenseGetWorkSpace", MSGDS_CVMEM_NULL);
+    return(CVDENSE_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (lmem == NULL) {
+    CVProcessError(cv_mem, CVDENSE_LMEM_NULL, "CVDENSE", "CVDenseGetWorkSpace", MSGDS_LMEM_NULL);
+    return(CVDENSE_LMEM_NULL);
+  }
+  cvdense_mem = (CVDenseMem) lmem;
+
+  *lenrwLS = 2*n*n;
+  *leniwLS = n;
+
+  return(CVDENSE_SUCCESS);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVDenseGetNumJacEvals
+ * -----------------------------------------------------------------
+ */
+
+int CVDenseGetNumJacEvals(void *cvode_mem, long int *njevals)
+{
+  CVodeMem cv_mem;
+  CVDenseMem cvdense_mem;
+
+  /* Return immediately if cvode_mem is NULL */
+  if (cvode_mem == NULL) {
+    CVProcessError(NULL, CVDENSE_MEM_NULL, "CVDENSE", "CVDenseGetNumJacEvals", MSGDS_CVMEM_NULL);
+    return(CVDENSE_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (lmem == NULL) {
+    CVProcessError(cv_mem, CVDENSE_LMEM_NULL, "CVDENSE", "CVDenseGetNumJacEvals", MSGDS_LMEM_NULL);
+    return(CVDENSE_LMEM_NULL);
+  }
+  cvdense_mem = (CVDenseMem) lmem;
+
+  *njevals = nje;
+
+  return(CVDENSE_SUCCESS);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVDenseGetNumRhsEvals
+ * -----------------------------------------------------------------
+ */
+
+int CVDenseGetNumRhsEvals(void *cvode_mem, long int *nfevalsLS)
+{
+  CVodeMem cv_mem;
+  CVDenseMem cvdense_mem;
+
+  /* Return immediately if cvode_mem is NULL */
+  if (cvode_mem == NULL) {
+    CVProcessError(NULL, CVDENSE_MEM_NULL, "CVDENSE", "CVDenseGetNumRhsEvals", MSGDS_CVMEM_NULL);
+    return(CVDENSE_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (lmem == NULL) {
+    CVProcessError(cv_mem, CVDENSE_LMEM_NULL, "CVDENSE", "CVDenseGetNumRhsEvals", MSGDS_LMEM_NULL);
+    return(CVDENSE_LMEM_NULL);
+  }
+  cvdense_mem = (CVDenseMem) lmem;
+
+  *nfevalsLS = nfeD;
+
+  return(CVDENSE_SUCCESS);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVDenseGetLastFlag
+ * -----------------------------------------------------------------
+ */
+
+int CVDenseGetLastFlag(void *cvode_mem, int *flag)
+{
+  CVodeMem cv_mem;
+  CVDenseMem cvdense_mem;
+
+  /* Return immediately if cvode_mem is NULL */
+  if (cvode_mem == NULL) {
+    CVProcessError(NULL, CVDENSE_MEM_NULL, "CVDENSE", "CVDenseGetLastFlag", MSGDS_CVMEM_NULL);
+    return(CVDENSE_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (lmem == NULL) {
+    CVProcessError(cv_mem, CVDENSE_LMEM_NULL, "CVDENSE", "CVDenseGetLastFlag", MSGDS_LMEM_NULL);
+    return(CVDENSE_LMEM_NULL);
+  }
+  cvdense_mem = (CVDenseMem) lmem;
+
+  *flag = last_flag;
+
+  return(CVDENSE_SUCCESS);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVDenseGetReturnFlagName
+ * -----------------------------------------------------------------
+ */
+
+char *CVDenseGetReturnFlagName(int flag)
+{
+  char *name;
+
+  name = (char *)malloc(30*sizeof(char));
+
+  switch(flag) {
+  case CVDENSE_SUCCESS:
+    sprintf(name,"CVDENSE_SUCCESS");
+    break; 
+  case CVDENSE_MEM_NULL:
+    sprintf(name,"CVDENSE_MEM_NULL");
+    break;
+  case CVDENSE_LMEM_NULL:
+    sprintf(name,"CVDENSE_LMEM_NULL");
+    break;
+  case CVDENSE_ILL_INPUT:
+    sprintf(name,"CVDENSE_ILL_INPUT");
+    break;
+  case CVDENSE_MEM_FAIL:
+    sprintf(name,"CVDENSE_MEM_FAIL");
+    break;
+  case CVDENSE_JACFUNC_UNRECVR:
+    sprintf(name,"CVDENSE_JACFUNC_UNRECVR");
+    break;
+  case CVDENSE_JACFUNC_RECVR:
+    sprintf(name,"CVDENSE_JACFUNC_RECVR");
+    break;
+  case CVDENSE_ADJMEM_NULL:
+    sprintf(name,"CVDENSE_ADJMEM_NULL");
+    break;
+  case CVDENSE_LMEMB_NULL:
+    sprintf(name,"CVDENSE_LMEMB_NULL");
+    break;
+  default:
+    sprintf(name,"NONE");
+  }
+
+  return(name);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVDenseInit
+ * -----------------------------------------------------------------
+ * This routine does remaining initializations specific to the dense
+ * linear solver.
+ * -----------------------------------------------------------------
+ */
+
+static int CVDenseInit(CVodeMem cv_mem)
+{
+  CVDenseMem cvdense_mem;
+
+  cvdense_mem = (CVDenseMem) lmem;
+  
+  nje   = 0;
+  nfeD  = 0;
+  nstlj = 0;
+  
+  if (jac == NULL) {
+    jac = CVDenseDQJac;
+    J_data = cv_mem;
+  }
+
+  last_flag = CVDENSE_SUCCESS;
+  return(0);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVDenseSetup
+ * -----------------------------------------------------------------
+ * This routine does the setup operations for the dense linear solver.
+ * It makes a decision whether or not to call the Jacobian evaluation
+ * routine based on various state variables, and if not it uses the 
+ * saved copy.  In any case, it constructs the Newton matrix 
+ * M = I - gamma*J, updates counters, and calls the dense LU 
+ * factorization routine.
+ * -----------------------------------------------------------------
+ */
+
+static int CVDenseSetup(CVodeMem cv_mem, int convfail, N_Vector ypred,
+                        N_Vector fpred, booleantype *jcurPtr, 
+                        N_Vector vtemp1, N_Vector vtemp2, N_Vector vtemp3)
+{
+  booleantype jbad, jok;
+  realtype dgamma;
+  long int ier;
+  CVDenseMem cvdense_mem;
+  int retval;
+
+  cvdense_mem = (CVDenseMem) lmem;
+ 
+  /* Use nst, gamma/gammap, and convfail to set J eval. flag jok */
+ 
+  dgamma = ABS((gamma/gammap) - ONE);
+  jbad = (nst == 0) || (nst > nstlj + CVD_MSBJ) ||
+         ((convfail == CV_FAIL_BAD_J) && (dgamma < CVD_DGMAX)) ||
+         (convfail == CV_FAIL_OTHER);
+  jok = !jbad;
+ 
+  if (jok) {
+
+    /* If jok = TRUE, use saved copy of J */
+    *jcurPtr = FALSE;
+    DenseCopy(savedJ, M);
+
+  } else {
+
+    /* If jok = FALSE, call jac routine for new J value */
+    nje++;
+    nstlj = nst;
+    *jcurPtr = TRUE;
+    DenseZero(M);
+
+    retval = jac(n, M, tn, ypred, fpred, J_data, vtemp1, vtemp2, vtemp3);
+    if (retval < 0) {
+      CVProcessError(cv_mem, CVDENSE_JACFUNC_UNRECVR, "CVDENSE", "CVDenseSetup", MSGDS_JACFUNC_FAILED);
+      last_flag = CVDENSE_JACFUNC_UNRECVR;
+      return(-1);
+    }
+    if (retval > 0) {
+      last_flag = CVDENSE_JACFUNC_RECVR;
+      return(1);
+    }
+
+    DenseCopy(M, savedJ);
+
+  }
+  
+  /* Scale and add I to get M = I - gamma*J */
+  DenseScale(-gamma, M);
+  DenseAddI(M);
+
+  /* Do LU factorization of M */
+  ier = DenseGETRF(M, pivots); 
+
+  /* Return 0 if the LU was complete; otherwise return 1 */
+  last_flag = ier;
+  if (ier > 0) return(1);
+  return(0);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVDenseSolve
+ * -----------------------------------------------------------------
+ * This routine handles the solve operation for the dense linear solver
+ * by calling the dense backsolve routine.  The returned value is 0.
+ * -----------------------------------------------------------------
+ */
+
+static int CVDenseSolve(CVodeMem cv_mem, N_Vector b, N_Vector weight,
+                        N_Vector ycur, N_Vector fcur)
+{
+  CVDenseMem cvdense_mem;
+  realtype *bd;
+
+  cvdense_mem = (CVDenseMem) lmem;
+  
+  bd = N_VGetArrayPointer(b);
+
+  DenseGETRS(M, pivots, bd);
+
+  /* If CV_BDF, scale the correction to account for change in gamma */
+  if ((lmm == CV_BDF) && (gamrat != ONE)) {
+    N_VScale(TWO/(ONE + gamrat), b, b);
+  }
+  
+  last_flag = CVDENSE_SUCCESS;
+  return(0);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVDenseFree
+ * -----------------------------------------------------------------
+ * This routine frees memory specific to the dense linear solver.
+ * -----------------------------------------------------------------
+ */
+
+static void CVDenseFree(CVodeMem cv_mem)
+{
+  CVDenseMem  cvdense_mem;
+
+  cvdense_mem = (CVDenseMem) lmem;
+  
+  DenseFreeMat(M);
+  DenseFreeMat(savedJ);
+  DenseFreePiv(pivots);
+  free(cvdense_mem); cvdense_mem = NULL;
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVDenseDQJac 
+ * -----------------------------------------------------------------
+ * This routine generates a dense difference quotient approximation to
+ * the Jacobian of f(t,y). It assumes that a dense matrix of type
+ * DenseMat is stored column-wise, and that elements within each column
+ * are contiguous. The address of the jth column of J is obtained via
+ * the macro DENSE_COL and this pointer is associated with an N_Vector
+ * using the N_VGetArrayPointer/N_VSetArrayPointer functions. 
+ * Finally, the actual computation of the jth column of the Jacobian is 
+ * done with a call to N_VLinearSum.
+ * -----------------------------------------------------------------
+ */
+ 
+static int CVDenseDQJac(long int N, DenseMat J, realtype t, 
+                        N_Vector y, N_Vector fy, void *jac_data,
+                        N_Vector tmp1, N_Vector tmp2, N_Vector tmp3)
+{
+  realtype fnorm, minInc, inc, inc_inv, yjsaved, srur;
+  realtype *tmp2_data, *y_data, *ewt_data;
+  N_Vector ftemp, jthCol;
+  long int j;
+  int retval = 0;
+
+  CVodeMem cv_mem;
+  CVDenseMem  cvdense_mem;
+
+  /* jac_data points to cvode_mem */
+  cv_mem = (CVodeMem) jac_data;
+  cvdense_mem = (CVDenseMem) lmem;
+
+  /* Save pointer to the array in tmp2 */
+  tmp2_data = N_VGetArrayPointer(tmp2);
+
+  /* Rename work vectors for readibility */
+  ftemp = tmp1; 
+  jthCol = tmp2;
+
+  /* Obtain pointers to the data for ewt, y */
+  ewt_data = N_VGetArrayPointer(ewt);
+  y_data   = N_VGetArrayPointer(y);
+
+  /* Set minimum increment based on uround and norm of f */
+  srur = RSqrt(uround);
+  fnorm = N_VWrmsNorm(fy, ewt);
+  minInc = (fnorm != ZERO) ?
+           (MIN_INC_MULT * ABS(h) * uround * N * fnorm) : ONE;
+
+  /* This is the only for loop for 0..N-1 in CVODE */
+
+  for (j = 0; j < N; j++) {
+
+    /* Generate the jth col of J(tn,y) */
+
+    N_VSetArrayPointer(DENSE_COL(J,j), jthCol);
+
+    yjsaved = y_data[j];
+    inc = MAX(srur*ABS(yjsaved), minInc/ewt_data[j]);
+    y_data[j] += inc;
+
+    retval = f(tn, y, ftemp, f_data);
+    nfeD++;
+    if (retval != 0) break;
+
+    y_data[j] = yjsaved;
+
+    inc_inv = ONE/inc;
+    N_VLinearSum(inc_inv, ftemp, -inc_inv, fy, jthCol);
+
+    DENSE_COL(J,j) = N_VGetArrayPointer(jthCol);
+  }
+
+  /* Restore original array pointer in tmp2 */
+  N_VSetArrayPointer(tmp2_data, tmp2);
+
+  return(retval);
+}
+
+
+/* 
+ * ================================================================
+ *
+ *                   PART II - backward problems
+ *
+ * ================================================================
+ */
+
+
+/* Additional readability replacements */
+
+#define ytmp        (ca_mem->ca_ytmp)
+#define getY        (ca_mem->ca_getY)
+#define lmemB       (ca_mem->ca_lmemB)
+#define lfreeB      (ca_mem->ca_lfreeB)
+
+#define djac_B      (cvdenseB_mem->d_djacB)
+#define jac_data_B  (cvdenseB_mem->d_jac_dataB)
+
+
+/*
+ * CVDenseB and CVdenseSet*B
+ *
+ * Wrappers for the backward phase around the corresponding 
+ * CVODES functions
+ */
+
+int CVDenseB(void *cvadj_mem, long int nB)
+{
+  CVadjMem ca_mem;
+  CVDenseMemB cvdenseB_mem;
+  CVodeMem cvB_mem;
+  int flag;
+
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CVDENSE_ADJMEM_NULL, "CVDENSE", "CVDenseB", MSGDS_CAMEM_NULL);
+    return(CVDENSE_ADJMEM_NULL);
+  }
+  ca_mem = (CVadjMem) cvadj_mem;
+
+  cvB_mem = ca_mem->cvb_mem;
+
+  /* Get memory for CVDenseMemRecB */
+  cvdenseB_mem = (CVDenseMemB) malloc(sizeof(CVDenseMemRecB));
+  if (cvdenseB_mem == NULL) {
+    CVProcessError(cvB_mem, CVDENSE_MEM_FAIL, "CVDENSE", "CVDenseB", MSGDS_MEM_FAIL);
+    return(CVDENSE_MEM_FAIL);
+  }
+
+  djac_B = NULL;
+  jac_data_B = NULL;
+
+  /* attach lmemB and lfreeB */
+  lmemB = cvdenseB_mem;
+  lfreeB = CVDenseFreeB;
+
+  flag = CVDense(cvB_mem, nB);
+
+  if (flag != CVDENSE_SUCCESS) {
+    free(cvdenseB_mem);
+    cvdenseB_mem = NULL;
+  }
+
+  return(flag);
+}
+
+int CVDenseSetJacFnB(void *cvadj_mem, CVDenseJacFnB djacB, void *jac_dataB)
+{
+  CVadjMem ca_mem;
+  CVDenseMemB cvdenseB_mem;
+  CVodeMem cvB_mem;
+  int flag;
+
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CVDENSE_ADJMEM_NULL, "CVDENSE", "CVDenseSetJacFnB", MSGDS_CAMEM_NULL);
+    return(CVDENSE_ADJMEM_NULL);
+  }
+  ca_mem = (CVadjMem) cvadj_mem;
+
+  cvB_mem = ca_mem->cvb_mem;
+
+  if (lmemB == NULL) {
+    CVProcessError(cvB_mem, CVDENSE_LMEMB_NULL, "CVDENSE", "CVDenseSetJacFnB", MSGDS_LMEMB_NULL);
+    return(CVDENSE_LMEMB_NULL);
+  }
+  cvdenseB_mem = (CVDenseMemB) lmemB;
+
+  djac_B     = djacB;
+  jac_data_B = jac_dataB;
+
+  flag = CVDenseSetJacFn(cvB_mem, CVAdenseJac, cvadj_mem);
+
+  return(flag);
+}
+
+/*
+ * CVDenseFreeB 
+ */
+
+
+static void CVDenseFreeB(CVadjMem ca_mem)
+{
+  CVDenseMemB cvdenseB_mem;
+
+  cvdenseB_mem = (CVDenseMemB) lmemB;
+
+  free(cvdenseB_mem);
+}
+
+
+/*
+ * CVAdenseJac
+ *
+ * This routine interfaces to the CVDenseJacFnB routine provided 
+ * by the user.
+ * NOTE: jac_data actually contains cvadj_mem
+ */
+
+static int CVAdenseJac(long int nB, DenseMat JB, realtype t, 
+                       N_Vector yB, N_Vector fyB, void *cvadj_mem,
+                       N_Vector tmp1B, N_Vector tmp2B, N_Vector tmp3B)
+{
+  CVadjMem ca_mem;
+  CVodeMem cvB_mem;
+  CVDenseMemB cvdenseB_mem;
+  int retval, flag;
+
+  ca_mem = (CVadjMem) cvadj_mem;
+  cvB_mem = ca_mem->cvb_mem;
+  cvdenseB_mem = (CVDenseMemB) lmemB;
+
+  /* Forward solution from interpolation */
+  flag = getY(ca_mem, t, ytmp);
+  if (flag != CV_SUCCESS) {
+    CVProcessError(cvB_mem, -1, "CVDENSE", "CVAdenseJac", MSGDS_BAD_T);
+    return(-1);
+  }
+
+  /* Call user's adjoint dense djacB routine */
+  retval = djac_B(nB, JB, t, ytmp, yB, fyB, jac_data_B, 
+                  tmp1B, tmp2B, tmp3B);
+
+  return(retval);
+
+}
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_dense_impl.h b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_dense_impl.h
new file mode 100644
index 0000000000000000000000000000000000000000..9082818827084d92b7e2a3c7957eb2270530c220
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_dense_impl.h	
@@ -0,0 +1,99 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * ----------------------------------------------------------------- 
+ * Programmer(s): Radu Serban @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2005, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * Implementation header file for the dense linear solver, CVDENSE.
+ * -----------------------------------------------------------------
+ */
+
+#ifndef _CVSDENSE_IMPL_H
+#define _CVSDENSE_IMPL_H
+
+#ifdef __cplusplus  /* wrapper to enable C++ usage */
+extern "C" {
+#endif
+
+#include <cvodes/cvodes_dense.h>
+
+  /*
+   * -----------------------------------------------------------------
+   * Types : CVDenseMemRec, CVDenseMem                             
+   * -----------------------------------------------------------------
+   * The type CVDenseMem is pointer to a CVDenseMemRec.
+   * This structure contains CVDense solver-specific data.
+   *
+   * CVDense attaches such a structure to the lmem field of CVodeMem
+   * -----------------------------------------------------------------
+   */
+
+  typedef struct {
+
+    long int d_n;        /* problem dimension                       */
+
+    CVDenseJacFn d_jac;  /* jac = Jacobian routine to be called     */
+
+    DenseMat d_M;        /* M = I - gamma J, gamma = h / l1         */
+  
+    long int *d_pivots;  /* pivots = pivot array for PM = LU        */
+  
+    DenseMat d_savedJ;   /* savedJ = old Jacobian                   */
+  
+    long int  d_nstlj;   /* nstlj = nst at last Jacobian eval.      */
+  
+    long int d_nje;      /* nje = no. of calls to jac               */
+
+    long int d_nfeD;     /* nfeD = no. of calls to f due to
+                            difference quotient approximation of J  */
+  
+    void *d_J_data;      /* J_data is passed to jac                 */
+
+    int d_last_flag;     /* last error return flag                  */
+  
+  } CVDenseMemRec, *CVDenseMem;
+
+
+  /*
+   * -----------------------------------------------------------------
+   * Types : CVDenseMemRecB, CVDenseMemB       
+   * -----------------------------------------------------------------
+   * CVDenseB attaches such a structure to the lmemB filed of CVadjMem
+   * -----------------------------------------------------------------
+   */
+
+  typedef struct {
+
+    CVDenseJacFnB d_djacB;
+    void *d_jac_dataB;
+
+  } CVDenseMemRecB, *CVDenseMemB;
+
+  /*
+   * -----------------------------------------------------------------
+   * Error Messages 
+   * -----------------------------------------------------------------
+   */
+
+#define MSGDS_CVMEM_NULL "Integrator memory is NULL."
+#define MSGDS_MEM_FAIL "A memory request failed."
+#define MSGDS_BAD_NVECTOR "A required vector operation is not implemented."
+#define MSGDS_LMEM_NULL "CVDENSE memory is NULL."
+#define MSGDS_JACFUNC_FAILED "The Jacobian routine failed in an unrecoverable manner."
+
+#define MSGDS_CAMEM_NULL "cvadj_mem = NULL illegal."
+#define MSGDS_LMEMB_NULL "CVDENSE memory is NULL for the backward integration."
+#define MSGDS_BAD_T "Bad t for interpolation."
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_diag.c b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_diag.c
new file mode 100644
index 0000000000000000000000000000000000000000..3f965d1003c460c622dbf3f2b18db457bd5ecb53
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_diag.c	
@@ -0,0 +1,488 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * ----------------------------------------------------------------- 
+ * Programmer(s): Radu Serban @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2005, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This is the implementation file for the CVDIAG linear solver.
+ * -----------------------------------------------------------------
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "cvodes_diag_impl.h"
+#include "cvodes_impl.h"
+
+/* Other Constants */
+  
+#define FRACT RCONST(0.1)
+#define ONE   RCONST(1.0)
+
+/* CVDIAG linit, lsetup, lsolve, and lfree routines */
+
+static int CVDiagInit(CVodeMem cv_mem);
+
+static int CVDiagSetup(CVodeMem cv_mem, int convfail, N_Vector ypred,
+                       N_Vector fpred, booleantype *jcurPtr, N_Vector vtemp1,
+                       N_Vector vtemp2, N_Vector vtemp3);
+
+static int CVDiagSolve(CVodeMem cv_mem, N_Vector b, N_Vector weight,
+                       N_Vector ycur, N_Vector fcur);
+
+static void CVDiagFree(CVodeMem cv_mem);
+
+
+/* 
+ * ================================================================
+ *
+ *                   PART I - forward problems
+ *
+ * ================================================================
+ */
+
+
+/* Readability Replacements */
+
+#define lrw1      (cv_mem->cv_lrw1)
+#define liw1      (cv_mem->cv_liw1)
+#define f         (cv_mem->cv_f)
+#define f_data    (cv_mem->cv_f_data)
+#define uround    (cv_mem->cv_uround)
+#define tn        (cv_mem->cv_tn)
+#define h         (cv_mem->cv_h)
+#define rl1       (cv_mem->cv_rl1)
+#define gamma     (cv_mem->cv_gamma)
+#define ewt       (cv_mem->cv_ewt)
+#define nfe       (cv_mem->cv_nfe)
+#define zn        (cv_mem->cv_zn)
+#define linit     (cv_mem->cv_linit)
+#define lsetup    (cv_mem->cv_lsetup)
+#define lsolve    (cv_mem->cv_lsolve)
+#define lfree     (cv_mem->cv_lfree)
+#define lmem      (cv_mem->cv_lmem)
+#define vec_tmpl  (cv_mem->cv_tempv)
+#define setupNonNull   (cv_mem->cv_setupNonNull)
+
+#define gammasv   (cvdiag_mem->di_gammasv)
+#define M         (cvdiag_mem->di_M)
+#define bit       (cvdiag_mem->di_bit)
+#define bitcomp   (cvdiag_mem->di_bitcomp)
+#define nfeDI     (cvdiag_mem->di_nfeDI)
+#define last_flag (cvdiag_mem->di_last_flag)
+
+
+/*
+ * -----------------------------------------------------------------
+ * CVDiag 
+ * -----------------------------------------------------------------
+ * This routine initializes the memory record and sets various function
+ * fields specific to the diagonal linear solver module.  CVDense first
+ * calls the existing lfree routine if this is not NULL.  Then it sets
+ * the cv_linit, cv_lsetup, cv_lsolve, cv_lfree fields in (*cvode_mem)
+ * to be CVDiagInit, CVDiagSetup, CVDiagSolve, and CVDiagFree,
+ * respectively.  It allocates memory for a structure of type
+ * CVDiagMemRec and sets the cv_lmem field in (*cvode_mem) to the
+ * address of this structure.  It sets setupNonNull in (*cvode_mem) to
+ * TRUE.  Finally, it allocates memory for M, bit, and bitcomp.
+ * The CVDiag return value is SUCCESS = 0, LMEM_FAIL = -1, or 
+ * LIN_ILL_INPUT=-2.
+ * -----------------------------------------------------------------
+ */
+  
+int CVDiag(void *cvode_mem)
+{
+  CVodeMem cv_mem;
+  CVDiagMem cvdiag_mem;
+
+  /* Return immediately if cvode_mem is NULL */
+  if (cvode_mem == NULL) {
+    CVProcessError(NULL, CVDIAG_MEM_NULL, "CVDIAG", "CVDiag", MSGDG_CVMEM_NULL);
+    return(CVDIAG_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;
+
+  /* Check if N_VCompare and N_VInvTest are present */
+  if(vec_tmpl->ops->nvcompare == NULL ||
+     vec_tmpl->ops->nvinvtest == NULL) {
+    CVProcessError(cv_mem, CVDIAG_ILL_INPUT, "CVDIAG", "CVDiag", MSGDG_BAD_NVECTOR);
+    return(CVDIAG_ILL_INPUT);
+  }
+
+  if (lfree != NULL) lfree(cv_mem);
+  
+  /* Set four main function fields in cv_mem */
+  linit  = CVDiagInit;
+  lsetup = CVDiagSetup;
+  lsolve = CVDiagSolve;
+  lfree  = CVDiagFree;
+
+  /* Get memory for CVDiagMemRec */
+  cvdiag_mem = NULL;
+  cvdiag_mem = (CVDiagMem) malloc(sizeof(CVDiagMemRec));
+  if (cvdiag_mem == NULL) {
+    CVProcessError(cv_mem, CVDIAG_MEM_FAIL, "CVDIAG", "CVDiag", MSGDG_MEM_FAIL);
+    return(CVDIAG_MEM_FAIL);
+  }
+
+  last_flag = CVDIAG_SUCCESS;
+
+  /* Set flag setupNonNull = TRUE */
+  setupNonNull = TRUE;
+
+  /* Allocate memory for M, bit, and bitcomp */
+    
+  M = NULL;
+  M = N_VClone(vec_tmpl);
+  if (M == NULL) {
+    CVProcessError(cv_mem, CVDIAG_MEM_FAIL, "CVDIAG", "CVDiag", MSGDG_MEM_FAIL);
+    free(cvdiag_mem); cvdiag_mem = NULL;
+    return(CVDIAG_MEM_FAIL);
+  }
+  bit = NULL;
+  bit = N_VClone(vec_tmpl);
+  if (bit == NULL) {
+    CVProcessError(cv_mem, CVDIAG_MEM_FAIL, "CVDIAG", "CVDiag", MSGDG_MEM_FAIL);
+    N_VDestroy(M);
+    free(cvdiag_mem); cvdiag_mem = NULL;
+    return(CVDIAG_MEM_FAIL);
+  }
+  bitcomp = NULL;
+  bitcomp = N_VClone(vec_tmpl);
+  if (bitcomp == NULL) {
+    CVProcessError(cv_mem, CVDIAG_MEM_FAIL, "CVDIAG", "CVDiag", MSGDG_MEM_FAIL);
+    N_VDestroy(M);
+    N_VDestroy(bit);
+    free(cvdiag_mem); cvdiag_mem = NULL;
+    return(CVDIAG_MEM_FAIL);
+  }
+
+  /* Attach linear solver memory to integrator memory */
+  lmem = cvdiag_mem;
+
+  return(CVDIAG_SUCCESS);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVDiagGetWorkSpace
+ * -----------------------------------------------------------------
+ */
+
+int CVDiagGetWorkSpace(void *cvode_mem, long int *lenrwLS, long int *leniwLS)
+{
+  CVodeMem cv_mem;
+
+  /* Return immediately if cvode_mem is NULL */
+  if (cvode_mem == NULL) {
+    CVProcessError(NULL, CVDIAG_MEM_NULL, "CVDIAG", "CVDiagGetWorkSpace", MSGDG_CVMEM_NULL);
+    return(CVDIAG_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;
+
+  *lenrwLS = 3*lrw1;
+  *leniwLS = 3*liw1;
+
+  return(CVDIAG_SUCCESS);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVDiagGetNumRhsEvals
+ * -----------------------------------------------------------------
+ */
+
+int CVDiagGetNumRhsEvals(void *cvode_mem, long int *nfevalsLS)
+{
+  CVodeMem cv_mem;
+  CVDiagMem cvdiag_mem;
+
+  /* Return immediately if cvode_mem is NULL */
+  if (cvode_mem == NULL) {
+    CVProcessError(NULL, CVDIAG_MEM_NULL, "CVDIAG", "CVDiagGetNumRhsEvals", MSGDG_CVMEM_NULL);
+    return(CVDIAG_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (lmem == NULL) {
+    CVProcessError(cv_mem, CVDIAG_LMEM_NULL, "CVDIAG", "CVDiagGetNumRhsEvals", MSGDG_LMEM_NULL);
+    return(CVDIAG_LMEM_NULL);
+  }
+  cvdiag_mem = (CVDiagMem) lmem;
+
+  *nfevalsLS = nfeDI;
+
+  return(CVDIAG_SUCCESS);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVDiagGetLastFlag
+ * -----------------------------------------------------------------
+ */
+
+int CVDiagGetLastFlag(void *cvode_mem, int *flag)
+{
+  CVodeMem cv_mem;
+  CVDiagMem cvdiag_mem;
+
+  /* Return immediately if cvode_mem is NULL */
+  if (cvode_mem == NULL) {
+    CVProcessError(NULL, CVDIAG_MEM_NULL, "CVDIAG", "CVDiagGetLastFlag", MSGDG_CVMEM_NULL);
+    return(CVDIAG_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (lmem == NULL) {
+    CVProcessError(cv_mem, CVDIAG_LMEM_NULL, "CVDIAG", "CVDiagGetLastFlag", MSGDG_LMEM_NULL);
+    return(CVDIAG_LMEM_NULL);
+  }
+  cvdiag_mem = (CVDiagMem) lmem;
+
+  *flag = last_flag;
+
+  return(CVDIAG_SUCCESS);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVDiagGetReturnFlagName
+ * -----------------------------------------------------------------
+ */
+
+char *CVDiagGetReturnFlagName(int flag)
+{
+  char *name;
+
+  name = (char *)malloc(30*sizeof(char));
+
+  switch(flag) {
+  case CVDIAG_SUCCESS:
+    sprintf(name,"CVDIAG_SUCCESS");
+    break;  
+  case CVDIAG_MEM_NULL:
+    sprintf(name,"CVDIAG_MEM_NULL");
+    break;
+  case CVDIAG_LMEM_NULL:
+    sprintf(name,"CVDIAG_LMEM_NULL");
+    break;
+  case CVDIAG_ILL_INPUT:
+    sprintf(name,"CVDIAG_ILL_INPUT");
+    break;
+  case CVDIAG_MEM_FAIL:
+    sprintf(name,"CVDIAG_MEM_FAIL");
+    break;
+  case CVDIAG_INV_FAIL:
+    sprintf(name,"CVDIAG_INV_FAIL");
+    break;
+  case CVDIAG_RHSFUNC_UNRECVR:
+    sprintf(name,"CVDIAG_RHSFUNC_UNRECVR");
+    break;
+  case CVDIAG_RHSFUNC_RECVR:
+    sprintf(name,"CVDIAG_RHSFUNC_RECVR");
+    break;
+  case CVDIAG_ADJMEM_NULL:
+    sprintf(name,"CVDIAG_ADJMEM_NULL");
+    break;
+  default:
+    sprintf(name,"NONE");
+  }
+
+  return(name);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVDiagInit
+ * -----------------------------------------------------------------
+ * This routine does remaining initializations specific to the diagonal
+ * linear solver.
+ * -----------------------------------------------------------------
+ */
+
+static int CVDiagInit(CVodeMem cv_mem)
+{
+  CVDiagMem cvdiag_mem;
+
+  cvdiag_mem = (CVDiagMem) lmem;
+
+  nfeDI = 0;
+
+  last_flag = CVDIAG_SUCCESS;
+  return(0);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVDiagSetup
+ * -----------------------------------------------------------------
+ * This routine does the setup operations for the diagonal linear 
+ * solver.  It constructs a diagonal approximation to the Newton matrix 
+ * M = I - gamma*J, updates counters, and inverts M.
+ * -----------------------------------------------------------------
+ */
+
+static int CVDiagSetup(CVodeMem cv_mem, int convfail, N_Vector ypred,
+                       N_Vector fpred, booleantype *jcurPtr, N_Vector vtemp1,
+                       N_Vector vtemp2, N_Vector vtemp3)
+{
+  realtype r;
+  N_Vector ftemp, y;
+  booleantype invOK;
+  CVDiagMem cvdiag_mem;
+  int retval;
+
+  cvdiag_mem = (CVDiagMem) lmem;
+
+  /* Rename work vectors for use as temporary values of y and f */
+  ftemp = vtemp1;
+  y     = vtemp2;
+
+  /* Form y with perturbation = FRACT*(func. iter. correction) */
+  r = FRACT * rl1;
+  N_VLinearSum(h, fpred, -ONE, zn[1], ftemp);
+  N_VLinearSum(r, ftemp, ONE, ypred, y);
+
+  /* Evaluate f at perturbed y */
+  retval = f(tn, y, M, f_data);
+  nfeDI++;
+  if (retval < 0) {
+    CVProcessError(cv_mem, CVDIAG_RHSFUNC_UNRECVR, "CVDIAG", "CVDiagSetup", MSGDG_RHSFUNC_FAILED);
+    last_flag = CVDIAG_RHSFUNC_UNRECVR;
+    return(-1);
+  }
+  if (retval > 0) {
+    last_flag = CVDIAG_RHSFUNC_RECVR;
+    return(1);
+  }
+
+  /* Construct M = I - gamma*J with J = diag(deltaf_i/deltay_i) */
+  N_VLinearSum(ONE, M, -ONE, fpred, M);
+  N_VLinearSum(FRACT, ftemp, -h, M, M);
+  N_VProd(ftemp, ewt, y);
+  /* Protect against deltay_i being at roundoff level */
+  N_VCompare(uround, y, bit);
+  N_VAddConst(bit, -ONE, bitcomp);
+  N_VProd(ftemp, bit, y);
+  N_VLinearSum(FRACT, y, -ONE, bitcomp, y);
+  N_VDiv(M, y, M);
+  N_VProd(M, bit, M);
+  N_VLinearSum(ONE, M, -ONE, bitcomp, M);
+
+  /* Invert M with test for zero components */
+  invOK = N_VInvTest(M, M);
+  if (!invOK) {
+    last_flag = CVDIAG_INV_FAIL;
+    return(1);
+  }
+
+  /* Set jcur = TRUE, save gamma in gammasv, and return */
+  *jcurPtr = TRUE;
+  gammasv = gamma;
+  last_flag = CVDIAG_SUCCESS;
+  return(0);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVDiagSolve
+ * -----------------------------------------------------------------
+ * This routine performs the solve operation for the diagonal linear
+ * solver.  If necessary it first updates gamma in M = I - gamma*J.
+ * -----------------------------------------------------------------
+ */
+
+static int CVDiagSolve(CVodeMem cv_mem, N_Vector b, N_Vector weight,
+                       N_Vector ycur, N_Vector fcur)
+{
+  booleantype invOK;
+  realtype r;
+  CVDiagMem cvdiag_mem;
+
+  cvdiag_mem = (CVDiagMem) lmem;
+  
+  /* If gamma has changed, update factor in M, and save gamma value */
+
+  if (gammasv != gamma) {
+    r = gamma / gammasv;
+    N_VInv(M, M);
+    N_VAddConst(M, -ONE, M);
+    N_VScale(r, M, M);
+    N_VAddConst(M, ONE, M);
+    invOK = N_VInvTest(M, M);
+    if (!invOK) {
+      last_flag = CVDIAG_INV_FAIL;
+      return (1);
+    }
+    gammasv = gamma;
+  }
+
+  /* Apply M-inverse to b */
+  N_VProd(b, M, b);
+
+  last_flag = CVDIAG_SUCCESS;
+  return(0);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVDiagFree
+ * -----------------------------------------------------------------
+ * This routine frees memory specific to the diagonal linear solver.
+ * -----------------------------------------------------------------
+ */
+
+static void CVDiagFree(CVodeMem cv_mem)
+{
+  CVDiagMem cvdiag_mem;
+  
+  cvdiag_mem = (CVDiagMem) lmem;
+
+  N_VDestroy(M);
+  N_VDestroy(bit);
+  N_VDestroy(bitcomp);
+  free(cvdiag_mem); cvdiag_mem = NULL;
+}
+
+
+/* 
+ * ================================================================
+ *
+ *                   PART II - backward problems
+ *
+ * ================================================================
+ */
+
+
+/*
+ * CVDiagB
+ *
+ * Wrappers for the backward phase around the corresponding 
+ * CVODES functions
+ */
+
+int CVDiagB(void *cvadj_mem)
+{
+  CVadjMem ca_mem;
+  CVodeMem cvB_mem;
+  int flag;
+
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CVDIAG_ADJMEM_NULL, "CVDIAG", "CVDiagB", MSGDG_CAMEM_NULL);
+    return(CVDIAG_ADJMEM_NULL);
+  }
+  ca_mem = (CVadjMem) cvadj_mem;
+
+  cvB_mem = ca_mem->cvb_mem;
+  
+  flag = CVDiag(cvB_mem);
+
+  return(flag);
+}
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_diag_impl.h b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_diag_impl.h
new file mode 100644
index 0000000000000000000000000000000000000000..c49b0a840e73fb5d6c7f4c102ea726125ba46020
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_diag_impl.h	
@@ -0,0 +1,67 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * ----------------------------------------------------------------- 
+ * Programmer(s): Radu Serban @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2005, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * Implementation header file for the diagonal linear solver, CVDIAG.
+ * -----------------------------------------------------------------
+ */
+
+#ifndef _CVSDIAG_IMPL_H
+#define _CVSDIAG_IMPL_H
+
+#ifdef __cplusplus  /* wrapper to enable C++ usage */
+extern "C" {
+#endif
+
+#include <cvodes/cvodes_diag.h>
+
+  /*
+   * -----------------------------------------------------------------
+   * Types: CVDiagMemRec, CVDiagMem
+   * -----------------------------------------------------------------
+   * The type CVDiagMem is pointer to a CVDiagMemRec.
+   * This structure contains CVDiag solver-specific data.
+   * -----------------------------------------------------------------
+   */
+
+  typedef struct {
+
+    realtype di_gammasv; /* gammasv = gamma at the last call to setup */
+    /* or solve                                  */
+
+    N_Vector di_M;       /* M = (I - gamma J)^{-1} , gamma = h / l1   */
+
+    N_Vector di_bit;     /* temporary storage vector                  */
+
+    N_Vector di_bitcomp; /* temporary storage vector                  */
+
+    long int di_nfeDI;   /* no. of calls to f due to difference 
+                            quotient diagonal Jacobian approximation  */
+
+    int di_last_flag;    /* last error return flag                    */
+
+  } CVDiagMemRec, *CVDiagMem;
+
+  /* Error Messages */
+
+#define MSGDG_CVMEM_NULL "Integrator memory is NULL."
+#define MSGDG_MEM_FAIL "A memory request failed."
+#define MSGDG_BAD_NVECTOR "A required vector operation is not implemented."
+#define MSGDG_LMEM_NULL "CVDIAG memory is NULL."
+#define MSGDG_RHSFUNC_FAILED "The right-hand side routine failed in an unrecoverable manner."
+
+#define MSGDG_CAMEM_NULL "cvadj_mem = NULL illegal."
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_impl.h b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_impl.h
new file mode 100644
index 0000000000000000000000000000000000000000..d3f52ced857d2c3105662d193e093a5bc9d864ed
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_impl.h	
@@ -0,0 +1,918 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * ----------------------------------------------------------------- 
+ * Programmer(s): Radu Serban @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2005, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * Implementation header file for the main CVODES integrator.
+ * -----------------------------------------------------------------
+ */
+
+#ifndef _CVODES_IMPL_H
+#define _CVODES_IMPL_H
+
+#ifdef __cplusplus  /* wrapper to enable C++ usage */
+extern "C" {
+#endif
+
+#include <stdarg.h>
+
+#include <cvodes/cvodes.h>
+#include <sundials/sundials_nvector.h>
+#include <sundials/sundials_types.h>
+
+  /* 
+   * =================================================================
+   *   M A I N    I N T E G R A T O R    M E M O R Y    B L O C K
+   * =================================================================
+   */
+
+  /* Basic CVODES constants */
+
+#define ADAMS_Q_MAX 12      /* max value of q for lmm == ADAMS    */
+#define BDF_Q_MAX    5      /* max value of q for lmm == BDF      */
+#define Q_MAX  ADAMS_Q_MAX  /* max value of q for either lmm      */
+#define L_MAX  (Q_MAX+1)    /* max value of L for either lmm      */
+#define NUM_TESTS    5      /* number of error test quantities    */
+
+#define HMIN_DEFAULT     RCONST(0.0)    /* hmin default value     */
+#define HMAX_INV_DEFAULT RCONST(0.0)    /* hmax_inv default value */
+#define MXHNIL_DEFAULT   10             /* mxhnil default value   */
+#define MXSTEP_DEFAULT   500            /* mxstep default value   */
+
+  /*                                                                
+   * ifS is the type of the function returning the sensitivity
+   * right-hand side. ifS can be either CV_ALLSENS if the function    
+   * (of type CVSensRhsFn) returns right hand sides for all    
+   * sensitivity systems at once, or CV_ONESENS if the function 
+   * (of type SensRhs1Fn) returns the right hand side of one 
+   *  sensitivity system at a time.                           
+   */
+
+#define CV_ONESENS 1
+#define CV_ALLSENS 2
+
+  /*
+   * -----------------------------------------------------------------
+   * Types: struct CVodeMemRec, CVodeMem
+   * -----------------------------------------------------------------
+   * The type CVodeMem is type pointer to struct CVodeMemRec.
+   * This structure contains fields to keep track of problem state.
+   * -----------------------------------------------------------------
+   */
+  
+  typedef struct CVodeMemRec {
+    
+    realtype cv_uround;      /* machine unit roundoff                        */   
+
+    /*-------------------------- 
+      Problem Specification Data 
+      --------------------------*/
+
+    CVRhsFn cv_f;            /* y' = f(t,y(t))                               */
+    void *cv_f_data;         /* user pointer passed to f                     */
+    int cv_lmm;              /* lmm = ADAMS or BDF                           */
+    int cv_iter;             /* iter = FUNCTIONAL or NEWTON                  */
+    int cv_itol;             /* itol = SS or SV                              */
+
+    realtype cv_reltol;      /* relative tolerance                           */
+    realtype cv_Sabstol;     /* scalar absolute tolerance                    */
+    N_Vector cv_Vabstol;     /* vector absolute tolerance                    */
+    CVEwtFn cv_efun;         /* function to set ewt                          */
+    void *cv_e_data;         /* user pointer passed to efun                  */
+
+    /*-----------------------
+      Quadrature Related Data 
+      -----------------------*/
+
+    booleantype cv_quadr;    /* TRUE if integrating quadratures              */
+
+    CVQuadRhsFn cv_fQ;
+    void *cv_fQ_data;        /* user pointer passed to fQ                    */
+    int cv_itolQ;
+    booleantype cv_errconQ;
+
+    realtype cv_reltolQ;     /* relative tolerance for quadratures           */
+    realtype cv_SabstolQ;    /* scalar absolute tolerance for quadratures    */
+    N_Vector cv_VabstolQ;    /* vector absolute tolerance for quadratures    */
+
+    /*------------------------
+      Sensitivity Related Data 
+      ------------------------*/
+
+    booleantype cv_sensi;    /* TRUE if computing sensitivities              */
+
+    int cv_Ns;               /* Number of sensitivities                      */
+
+    int cv_ism;              /* ism = SIMULTANEOUS or STAGGERED              */
+
+    CVSensRhsFn cv_fS;       /* fS = (df/dy)*yS + (df/dp)                    */
+    CVSensRhs1Fn cv_fS1;     /* fS1 = (df/dy)*yS_i + (df/dp)                 */
+    void *cv_user_fS_data;   /* user data pointer for fS                     */
+    void *cv_fS_data;        /* actual data pointer passed to fS             */
+    booleantype cv_fSDQ;
+    int cv_ifS;              /* ifS = ALLSENS or ONESENS                     */
+
+    realtype *cv_p;          /* parameters in f(t,y,p)                       */
+    realtype *cv_pbar;       /* scale factors for parameters                 */
+    int *cv_plist;           /* list of sensitivities                        */
+    int cv_DQtype;           /* central/forward finite differences           */
+    realtype cv_DQrhomax;    /* cut-off value for separate/simultaneous FD   */
+
+    booleantype cv_errconS;  /* TRUE if sensitivities are in err. control    */
+
+    int cv_itolS;
+    realtype cv_reltolS;     /* relative tolerance for sensitivities         */
+    realtype *cv_SabstolS;   /* scalar absolute tolerances for sensi.        */
+    N_Vector *cv_VabstolS;   /* vector absolute tolerances for sensi.        */
+
+    /*-----------------------
+      Nordsieck History Array 
+      -----------------------*/
+
+    N_Vector cv_zn[L_MAX];   /* Nordsieck array, of size N x (q+1).
+                                zn[j] is a vector of length N (j=0,...,q)
+                                zn[j] = [1/factorial(j)] * h^j * 
+                                (jth derivative of the interpolating 
+                                polynomial                                   */
+
+    /*-------------------
+      Vectors of length N 
+      -------------------*/
+
+    N_Vector cv_ewt;         /* error weight vector                          */
+    N_Vector cv_y;           /* y is used as temporary storage by the solver.
+                                The memory is provided by the user to CVode 
+                                where the vector is named yout.              */
+    N_Vector cv_acor;        /* In the context of the solution of the
+                                nonlinear equation, acor = y_n(m) - y_n(0).
+                                On return, this vector is scaled to give
+                                the estimated local error in y.              */
+    N_Vector cv_tempv;       /* temporary storage vector                     */
+    N_Vector cv_ftemp;       /* temporary storage vector                     */
+
+    /*--------------------------
+      Quadrature Related Vectors 
+      --------------------------*/
+
+    N_Vector cv_znQ[L_MAX];  /* Nordsieck arrays for quadratures             */
+    N_Vector cv_ewtQ;        /* error weight vector for quadratures          */
+    N_Vector cv_yQ;          /* Unlike y, yQ is not allocated by the user    */
+    N_Vector cv_acorQ;       /* acorQ = yQ_n(m) - yQ_n(0)                    */
+    N_Vector cv_tempvQ;      /* temporary storage vector (~ tempv)           */
+
+    /*---------------------------
+      Sensitivity Related Vectors 
+      ---------------------------*/
+
+    N_Vector *cv_znS[L_MAX]; /* Nordsieck arrays for sensitivities           */
+    N_Vector *cv_ewtS;       /* error weight vectors for sensitivities       */
+    N_Vector *cv_yS;         /* yS=yS0 (allocated by the user)               */
+    N_Vector *cv_acorS;      /* acorS = yS_n(m) - yS_n(0)                    */
+    N_Vector *cv_tempvS;     /* temporary storage vector (~ tempv)           */
+    N_Vector *cv_ftempS;     /* temporary storage vector (~ ftemp)           */
+
+    /*-----------------------------------------------
+      Does CVodeSensMalloc allocate additional space?
+      -----------------------------------------------*/  
+
+    booleantype cv_stgr1alloc; /* Did we allocate ncfS1, ncfnS1, and nniS1?  */
+
+    /*-----------------
+      Tstop information
+      -----------------*/
+    booleantype cv_istop;
+    booleantype cv_tstopset;
+    realtype cv_tstop;
+
+    /*---------
+      Step Data 
+      ---------*/
+
+    int cv_q;                    /* current order                            */
+    int cv_qprime;               /* order to be used on the next step        */ 
+    /* = q-1, q, or q+1                         */
+    int cv_next_q;               /* order to be used on the next step        */
+    int cv_qwait;                /* number of internal steps to wait before  */
+    /* considering a change in q                */
+    int cv_L;                    /* L = q + 1                                */
+
+    realtype cv_hin;
+    realtype cv_h;               /* current step size                        */
+    realtype cv_hprime;          /* step size to be used on the next step    */ 
+    realtype cv_next_h;          /* step size to be used on the next step    */ 
+    realtype cv_eta;             /* eta = hprime / h                         */
+    realtype cv_hscale;          /* value of h used in zn                    */
+    realtype cv_tn;              /* current internal value of t              */
+    realtype cv_tretlast;        /* last value of t returned                 */
+
+    realtype cv_tau[L_MAX+1];    /* array of previous q+1 successful step
+                                    sizes indexed from 1 to q+1              */
+    realtype cv_tq[NUM_TESTS+1]; /* array of test quantities indexed from
+                                    1 to NUM_TESTS(=5)                       */
+    realtype cv_l[L_MAX];        /* coefficients of l(x) (degree q poly)     */
+
+    realtype cv_rl1;             /* the scalar 1/l[1]                        */
+    realtype cv_gamma;           /* gamma = h * rl1                          */
+    realtype cv_gammap;          /* gamma at the last setup call             */
+    realtype cv_gamrat;          /* gamma / gammap                           */
+
+    realtype cv_crate;           /* est. corrector conv. rate in Nls         */
+    realtype cv_crateS;          /* est. corrector conv. rate in NlsStgr     */
+    realtype cv_acnrm;           /* | acor |                                 */
+    realtype cv_acnrmS;          /* | acorS |                                */
+    realtype cv_acnrmQ;          /* | acorQ |                                */
+    realtype cv_nlscoef;         /* coeficient in nonlinear convergence test */
+    int  cv_mnewt;               /* Newton iteration counter                 */
+    int  *cv_ncfS1;              /* Array of Ns local counters for conv.  
+                                    failures (used in CVStep for STAGGERED1) */
+
+    /*------
+      Limits 
+      ------*/
+
+    int cv_qmax;             /* q <= qmax                                    */
+    long int cv_mxstep;      /* maximum number of internal steps for one 
+                                user call                                    */
+    int cv_maxcor;           /* maximum number of corrector iterations for 
+                                the solution of the nonlinear equation       */
+    int cv_maxcorS;
+    int cv_mxhnil;           /* maximum number of warning messages issued to 
+                                the user that t + h == t for the next 
+                                internal step                                */
+    int cv_maxnef;           /* maximum number of error test failures        */
+    int cv_maxncf;           /* maximum number of nonlinear conv. failures   */
+
+    realtype cv_hmin;        /* |h| >= hmin                                  */
+    realtype cv_hmax_inv;    /* |h| <= 1/hmax_inv                            */
+    realtype cv_etamax;      /* eta <= etamax                                */
+
+    /*----------
+      Counters 
+      ----------*/
+
+    long int cv_nst;         /* number of internal steps taken               */
+    long int cv_nfe;         /* number of f calls                            */
+    long int cv_nfSe;        /* number of fS calls                           */
+    long int cv_nfQe;        /* number of fQ calls                           */
+    long int cv_nfeS;        /* number of f calls from sensi DQ              */
+
+    long int cv_ncfn;        /* number of corrector convergence failures     */
+    long int cv_ncfnS;       /* number of total sensi. corr. conv. failures  */
+    long int *cv_ncfnS1;     /* number of sensi. corrector conv. failures    */
+
+    long int cv_nni;         /* number of nonlinear iterations performed     */
+    long int cv_nniS;        /* number of total sensi. nonlinear iterations  */
+    long int *cv_nniS1;      /* number of sensi. nonlinear iterations        */
+
+    long int cv_netf;        /* number of error test failures                */
+    long int cv_netfS;       /* number of sensi. error test failures         */
+    long int cv_netfQ;       /* number of quadr. error test failures         */
+
+    long int cv_nsetups;     /* number of setup calls                        */
+    long int cv_nsetupsS;    /* number of setup calls due to sensitivities   */
+
+    int cv_nhnil;            /* number of messages issued to the user that
+                                t + h == t for the next iternal step    */
+
+    /*-----------------------------
+      Space requirements for CVODES 
+      -----------------------------*/
+
+    long int cv_lrw1;        /* no. of realtype words in 1 N_Vector y        */ 
+    long int cv_liw1;        /* no. of integer words in 1 N_Vector y         */ 
+    long int cv_lrw1Q;       /* no. of realtype words in 1 N_Vector yQ       */ 
+    long int cv_liw1Q;       /* no. of integer words in 1 N_Vector yQ        */ 
+    long int cv_lrw;         /* no. of realtype words in CVODES work vectors */
+    long int cv_liw;         /* no. of integer words in CVODES work vectors  */
+
+    /*----------------
+      Step size ratios
+      ----------------*/
+
+    realtype cv_etaqm1;      /* ratio of new to old h for order q-1          */
+    realtype cv_etaq;        /* ratio of new to old h for order q            */
+    realtype cv_etaqp1;      /* ratio of new to old h for order q+1          */
+
+    /*------------------
+      Linear Solver Data 
+      ------------------*/
+
+    /* Linear Solver functions to be called */
+
+    int (*cv_linit)(struct CVodeMemRec *cv_mem);
+
+    int (*cv_lsetup)(struct CVodeMemRec *cv_mem, int convfail, 
+                     N_Vector ypred, N_Vector fpred, booleantype *jcurPtr, 
+                     N_Vector vtemp1, N_Vector vtemp2, N_Vector vtemp3); 
+
+    int (*cv_lsolve)(struct CVodeMemRec *cv_mem, N_Vector b, N_Vector weight,
+                     N_Vector ycur, N_Vector fcur);
+
+    void (*cv_lfree)(struct CVodeMemRec *cv_mem);
+
+    /* Linear Solver specific memory */
+
+    void *cv_lmem;           
+
+    /* Flag to request a call to the setup routine */
+
+    booleantype cv_forceSetup;
+
+    /*------------
+      Saved Values
+      ------------*/
+
+    int cv_qu;             /* last successful q value used                        */
+    long int cv_nstlp;     /* step number of last setup call                      */
+    realtype cv_h0u;       /* actual initial stepsize                             */
+    realtype cv_hu;        /* last successful h value used                        */
+    realtype cv_saved_tq5; /* saved value of tq[5]                                */
+    booleantype cv_jcur;   /* Is the Jacobian info used by linear solver current? */
+    realtype cv_tolsf;     /* tolerance scale factor                              */
+    int cv_qmax_alloc;     /* value of qmax used when allocating memory           */
+    int cv_qmax_allocQ;    /* value of qmax used when allocating quad. memory     */
+    int cv_qmax_allocS;    /* value of qmax used when allocating sensi. memory    */
+    int cv_indx_acor;      /* index of the zn vector in which acor is saved       */
+    booleantype cv_setupNonNull; /* Does setup do something?                      */
+
+    /*--------------------------------------------------------------------
+      Flags turned ON by CVodeMalloc, CVodeSensMalloc, and CVodeQuadMalloc 
+      and read by CVodeReInit, CVodeSensReInit, and CVodeQuadReInit
+      --------------------------------------------------------------------*/
+
+    booleantype cv_VabstolMallocDone;
+    booleantype cv_MallocDone;
+
+    booleantype cv_VabstolQMallocDone;
+    booleantype cv_quadMallocDone;
+
+    booleantype cv_VabstolSMallocDone;
+    booleantype cv_SabstolSMallocDone;
+    booleantype cv_sensMallocDone;
+
+    /*-------------------------------------------
+      Error handler function and error ouput file 
+      -------------------------------------------*/
+
+    CVErrHandlerFn cv_ehfun;    /* Error messages are handled by ehfun       */
+    void *cv_eh_data;           /* user pointer passed to ehfun              */
+    FILE *cv_errfp;             /* CVODES error messages are sent to errfp   */    
+
+    /*-------------------------
+      Stability Limit Detection
+      -------------------------*/
+
+    booleantype cv_sldeton;     /* Is Stability Limit Detection on?          */
+    realtype cv_ssdat[6][4];    /* scaled data array for STALD               */
+    int cv_nscon;               /* counter for STALD method                  */
+    long int cv_nor;            /* counter for number of order reductions    */
+
+    /*----------------
+      Rootfinding Data
+      ----------------*/
+
+    CVRootFn cv_gfun;     /* Function g for roots sought                     */
+    int cv_nrtfn;         /* number of components of g                       */
+    void *cv_g_data;      /* pointer to user data for g                      */
+    int *cv_iroots;       /* int array for root information                  */
+    realtype cv_tlo;      /* nearest endpoint of interval in root search     */
+    realtype cv_thi;      /* farthest endpoint of interval in root search    */
+    realtype cv_trout;    /* t value returned by rootfinding routine         */
+    realtype *cv_glo;     /* saved array of g values at t = tlo              */
+    realtype *cv_ghi;     /* saved array of g values at t = thi              */
+    realtype *cv_grout;   /* array of g values at t = trout                  */
+    realtype cv_toutc;    /* copy of tout (if NORMAL mode)                   */
+    realtype cv_ttol;     /* tolerance on root location trout                */
+    int cv_taskc;         /* copy of parameter task                          */
+    int cv_irfnd;         /* flag showing whether last step had a root       */
+    long int cv_nge;      /* counter for g evaluations                       */
+
+  } *CVodeMem;
+
+
+  /* 
+   * =================================================================
+   *   A D J O I N T   M O D U L E    M E M O R Y    B L O C K
+   * =================================================================
+   */
+
+  /*
+   * -----------------------------------------------------------------
+   * Forward references for pointers to various structures 
+   * -----------------------------------------------------------------
+   */
+
+  typedef struct CVadjMemRec *CVadjMem;
+  typedef struct CkpntMemRec *CkpntMem;
+  typedef struct DtpntMemRec *DtpntMem;
+
+  /*
+   * -----------------------------------------------------------------
+   * Types for functions provided by an interpolation module
+   * -----------------------------------------------------------------
+   * CVAGetYFn:   Function type for a function that returns the 
+   *              interpolated forward solution.
+   * CVAStorePnt: Function type for a function that stores a new
+   *              point in the structure d
+   * -----------------------------------------------------------------
+   */
+
+  typedef int (*CVAGetYFn)(CVadjMem ca_mem, realtype t, N_Vector y);
+  typedef int (*CVAStorePntFn)(CVodeMem cv_mem, DtpntMem d);
+
+  /*
+   * -----------------------------------------------------------------
+   * Types : struct CkpntMemRec, CkpntMem
+   * -----------------------------------------------------------------
+   * The type CkpntMem is type pointer to struct CkpntMemRec.
+   * This structure contains fields to store all information at a
+   * check point that is needed to 'hot' start cvodes.
+   * -----------------------------------------------------------------
+   */
+
+  struct CkpntMemRec {
+
+    /* Integration limits */
+    realtype ck_t0;
+    realtype ck_t1;
+    
+    /* Nordsieck History Array */
+    N_Vector ck_zn[L_MAX];
+    
+    /* Nordsieck History Array for quadratures */
+    N_Vector ck_znQ[L_MAX];
+    
+    /* Do we need to carry quadratures? */
+    booleantype ck_quadr;
+    
+    /* Was ck_zn[qmax] allocated?
+       ck_zqm = 0    - no
+       ck_zqm = qmax - yes      */
+    int ck_zqm;
+    
+    /* Step data */
+    long int ck_nst;
+    realtype ck_tretlast;
+    int      ck_q;
+    int      ck_qprime;
+    int      ck_qwait;
+    int      ck_L;
+    realtype ck_gammap;
+    realtype ck_h;
+    realtype ck_hprime;
+    realtype ck_hscale;
+    realtype ck_eta;
+    realtype ck_etamax;
+    realtype ck_tau[L_MAX+1];
+    realtype ck_tq[NUM_TESTS+1];
+    realtype ck_l[L_MAX];
+    
+    /* Saved values */
+    realtype ck_saved_tq5;
+    
+    /* Pointer to next structure in list */
+    struct CkpntMemRec *ck_next;
+    
+  };
+  
+  /*
+   * -----------------------------------------------------------------
+   * Type : struct DtpntMemRec
+   * -----------------------------------------------------------------
+   * This structure contains fields to store all information at a
+   * data point that is needed to interpolate solution of forward
+   * simulations. Its content field is interpType-dependent.
+   * -----------------------------------------------------------------
+   */
+  
+  struct DtpntMemRec {
+    realtype t;    /* time */
+    void *content; /* interpType-dependent content */
+  };
+
+  /* Data for cubic Hermite interpolation */
+  typedef struct HermiteDataMemRec {
+    N_Vector y;
+    N_Vector yd;
+  } *HermiteDataMem;
+
+  /* Data for polynomial interpolation */
+  typedef struct PolynomialDataMemRec {
+    N_Vector y;
+    int order;
+  } *PolynomialDataMem;
+
+  /*
+   * -----------------------------------------------------------------
+   * Type : struct CVadjMemRec
+   * -----------------------------------------------------------------
+   * The type CVadjMem is type pointer to struct CVadjMemRec.
+   * This structure contins fields to store all information
+   * necessary for adjoint sensitivity analysis.
+   * -----------------------------------------------------------------
+   */
+
+  struct CVadjMemRec {
+    
+    /* CVODE memory for forward runs */
+    struct CVodeMemRec *cv_mem;
+    
+    /* CVODE memory for backward run */
+    struct CVodeMemRec *cvb_mem;
+    
+    /* Storage for check point information */
+    struct CkpntMemRec *ck_mem;
+
+    /* Interpolation type */
+    int ca_interpType;
+
+    /* Storage for data from forward runs */
+    struct DtpntMemRec **dt_mem;
+    
+    /* Functions set by the interpolation module */
+    CVAStorePntFn ca_storePnt; /* store a new interpolation point */
+    CVAGetYFn     ca_getY;     /* interpolate forward solution    */
+    
+    /* Right hand side function (fB) for backward run */
+    CVRhsFnB ca_fB;
+    
+    /* Right hand side quadrature function (fQB) for backward run */
+    CVQuadRhsFnB ca_fQB;
+
+    /* User f_dataB */
+    void *ca_f_dataB;
+    
+    /* User fQ_dataB */
+    void *ca_fQ_dataB;
+    
+    /* Memory block for a linear solver's interface to CVODEA */
+    void *ca_lmemB;
+
+    /* Function to free any memory allocated by the linear solver */
+    void (*ca_lfreeB)(CVadjMem ca_mem);
+
+    /* Memory block for a preconditioner's module interface to CVODEA */ 
+    void *ca_pmemB;
+    
+    /* Unit roundoff */
+    realtype ca_uround;
+    
+    /* Integration interval */
+    realtype ca_tinitial, ca_tfinal;
+    
+    /* Time at which to extract quadratures */
+    realtype ca_t_for_quad;
+    
+    /* Number of check points */
+    int ca_nckpnts;
+    
+    /* Number of steps between 2 check points */
+    long int ca_nsteps;
+    
+    /* Flag to indicate that data in dt_mem is new */
+    booleantype ca_newData;
+    
+    /* address of the check point structure for which data is available */
+    struct CkpntMemRec *ca_ckpntData;
+    
+    /* Actual number of data points saved in current dt_mem */
+    /* Commonly, np = nsteps+1                              */
+    long int ca_np;
+    
+    /* Workspace used by the Hermite interpolation */
+    N_Vector ca_Y0, ca_Y1;    /* pointers to zn[0] and zn[1] */
+
+    /* Workspace for polynomial interpolation */
+    N_Vector ca_Y[L_MAX];     /* pointers to zn[i] */
+    realtype ca_T[L_MAX];
+
+    /* Workspace for wrapper functions */
+    N_Vector ca_ytmp;
+    
+  };
+  
+
+  /*
+   * =================================================================
+   *     I N T E R F A C E   T O    L I N E A R   S O L V E R S
+   * =================================================================
+   */
+
+  /*
+   * -----------------------------------------------------------------
+   * Communication between CVODE and a CVODE Linear Solver
+   * -----------------------------------------------------------------
+   * convfail (input to cv_lsetup)
+   *
+   * CV_NO_FAILURES : Either this is the first cv_setup call for this
+   *                  step, or the local error test failed on the
+   *                  previous attempt at this step (but the Newton
+   *                  iteration converged).
+   *
+   * CV_FAIL_BAD_J  : This value is passed to cv_lsetup if
+   *
+   *                  (a) The previous Newton corrector iteration
+   *                      did not converge and the linear solver's
+   *                      setup routine indicated that its Jacobian-
+   *                      related data is not current
+   *                                   or
+   *                  (b) During the previous Newton corrector
+   *                      iteration, the linear solver's solve routine
+   *                      failed in a recoverable manner and the
+   *                      linear solver's setup routine indicated that
+   *                      its Jacobian-related data is not current.
+   *
+   * CV_FAIL_OTHER  : During the current internal step try, the
+   *                  previous Newton iteration failed to converge
+   *                  even though the linear solver was using current
+   *                  Jacobian-related data.
+   * -----------------------------------------------------------------
+   */
+
+  /* Constants for convfail (input to cv_lsetup) */
+
+#define CV_NO_FAILURES 0
+#define CV_FAIL_BAD_J  1
+#define CV_FAIL_OTHER  2
+
+  /*
+   * -----------------------------------------------------------------
+   * int (*cv_linit)(CVodeMem cv_mem);
+   * -----------------------------------------------------------------
+   * The purpose of cv_linit is to complete initializations for a
+   * specific linear solver, such as counters and statistics.
+   * An LInitFn should return 0 if it has successfully initialized the
+   * CVODE linear solver and a negative value otherwise.
+   * If an error does occur, an appropriate message should be sent to
+   * the error handler function.
+   * -----------------------------------------------------------------
+   */
+
+  /*
+   * -----------------------------------------------------------------
+   * int (*cv_lsetup)(CVodeMem cv_mem, int convfail, N_Vector ypred,
+   *                 N_Vector fpred, booleantype *jcurPtr,
+   *                 N_Vector vtemp1, N_Vector vtemp2,
+   *                 N_Vector vtemp3);
+   * -----------------------------------------------------------------
+   * The job of cv_lsetup is to prepare the linear solver for
+   * subsequent calls to cv_lsolve. It may recompute Jacobian-
+   * related data is it deems necessary. Its parameters are as
+   * follows:
+   *
+   * cv_mem - problem memory pointer of type CVodeMem. See the
+   *          typedef earlier in this file.
+   *
+   * convfail - a flag to indicate any problem that occurred during
+   *            the solution of the nonlinear equation on the
+   *            current time step for which the linear solver is
+   *            being used. This flag can be used to help decide
+   *            whether the Jacobian data kept by a CVODE linear
+   *            solver needs to be updated or not.
+   *            Its possible values have been documented above.
+   *
+   * ypred - the predicted y vector for the current CVODE internal
+   *         step.
+   *
+   * fpred - f(tn, ypred).
+   *
+   * jcurPtr - a pointer to a boolean to be filled in by cv_lsetup.
+   *           The function should set *jcurPtr=TRUE if its Jacobian
+   *           data is current after the call and should set
+   *           *jcurPtr=FALSE if its Jacobian data is not current.
+   *           Note: If cv_lsetup calls for re-evaluation of
+   *           Jacobian data (based on convfail and CVODE state
+   *           data), it should return *jcurPtr=TRUE always;
+   *           otherwise an infinite loop can result.
+   *
+   * vtemp1 - temporary N_Vector provided for use by cv_lsetup.
+   *
+   * vtemp3 - temporary N_Vector provided for use by cv_lsetup.
+   *
+   * vtemp3 - temporary N_Vector provided for use by cv_lsetup.
+   *
+   * The cv_lsetup routine should return 0 if successful, a positive
+   * value for a recoverable error, and a negative value for an
+   * unrecoverable error.
+   * -----------------------------------------------------------------
+   */
+
+  /*
+   * -----------------------------------------------------------------
+   * int (*cv_lsolve)(CVodeMem cv_mem, N_Vector b, N_Vector weight,
+   *                  N_Vector ycur, N_Vector fcur);
+   * -----------------------------------------------------------------
+   * cv_lsolve must solve the linear equation P x = b, where
+   * P is some approximation to (I - gamma J), J = (df/dy)(tn,ycur)
+   * and the RHS vector b is input. The N-vector ycur contains
+   * the solver's current approximation to y(tn) and the vector
+   * fcur contains the N_Vector f(tn,ycur). The solution is to be
+   * returned in the vector b. cv_lsolve returns a positive value
+   * for a recoverable error and a negative value for an
+   * unrecoverable error. Success is indicated by a 0 return value.
+   * -----------------------------------------------------------------
+   */
+
+  /*
+   * -----------------------------------------------------------------
+   * void (*cv_lfree)(CVodeMem cv_mem);
+   * -----------------------------------------------------------------
+   * cv_lfree should free up any memory allocated by the linear
+   * solver. This routine is called once a problem has been
+   * completed and the linear solver is no longer needed.
+   * -----------------------------------------------------------------
+   */
+
+  /*
+   * =================================================================
+   *   C V O D E S    I N T E R N A L   F U N C T I O N S
+   * =================================================================
+   */
+  
+  /* Prototype of internal ewtSet function */
+
+  int CVEwtSet(N_Vector ycur, N_Vector weight, void *e_data);
+
+  /* High level error handler */
+
+  void CVProcessError(CVodeMem cv_mem, 
+                      int error_code, const char *module, const char *fname, 
+                      const char *msgfmt, ...);
+
+  /* Prototype of internal errHandler function */
+
+  void CVErrHandler(int error_code, const char *module, const char *function, 
+                    char *msg, void *eh_data);
+
+  /* Prototypes for internal sensitivity rhs DQ functions */
+
+  int CVSensRhsDQ(int Ns, realtype t, 
+                  N_Vector y, N_Vector ydot, 
+                  N_Vector *yS, N_Vector *ySdot, 
+                  void *fS_data,  
+                  N_Vector tempv, N_Vector ftemp);
+
+  int CVSensRhs1DQ(int Ns, realtype t, 
+                   N_Vector y, N_Vector ydot, 
+                   int is, N_Vector yS, N_Vector ySdot, 
+                   void *fS_data,
+                   N_Vector tempv, N_Vector ftemp);
+
+
+  /* 
+   * =================================================================
+   *   C V O D E S    E R R O R    M E S S A G E S
+   * =================================================================
+   */
+
+#if defined(SUNDIALS_EXTENDED_PRECISION)
+
+#define MSG_TIME      "t = %Lg"
+#define MSG_TIME_H    "t = %Lg and h = %Lg"
+#define MSG_TIME_INT  "t = %Lg is not between tcur - hu = %Lg and tcur = %Lg."
+#define MSG_TIME_TOUT "tout = %Lg"
+
+#elif defined(SUNDIALS_DOUBLE_PRECISION)
+
+#define MSG_TIME      "t = %lg"
+#define MSG_TIME_H    "t = %lg and h = %lg"
+#define MSG_TIME_INT  "t = %lg is not between tcur - hu = %lg and tcur = %lg."
+#define MSG_TIME_TOUT "tout = %lg"
+
+#else
+
+#define MSG_TIME      "t = %g"
+#define MSG_TIME_H    "t = %g and h = %g"
+#define MSG_TIME_INT  "t = %g is not between tcur - hu = %g and tcur = %g."
+#define MSG_TIME_TOUT "tout = %g"
+
+#endif
+
+
+/* Initialization and I/O error messages */
+
+#define MSGCV_NO_MEM "cvode_mem = NULL illegal."
+#define MSGCV_CVMEM_FAIL "Allocation of cvode_mem failed."
+#define MSGCV_MEM_FAIL "A memory request failed."
+#define MSGCV_BAD_LMM  "Illegal value for lmm. The legal values are CV_ADAMS and CV_BDF."
+#define MSGCV_BAD_ITER  "Illegal value for iter. The legal values are CV_FUNCTIONAL and CV_NEWTON."
+#define MSGCV_BAD_ITOL "Illegal value for itol. The legal values are CV_SS, CV_SV, and CV_WF."
+#define MSGCV_NO_MALLOC "Attempt to call before CVodeMalloc."
+#define MSGCV_NEG_MAXORD "maxord <= 0 illegal."
+#define MSGCV_BAD_MAXORD  "Illegal attempt to increase maximum method order."
+#define MSGCV_NEG_MXSTEPS "mxsteps < 0 illegal."
+#define MSGCV_SET_SLDET  "Attempt to use stability limit detection with the CV_ADAMS method illegal."
+#define MSGCV_NEG_HMIN "hmin < 0 illegal."
+#define MSGCV_NEG_HMAX "hmax < 0 illegal."
+#define MSGCV_BAD_HMIN_HMAX "Inconsistent step size limits: hmin > hmax."
+#define MSGCV_BAD_RELTOL "reltol < 0 illegal."
+#define MSGCV_BAD_ABSTOL "abstol has negative component(s) (illegal)."
+#define MSGCV_NULL_ABSTOL "abstol = NULL illegal."
+#define MSGCV_NULL_Y0 "y0 = NULL illegal."
+#define MSGCV_NULL_F "f = NULL illegal."
+#define MSGCV_NULL_G "g = NULL illegal."
+#define MSGCV_BAD_NVECTOR "A required vector operation is not implemented."
+#define MSGCV_BAD_K "Illegal value for k."
+#define MSGCV_NULL_DKY "dky = NULL illegal."
+#define MSGCV_BAD_T "Illegal value for t." MSG_TIME_INT
+
+#define MSGCV_NO_QUAD  "Illegal attempt to call before calling CVodeQuadMalloc."
+#define MSGCV_BAD_ITOLQ "Illegal value for itolQ. The legal values are CV_SS and CV_SV."
+#define MSGCV_NULL_ABSTOLQ "abstolQ = NULL illegal."
+#define MSGCV_BAD_RELTOLQ "reltolQ < 0 illegal."
+#define MSGCV_BAD_ABSTOLQ "abstolQ has negative component(s) (illegal)."  
+
+#define MSGCV_NO_SENSI  "Illegal attempt to call before calling CVodeSensMalloc."
+#define MSGCV_BAD_ITOLS "Illegal value for itolS. The legal values are CV_SS, CV_SV, and CV_EE."
+#define MSGCV_NULL_ABSTOLS "abstolS = NULL illegal."
+#define MSGCV_BAD_RELTOLS "reltolS < 0 illegal."
+#define MSGCV_BAD_ABSTOLS "abstolS has negative component(s) (illegal)."  
+#define MSGCV_BAD_PBAR "pbar has zero component(s) (illegal)."
+#define MSGCV_BAD_PLIST "plist has negative component(s) (illegal)."
+#define MSGCV_BAD_NS "NS <= 0 illegal."
+#define MSGCV_NULL_YS0 "yS0 = NULL illegal."
+#define MSGCV_BAD_ISM "Illegal value for ism. Legal values are: CV_SIMULTANEOUS, CV_STAGGERED and CV_STAGGERED1."
+#define MSGCV_BAD_IS "Illegal value for is."
+#define MSGCV_NULL_DKYA "dkyA = NULL illegal."
+#define MSGCV_BAD_DQTYPE "Illegal value for DQtype. Legal values are: CV_CENTERED and CV_FORWARD."
+#define MSGCV_BAD_DQRHO "DQrhomax < 0 illegal."
+
+/* CVode Error Messages */
+
+#define MSGCV_LSOLVE_NULL "The linear solver's solve routine is NULL."
+#define MSGCV_YOUT_NULL "yout = NULL illegal."
+#define MSGCV_TRET_NULL "tret = NULL illegal."
+#define MSGCV_BAD_EWT "Initial ewt has component(s) equal to zero (illegal)."
+#define MSGCV_EWT_NOW_BAD "At " MSG_TIME ", a component of ewt has become <= 0."
+#define MSGCV_BAD_ITASK "Illegal value for itask."
+#define MSGCV_BAD_H0 "h0 and tout - t0 inconsistent."
+#define MSGCV_BAD_INIT_ROOT "Root found at and very near initial t."
+#define MSGCV_BAD_TOUT "Trouble interpolating at " MSG_TIME_TOUT ". tout too far back in direction of integration"
+#define MSGCV_NO_EFUN "itol = CV_WF but no EwtSet function was provided."
+#define MSGCV_NO_TSTOP "itask = CV_NORMAL_TSTOP or itask = CV_ONE_STEP_TSTOP but tstop was not set."
+#define MSGCV_EWT_FAIL "The user-provide EwtSet function failed."
+#define MSGCV_EWT_NOW_FAIL "At " MSG_TIME ", the user-provide EwtSet function failed."
+#define MSGCV_LINIT_FAIL "The linear solver's init routine failed."
+#define MSGCV_HNIL_DONE "The above warning has been issued mxhnil times and will not be issued again for this problem."
+#define MSGCV_TOO_CLOSE "tout too close to t0 to start integration."
+#define MSGCV_MAX_STEPS "At " MSG_TIME ", mxstep steps taken before reaching tout."
+#define MSGCV_TOO_MUCH_ACC "At " MSG_TIME ", too much accuracy requested."
+#define MSGCV_HNIL "Internal " MSG_TIME_H " are such that t + h = t on the next step. The solver will continue anyway."
+#define MSGCV_ERR_FAILS "At " MSG_TIME_H ", the error test failed repeatedly or with |h| = hmin."
+#define MSGCV_CONV_FAILS "At " MSG_TIME_H ", the corrector convergence test failed repeatedly or with |h| = hmin."
+#define MSGCV_SETUP_FAILED "At " MSG_TIME ", the setup routine failed in an unrecoverable manner."
+#define MSGCV_SOLVE_FAILED "At " MSG_TIME ", the solve routine failed in an unrecoverable manner."
+#define MSGCV_RHSFUNC_FAILED "At " MSG_TIME ", the right-hand side routine failed in an unrecoverable manner."
+#define MSGCV_RHSFUNC_UNREC "At " MSG_TIME ", the right-hand side failed in a recoverable manner, but no recovery is possible."
+#define MSGCV_RHSFUNC_REPTD "At " MSG_TIME "repeated recoverable right-hand side function errors."
+#define MSGCV_RHSFUNC_FIRST "The right-hand side routine failed at the first call."
+#define MSGCV_RTFUNC_FAILED "At " MSG_TIME ", the rootfinding routine failed in an unrecoverable manner."
+#define MSGCV_CLOSE_ROOTS "Root found at and very near " MSG_TIME "."
+#define MSGCV_BAD_TSTOP "tstop is behind current " MSG_TIME "in the direction of integration."
+
+#define MSGCV_BAD_EWTQ "Initial ewtQ has component(s) equal to zero (illegal)."
+#define MSGCV_EWTQ_NOW_BAD "At " MSG_TIME ", a component of ewtQ has become <= 0."
+#define MSGCV_QRHSFUNC_FAILED "At " MSG_TIME ", the quadrature right-hand side routine failed in an unrecoverable manner."
+#define MSGCV_QRHSFUNC_UNREC "At " MSG_TIME ", the quadrature right-hand side failed in a recoverable manner, but no recovery is possible."
+#define MSGCV_QRHSFUNC_REPTD "At " MSG_TIME "repeated recoverable quadrature right-hand side function errors."
+#define MSGCV_QRHSFUNC_FIRST "The quadrature right-hand side routine failed at the first call."
+
+#define MSGCV_BAD_ISM_IFS "Illegal sens. rhs for ism = CV_STAGGERED1."
+#define MSGCV_NULL_P "p = NULL when using internal DQ for sensitivity RHS illegal."
+#define MSGCV_BAD_EWTS "Initial ewtS has component(s) equal to zero (illegal)."
+#define MSGCV_EWTS_NOW_BAD "At " MSG_TIME ", a component of ewtS has become <= 0."
+#define MSGCV_SRHSFUNC_FAILED "At " MSG_TIME ", the sensitivity right-hand side routine failed in an unrecoverable manner."
+#define MSGCV_SRHSFUNC_UNREC "At " MSG_TIME ", the sensitivity right-hand side failed in a recoverable manner, but no recovery is possible."
+#define MSGCV_SRHSFUNC_REPTD "At " MSG_TIME "repeated recoverable sensitivity right-hand side function errors."
+#define MSGCV_SRHSFUNC_FIRST "The sensitivity right-hand side routine failed at the first call."
+
+  /* 
+   * =================================================================
+   *   C V O D E A    E R R O R    M E S S A G E S
+   * =================================================================
+   */
+
+#define MSGAM_NULL_CVMEM   "cvode_mem = NULL illegal."
+#define MSGAM_NULL_CAMEM   "cvadj_mem = NULL illegal."
+#define MSGAM_BAD_STEPS    "Steps nonpositive illegal."
+#define MSGAM_MEM_FAIL     "A memory request failed."
+#define MSGAM_BAD_INTERP   "Illegal value for interp."
+#define MSGAM_BAD_ITASKB   "Illegal value for itaskB. Legal values are CV_NORMAL and CV_ONE_STEP."
+#define MSGAM_BAD_TB0      "The initial time tB0 is outside the interval over which the forward problem was solved."
+#define MSGAM_BAD_TBOUT    "The final time tBout is outside the interval over which the forward problem was solved."
+#define MSGAM_BAD_T        "Bad t for interpolation."
+#define MSGAM_WRONG_INTERP "This function cannot be called for the specified interp type."
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_io.c b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_io.c
new file mode 100644
index 0000000000000000000000000000000000000000..59c4cde97916f7075dbd260639f056c43b21bbe9
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_io.c	
@@ -0,0 +1,2051 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * -----------------------------------------------------------------
+ * Programmer(s): Alan C. Hindmarsh and Radu Serban @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2005, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This is the implementation file for the optional input and output
+ * functions for the CVODES solver.
+ * -----------------------------------------------------------------
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "cvodes_impl.h"
+
+#include <sundials/sundials_math.h>
+#include <sundials/sundials_types.h>
+
+#define ZERO RCONST(0.0)
+#define ONE  RCONST(1.0)
+
+/* 
+ * =================================================================
+ * CVODES optional input functions
+ * =================================================================
+ */
+
+/* 
+ * Readability constants
+ */
+
+#define lrw   (cv_mem->cv_lrw)
+#define liw   (cv_mem->cv_liw)
+#define lrw1  (cv_mem->cv_lrw1)
+#define liw1  (cv_mem->cv_liw1)
+
+/* 
+ * CVodeSetErrHandlerFn
+ *
+ * Specifies the error handler function
+ */
+
+int CVodeSetErrHandlerFn(void *cvode_mem, CVErrHandlerFn ehfun, void *eh_data)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetErrHandlerFn", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  cv_mem->cv_ehfun = ehfun;
+  cv_mem->cv_eh_data = eh_data;
+
+  return(CV_SUCCESS);
+}
+
+/* 
+ * CVodeSetErrFile
+ *
+ * Specifies the FILE pointer for output (NULL means no messages)
+ */
+
+int CVodeSetErrFile(void *cvode_mem, FILE *errfp)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetErrFile", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  cv_mem->cv_errfp = errfp;
+
+  return(CV_SUCCESS);
+}
+
+/* 
+ * CVodeSetIterType
+ *
+ * Specifies the iteration type (CV_FUNCTIONAL or CV_NEWTON)
+ */
+
+int CVodeSetIterType(void *cvode_mem, int iter)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetIterType", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if ((iter != CV_FUNCTIONAL) && (iter != CV_NEWTON)) {
+    CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetIterType", MSGCV_BAD_ITER);
+    return (CV_ILL_INPUT);
+  }
+
+  cv_mem->cv_iter = iter;
+
+  return(CV_SUCCESS);
+}
+
+/* 
+ * CVodeSetFdata
+ *
+ * Specifies the user data pointer for f
+ */
+
+int CVodeSetFdata(void *cvode_mem, void *f_data)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetFdata", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  cv_mem->cv_f_data = f_data;
+
+  return(CV_SUCCESS);
+}
+
+/* 
+ * CVodeSetMaxOrd
+ *
+ * Specifies the maximum method order
+ */
+
+int CVodeSetMaxOrd(void *cvode_mem, int maxord)
+{
+  CVodeMem cv_mem;
+  int qmax_alloc;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetMaxOrd", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (maxord <= 0) {
+    CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetMaxOrd", MSGCV_NEG_MAXORD);
+    return(CV_ILL_INPUT);
+  }
+  
+  /* Cannot increase maximum order beyond the value that
+     was used when allocating memory */
+  qmax_alloc = cv_mem->cv_qmax_alloc;
+  qmax_alloc = MIN(qmax_alloc, cv_mem->cv_qmax_allocQ);
+  qmax_alloc = MIN(qmax_alloc, cv_mem->cv_qmax_allocS);  
+
+  if (maxord > qmax_alloc) {
+    CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetMaxOrd", MSGCV_BAD_MAXORD);
+    return(CV_ILL_INPUT);
+  }
+
+  cv_mem->cv_qmax = maxord;
+
+  return(CV_SUCCESS);
+}
+
+/* 
+ * CVodeSetMaxNumSteps
+ *
+ * Specifies the maximum number of integration steps
+ */
+
+int CVodeSetMaxNumSteps(void *cvode_mem, long int mxsteps)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetMaxNumSteps", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (mxsteps < 0) {
+    CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetMaxNumSteps", MSGCV_NEG_MXSTEPS);
+    return(CV_ILL_INPUT);
+  }
+
+  /* Passing 0 sets the default */
+  if (mxsteps == 0)
+    cv_mem->cv_mxstep = MXSTEP_DEFAULT;
+  else
+    cv_mem->cv_mxstep = mxsteps;
+
+  return(CV_SUCCESS);
+}
+
+/* 
+ * CVodeSetMaxHnilWarns
+ *
+ * Specifies the maximum number of warnings for small h
+ */
+
+int CVodeSetMaxHnilWarns(void *cvode_mem, int mxhnil)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetMaxHnilWarns", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  cv_mem->cv_mxhnil = mxhnil;
+
+  return(CV_SUCCESS);
+}
+
+/* 
+ *CVodeSetStabLimDet
+ *
+ * Turns on/off the stability limit detection algorithm
+ */
+
+int CVodeSetStabLimDet(void *cvode_mem, booleantype sldet)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetStabLimDet", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if( sldet && (cv_mem->cv_lmm != CV_BDF) ) {
+    CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetStabLimDet", MSGCV_SET_SLDET);
+    return(CV_ILL_INPUT);
+  }
+
+  cv_mem->cv_sldeton = sldet;
+
+  return(CV_SUCCESS);
+}
+
+/* 
+ * CVodeSetInitStep
+ *
+ * Specifies the initial step size
+ */
+
+int CVodeSetInitStep(void *cvode_mem, realtype hin)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetInitStep", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  cv_mem->cv_hin = hin;
+
+  return(CV_SUCCESS);
+}
+
+/* 
+ * CVodeSetMinStep
+ *
+ * Specifies the minimum step size
+ */
+
+int CVodeSetMinStep(void *cvode_mem, realtype hmin)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetMinStep", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (hmin<0) {
+    CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetMinStep", MSGCV_NEG_HMIN);
+    return(CV_ILL_INPUT);
+  }
+
+  /* Passing 0 sets hmin = zero */
+  if (hmin == ZERO) {
+    cv_mem->cv_hmin = HMIN_DEFAULT;
+    return(CV_SUCCESS);
+  }
+
+  if (hmin * cv_mem->cv_hmax_inv > ONE) {
+    CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetMinStep", MSGCV_BAD_HMIN_HMAX);
+    return(CV_ILL_INPUT);
+  }
+
+  cv_mem->cv_hmin = hmin;
+
+  return(CV_SUCCESS);
+}
+
+/* 
+ * CVodeSetMaxStep
+ *
+ * Specifies the maximum step size
+ */
+
+int CVodeSetMaxStep(void *cvode_mem, realtype hmax)
+{
+  realtype hmax_inv;
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetMaxStep", MSGCV_NO_MEM);
+    return (CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (hmax < 0) {
+    CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetMaxStep", MSGCV_NEG_HMAX);
+    return(CV_ILL_INPUT);
+  }
+
+  /* Passing 0 sets hmax = infinity */
+  if (hmax == ZERO) {
+    cv_mem->cv_hmax_inv = HMAX_INV_DEFAULT;
+    return(CV_SUCCESS);
+  }
+
+  hmax_inv = ONE/hmax;
+  if (hmax_inv * cv_mem->cv_hmin > ONE) {
+    CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetMaxStep", MSGCV_BAD_HMIN_HMAX);
+    return(CV_ILL_INPUT);
+  }
+
+  cv_mem->cv_hmax_inv = hmax_inv;
+
+  return(CV_SUCCESS);
+}
+
+/* 
+ * CVodeSetStopTime
+ *
+ * Specifies the time beyond which the integration is not to
+ * proceed
+ */
+
+int CVodeSetStopTime(void *cvode_mem, realtype tstop)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetStopTime", MSGCV_NO_MEM);
+    return (CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  cv_mem->cv_tstop = tstop;
+  cv_mem->cv_tstopset = TRUE;
+
+  return(CV_SUCCESS);
+}
+
+/* 
+ * CVodeSetMaxErrTestFails
+ *
+ * Specifies the maximum number of error test failures during one
+ * step try.
+ */
+
+int CVodeSetMaxErrTestFails(void *cvode_mem, int maxnef)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetMaxErrTestFails", MSGCV_NO_MEM);
+    return (CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  cv_mem->cv_maxnef = maxnef;
+
+  return(CV_SUCCESS);
+}
+
+/* 
+ * CVodeSetMaxConvFails
+ *
+ * Specifies the maximum number of nonlinear convergence failures 
+ * during one step try.
+ */
+
+int CVodeSetMaxConvFails(void *cvode_mem, int maxncf)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetMaxConvFails", MSGCV_NO_MEM);
+    return (CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  cv_mem->cv_maxncf = maxncf;
+
+  return(CV_SUCCESS);
+}
+
+/* 
+ * CVodeSetMaxNonlinIters
+ *
+ * Specifies the maximum number of nonlinear iterations during
+ * one solve.
+ */
+
+int CVodeSetMaxNonlinIters(void *cvode_mem, int maxcor)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetMaxNonlinIters", MSGCV_NO_MEM);
+    return (CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  cv_mem->cv_maxcor = maxcor;
+
+  return(CV_SUCCESS);
+}
+
+/* 
+ * CVodeSetNonlinConvCoef
+ *
+ * Specifies the coeficient in the nonlinear solver convergence
+ * test
+ */
+
+int CVodeSetNonlinConvCoef(void *cvode_mem, realtype nlscoef)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetNonlinConvCoef", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  cv_mem->cv_nlscoef = nlscoef;
+
+  return(CV_SUCCESS);
+}
+
+/*
+ * CVodeSetTolerances
+ *
+ * Changes the integration tolerances between calls to CVode()
+ */
+
+int CVodeSetTolerances(void *cvode_mem, 
+                       int itol, realtype reltol, void *abstol)
+{
+  CVodeMem cv_mem;
+  booleantype neg_abstol;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetTolerances", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  /* Check if cvode_mem was allocated */
+
+  if (cv_mem->cv_MallocDone == FALSE) {
+    CVProcessError(cv_mem, CV_NO_MALLOC, "CVODES", "CVodeSetTolerances", MSGCV_NO_MALLOC);
+    return(CV_NO_MALLOC);
+  }
+
+  /* Check inputs */
+
+  if ( (itol != CV_SS) && (itol != CV_SV) ) {
+    CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetTolerances", MSGCV_BAD_ITOL);
+    return(CV_ILL_INPUT);
+  }
+
+  if (abstol == NULL) {
+    CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetTolerances", MSGCV_NULL_ABSTOL);
+    return(CV_ILL_INPUT);
+  }
+
+  if (reltol < ZERO) {
+    CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetTolerances", MSGCV_BAD_RELTOL);
+    return(CV_ILL_INPUT);
+  }
+
+  if (itol == CV_SS)
+    neg_abstol = (*((realtype *)abstol) < ZERO);
+  else
+    neg_abstol = (N_VMin((N_Vector)abstol) < ZERO);
+    
+  if (neg_abstol) {
+    CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetTolerances", MSGCV_BAD_ABSTOL);
+    return(CV_ILL_INPUT);
+  }
+
+  /* Copy tolerances into memory */
+
+  if ( (itol != CV_SV) && (cv_mem->cv_VabstolMallocDone) ) {
+    N_VDestroy(cv_mem->cv_Vabstol);
+    lrw -= lrw1;
+    liw -= liw1;
+    cv_mem->cv_VabstolMallocDone = FALSE;
+  }
+
+  if ( (itol == CV_SV) && !(cv_mem->cv_VabstolMallocDone) ) {
+    cv_mem->cv_Vabstol = NULL;
+    cv_mem->cv_Vabstol = N_VClone(cv_mem->cv_ewt);
+    lrw += lrw1;
+    liw += liw1;
+    cv_mem->cv_VabstolMallocDone = TRUE;
+  }
+
+  cv_mem->cv_itol   = itol;
+  cv_mem->cv_reltol = reltol;
+  if (itol == CV_SS)
+    cv_mem->cv_Sabstol = *((realtype *)abstol);
+  else
+    N_VScale(ONE, (N_Vector)abstol, cv_mem->cv_Vabstol);
+
+  cv_mem->cv_efun = CVEwtSet;
+  cv_mem->cv_e_data = cvode_mem;
+
+
+  return(CV_SUCCESS);
+}
+
+/* 
+ * CVodeSetEwtFn
+ *
+ * Specifies the user-provide EwtSet function and data pointer for e
+ */
+
+int CVodeSetEwtFn(void *cvode_mem, CVEwtFn efun, void *e_data)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetEwtFn", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if ( cv_mem->cv_VabstolMallocDone ) {
+    N_VDestroy(cv_mem->cv_Vabstol);
+    lrw -= lrw1;
+    liw -= liw1;
+    cv_mem->cv_VabstolMallocDone = FALSE;
+  }
+
+  cv_mem->cv_itol = CV_WF;
+  cv_mem->cv_efun = efun;
+  cv_mem->cv_e_data = e_data;
+
+  return(CV_SUCCESS);
+}
+
+
+/* 
+ * =================================================================
+ * Quadrature optional input functions
+ * =================================================================
+ */
+
+/* 
+ * Readability constants
+ */
+
+#define lrw1Q (cv_mem->cv_lrw1Q)
+#define liw1Q (cv_mem->cv_liw1Q)
+
+/*-----------------------------------------------------------------*/
+
+int CVodeSetQuadFdata(void *cvode_mem, void *fQ_data)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetQuadFdata", MSGCV_NO_MEM);    
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  cv_mem->cv_fQ_data = fQ_data;
+
+  return(CV_SUCCESS);
+}
+
+/*-----------------------------------------------------------------*/
+
+int CVodeSetQuadErrCon(void *cvode_mem, booleantype errconQ, 
+                       int itolQ, realtype reltolQ, void *abstolQ)
+{
+  CVodeMem cv_mem;
+  booleantype neg_abstol;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetQuadErrCon", MSGCV_NO_MEM);    
+    return(CV_MEM_NULL);
+  }
+  
+  cv_mem = (CVodeMem) cvode_mem;
+
+  cv_mem->cv_errconQ = errconQ;
+
+  /* Ckeck if quadrature was initialized? */
+
+  if (cv_mem->cv_quadMallocDone == FALSE) {
+    CVProcessError(cv_mem, CV_NO_QUAD, "CVODES", "CVodeSetQuadErrCon", MSGCV_NO_QUAD); 
+    return(CV_NO_QUAD);
+  }
+
+  /* Check inputs */
+
+  if(errconQ == FALSE) {
+    if (cv_mem->cv_VabstolQMallocDone) {
+      N_VDestroy(cv_mem->cv_VabstolQ);
+      lrw -= lrw1Q;
+      liw -= liw1Q;
+      cv_mem->cv_VabstolQMallocDone = FALSE;
+    }
+    return(CV_SUCCESS);
+  }
+  
+  if ((itolQ != CV_SS) && (itolQ != CV_SV)) {
+    CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetQuadErrCon", MSGCV_BAD_ITOLQ);
+    return(CV_ILL_INPUT);
+  }
+
+  if (abstolQ == NULL) {
+    CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetQuadErrCon", MSGCV_NULL_ABSTOLQ);
+    return(CV_ILL_INPUT);
+  }
+
+  if (reltolQ < ZERO) {
+    CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetQuadErrCon", MSGCV_BAD_RELTOLQ);
+    return(CV_ILL_INPUT);
+  }
+
+  if (itolQ == CV_SS)
+    neg_abstol = (*((realtype *)abstolQ) < ZERO);
+  else
+    neg_abstol = (N_VMin((N_Vector)abstolQ) < ZERO);
+
+  if (neg_abstol) {
+    CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetQuadErrCon", MSGCV_BAD_ABSTOLQ);
+    return(CV_ILL_INPUT);
+  }
+
+  /* See if we need to free or allocate memory */
+
+  if ( (itolQ != CV_SV) && (cv_mem->cv_VabstolQMallocDone) ) {
+    N_VDestroy(cv_mem->cv_VabstolQ);
+    lrw -= lrw1Q;
+    liw -= liw1Q;
+    cv_mem->cv_VabstolQMallocDone = FALSE;
+  }
+
+  if ( (itolQ == CV_SV) && !(cv_mem->cv_VabstolQMallocDone) ) {
+    cv_mem->cv_VabstolQ = NULL;
+    cv_mem->cv_VabstolQ = N_VClone(cv_mem->cv_tempvQ);
+    lrw += lrw1Q;
+    liw += liw1Q;
+    cv_mem->cv_VabstolQMallocDone = TRUE;
+  }
+
+  /* Copy tolerances into memory */
+
+  cv_mem->cv_itolQ    = itolQ;
+  cv_mem->cv_reltolQ  = reltolQ;
+
+  if (itolQ == CV_SS)
+    cv_mem->cv_SabstolQ = *((realtype *)abstolQ);
+  else
+    N_VScale(ONE, (N_Vector)abstolQ, cv_mem->cv_VabstolQ);
+  
+  return(CV_SUCCESS);
+}
+
+/* 
+ * =================================================================
+ * FSA optional input functions
+ * =================================================================
+ */
+
+
+int CVodeSetSensRhsFn(void *cvode_mem, CVSensRhsFn fS, void *fS_data)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetSensRhsFn", MSGCV_NO_MEM);    
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (fS != NULL) {
+    cv_mem->cv_ifS  = CV_ALLSENS;
+    cv_mem->cv_fS      = fS;
+    cv_mem->cv_fS_data = fS_data;
+    cv_mem->cv_fSDQ    = FALSE;
+  } else {
+    cv_mem->cv_fSDQ    = TRUE;
+  }
+
+  return(CV_SUCCESS);
+}
+
+/*-----------------------------------------------------------------*/
+
+int CVodeSetSensRhs1Fn(void *cvode_mem, CVSensRhs1Fn fS1, void *fS_data)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetSensRhs1Fn", MSGCV_NO_MEM);    
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+  
+  if(fS1 != NULL) {
+    cv_mem->cv_ifS  = CV_ONESENS;
+    cv_mem->cv_fS1     = fS1;
+    cv_mem->cv_fS_data = fS_data;
+    cv_mem->cv_fSDQ    = FALSE;
+  } else {
+    cv_mem->cv_fSDQ    = TRUE;
+  }
+
+  return(CV_SUCCESS);
+}
+
+/*-----------------------------------------------------------------*/
+
+int CVodeSetSensDQMethod(void *cvode_mem, int DQtype, realtype DQrhomax)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetSensDQMethod", MSGCV_NO_MEM);    
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if ( (DQtype != CV_CENTERED) && (DQtype != CV_FORWARD) ) {
+    CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetSensDQMethod", MSGCV_BAD_DQTYPE);    
+    return(CV_ILL_INPUT);
+  }
+
+  if (DQrhomax < ZERO ) {
+    CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetSensDQMethod", MSGCV_BAD_DQRHO);    
+    return(CV_ILL_INPUT);
+  }
+
+  cv_mem->cv_DQtype = DQtype;
+  cv_mem->cv_DQrhomax = DQrhomax;
+
+  return(CV_SUCCESS);
+}
+
+/*-----------------------------------------------------------------*/
+
+int CVodeSetSensErrCon(void *cvode_mem, booleantype errconS)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetSensErrCon", MSGCV_NO_MEM);    
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  cv_mem->cv_errconS = errconS;
+
+  return(CV_SUCCESS);
+}
+
+/*-----------------------------------------------------------------*/
+
+int CVodeSetSensMaxNonlinIters(void *cvode_mem, int maxcorS)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetSensMaxNonlinIters", MSGCV_NO_MEM);    
+    return (CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  cv_mem->cv_maxcorS = maxcorS;
+
+  return(CV_SUCCESS);
+}
+
+/*-----------------------------------------------------------------*/
+
+int CVodeSetSensParams(void *cvode_mem, realtype *p, realtype *pbar, int *plist)
+{
+  CVodeMem cv_mem;
+  int is, Ns;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetSensParams", MSGCV_NO_MEM);    
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  /* Was sensitivity initialized? */
+
+  if (cv_mem->cv_sensMallocDone == FALSE) {
+    CVProcessError(cv_mem, CV_NO_SENS, "CVODES", "CVodeSetSensParams", MSGCV_NO_SENSI);
+    return(CV_NO_SENS);
+  }
+
+  Ns = cv_mem->cv_Ns;
+
+  /* Parameters */
+
+  cv_mem->cv_p = p;
+
+  /* pbar */
+
+  if (pbar != NULL)
+    for (is=0; is<Ns; is++) {
+      if (pbar[is] == ZERO) {
+        CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetSensParams", MSGCV_BAD_PBAR);
+        return(CV_ILL_INPUT);
+      }
+      cv_mem->cv_pbar[is] = ABS(pbar[is]);
+    }
+  else
+    for (is=0; is<Ns; is++)
+      cv_mem->cv_pbar[is] = ONE;
+
+  /* plist */
+
+  if (plist != NULL)
+    for (is=0; is<Ns; is++) {
+      if ( plist[is] < 0 ) {
+        CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetSensParams", MSGCV_BAD_PLIST);
+        return(CV_ILL_INPUT);
+      }
+      cv_mem->cv_plist[is] = plist[is];
+    }
+  else
+    for (is=0; is<Ns; is++)
+      cv_mem->cv_plist[is] = is;
+
+  return(CV_SUCCESS);
+}
+
+/*-----------------------------------------------------------------*/
+
+int CVodeSetSensTolerances(void *cvode_mem, int itolS,
+                           realtype reltolS, void *abstolS)
+{
+  CVodeMem cv_mem;
+  booleantype neg_abstol;
+  realtype *atolSS;
+  N_Vector *atolSV;
+  int is, Ns;
+
+  atolSS = NULL;
+  atolSV = NULL;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeSetSensTolerances", MSGCV_NO_MEM);    
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  /* Was sensitivity initialized? */
+
+  if (cv_mem->cv_sensMallocDone == FALSE) {
+    CVProcessError(cv_mem, CV_NO_SENS, "CVODES", "CVodeSetSensTolerances", MSGCV_NO_SENSI);
+    return(CV_NO_SENS);
+  } 
+
+  /* Check inputs */
+
+  Ns = cv_mem->cv_Ns;
+
+  if ((itolS != CV_SS) && (itolS != CV_SV) && (itolS != CV_EE)) {
+    CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetSensTolerances", MSGCV_BAD_ITOLS);
+    return(CV_ILL_INPUT);
+  }
+
+  if (itolS != CV_EE) {
+
+    /* Test user-supplied tolerances */
+    
+    if (reltolS < ZERO) {
+      CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetSensTolerances", MSGCV_BAD_RELTOLS);
+      return(CV_ILL_INPUT);
+    }
+
+    if (abstolS == NULL) {
+      CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetSensTolerances", MSGCV_NULL_ABSTOLS);
+      return(CV_ILL_INPUT);
+    }
+
+    neg_abstol = FALSE;
+
+    if (itolS == CV_SS) {
+      atolSS = (realtype *) abstolS;
+      for (is=0; is<Ns; is++)
+        if (atolSS[is] < ZERO) {neg_abstol = TRUE; break;}
+    } else {
+      atolSV = (N_Vector *) abstolS;
+      for (is=0; is<Ns; is++) 
+        if (N_VMin(atolSV[is]) < ZERO) {neg_abstol = TRUE; break;}
+    }
+
+    if (neg_abstol) {
+      CVProcessError(cv_mem, CV_ILL_INPUT, "CVODES", "CVodeSetSensTolerances", MSGCV_BAD_ABSTOLS);
+      return(CV_ILL_INPUT);
+    }
+    
+  }
+
+  /* See if we should release some memory */
+
+  if ( (itolS != CV_SV) && (cv_mem->cv_VabstolSMallocDone) ) {
+    N_VDestroyVectorArray(cv_mem->cv_VabstolS, Ns);
+    lrw -= Ns*lrw1;
+    liw -= Ns*liw1;
+    cv_mem->cv_VabstolSMallocDone = FALSE;
+  }
+
+  if ( (itolS != CV_SS) && (cv_mem->cv_SabstolSMallocDone) ) {
+    free(cv_mem->cv_SabstolS); cv_mem->cv_SabstolS = NULL;
+    lrw -= Ns;
+    cv_mem->cv_SabstolSMallocDone = FALSE;
+  }
+
+  /* If tolerances will be estimated, return now */
+
+  if (itolS == CV_EE) return(CV_SUCCESS);
+
+  /* See if we need to allocate some memory */
+
+  if ( (itolS == CV_SV) && !(cv_mem->cv_VabstolSMallocDone) ) {
+    cv_mem->cv_VabstolS = NULL;
+    cv_mem->cv_VabstolS = N_VCloneVectorArray(Ns, cv_mem->cv_tempv);
+    lrw += Ns*lrw1;
+    liw += Ns*liw1;
+    cv_mem->cv_VabstolSMallocDone = TRUE;
+  }
+
+  if ( (itolS == CV_SS) && !(cv_mem->cv_SabstolSMallocDone) ) {
+    cv_mem->cv_SabstolS = NULL;
+    cv_mem->cv_SabstolS = (realtype *)malloc(Ns*sizeof(realtype));
+    lrw += Ns;
+    cv_mem->cv_SabstolSMallocDone = TRUE;
+  }
+
+  /* Copy tolerances into memory */
+
+  cv_mem->cv_itolS   = itolS;
+  cv_mem->cv_reltolS = reltolS;
+
+  if (itolS == CV_SS)
+    for (is=0; is<Ns; is++)
+      cv_mem->cv_SabstolS[is] = atolSS[is];
+  else
+    for (is=0; is<Ns; is++)    
+      N_VScale(ONE, atolSV[is], cv_mem->cv_VabstolS[is]);
+
+  return(CV_SUCCESS);
+}
+
+/* 
+ * =================================================================
+ * CVODES optional output functions
+ * =================================================================
+ */
+
+/* 
+ * Readability constants
+ */
+
+#define nst            (cv_mem->cv_nst)
+#define nfe            (cv_mem->cv_nfe)
+#define ncfn           (cv_mem->cv_ncfn)
+#define netf           (cv_mem->cv_netf)
+#define nni            (cv_mem->cv_nni)
+#define nsetups        (cv_mem->cv_nsetups)
+#define qu             (cv_mem->cv_qu)
+#define next_q         (cv_mem->cv_next_q)
+#define ewt            (cv_mem->cv_ewt)  
+#define hu             (cv_mem->cv_hu)
+#define next_h         (cv_mem->cv_next_h)
+#define h0u            (cv_mem->cv_h0u)
+#define tolsf          (cv_mem->cv_tolsf)  
+#define acor           (cv_mem->cv_acor)
+#define lrw            (cv_mem->cv_lrw)
+#define liw            (cv_mem->cv_liw)
+#define nge            (cv_mem->cv_nge)
+#define iroots         (cv_mem->cv_iroots)
+#define nor            (cv_mem->cv_nor)
+#define sldeton        (cv_mem->cv_sldeton)
+#define tn             (cv_mem->cv_tn)
+#define efun           (cv_mem->cv_efun)
+#define e_data         (cv_mem->cv_e_data) 
+
+/*
+ * CVodeGetNumSteps
+ *
+ * Returns the current number of integration steps
+ */
+
+int CVodeGetNumSteps(void *cvode_mem, long int *nsteps)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetNumSteps", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  *nsteps = nst;
+
+  return(CV_SUCCESS);
+}
+
+/* 
+ * CVodeGetNumRhsEvals
+ *
+ * Returns the current number of calls to f
+ */
+
+int CVodeGetNumRhsEvals(void *cvode_mem, long int *nfevals)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetNumRhsEvals", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  *nfevals = nfe;
+
+  return(CV_SUCCESS);
+}
+
+/* 
+ * CVodeGetNumLinSolvSetups
+ *
+ * Returns the current number of calls to the linear solver setup routine
+ */
+
+int CVodeGetNumLinSolvSetups(void *cvode_mem, long int *nlinsetups)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetNumLinSolvSetups", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  *nlinsetups = nsetups;
+
+  return(CV_SUCCESS);
+}
+
+/*
+ * CVodeGetNumErrTestFails
+ *
+ * Returns the current number of error test failures
+ */
+
+int CVodeGetNumErrTestFails(void *cvode_mem, long int *netfails)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetNumErrTestFails", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  *netfails = netf;
+
+  return(CV_SUCCESS);
+}
+
+/* 
+ * CVodeGetLastOrder
+ *
+ * Returns the order on the last succesful step
+ */
+
+int CVodeGetLastOrder(void *cvode_mem, int *qlast)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetLastOrder", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  *qlast = qu;
+
+  return(CV_SUCCESS);
+}
+
+/* 
+ * CVodeGetCurrentOrder
+ *
+ * Returns the order to be attempted on the next step
+ */
+
+int CVodeGetCurrentOrder(void *cvode_mem, int *qcur)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetCurrentOrder", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  *qcur = next_q;
+
+  return(CV_SUCCESS);
+}
+
+/* 
+ * CVodeGetNumStabLimOrderReds
+ *
+ * Returns the number of order reductions triggered by the stability
+ * limit detection algorithm
+ */
+
+int CVodeGetNumStabLimOrderReds(void *cvode_mem, long int *nslred)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetNumStabLimOrderReds", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (sldeton==FALSE)
+    *nslred = 0;
+  else
+    *nslred = nor;
+
+  return(CV_SUCCESS);
+}
+
+/* 
+ * CVodeGetActualInitStep
+ *
+ * Returns the step size used on the first step
+ */
+
+int CVodeGetActualInitStep(void *cvode_mem, realtype *hinused)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetActualInitStep", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  *hinused = h0u;
+
+  return(CV_SUCCESS);
+}
+
+/*
+ * CVodeGetLastStep
+ *
+ * Returns the step size used on the last successful step
+ */
+
+int CVodeGetLastStep(void *cvode_mem, realtype *hlast)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetLastStep", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  *hlast = hu;
+
+  return(CV_SUCCESS);
+}
+
+/* 
+ * CVodeGetCurrentStep
+ *
+ * Returns the step size to be attempted on the next step
+ */
+
+int CVodeGetCurrentStep(void *cvode_mem, realtype *hcur)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetCurrentStep", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+  
+  *hcur = next_h;
+
+  return(CV_SUCCESS);
+}
+
+/* 
+ * CVodeGetCurrentTime
+ *
+ * Returns the current value of the independent variable
+ */
+
+int CVodeGetCurrentTime(void *cvode_mem, realtype *tcur)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetCurrentTime", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  *tcur = tn;
+
+  return(CV_SUCCESS);
+}
+
+/* 
+ * CVodeGetTolScaleFactor
+ *
+ * Returns a suggested factor for scaling tolerances
+ */
+
+int CVodeGetTolScaleFactor(void *cvode_mem, realtype *tolsfact)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetTolScaleFactor", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  *tolsfact = tolsf;
+
+  return(CV_SUCCESS);
+}
+
+/* 
+ * CVodeGetErrWeights
+ *
+ * This routine returns the current weight vector.
+ */
+
+int CVodeGetErrWeights(void *cvode_mem, N_Vector eweight)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetErrWeights", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  N_VScale(ONE, ewt, eweight);
+
+  return(CV_SUCCESS);
+}
+
+/*
+ * CVodeGetEstLocalErrors
+ *
+ * Returns an estimate of the local error
+ */
+
+int CVodeGetEstLocalErrors(void *cvode_mem, N_Vector ele)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetEstLocalErrors", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  N_VScale(ONE, acor, ele);
+
+  return(CV_SUCCESS);
+}
+
+/* 
+ * CVodeGetWorkSpace
+ *
+ * Returns integrator work space requirements
+ */
+
+int CVodeGetWorkSpace(void *cvode_mem, long int *lenrw, long int *leniw)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetWorkSpace", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  *leniw = liw;
+  *lenrw = lrw;
+
+  return(CV_SUCCESS);
+}
+
+/* 
+ * CVodeGetIntegratorStats
+ *
+ * Returns integrator statistics
+ */
+
+int CVodeGetIntegratorStats(void *cvode_mem, long int *nsteps, long int *nfevals, 
+                            long int *nlinsetups, long int *netfails, int *qlast, 
+                            int *qcur, realtype *hinused, realtype *hlast, 
+                            realtype *hcur, realtype *tcur)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetIntegratorStats", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  *nsteps = nst;
+  *nfevals = nfe;
+  *nlinsetups = nsetups;
+  *netfails = netf;
+  *qlast = qu;
+  *qcur = next_q;
+  *hinused = h0u;
+  *hlast = hu;
+  *hcur = next_h;
+  *tcur = tn;
+
+  return(CV_SUCCESS);
+}
+
+/* 
+ * CVodeGetNumGEvals
+ *
+ * Returns the current number of calls to g (for rootfinding)
+ */
+
+int CVodeGetNumGEvals(void *cvode_mem, long int *ngevals)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetNumGEvals", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  *ngevals = nge;
+
+  return(CV_SUCCESS);
+}
+
+/* 
+ * CVodeGetRootInfo
+ *
+ * Returns pointer to array rootsfound showing roots found
+ */
+
+int CVodeGetRootInfo(void *cvode_mem, int *rootsfound)
+{
+  CVodeMem cv_mem;
+  int i, nrt;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetRootInfo", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  nrt = cv_mem->cv_nrtfn;
+
+  for (i=0; i<nrt; i++) rootsfound[i] = iroots[i];
+
+  return(CV_SUCCESS);
+}
+
+
+/* 
+ * CVodeGetNumNonlinSolvIters
+ *
+ * Returns the current number of iterations in the nonlinear solver
+ */
+
+int CVodeGetNumNonlinSolvIters(void *cvode_mem, long int *nniters)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetNumNonlinSolvIters", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  *nniters = nni;
+
+  return(CV_SUCCESS);
+}
+
+/* 
+ * CVodeGetNumNonlinSolvConvFails
+ *
+ * Returns the current number of convergence failures in the
+ * nonlinear solver
+ */
+
+int CVodeGetNumNonlinSolvConvFails(void *cvode_mem, long int *nncfails)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetNumNonlinSolvConvFails", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  *nncfails = ncfn;
+
+  return(CV_SUCCESS);
+}
+
+/* 
+ * CVodeGetNonlinSolvStats
+ *
+ * Returns nonlinear solver statistics
+ */
+
+int CVodeGetNonlinSolvStats(void *cvode_mem, long int *nniters, 
+                            long int *nncfails)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetNonlinSolvStats", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  *nniters = nni;
+  *nncfails = ncfn;
+
+  return(CV_SUCCESS);
+}
+
+
+/* 
+ * =================================================================
+ * Quadrature optional output functions
+ * =================================================================
+ */
+
+/* 
+ * Readability constants
+ */
+
+#define quadr          (cv_mem->cv_quadr)
+#define nfQe           (cv_mem->cv_nfQe)
+#define netfQ          (cv_mem->cv_netfQ)
+#define ewtQ           (cv_mem->cv_ewtQ)
+#define errconQ        (cv_mem->cv_errconQ)
+
+/*-----------------------------------------------------------------*/
+
+int CVodeGetQuadNumRhsEvals(void *cvode_mem, long int *nfQevals)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetQuadNumRhsEvals", MSGCV_NO_MEM);    
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (quadr==FALSE) {
+    CVProcessError(cv_mem, CV_NO_QUAD, "CVODES", "CVodeGetQuadNumRhsEvals", MSGCV_NO_QUAD); 
+    return(CV_NO_QUAD);
+  }
+
+  *nfQevals = nfQe;
+
+  return(CV_SUCCESS);
+}
+
+/*-----------------------------------------------------------------*/
+
+int CVodeGetQuadNumErrTestFails(void *cvode_mem, long int *nQetfails)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetQuadNumErrTestFails", MSGCV_NO_MEM);    
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (quadr==FALSE) {
+    CVProcessError(cv_mem, CV_NO_QUAD, "CVODES", "CVodeGetQuadNumErrTestFails", MSGCV_NO_QUAD); 
+    return(CV_NO_QUAD);
+  }
+
+  *nQetfails = netfQ;
+
+  return(CV_SUCCESS);
+}
+
+/*-----------------------------------------------------------------*/
+
+int CVodeGetQuadErrWeights(void *cvode_mem, N_Vector eQweight)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetQuadErrWeights", MSGCV_NO_MEM); 
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (quadr==FALSE) {
+    CVProcessError(cv_mem, CV_NO_QUAD, "CVODES", "CVodeGetQuadErrWeights", MSGCV_NO_QUAD); 
+    return(CV_NO_QUAD);
+  }
+
+  if(errconQ) N_VScale(ONE, ewtQ, eQweight);
+
+  return(CV_SUCCESS);
+}
+
+/*-----------------------------------------------------------------*/
+
+int CVodeGetQuadStats(void *cvode_mem, long int *nfQevals, long int *nQetfails)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetQuadStats", MSGCV_NO_MEM);    
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (quadr==FALSE) {
+    CVProcessError(cv_mem, CV_NO_QUAD, "CVODES", "CVodeGetQuadStats", MSGCV_NO_QUAD); 
+    return(CV_NO_QUAD);
+  }
+
+  *nfQevals = nfQe;
+  *nQetfails = netfQ;
+
+  return(CV_SUCCESS);
+}
+
+/* 
+ * =================================================================
+ * FSA optional output functions
+ * =================================================================
+ */
+
+/* 
+ * Readability constants
+ */
+
+#define sensi          (cv_mem->cv_sensi)
+#define ism            (cv_mem->cv_ism)
+#define ewtS           (cv_mem->cv_ewtS)
+#define nfSe           (cv_mem->cv_nfSe)
+#define nfeS           (cv_mem->cv_nfeS)
+#define nniS           (cv_mem->cv_nniS)
+#define ncfnS          (cv_mem->cv_ncfnS)
+#define netfS          (cv_mem->cv_netfS)
+#define nsetupsS       (cv_mem->cv_nsetupsS)
+#define nniS1          (cv_mem->cv_nniS1)
+#define ncfnS1         (cv_mem->cv_ncfnS1)
+#define ncfS1          (cv_mem->cv_ncfS1)
+
+/*-----------------------------------------------------------------*/
+
+int CVodeGetNumSensRhsEvals(void *cvode_mem, long int *nfSevals)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetNumSensRhsEvals", MSGCV_NO_MEM);    
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (sensi==FALSE) {
+    CVProcessError(cv_mem, CV_NO_SENS, "CVODES", "CVodeGetNumSensRhsEvals", MSGCV_NO_SENSI);
+    return(CV_NO_SENS);
+  }
+
+  *nfSevals = nfSe;
+
+  return(CV_SUCCESS);
+}
+
+/*-----------------------------------------------------------------*/
+
+int CVodeGetNumRhsEvalsSens(void *cvode_mem, long int *nfevalsS)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetNumRhsEvalsSens", MSGCV_NO_MEM);    
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (sensi==FALSE) {
+    CVProcessError(cv_mem, CV_NO_SENS, "CVODES", "CVodeGetNumRhsEvalsSens", MSGCV_NO_SENSI);
+    return(CV_NO_SENS);
+  }
+
+  *nfevalsS = nfeS;
+
+  return(CV_SUCCESS);
+}
+
+/*-----------------------------------------------------------------*/
+
+int CVodeGetNumSensErrTestFails(void *cvode_mem, long int *nSetfails)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetNumSensErrTestFails", MSGCV_NO_MEM);    
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (sensi==FALSE) {
+    CVProcessError(cv_mem, CV_NO_SENS, "CVODES", "CVodeGetNumSensErrTestFails", MSGCV_NO_SENSI);
+    return(CV_NO_SENS);
+  }
+
+  *nSetfails = netfS;
+
+  return(CV_SUCCESS);
+}
+
+/*-----------------------------------------------------------------*/
+
+int CVodeGetNumSensLinSolvSetups(void *cvode_mem, long int *nlinsetupsS)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetNumSensLinSolvSetups", MSGCV_NO_MEM);    
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (sensi==FALSE) {
+    CVProcessError(cv_mem, CV_NO_SENS, "CVODES", "CVodeGetNumSensLinSolvSetups", MSGCV_NO_SENSI);
+    return(CV_NO_SENS);
+  }
+
+  *nlinsetupsS = nsetupsS;
+
+  return(CV_SUCCESS);
+}
+
+/*-----------------------------------------------------------------*/
+
+int CVodeGetSensErrWeights(void *cvode_mem, N_Vector_S eSweight)
+{
+  CVodeMem cv_mem;
+  int is, Ns;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetSensErrWeights", MSGCV_NO_MEM);    
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (sensi==FALSE) {
+    CVProcessError(cv_mem, CV_NO_SENS, "CVODES", "CVodeGetSensErrWeights", MSGCV_NO_SENSI);
+    return(CV_NO_SENS);
+  }
+
+  Ns = cv_mem->cv_Ns;
+
+  for (is=0; is<Ns; is++)
+    N_VScale(ONE, ewtS[is], eSweight[is]);
+
+  return(CV_SUCCESS);
+}
+
+/*-----------------------------------------------------------------*/
+
+int CVodeGetSensStats(void *cvode_mem, long int *nfSevals, long int *nfevalsS, 
+                      long int *nSetfails, long int *nlinsetupsS)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetSensStats", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (sensi==FALSE) {
+    CVProcessError(cv_mem, CV_NO_SENS, "CVODES", "CVodeGetSensStats", MSGCV_NO_SENSI);
+    return(CV_NO_SENS);
+  }
+
+  *nfSevals = nfSe;
+  *nfevalsS = nfeS;
+  *nSetfails = netfS;
+  *nlinsetupsS = nsetupsS;
+
+  return(CV_SUCCESS);
+}
+
+/*-----------------------------------------------------------------*/
+
+int CVodeGetNumSensNonlinSolvIters(void *cvode_mem, long int *nSniters)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetNumSensNonlinSolvIters", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (sensi==FALSE) {
+    CVProcessError(cv_mem, CV_NO_SENS, "CVODES", "CVodeGetNumSensNonlinSolvIters", MSGCV_NO_SENSI);
+    return(CV_NO_SENS);
+  }
+
+  *nSniters = nniS;
+
+  return(CV_SUCCESS);
+}
+
+/*-----------------------------------------------------------------*/
+
+int CVodeGetNumSensNonlinSolvConvFails(void *cvode_mem, long int *nSncfails)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetNumSensNonlinSolvConvFails", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (sensi==FALSE) {
+    CVProcessError(cv_mem, CV_NO_SENS, "CVODES", "CVodeGetNumSensNonlinSolvConvFails", MSGCV_NO_SENSI);
+    return(CV_NO_SENS);
+  }
+
+  *nSncfails = ncfnS;
+
+  return(CV_SUCCESS);
+}
+
+/*-----------------------------------------------------------------*/
+
+int CVodeGetNumStgrSensNonlinSolvIters(void *cvode_mem, long int *nSTGR1niters)
+{
+  CVodeMem cv_mem;
+  int is, Ns;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetNumStgrSensNonlinSolvIters", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  Ns = cv_mem->cv_Ns;
+
+  if (sensi==FALSE) {
+    CVProcessError(cv_mem, CV_NO_SENS, "CVODES", "CVodeGetNumStgrSensNonlinSolvIters", MSGCV_NO_SENSI);
+    return(CV_NO_SENS);
+  }
+
+  if(ism==CV_STAGGERED1) 
+    for(is=0; is<Ns; is++) nSTGR1niters[is] = nniS1[is];
+
+  return(CV_SUCCESS);
+}
+
+/*-----------------------------------------------------------------*/
+
+int CVodeGetNumStgrSensNonlinSolvConvFails(void *cvode_mem, long int *nSTGR1ncfails)
+{
+  CVodeMem cv_mem;
+  int is, Ns;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetNumStgrSensNonlinSolvConvFails", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  Ns = cv_mem->cv_Ns;
+
+  if (sensi==FALSE) {
+    CVProcessError(cv_mem, CV_NO_SENS, "CVODES", "CVodeGetNumStgrSensNonlinSolvConvFails", MSGCV_NO_SENSI);
+    return(CV_NO_SENS);
+  }
+
+  if(ism==CV_STAGGERED1) 
+    for(is=0; is<Ns; is++) nSTGR1ncfails[is] = ncfnS1[is];
+
+  return(CV_SUCCESS);
+}
+
+/*-----------------------------------------------------------------*/
+
+int CVodeGetSensNonlinSolvStats(void *cvode_mem, long int *nSniters, 
+                                long int *nSncfails)
+{
+  CVodeMem cv_mem;
+
+  if (cvode_mem==NULL) {
+    CVProcessError(NULL, CV_MEM_NULL, "CVODES", "CVodeGetSensNonlinSolvstats", MSGCV_NO_MEM);
+    return(CV_MEM_NULL);
+  }
+
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (sensi==FALSE) {
+    CVProcessError(cv_mem, CV_NO_SENS, "CVODES", "CVodeGetSensNonlinSolvStats", MSGCV_NO_SENSI);
+    return(CV_NO_SENS);
+  }
+
+  *nSniters = nniS;
+  *nSncfails = ncfnS;
+
+  return(CV_SUCCESS);
+}
+
+/*-----------------------------------------------------------------*/
+
+char *CVodeGetReturnFlagName(int flag)
+{
+  char *name;
+
+  name = (char *)malloc(24*sizeof(char));
+
+  switch(flag) {
+  case CV_SUCCESS:
+    sprintf(name,"CV_SUCCESS");
+    break;
+  case CV_TSTOP_RETURN:
+    sprintf(name,"CV_TSTOP_RETURN");
+    break;
+  case CV_ROOT_RETURN:
+    sprintf(name,"CV_ROOT_RETURN");
+    break;
+  case CV_TOO_MUCH_WORK:
+    sprintf(name,"CV_TOO_MUCH_WORK");
+    break;
+  case CV_TOO_MUCH_ACC:
+    sprintf(name,"CV_TOO_MUCH_ACC");
+    break;
+  case CV_ERR_FAILURE:
+    sprintf(name,"CV_ERR_FAILURE");
+    break;
+  case CV_CONV_FAILURE:
+    sprintf(name,"CV_CONV_FAILURE");
+    break;
+  case CV_LINIT_FAIL:
+    sprintf(name,"CV_LINIT_FAIL");
+    break;
+  case CV_LSETUP_FAIL:
+    sprintf(name,"CV_LSETUP_FAIL");
+    break;
+  case CV_LSOLVE_FAIL:
+    sprintf(name,"CV_LSOLVE_FAIL");
+    break;
+  case CV_RHSFUNC_FAIL:
+    sprintf(name,"CV_RHSFUNC_FAIL");
+    break;
+  case CV_FIRST_RHSFUNC_ERR:
+    sprintf(name,"CV_FIRST_RHSFUNC_ERR");
+    break;
+  case CV_REPTD_RHSFUNC_ERR:
+    sprintf(name,"CV_REPTD_RHSFUNC_ERR");
+    break;
+  case CV_UNREC_RHSFUNC_ERR:
+    sprintf(name,"CV_UNREC_RHSFUNC_ERR");
+    break;
+  case CV_RTFUNC_FAIL:
+    sprintf(name,"CV_RTFUNC_FAIL");
+    break;
+  case CV_MEM_FAIL:
+    sprintf(name,"CV_MEM_FAIL");
+    break;
+  case CV_MEM_NULL:
+    sprintf(name,"CV_MEM_NULL");
+    break;
+  case CV_ILL_INPUT:
+    sprintf(name,"CV_ILL_INPUT");
+    break;
+  case CV_NO_MALLOC:
+    sprintf(name,"CV_NO_MALLOC");
+    break;
+  case CV_BAD_K:
+    sprintf(name,"CV_BAD_K");
+    break;
+  case CV_BAD_T:
+    sprintf(name,"CV_BAD_T");
+    break;
+  case CV_BAD_DKY:
+    sprintf(name,"CV_BAD_DKY");
+    break;
+  case CV_NO_QUAD:
+    sprintf(name,"CV_NO_QUAD");
+    break;
+  case CV_QRHSFUNC_FAIL:
+    sprintf(name,"CV_QRHSFUNC_FAIL");
+    break;
+  case CV_FIRST_QRHSFUNC_ERR:
+    sprintf(name,"CV_FIRST_QRHSFUNC_ERR");
+    break;
+  case CV_REPTD_QRHSFUNC_ERR:
+    sprintf(name,"CV_REPTD_QRHSFUNC_ERR");
+    break;
+  case CV_UNREC_QRHSFUNC_ERR:
+    sprintf(name,"CV_UNREC_QRHSFUNC_ERR");
+    break;
+  case CV_BAD_IS:
+    sprintf(name,"CV_BAD_IS");
+    break;
+  case CV_NO_SENS:
+    sprintf(name,"CV_NO_SENS");
+    break;
+  case CV_SRHSFUNC_FAIL:
+    sprintf(name,"CV_SRHSFUNC_FAIL");
+    break;
+  case CV_FIRST_SRHSFUNC_ERR:
+    sprintf(name,"CV_FIRST_SRHSFUNC_ERR");
+    break;
+  case CV_REPTD_SRHSFUNC_ERR:
+    sprintf(name,"CV_REPTD_SRHSFUNC_ERR");
+    break;
+  case CV_UNREC_SRHSFUNC_ERR:
+    sprintf(name,"CV_UNREC_SRHSFUNC_ERR");
+    break;
+  case CV_TOO_CLOSE:
+    sprintf(name,"CV_TOO_CLOSE");
+    break;    
+  default:
+    sprintf(name,"NONE");
+  }
+
+  return(name);
+}
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_spbcgs.c b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_spbcgs.c
new file mode 100644
index 0000000000000000000000000000000000000000..ba8142b087210e05e3815a828c697fe5ded75d70
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_spbcgs.c	
@@ -0,0 +1,550 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * ----------------------------------------------------------------- 
+ * Programmer(s): Aaron Collier and Radu Serban @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2005, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This is the implementation file for the CVSPBCG linear solver.
+ * -----------------------------------------------------------------
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <cvodes/cvodes_spbcgs.h>
+#include "cvodes_spils_impl.h"
+#include "cvodes_impl.h"
+
+#include <sundials/sundials_spbcgs.h>
+#include <sundials/sundials_math.h>
+
+/* Constants */
+
+#define ZERO RCONST(0.0)
+#define ONE  RCONST(1.0)
+
+/* CVSPBCG linit, lsetup, lsolve, and lfree routines */
+
+static int CVSpbcgInit(CVodeMem cv_mem);
+
+static int CVSpbcgSetup(CVodeMem cv_mem, int convfail, N_Vector ypred,
+                        N_Vector fpred, booleantype *jcurPtr, N_Vector vtemp1,
+                        N_Vector vtemp2, N_Vector vtemp3);
+
+static int CVSpbcgSolve(CVodeMem cv_mem, N_Vector b, N_Vector weight,
+                        N_Vector ynow, N_Vector fnow);
+
+static void CVSpbcgFree(CVodeMem cv_mem);
+
+/* CVSPBCG lfreeB function */
+
+static void CVSpbcgFreeB(CVadjMem ca_mem);
+
+/* 
+ * ================================================================
+ *
+ *                   PART I - forward problems
+ *
+ * ================================================================
+ */
+
+/* Readability Replacements */
+
+#define tq           (cv_mem->cv_tq)
+#define nst          (cv_mem->cv_nst)
+#define tn           (cv_mem->cv_tn)
+#define gamma        (cv_mem->cv_gamma)
+#define gammap       (cv_mem->cv_gammap)
+#define f            (cv_mem->cv_f)
+#define f_data       (cv_mem->cv_f_data)
+#define ewt          (cv_mem->cv_ewt)
+#define errfp        (cv_mem->cv_errfp)
+#define mnewt        (cv_mem->cv_mnewt)
+#define linit        (cv_mem->cv_linit)
+#define lsetup       (cv_mem->cv_lsetup)
+#define lsolve       (cv_mem->cv_lsolve)
+#define lfree        (cv_mem->cv_lfree)
+#define lmem         (cv_mem->cv_lmem)
+#define vec_tmpl     (cv_mem->cv_tempv)
+#define setupNonNull (cv_mem->cv_setupNonNull)
+
+#define sqrtN     (cvspils_mem->s_sqrtN)   
+#define ytemp     (cvspils_mem->s_ytemp)
+#define x         (cvspils_mem->s_x)
+#define ycur      (cvspils_mem->s_ycur)
+#define fcur      (cvspils_mem->s_fcur)
+#define delta     (cvspils_mem->s_delta)
+#define deltar    (cvspils_mem->s_deltar)
+#define npe       (cvspils_mem->s_npe)
+#define nli       (cvspils_mem->s_nli)
+#define nps       (cvspils_mem->s_nps)
+#define ncfl      (cvspils_mem->s_ncfl)
+#define nstlpre   (cvspils_mem->s_nstlpre)
+#define njtimes   (cvspils_mem->s_njtimes)
+#define nfes      (cvspils_mem->s_nfes)
+#define spils_mem (cvspils_mem->s_spils_mem)
+#define last_flag (cvspils_mem->s_last_flag)
+
+/*
+ * -----------------------------------------------------------------
+ * Function : CVSpbcg
+ * -----------------------------------------------------------------
+ * This routine initializes the memory record and sets various function
+ * fields specific to the Spbcg linear solver module. CVSpbcg first
+ * calls the existing lfree routine if this is not NULL. It then sets
+ * the cv_linit, cv_lsetup, cv_lsolve, cv_lfree fields in (*cvode_mem)
+ * to be CVSpbcgInit, CVSpbcgSetup, CVSpbcgSolve, and CVSpbcgFree,
+ * respectively. It allocates memory for a structure of type
+ * CVSpilsMemRec and sets the cv_lmem field in (*cvode_mem) to the
+ * address of this structure. It sets setupNonNull in (*cvode_mem),
+ * and sets the following fields in the CVSpilsMemRec structure:
+ *
+ *   s_pretype   = pretype
+ *   s_maxl      = CVSPILS_MAXL  if maxl <= 0
+ *               = maxl          if maxl >  0
+ *   s_delt      = CVSPILS_DELT
+ *   s_P_data    = NULL
+ *   s_pset      = NULL
+ *   s_psolve    = NULL
+ *   s_jtimes    = CVSpilsDQJtimes
+ *   s_j_data    = cvode_mem
+ *   s_last_flag = CVSPILS_SUCCESS
+ *
+ * Finally, CVSpbcg allocates memory for ytemp and x, and calls
+ * SpbcgMalloc to allocate memory for the Spbcg solver.
+ * -----------------------------------------------------------------
+ */
+
+int CVSpbcg(void *cvode_mem, int pretype, int maxl)
+{
+  CVodeMem cv_mem;
+  CVSpilsMem cvspils_mem;
+  SpbcgMem spbcg_mem;
+  int mxl;
+
+  /* Return immediately if cvode_mem is NULL */
+  if (cvode_mem == NULL) {
+    CVProcessError(NULL, CVSPILS_MEM_NULL, "CVSPBCG", "CVSpbcg", MSGS_CVMEM_NULL);
+    return(CVSPILS_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;
+
+  /* Check if N_VDotProd is present */
+  if (vec_tmpl->ops->nvdotprod == NULL) {
+    CVProcessError(cv_mem, CVSPILS_ILL_INPUT, "CVSPBCG", "CVSpbcg", MSGS_BAD_NVECTOR);
+    return(CVSPILS_ILL_INPUT);
+  }
+
+  if (lfree != NULL) lfree(cv_mem);
+
+  /* Set four main function fields in cv_mem */
+  linit  = CVSpbcgInit;
+  lsetup = CVSpbcgSetup;
+  lsolve = CVSpbcgSolve;
+  lfree  = CVSpbcgFree;
+
+  /* Get memory for CVSpilsMemRec */
+  cvspils_mem = NULL;
+  cvspils_mem = (CVSpilsMem) malloc(sizeof(CVSpilsMemRec));
+  if (cvspils_mem == NULL) {
+    CVProcessError(cv_mem, CVSPILS_MEM_FAIL, "CVSPBCG", "CVSpbcg", MSGS_MEM_FAIL);
+    return(CVSPILS_MEM_FAIL);
+  }
+
+  /* Set ILS type */
+  cvspils_mem->s_type = SPILS_SPBCG;
+
+  /* Set Spbcg parameters that have been passed in call sequence */
+  cvspils_mem->s_pretype = pretype;
+  mxl = cvspils_mem->s_maxl = (maxl <= 0) ? CVSPILS_MAXL : maxl;
+
+  /* Set default values for the rest of the Spbcg parameters */
+  cvspils_mem->s_delt      = CVSPILS_DELT;
+  cvspils_mem->s_P_data    = NULL;
+  cvspils_mem->s_pset      = NULL;
+  cvspils_mem->s_psolve    = NULL;
+  cvspils_mem->s_jtimes    = CVSpilsDQJtimes;
+  cvspils_mem->s_j_data    = cvode_mem;
+  cvspils_mem->s_last_flag = CVSPILS_SUCCESS;
+
+  setupNonNull = FALSE;
+
+  /* Check for legal pretype */ 
+  if ((pretype != PREC_NONE) && (pretype != PREC_LEFT) &&
+      (pretype != PREC_RIGHT) && (pretype != PREC_BOTH)) {
+    CVProcessError(cv_mem, CVSPILS_ILL_INPUT, "CVSPBCG", "CVSpbcg", MSGS_BAD_PRETYPE);
+    return(CVSPILS_ILL_INPUT);
+  }
+
+  /* Allocate memory for ytemp and x */
+  ytemp = NULL;
+  ytemp = N_VClone(vec_tmpl);
+  if (ytemp == NULL) {
+    CVProcessError(cv_mem, CVSPILS_MEM_FAIL, "CVSPBCG", "CVSpbcg", MSGS_MEM_FAIL);
+    free(cvspils_mem); cvspils_mem = NULL;
+    return(CVSPILS_MEM_FAIL);
+  }
+  x = NULL;
+  x = N_VClone(vec_tmpl);
+  if (x == NULL) {
+    CVProcessError(cv_mem, CVSPILS_MEM_FAIL, "CVSPBCG", "CVSpbcg", MSGS_MEM_FAIL);
+    N_VDestroy(ytemp);
+    free(cvspils_mem); cvspils_mem = NULL;
+    return(CVSPILS_MEM_FAIL);
+  }
+
+  /* Compute sqrtN from a dot product */
+  N_VConst(ONE, ytemp);
+  sqrtN = RSqrt(N_VDotProd(ytemp, ytemp));
+
+  /* Call SpbcgMalloc to allocate workspace for Spbcg */
+  spbcg_mem = NULL;
+  spbcg_mem = SpbcgMalloc(mxl, vec_tmpl);
+  if (spbcg_mem == NULL) {
+    CVProcessError(cv_mem, CVSPILS_MEM_FAIL, "CVSPBCG", "CVSpbcg", MSGS_MEM_FAIL);
+    N_VDestroy(ytemp);
+    N_VDestroy(x);
+    free(cvspils_mem); cvspils_mem = NULL;
+    return(CVSPILS_MEM_FAIL);
+  }
+  
+  /* Attach SPBCG memory to spils memory structure */
+  spils_mem = (void *) spbcg_mem;
+
+  /* Attach linear solver memory to integrator memory */
+  lmem = cvspils_mem;
+
+  return(CVSPILS_SUCCESS);
+}
+
+
+
+/* Additional readability replacements */
+
+#define pretype (cvspils_mem->s_pretype)
+#define delt    (cvspils_mem->s_delt)
+#define maxl    (cvspils_mem->s_maxl)
+#define psolve  (cvspils_mem->s_psolve)
+#define pset    (cvspils_mem->s_pset)
+#define P_data  (cvspils_mem->s_P_data)
+#define jtimes  (cvspils_mem->s_jtimes)
+#define j_data  (cvspils_mem->s_j_data)
+
+/*
+ * -----------------------------------------------------------------
+ * Function : CVSpbcgInit
+ * -----------------------------------------------------------------
+ * This routine does remaining initializations specific to the Spbcg
+ * linear solver.
+ * -----------------------------------------------------------------
+ */
+
+static int CVSpbcgInit(CVodeMem cv_mem)
+{
+  CVSpilsMem cvspils_mem;
+  SpbcgMem spbcg_mem;
+
+  cvspils_mem = (CVSpilsMem) lmem;
+  spbcg_mem = (SpbcgMem) spils_mem;
+
+
+  /* Initialize counters */
+  npe = nli = nps = ncfl = nstlpre = 0;
+  njtimes = nfes = 0;
+
+  /* Check for legal combination pretype - psolve */
+  if ((pretype != PREC_NONE) && (psolve == NULL)) {
+    CVProcessError(cv_mem, -1, "CVSPBCG", "CVSpbcgInit", MSGS_PSOLVE_REQ);
+    last_flag = CVSPILS_ILL_INPUT;
+    return(-1);
+  }
+
+  /* Set setupNonNull = TRUE iff there is preconditioning
+     (pretype != PREC_NONE)  and there is a preconditioning
+     setup phase (pset != NULL) */
+  setupNonNull = (pretype != PREC_NONE) && (pset != NULL);
+
+  /* If jtimes is NULL at this time, set it to DQ */
+  if (jtimes == NULL) {
+    jtimes = CVSpilsDQJtimes;
+    j_data = cv_mem;
+  }
+
+  /*  Set maxl in the SPBCG memory in case it was changed by the user */
+  spbcg_mem->l_max  = maxl;
+
+  last_flag = CVSPILS_SUCCESS;
+  return(0);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * Function : CVSpbcgSetup
+ * -----------------------------------------------------------------
+ * This routine does the setup operations for the Spbcg linear solver.
+ * It makes a decision as to whether or not to signal for reevaluation
+ * of Jacobian data in the pset routine, based on various state
+ * variables, then it calls pset. If we signal for reevaluation,
+ * then we reset jcur = *jcurPtr to TRUE, regardless of the pset output.
+ * In any case, if jcur == TRUE, we increment npe and save nst in nstlpre.
+ * -----------------------------------------------------------------
+ */
+
+static int CVSpbcgSetup(CVodeMem cv_mem, int convfail, N_Vector ypred,
+                        N_Vector fpred, booleantype *jcurPtr, N_Vector vtemp1,
+                        N_Vector vtemp2, N_Vector vtemp3)
+{
+  booleantype jbad, jok;
+  realtype dgamma;
+  int  retval;
+  CVSpilsMem cvspils_mem;
+
+  cvspils_mem = (CVSpilsMem) lmem;
+
+  /* Use nst, gamma/gammap, and convfail to set J eval. flag jok */
+  dgamma = ABS((gamma/gammap) - ONE);
+  jbad = (nst == 0) || (nst > nstlpre + CVSPILS_MSBPRE) ||
+      ((convfail == CV_FAIL_BAD_J) && (dgamma < CVSPILS_DGMAX)) ||
+      (convfail == CV_FAIL_OTHER);
+  *jcurPtr = jbad;
+  jok = !jbad;
+
+  /* Call pset routine and possibly reset jcur */
+  retval = pset(tn, ypred, fpred, jok, jcurPtr, gamma, P_data, 
+                vtemp1, vtemp2, vtemp3);
+  if (retval < 0) {
+    CVProcessError(cv_mem, SPBCG_PSET_FAIL_UNREC, "CVSPBCG", "CVSpbcgSetup", MSGS_PSET_FAILED);
+    last_flag = SPBCG_PSET_FAIL_UNREC;
+  }
+  if (retval > 0) {
+    last_flag = SPBCG_PSET_FAIL_REC;
+  }
+
+  if (jbad) *jcurPtr = TRUE;
+
+  /* If jcur = TRUE, increment npe and save nst value */
+  if (*jcurPtr) {
+    npe++;
+    nstlpre = nst;
+  }
+
+  last_flag = SPBCG_SUCCESS;
+
+  /* Return the same value that pset returned */
+  return(retval);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * Function : CVSpbcgSolve
+ * -----------------------------------------------------------------
+ * This routine handles the call to the generic solver SpbcgSolve
+ * for the solution of the linear system Ax = b with the SPBCG method.
+ * The solution x is returned in the vector b.
+ *
+ * If the WRMS norm of b is small, we return x = b (if this is the first
+ * Newton iteration) or x = 0 (if a later Newton iteration).
+ *
+ * Otherwise, we set the tolerance parameter and initial guess (x = 0),
+ * call SpbcgSolve, and copy the solution x into b. The x-scaling and
+ * b-scaling arrays are both equal to weight.
+ *
+ * The counters nli, nps, and ncfl are incremented, and the return value
+ * is set according to the success of SpbcgSolve. The success flag is
+ * returned if SpbcgSolve converged, or if this is the first Newton
+ * iteration and the residual norm was reduced below its initial value.
+ * -----------------------------------------------------------------
+ */
+
+static int CVSpbcgSolve(CVodeMem cv_mem, N_Vector b, N_Vector weight,
+                        N_Vector ynow, N_Vector fnow)
+{
+  realtype bnorm, res_norm;
+  CVSpilsMem cvspils_mem;
+  SpbcgMem spbcg_mem;
+  int nli_inc, nps_inc, retval;
+  
+  cvspils_mem = (CVSpilsMem) lmem;
+
+  spbcg_mem = (SpbcgMem) spils_mem;
+
+  /* Test norm(b); if small, return x = 0 or x = b */
+  deltar = delt * tq[4]; 
+
+  bnorm = N_VWrmsNorm(b, weight);
+  if (bnorm <= deltar) {
+    if (mnewt > 0) N_VConst(ZERO, b); 
+    return(0);
+  }
+
+  /* Set vectors ycur and fcur for use by the Atimes and Psolve routines */
+  ycur = ynow;
+  fcur = fnow;
+
+  /* Set inputs delta and initial guess x = 0 to SpbcgSolve */  
+  delta = deltar * sqrtN;
+  N_VConst(ZERO, x);
+  
+  /* Call SpbcgSolve and copy x to b */
+  retval = SpbcgSolve(spbcg_mem, cv_mem, x, b, pretype, delta,
+                      cv_mem, weight, weight, CVSpilsAtimes, CVSpilsPSolve,
+                      &res_norm, &nli_inc, &nps_inc);
+
+  N_VScale(ONE, x, b);
+  
+  /* Increment counters nli, nps, and ncfl */
+  nli += nli_inc;
+  nps += nps_inc;
+  if (retval != SPBCG_SUCCESS) ncfl++;
+
+  /* Interpret return value from SpbcgSolve */
+
+  last_flag = retval;
+
+  switch(retval) {
+
+  case SPBCG_SUCCESS:
+    return(0);
+    break;
+  case SPBCG_RES_REDUCED:
+    if (mnewt == 0) return(0);
+    else            return(1);
+    break;
+  case SPBCG_CONV_FAIL:
+    return(1);
+    break;
+  case SPBCG_PSOLVE_FAIL_REC:
+    return(1);
+    break;
+  case SPBCG_ATIMES_FAIL_REC:
+    return(1);
+    break;
+  case SPBCG_MEM_NULL:
+    return(-1);
+    break;
+  case SPBCG_ATIMES_FAIL_UNREC:
+    CVProcessError(cv_mem, SPBCG_ATIMES_FAIL_UNREC, "CVSPBCG", "CVSpbcgSolve", MSGS_JTIMES_FAILED);    
+    return(-1);
+    break;
+  case SPBCG_PSOLVE_FAIL_UNREC:
+    CVProcessError(cv_mem, SPBCG_PSOLVE_FAIL_UNREC, "CVSPBCG", "CVSpbcgSolve", MSGS_PSOLVE_FAILED);
+    return(-1);
+    break;
+  }
+
+  return(0);  
+
+}
+
+/*
+ * -----------------------------------------------------------------
+ * Function : CVSpbcgFree
+ * -----------------------------------------------------------------
+ * This routine frees memory specific to the Spbcg linear solver.
+ * -----------------------------------------------------------------
+ */
+
+static void CVSpbcgFree(CVodeMem cv_mem)
+{
+  CVSpilsMem cvspils_mem;
+  SpbcgMem spbcg_mem;
+
+  cvspils_mem = (CVSpilsMem) lmem;
+
+  spbcg_mem = (SpbcgMem) spils_mem;
+
+  N_VDestroy(ytemp);
+  N_VDestroy(x);
+  SpbcgFree(spbcg_mem);
+  free(cvspils_mem); cvspils_mem = NULL;
+}
+
+
+/* 
+ * ================================================================
+ *
+ *                   PART II - backward problems
+ *
+ * ================================================================
+ */
+
+
+/* Additional readability replacements */
+
+#define lmemB       (ca_mem->ca_lmemB)
+#define lfreeB      (ca_mem->ca_lfreeB)
+
+#define pset_B      (cvspilsB_mem->s_psetB)
+#define psolve_B    (cvspilsB_mem->s_psolveB)
+#define jtimes_B    (cvspilsB_mem->s_jtimesB)
+#define P_data_B    (cvspilsB_mem->s_P_dataB)
+#define jac_data_B  (cvspilsB_mem->s_jac_dataB)
+
+/*
+ * CVSpbcgB
+ *
+ * Wrapper for the backward phase
+ */
+
+int CVSpbcgB(void *cvadj_mem, int pretypeB, int maxlB)
+{
+  CVadjMem ca_mem;
+  CVSpilsMemB cvspilsB_mem;
+  CVodeMem cvB_mem;
+  int flag;
+
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CVSPILS_ADJMEM_NULL, "CVSPBCG", "CVSpbcgB", MSGS_CAMEM_NULL);
+    return(CVSPILS_ADJMEM_NULL);
+  }
+  ca_mem = (CVadjMem) cvadj_mem;
+
+  cvB_mem = ca_mem->cvb_mem;
+  
+  /* Get memory for CVSpilsMemRecB */
+  cvspilsB_mem = NULL;
+  cvspilsB_mem = (CVSpilsMemB) malloc(sizeof(CVSpilsMemRecB));
+  if (cvspilsB_mem == NULL) {
+    CVProcessError(cvB_mem, CVSPILS_MEM_FAIL, "CVSPBCG", "CVSpbcgB", MSGS_MEM_FAIL);
+    return(CVSPILS_MEM_FAIL);
+  }
+
+  pset_B = NULL;
+  psolve_B = NULL;
+  jtimes_B = NULL;
+  P_data_B = NULL;
+  jac_data_B = NULL;
+
+  /* attach lmemB and lfree */
+  lmemB = cvspilsB_mem;
+  lfreeB = CVSpbcgFreeB;
+
+  flag = CVSpbcg(cvB_mem, pretypeB, maxlB);
+
+  if (flag != CVSPILS_SUCCESS) {
+    free(cvspilsB_mem);
+    cvspilsB_mem = NULL;
+  }
+
+  return(flag);
+}
+
+/*
+ * CVSpbcgFreeB 
+ */
+
+
+static void CVSpbcgFreeB(CVadjMem ca_mem)
+{
+  CVSpilsMemB cvspilsB_mem;
+
+  cvspilsB_mem = (CVSpilsMemB) lmemB;
+
+  free(cvspilsB_mem);
+}
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_spgmr.c b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_spgmr.c
new file mode 100644
index 0000000000000000000000000000000000000000..bd2bacc8ee8d247d7baaa40810d6044809cc6af4
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_spgmr.c	
@@ -0,0 +1,558 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * ----------------------------------------------------------------- 
+ * Programmer(s): Radu Serban @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2005, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This is the implementation file for the CVSPGMR linear solver.
+ * -----------------------------------------------------------------
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <cvodes/cvodes_spgmr.h>
+#include "cvodes_spils_impl.h"
+#include "cvodes_impl.h"
+
+#include <sundials/sundials_spgmr.h>
+#include <sundials/sundials_math.h>
+
+/* Constants */
+
+#define ZERO RCONST(0.0)
+#define ONE  RCONST(1.0)
+
+/* CVSPGMR linit, lsetup, lsolve, and lfree routines */
+
+static int CVSpgmrInit(CVodeMem cv_mem);
+
+static int CVSpgmrSetup(CVodeMem cv_mem, int convfail, N_Vector ypred,
+                        N_Vector fpred, booleantype *jcurPtr, N_Vector vtemp1,
+                        N_Vector vtemp2, N_Vector vtemp3);
+
+static int CVSpgmrSolve(CVodeMem cv_mem, N_Vector b, N_Vector weight,
+                        N_Vector ynow, N_Vector fnow);
+
+static void CVSpgmrFree(CVodeMem cv_mem);
+
+/* CVSPGMR lfreeB function */
+
+static void CVSpgmrFreeB(CVadjMem ca_mem);
+
+/* 
+ * ================================================================
+ *
+ *                   PART I - forward problems
+ *
+ * ================================================================
+ */
+
+
+/* Readability Replacements */
+
+#define uround  (cv_mem->cv_uround)
+#define tq      (cv_mem->cv_tq)
+#define nst     (cv_mem->cv_nst)
+#define tn      (cv_mem->cv_tn)
+#define h       (cv_mem->cv_h)
+#define gamma   (cv_mem->cv_gamma)
+#define gammap  (cv_mem->cv_gammap)   
+#define f       (cv_mem->cv_f)
+#define f_data  (cv_mem->cv_f_data)
+#define ewt     (cv_mem->cv_ewt)
+#define mnewt   (cv_mem->cv_mnewt)
+#define ropt    (cv_mem->cv_ropt)
+#define linit   (cv_mem->cv_linit)
+#define lsetup  (cv_mem->cv_lsetup)
+#define lsolve  (cv_mem->cv_lsolve)
+#define lfree   (cv_mem->cv_lfree)
+#define lmem    (cv_mem->cv_lmem)
+#define vec_tmpl     (cv_mem->cv_tempv)
+#define setupNonNull (cv_mem->cv_setupNonNull)
+
+#define sqrtN   (cvspils_mem->s_sqrtN)   
+#define ytemp   (cvspils_mem->s_ytemp)
+#define x       (cvspils_mem->s_x)
+#define ycur    (cvspils_mem->s_ycur)
+#define fcur    (cvspils_mem->s_fcur)
+#define delta   (cvspils_mem->s_delta)
+#define deltar  (cvspils_mem->s_deltar)
+#define npe     (cvspils_mem->s_npe)
+#define nli     (cvspils_mem->s_nli)
+#define nps     (cvspils_mem->s_nps)
+#define ncfl    (cvspils_mem->s_ncfl)
+#define nstlpre (cvspils_mem->s_nstlpre)
+#define njtimes (cvspils_mem->s_njtimes)
+#define nfes   (cvspils_mem->s_nfes)
+#define spils_mem (cvspils_mem->s_spils_mem)
+#define last_flag (cvspils_mem->s_last_flag)
+
+/*
+ * -----------------------------------------------------------------
+ * CVSpgmr
+ * -----------------------------------------------------------------
+ * This routine initializes the memory record and sets various function
+ * fields specific to the Spgmr linear solver module. CVSpgmr first
+ * calls the existing lfree routine if this is not NULL.  It then sets
+ * the cv_linit, cv_lsetup, cv_lsolve, cv_lfree fields in (*cvode_mem)
+ * to be CVSpgmrInit, CVSpgmrSetup, CVSpgmrSolve, and CVSpgmrFree,
+ * respectively.  It allocates memory for a structure of type
+ * CVSpilsMemRec and sets the cv_lmem field in (*cvode_mem) to the
+ * address of this structure.  It sets setupNonNull in (*cvode_mem),
+ * and sets the following fields in the CVSpilsMemRec structure:
+ *   s_pretype = pretype                                       
+ *   s_gstype  = gstype                                       
+ *   s_maxl    = MIN(N,CVSPILS_MAXL  if maxl <= 0             
+ *             = maxl                 if maxl > 0              
+ *   s_delt    = CVSPILS_DELT if delt == 0.0                     
+ *             = delt         if delt != 0.0                     
+ *   s_P_data  = P_data                                        
+ *   s_pset    = pset                                       
+ *   s_psolve  = psolve                                        
+ *   s_jtimes  = input parameter jtimes  if jtimes != NULL
+ *             = CVSpilsDQJtimes         otherwise
+ *   s_j_data  = input parameter jac_data
+ * Finally, CVSpgmr allocates memory for ytemp and x, and calls
+ * SpgmrMalloc to allocate memory for the Spgmr solver.
+ * -----------------------------------------------------------------
+ */
+
+int CVSpgmr(void *cvode_mem, int pretype, int maxl)
+{
+  CVodeMem cv_mem;
+  CVSpilsMem cvspils_mem;
+  SpgmrMem spgmr_mem;
+  int mxl;
+
+  /* Return immediately if cvode_mem is NULL */
+  if (cvode_mem == NULL) {
+    CVProcessError(NULL, CVSPILS_MEM_NULL, "CVSPGMR", "CVSpgmr", MSGS_CVMEM_NULL);
+    return(CVSPILS_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;
+
+  /* Check if N_VDotProd is present */
+  if(vec_tmpl->ops->nvdotprod == NULL) {
+    CVProcessError(cv_mem, CVSPILS_ILL_INPUT, "CVSPGMR", "CVSpgmr", MSGS_BAD_NVECTOR);
+    return(CVSPILS_ILL_INPUT);
+  }
+
+  if (lfree != NULL) lfree(cv_mem);
+
+  /* Set four main function fields in cv_mem */
+  linit  = CVSpgmrInit;
+  lsetup = CVSpgmrSetup;
+  lsolve = CVSpgmrSolve;
+  lfree  = CVSpgmrFree;
+
+  /* Get memory for CVSpilsMemRec */
+  cvspils_mem = NULL;
+  cvspils_mem = (CVSpilsMem) malloc(sizeof(CVSpilsMemRec));
+  if (cvspils_mem == NULL) {
+    CVProcessError(cv_mem, CVSPILS_MEM_FAIL, "CVSPGMR", "CVSpgmr", MSGS_MEM_FAIL);
+    return(CVSPILS_MEM_FAIL);
+  }
+
+  /* Set ILS type */
+  cvspils_mem->s_type = SPILS_SPGMR;
+
+  /* Set Spgmr parameters that have been passed in call sequence */
+  cvspils_mem->s_pretype    = pretype;
+  mxl = cvspils_mem->s_maxl = (maxl <= 0) ? CVSPILS_MAXL : maxl;
+
+  /* Set default values for the rest of the Spgmr parameters */
+  cvspils_mem->s_gstype     = MODIFIED_GS;
+  cvspils_mem->s_delt       = CVSPILS_DELT;
+  cvspils_mem->s_P_data     = NULL;
+  cvspils_mem->s_pset       = NULL;
+  cvspils_mem->s_psolve     = NULL;
+  cvspils_mem->s_jtimes     = CVSpilsDQJtimes;
+  cvspils_mem->s_j_data     = cvode_mem;
+  cvspils_mem->s_last_flag  = CVSPILS_SUCCESS;
+
+
+  setupNonNull = FALSE;
+
+  /* Check for legal pretype */ 
+  if ((pretype != PREC_NONE) && (pretype != PREC_LEFT) &&
+      (pretype != PREC_RIGHT) && (pretype != PREC_BOTH)) {
+    CVProcessError(cv_mem, CVSPILS_ILL_INPUT, "CVSPGMR", "CVSpgmr", MSGS_BAD_PRETYPE);
+    return(CVSPILS_ILL_INPUT);
+  }
+
+  /* Allocate memory for ytemp and x */
+  ytemp = NULL;
+  ytemp = N_VClone(vec_tmpl);
+  if (ytemp == NULL) {
+    CVProcessError(cv_mem, CVSPILS_MEM_FAIL, "CVSPGMR", "CVSpgmr", MSGS_MEM_FAIL);
+    free(cvspils_mem); cvspils_mem = NULL;
+    return(CVSPILS_MEM_FAIL);
+  }
+  x = NULL;
+  x = N_VClone(vec_tmpl);
+  if (x == NULL) {
+    CVProcessError(cv_mem, CVSPILS_MEM_FAIL, "CVSPGMR", "CVSpgmr", MSGS_MEM_FAIL);
+    N_VDestroy(ytemp);
+    free(cvspils_mem); cvspils_mem = NULL;
+    return(CVSPILS_MEM_FAIL);
+  }
+
+  /* Compute sqrtN from a dot product */
+  N_VConst(ONE, ytemp);
+  sqrtN = RSqrt( N_VDotProd(ytemp, ytemp) );
+
+  /* Call SpgmrMalloc to allocate workspace for Spgmr */
+  spgmr_mem = NULL;
+  spgmr_mem = SpgmrMalloc(mxl, vec_tmpl);
+  if (spgmr_mem == NULL) {
+    CVProcessError(cv_mem, CVSPILS_MEM_FAIL, "CVSPGMR", "CVSpgmr", MSGS_MEM_FAIL);
+    N_VDestroy(ytemp);
+    N_VDestroy(x);
+    free(cvspils_mem); cvspils_mem = NULL;
+    return(CVSPILS_MEM_FAIL);
+  }
+  
+  /* Attach SPGMR memory to spils memory structure */
+  spils_mem = (void *) spgmr_mem;
+
+  /* Attach linear solver memory to integrator memory */
+  lmem = cvspils_mem;
+
+  return(CVSPILS_SUCCESS);
+}
+
+
+/* Additional readability Replacements */
+
+#define pretype (cvspils_mem->s_pretype)
+#define gstype  (cvspils_mem->s_gstype)
+#define delt    (cvspils_mem->s_delt)
+#define maxl    (cvspils_mem->s_maxl)
+#define psolve  (cvspils_mem->s_psolve)
+#define pset    (cvspils_mem->s_pset)
+#define P_data  (cvspils_mem->s_P_data)
+#define jtimes  (cvspils_mem->s_jtimes)
+#define j_data  (cvspils_mem->s_j_data)
+
+/*
+ * -----------------------------------------------------------------
+ * CVSpgmrInit
+ * -----------------------------------------------------------------
+ * This routine does remaining initializations specific to the Spgmr 
+ * linear solver.
+ * -----------------------------------------------------------------
+ */
+
+static int CVSpgmrInit(CVodeMem cv_mem)
+{
+  CVSpilsMem cvspils_mem;
+  cvspils_mem = (CVSpilsMem) lmem;
+
+  /* Initialize counters */
+  npe = nli = nps = ncfl = nstlpre = 0;
+  njtimes = nfes = 0;
+
+  /* Check for legal combination pretype - psolve */
+  if ((pretype != PREC_NONE) && (psolve == NULL)) {
+    CVProcessError(cv_mem, -1, "CVSPGMR", "CVSpgmrInit", MSGS_PSOLVE_REQ);
+    last_flag = CVSPILS_ILL_INPUT;
+    return(-1);
+  }
+
+  /* Set setupNonNull = TRUE iff there is preconditioning (pretype != PREC_NONE)
+     and there is a preconditioning setup phase (pset != NULL)             */
+  setupNonNull = (pretype != PREC_NONE) && (pset != NULL);
+
+  /* If jtimes is NULL at this time, set it to DQ */
+  if (jtimes == NULL) {
+    jtimes = CVSpilsDQJtimes;
+    j_data = cv_mem;
+  }
+
+  last_flag = CVSPILS_SUCCESS;
+  return(0);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVSpgmrSetup
+ * -----------------------------------------------------------------
+ * This routine does the setup operations for the Spgmr linear solver.
+ * It makes a decision as to whether or not to signal for re-evaluation
+ * of Jacobian data in the pset routine, based on various state
+ * variables, then it calls pset.  If we signal for re-evaluation,
+ * then we reset jcur = *jcurPtr to TRUE, regardless of the pset output.
+ * In any case, if jcur == TRUE, we increment npe and save nst in nstlpre.
+ * -----------------------------------------------------------------
+ */
+
+static int CVSpgmrSetup(CVodeMem cv_mem, int convfail, N_Vector ypred,
+                        N_Vector fpred, booleantype *jcurPtr, N_Vector vtemp1,
+                        N_Vector vtemp2, N_Vector vtemp3)
+{
+  booleantype jbad, jok;
+  realtype dgamma;
+  int  retval;
+  CVSpilsMem cvspils_mem;
+
+  cvspils_mem = (CVSpilsMem) lmem;
+
+  /* Use nst, gamma/gammap, and convfail to set J eval. flag jok */
+  dgamma = ABS((gamma/gammap) - ONE);
+  jbad = (nst == 0) || (nst > nstlpre + CVSPILS_MSBPRE) ||
+    ((convfail == CV_FAIL_BAD_J) && (dgamma < CVSPILS_DGMAX)) ||
+    (convfail == CV_FAIL_OTHER);
+  *jcurPtr = jbad;
+  jok = !jbad;
+
+  /* Call pset routine and possibly reset jcur */
+  retval = pset(tn, ypred, fpred, jok, jcurPtr, gamma, P_data, 
+                vtemp1, vtemp2, vtemp3);
+  if (retval < 0) {
+    CVProcessError(cv_mem, SPGMR_PSET_FAIL_UNREC, "CVSPGMR", "CVSpgmrSetup", MSGS_PSET_FAILED);
+    last_flag = SPGMR_PSET_FAIL_UNREC;
+  }
+  if (retval > 0) {
+    last_flag = SPGMR_PSET_FAIL_REC;
+  }
+
+  if (jbad) *jcurPtr = TRUE;
+
+  /* If jcur = TRUE, increment npe and save nst value */
+  if (*jcurPtr) {
+    npe++;
+    nstlpre = nst;
+  }
+
+  last_flag = SPGMR_SUCCESS;
+
+  /* Return the same value that pset returned */
+  return(retval);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVSpgmrSolve
+ * -----------------------------------------------------------------
+ * This routine handles the call to the generic solver SpgmrSolve
+ * for the solution of the linear system Ax = b with the SPGMR method,
+ * without restarts.  The solution x is returned in the vector b.
+ *
+ * If the WRMS norm of b is small, we return x = b (if this is the first
+ * Newton iteration) or x = 0 (if a later Newton iteration).
+ *
+ * Otherwise, we set the tolerance parameter and initial guess (x = 0),
+ * call SpgmrSolve, and copy the solution x into b.  The x-scaling and
+ * b-scaling arrays are both equal to weight, and no restarts are allowed.
+ *
+ * The counters nli, nps, and ncfl are incremented, and the return value
+ * is set according to the success of SpgmrSolve.  The success flag is
+ * returned if SpgmrSolve converged, or if this is the first Newton
+ * iteration and the residual norm was reduced below its initial value.
+ * -----------------------------------------------------------------
+ */
+
+static int CVSpgmrSolve(CVodeMem cv_mem, N_Vector b, N_Vector weight,
+                        N_Vector ynow, N_Vector fnow)
+{
+  realtype bnorm, res_norm;
+  CVSpilsMem cvspils_mem;
+  SpgmrMem spgmr_mem;
+  int nli_inc, nps_inc, retval;
+  
+  cvspils_mem = (CVSpilsMem) lmem;
+
+  spgmr_mem = (SpgmrMem) spils_mem;
+
+  /* Test norm(b); if small, return x = 0 or x = b */
+  deltar = delt*tq[4]; 
+
+  bnorm = N_VWrmsNorm(b, weight);
+  if (bnorm <= deltar) {
+    if (mnewt > 0) N_VConst(ZERO, b); 
+    return(0);
+  }
+
+  /* Set vectors ycur and fcur for use by the Atimes and Psolve routines */
+  ycur = ynow;
+  fcur = fnow;
+
+  /* Set inputs delta and initial guess x = 0 to SpgmrSolve */  
+  delta = deltar * sqrtN;
+  N_VConst(ZERO, x);
+  
+  /* Call SpgmrSolve and copy x to b */
+  retval = SpgmrSolve(spgmr_mem, cv_mem, x, b, pretype, gstype, delta, 0,
+                   cv_mem, weight, weight, CVSpilsAtimes, CVSpilsPSolve,
+                   &res_norm, &nli_inc, &nps_inc);
+
+  N_VScale(ONE, x, b);
+  
+  /* Increment counters nli, nps, and ncfl */
+  nli += nli_inc;
+  nps += nps_inc;
+  if (retval != SPGMR_SUCCESS) ncfl++;
+
+  /* Interpret return value from SpgmrSolve */
+
+  last_flag = retval;
+
+  switch(retval) {
+
+  case SPGMR_SUCCESS:
+    return(0);
+    break;
+  case SPGMR_RES_REDUCED:
+    if (mnewt == 0) return(0);
+    else            return(1);
+    break;
+  case SPGMR_CONV_FAIL:
+    return(1);
+    break;
+  case SPGMR_QRFACT_FAIL:
+    return(1);
+    break;
+  case SPGMR_PSOLVE_FAIL_REC:
+    return(1);
+    break;
+  case SPGMR_ATIMES_FAIL_REC:
+    return(1);
+    break;
+  case SPGMR_MEM_NULL:
+    return(-1);
+    break;
+  case SPGMR_ATIMES_FAIL_UNREC:
+    CVProcessError(cv_mem, SPGMR_ATIMES_FAIL_UNREC, "CVSPGMR", "CVSpgmrSolve", MSGS_JTIMES_FAILED);    
+    return(-1);
+    break;
+  case SPGMR_PSOLVE_FAIL_UNREC:
+    CVProcessError(cv_mem, SPGMR_PSOLVE_FAIL_UNREC, "CVSPGMR", "CVSpgmrSolve", MSGS_PSOLVE_FAILED);
+    return(-1);
+    break;
+  case SPGMR_GS_FAIL:
+    return(-1);
+    break;
+  case SPGMR_QRSOL_FAIL:
+    return(-1);
+    break;
+  }
+
+  return(0);  
+
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVSpgmrFree
+ * -----------------------------------------------------------------
+ * This routine frees memory specific to the Spgmr linear solver.
+ * -----------------------------------------------------------------
+ */
+
+static void CVSpgmrFree(CVodeMem cv_mem)
+{
+  CVSpilsMem cvspils_mem;
+  SpgmrMem spgmr_mem;
+
+  cvspils_mem = (CVSpilsMem) lmem;
+  
+  spgmr_mem = (SpgmrMem) spils_mem;
+
+  N_VDestroy(ytemp);
+  N_VDestroy(x);
+  SpgmrFree(spgmr_mem);
+  free(cvspils_mem); cvspils_mem = NULL;
+}
+
+
+/* 
+ * ================================================================
+ *
+ *                   PART II - backward problems
+ *
+ * ================================================================
+ */
+
+
+/* Additional readability replacements */
+
+#define lmemB       (ca_mem->ca_lmemB)
+#define lfreeB      (ca_mem->ca_lfreeB)
+
+#define pset_B      (cvspilsB_mem->s_psetB)
+#define psolve_B    (cvspilsB_mem->s_psolveB)
+#define jtimes_B    (cvspilsB_mem->s_jtimesB)
+#define P_data_B    (cvspilsB_mem->s_P_dataB)
+#define jac_data_B  (cvspilsB_mem->s_jac_dataB)
+
+/*
+ * CVSpgmrB
+ *
+ * Wrapper for the backward phase
+ *
+ */
+
+int CVSpgmrB(void *cvadj_mem, int pretypeB, int maxlB)
+{
+  CVadjMem ca_mem;
+  CVSpilsMemB cvspilsB_mem;
+  CVodeMem cvB_mem;
+  int flag;
+
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CVSPILS_ADJMEM_NULL, "CVSPGMR", "CVSpgmrB", MSGS_CAMEM_NULL);
+    return(CVSPILS_ADJMEM_NULL);
+  }
+  ca_mem = (CVadjMem) cvadj_mem;
+
+  cvB_mem = ca_mem->cvb_mem;
+
+  /* Get memory for CVSpilsMemRecB */
+  cvspilsB_mem = NULL;
+  cvspilsB_mem = (CVSpilsMemB) malloc(sizeof(CVSpilsMemRecB));
+  if (cvspilsB_mem == NULL) {
+    CVProcessError(cvB_mem, CVSPILS_MEM_FAIL, "CVSPGMR", "CVSpgmrB", MSGS_MEM_FAIL);
+    return(CVSPILS_MEM_FAIL);
+  }
+
+  pset_B = NULL;
+  psolve_B = NULL;
+  jtimes_B = NULL;
+  P_data_B = NULL;
+  jac_data_B = NULL;
+
+  /* attach lmemB and lfreeB */
+  lmemB = cvspilsB_mem;
+  lfreeB = CVSpgmrFreeB;
+  
+  flag = CVSpgmr(cvB_mem, pretypeB, maxlB);
+
+  if (flag != CVSPILS_SUCCESS) {
+    free(cvspilsB_mem);
+    cvspilsB_mem = NULL;
+  }
+
+  return(flag);
+}
+
+
+/*
+ * CVSpgmrFreeB 
+ */
+
+
+static void CVSpgmrFreeB(CVadjMem ca_mem)
+{
+  CVSpilsMemB cvspilsB_mem;
+
+  cvspilsB_mem = (CVSpilsMemB) lmemB;
+
+  free(cvspilsB_mem);
+}
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_spils.c b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_spils.c
new file mode 100644
index 0000000000000000000000000000000000000000..802a92584060a92b6cd86e0d4322fb434943770d
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_spils.c	
@@ -0,0 +1,988 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * ----------------------------------------------------------------- 
+ * Programmer(s):Radu Serban @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2005, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This is the implementation file for the CVSPILS linear solvers.
+ *
+ * Part II contains wrappers for using the CVODES iterative linear 
+ * solvers on adjoint (backward) problems.
+ * -----------------------------------------------------------------
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "cvodes_impl.h"
+#include "cvodes_spils_impl.h"
+
+/* Private constants */
+
+#define ZERO   RCONST(0.0)
+#define PT25   RCONST(0.25)
+#define ONE    RCONST(1.0)
+
+/* Algorithmic constants */
+
+#define MAX_ITERS  3  /* max. number of attempts to recover in DQ J*v */
+
+/* 
+ * ================================================================
+ *
+ *                   PART I - forward problems
+ *
+ * ================================================================
+ */
+
+/* Readability Replacements */
+
+#define lrw1    (cv_mem->cv_lrw1)
+#define liw1    (cv_mem->cv_liw1)
+#define tq      (cv_mem->cv_tq)
+#define tn      (cv_mem->cv_tn)
+#define h       (cv_mem->cv_h)
+#define gamma   (cv_mem->cv_gamma)
+#define nfe     (cv_mem->cv_nfe)
+#define f       (cv_mem->cv_f)
+#define f_data  (cv_mem->cv_f_data)
+#define ewt     (cv_mem->cv_ewt)
+#define lmem    (cv_mem->cv_lmem)
+
+#define ils_type (cvspils_mem->s_type)
+#define sqrtN   (cvspils_mem->s_sqrtN)   
+#define ytemp   (cvspils_mem->s_ytemp)
+#define x       (cvspils_mem->s_x)
+#define ycur    (cvspils_mem->s_ycur)
+#define fcur    (cvspils_mem->s_fcur)
+#define delta   (cvspils_mem->s_delta)
+#define npe     (cvspils_mem->s_npe)
+#define nli     (cvspils_mem->s_nli)
+#define nps     (cvspils_mem->s_nps)
+#define ncfl    (cvspils_mem->s_ncfl)
+#define njtimes (cvspils_mem->s_njtimes)
+#define nfes    (cvspils_mem->s_nfes)
+
+#define last_flag (cvspils_mem->s_last_flag)
+
+
+/*
+ * -----------------------------------------------------------------
+ * OPTIONAL INPUT and OUTPUT FUNCTIONS
+ * -----------------------------------------------------------------
+ */
+
+
+/*
+ * -----------------------------------------------------------------
+ * CVSpilsSetPrecType
+ * -----------------------------------------------------------------
+ */
+
+int CVSpilsSetPrecType(void *cvode_mem, int pretype)
+{
+  CVodeMem cv_mem;
+  CVSpilsMem cvspils_mem;
+
+  /* Return immediately if cvode_mem is NULL */
+  if (cvode_mem == NULL) {
+    CVProcessError(NULL, CVSPILS_MEM_NULL, "CVSPILS", "CVSpilsSetPrecType", MSGS_CVMEM_NULL);
+    return(CVSPILS_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (lmem == NULL) {
+    CVProcessError(cv_mem, CVSPILS_LMEM_NULL, "CVSPILS", "CVSpilsSetPrecType", MSGS_LMEM_NULL);
+    return(CVSPILS_LMEM_NULL);
+  }
+  cvspils_mem = (CVSpilsMem) lmem;
+
+  /* Check for legal pretype */ 
+  if ((pretype != PREC_NONE) && (pretype != PREC_LEFT) &&
+      (pretype != PREC_RIGHT) && (pretype != PREC_BOTH)) {
+    CVProcessError(cv_mem, CVSPILS_ILL_INPUT, "CVSPILS", "CVSpilsSetPrecType", MSGS_BAD_PRETYPE);
+    return(CVSPILS_ILL_INPUT);
+  }
+
+  cvspils_mem->s_pretype = pretype;
+
+  return(CVSPILS_SUCCESS);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVSpilsSetGSType
+ * -----------------------------------------------------------------
+ */
+
+int CVSpilsSetGSType(void *cvode_mem, int gstype)
+{
+  CVodeMem cv_mem;
+  CVSpilsMem cvspils_mem;
+
+  /* Return immediately if cvode_mem is NULL */
+  if (cvode_mem == NULL) {
+    CVProcessError(NULL, CVSPILS_MEM_NULL, "CVSPILS", "CVSpilsSetGSType", MSGS_CVMEM_NULL);
+    return(CVSPILS_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (lmem == NULL) {
+    CVProcessError(cv_mem, CVSPILS_LMEM_NULL, "CVSPILS", "CVSpilsSetGSType", MSGS_LMEM_NULL);
+    return(CVSPILS_LMEM_NULL);
+  }
+  cvspils_mem = (CVSpilsMem) lmem;
+
+  if (ils_type != SPILS_SPGMR) {
+    CVProcessError(cv_mem, CVSPILS_ILL_INPUT, "CVSPILS", "CVSpilsSetGSType", MSGS_BAD_LSTYPE);
+    return(CVSPILS_ILL_INPUT);
+  }
+
+  /* Check for legal gstype */
+  if ((gstype != MODIFIED_GS) && (gstype != CLASSICAL_GS)) {
+    CVProcessError(cv_mem, CVSPILS_ILL_INPUT, "CVSPILS", "CVSpilsSetGSType", MSGS_BAD_GSTYPE);
+    return(CVSPILS_ILL_INPUT);
+  }
+
+  cvspils_mem->s_gstype = gstype;
+
+  return(CVSPILS_SUCCESS);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * Function : CVSpilsSetMaxl
+ * -----------------------------------------------------------------
+ */
+
+int CVSpilsSetMaxl(void *cvode_mem, int maxl)
+{
+  CVodeMem cv_mem;
+  CVSpilsMem cvspils_mem;
+  int mxl;
+
+  /* Return immediately if cvode_mem is NULL */
+  if (cvode_mem == NULL) {
+    CVProcessError(NULL, CVSPILS_MEM_NULL, "CVSPILS", "CVSpilsSetMaxl", MSGS_CVMEM_NULL);
+    return(CVSPILS_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (lmem == NULL) {
+    CVProcessError(NULL, CVSPILS_LMEM_NULL, "CVSPILS", "CVSpilsSetMaxl", MSGS_LMEM_NULL);
+    return(CVSPILS_LMEM_NULL);
+  }
+  cvspils_mem = (CVSpilsMem) lmem;
+
+  if (ils_type == SPILS_SPGMR) {
+    CVProcessError(cv_mem, CVSPILS_ILL_INPUT, "CVSPILS", "CVSpilsSetMaxl", MSGS_BAD_LSTYPE);
+    return(CVSPILS_ILL_INPUT);
+  }
+
+  mxl = (maxl <= 0) ? CVSPILS_MAXL : maxl;
+  cvspils_mem->s_maxl = mxl;
+
+  /*  spbcg_mem->l_max  = mxl; */
+
+  return(CVSPILS_SUCCESS);
+}
+
+
+/*
+ * -----------------------------------------------------------------
+ * CVSpilsSetDelt
+ * -----------------------------------------------------------------
+ */
+
+int CVSpilsSetDelt(void *cvode_mem, realtype delt)
+{
+  CVodeMem cv_mem;
+  CVSpilsMem cvspils_mem;
+
+  /* Return immediately if cvode_mem is NULL */
+  if (cvode_mem == NULL) {
+    CVProcessError(NULL, CVSPILS_MEM_NULL, "CVSPILS", "CVSpilsSetDelt", MSGS_CVMEM_NULL);
+    return(CVSPILS_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (lmem == NULL) {
+    CVProcessError(cv_mem, CVSPILS_LMEM_NULL, "CVSPILS", "CVSpilsSetDelt", MSGS_LMEM_NULL);
+    return(CVSPILS_LMEM_NULL);
+  }
+  cvspils_mem = (CVSpilsMem) lmem;
+
+  /* Check for legal delt */
+  if(delt < ZERO) {
+    CVProcessError(cv_mem, CVSPILS_ILL_INPUT, "CVSPILS", "CVSpilsSetDelt", MSGS_BAD_DELT);
+    return(CVSPILS_ILL_INPUT);
+  }
+
+  cvspils_mem->s_delt = (delt == ZERO) ? CVSPILS_DELT : delt;
+
+  return(CVSPILS_SUCCESS);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVSpilsSetPrecSetupFn
+ * -----------------------------------------------------------------
+ */
+
+int CVSpilsSetPreconditioner(void *cvode_mem, CVSpilsPrecSetupFn pset, 
+                             CVSpilsPrecSolveFn psolve, void *P_data)
+{
+  CVodeMem cv_mem;
+  CVSpilsMem cvspils_mem;
+
+  /* Return immediately if cvode_mem is NULL */
+  if (cvode_mem == NULL) {
+    CVProcessError(NULL, CVSPILS_MEM_NULL, "CVSPILS", "CVSpilsSetPreconditioner", MSGS_CVMEM_NULL);
+    return(CVSPILS_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (lmem == NULL) {
+    CVProcessError(cv_mem, CVSPILS_LMEM_NULL, "CVSPILS", "CVSpilsSetPreconditioner", MSGS_LMEM_NULL);
+    return(CVSPILS_LMEM_NULL);
+  }
+  cvspils_mem = (CVSpilsMem) lmem;
+
+  cvspils_mem->s_pset = pset;
+  cvspils_mem->s_psolve = psolve;
+  if (psolve != NULL) cvspils_mem->s_P_data = P_data;
+
+  return(CVSPILS_SUCCESS);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVSpilsSetJacTimesVecFn
+ * -----------------------------------------------------------------
+ */
+
+int CVSpilsSetJacTimesVecFn(void *cvode_mem, CVSpilsJacTimesVecFn jtimes, void *jac_data)
+{
+  CVodeMem cv_mem;
+  CVSpilsMem cvspils_mem;
+
+  /* Return immediately if cvode_mem is NULL */
+  if (cvode_mem == NULL) {
+    CVProcessError(NULL, CVSPILS_MEM_NULL, "CVSPILS", "CVSpilsSetJacTimesVecFn", MSGS_CVMEM_NULL);
+    return(CVSPILS_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (lmem == NULL) {
+    CVProcessError(cv_mem, CVSPILS_LMEM_NULL, "CVSPILS", "CVSpilsSetJacTimesVecFn", MSGS_LMEM_NULL);
+    return(CVSPILS_LMEM_NULL);
+  }
+  cvspils_mem = (CVSpilsMem) lmem;
+
+  cvspils_mem->s_jtimes = jtimes;
+  if (jtimes != NULL) cvspils_mem->s_j_data = jac_data;
+
+  return(CVSPILS_SUCCESS);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVSpilsGetWorkSpace
+ * -----------------------------------------------------------------
+ */
+
+int CVSpilsGetWorkSpace(void *cvode_mem, long int *lenrwLS, long int *leniwLS)
+{
+  CVodeMem cv_mem;
+  CVSpilsMem cvspils_mem;
+  int maxl;
+
+  /* Return immediately if cvode_mem is NULL */
+  if (cvode_mem == NULL) {
+    CVProcessError(NULL, CVSPILS_MEM_NULL, "CVSPILS", "CVSpilsGetWorkSpace", MSGS_CVMEM_NULL);
+    return(CVSPILS_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (lmem == NULL) {
+    CVProcessError(cv_mem, CVSPILS_LMEM_NULL, "CVSPILS", "CVSpilsGetWorkSpace", MSGS_LMEM_NULL);
+    return(CVSPILS_LMEM_NULL);
+  }
+  cvspils_mem = (CVSpilsMem) lmem;
+
+  
+  switch(ils_type) {
+  case SPILS_SPGMR:
+    maxl = cvspils_mem->s_maxl;
+    *lenrwLS = lrw1*(maxl + 5) + maxl*(maxl + 4) + 1;
+    *leniwLS = liw1*(maxl + 5);
+    break;
+  case SPILS_SPBCG:
+    *lenrwLS = lrw1 * 9;
+    *leniwLS = liw1 * 9;
+    break;
+  case SPILS_SPTFQMR:
+    *lenrwLS = lrw1*11;
+    *leniwLS = liw1*11;
+    break;
+  }
+
+
+  return(CVSPILS_SUCCESS);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVSpilsGetNumPrecEvals
+ * -----------------------------------------------------------------
+ */
+
+int CVSpilsGetNumPrecEvals(void *cvode_mem, long int *npevals)
+{
+  CVodeMem cv_mem;
+  CVSpilsMem cvspils_mem;
+
+  /* Return immediately if cvode_mem is NULL */
+  if (cvode_mem == NULL) {
+    CVProcessError(NULL, CVSPILS_MEM_NULL, "CVSPILS", "CVSpilsGetNumPrecEvals", MSGS_CVMEM_NULL);
+    return(CVSPILS_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (lmem == NULL) {
+    CVProcessError(cv_mem, CVSPILS_LMEM_NULL, "CVSPILS", "CVSpilsGetNumPrecEvals", MSGS_LMEM_NULL);
+    return(CVSPILS_LMEM_NULL);
+  }
+  cvspils_mem = (CVSpilsMem) lmem;
+
+  *npevals = npe;
+
+  return(CVSPILS_SUCCESS);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVSpilsGetNumPrecSolves
+ * -----------------------------------------------------------------
+ */
+
+int CVSpilsGetNumPrecSolves(void *cvode_mem, long int *npsolves)
+{
+  CVodeMem cv_mem;
+  CVSpilsMem cvspils_mem;
+
+  /* Return immediately if cvode_mem is NULL */
+  if (cvode_mem == NULL) {
+    CVProcessError(NULL, CVSPILS_MEM_NULL, "CVSPILS", "CVSpilsGetNumPrecSolves", MSGS_CVMEM_NULL);
+    return(CVSPILS_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (lmem == NULL) {
+    CVProcessError(cv_mem, CVSPILS_LMEM_NULL, "CVSPILS", "CVSpilsGetNumPrecSolves", MSGS_LMEM_NULL);
+    return(CVSPILS_LMEM_NULL);
+  }
+  cvspils_mem = (CVSpilsMem) lmem;
+
+  *npsolves = nps;
+
+  return(CVSPILS_SUCCESS);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVSpilsGetNumLinIters
+ * -----------------------------------------------------------------
+ */
+
+int CVSpilsGetNumLinIters(void *cvode_mem, long int *nliters)
+{
+  CVodeMem cv_mem;
+  CVSpilsMem cvspils_mem;
+
+  /* Return immediately if cvode_mem is NULL */
+  if (cvode_mem == NULL) {
+    CVProcessError(NULL, CVSPILS_MEM_NULL, "CVSPILS", "CVSpilsGetNumLinIters", MSGS_CVMEM_NULL);
+    return(CVSPILS_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (lmem == NULL) {
+    CVProcessError(cv_mem, CVSPILS_LMEM_NULL, "CVSPILS", "CVSpilsGetNumLinIters", MSGS_LMEM_NULL);
+    return(CVSPILS_LMEM_NULL);
+  }
+  cvspils_mem = (CVSpilsMem) lmem;
+
+  *nliters = nli;
+
+  return(CVSPILS_SUCCESS);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVSpilsGetNumConvFails
+ * -----------------------------------------------------------------
+ */
+
+int CVSpilsGetNumConvFails(void *cvode_mem, long int *nlcfails)
+{
+  CVodeMem cv_mem;
+  CVSpilsMem cvspils_mem;
+
+  /* Return immediately if cvode_mem is NULL */
+  if (cvode_mem == NULL) {
+    CVProcessError(NULL, CVSPILS_MEM_NULL, "CVSPILS", "CVSpilsGetNumConvFails", MSGS_CVMEM_NULL);
+    return(CVSPILS_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (lmem == NULL) {
+    CVProcessError(cv_mem, CVSPILS_LMEM_NULL, "CVSPILS", "CVSpilsGetNumConvFails", MSGS_LMEM_NULL);
+    return(CVSPILS_LMEM_NULL);
+  }
+  cvspils_mem = (CVSpilsMem) lmem;
+
+  *nlcfails = ncfl;
+
+  return(CVSPILS_SUCCESS);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVSpilsGetNumJtimesEvals
+ * -----------------------------------------------------------------
+ */
+
+int CVSpilsGetNumJtimesEvals(void *cvode_mem, long int *njvevals)
+{
+  CVodeMem cv_mem;
+  CVSpilsMem cvspils_mem;
+
+  /* Return immediately if cvode_mem is NULL */
+  if (cvode_mem == NULL) {
+    CVProcessError(NULL, CVSPILS_MEM_NULL, "CVSPILS", "CVSpilsGetNumJtimesEvals", MSGS_CVMEM_NULL);
+    return(CVSPILS_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (lmem == NULL) {
+    CVProcessError(cv_mem, CVSPILS_LMEM_NULL, "CVSPILS", "CVSpilsGetNumJtimesEvals", MSGS_LMEM_NULL);
+    return(CVSPILS_LMEM_NULL);
+  }
+  cvspils_mem = (CVSpilsMem) lmem;
+
+  *njvevals = njtimes;
+
+  return(CVSPILS_SUCCESS);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVSpilsGetNumRhsEvals
+ * -----------------------------------------------------------------
+ */
+
+int CVSpilsGetNumRhsEvals(void *cvode_mem, long int *nfevalsLS)
+{
+  CVodeMem cv_mem;
+  CVSpilsMem cvspils_mem;
+
+  /* Return immediately if cvode_mem is NULL */
+  if (cvode_mem == NULL) {
+    CVProcessError(NULL, CVSPILS_MEM_NULL, "CVSPILS", "CVSpilsGetNumRhsEvals", MSGS_CVMEM_NULL);
+    return(CVSPILS_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (lmem == NULL) {
+    CVProcessError(cv_mem, CVSPILS_LMEM_NULL, "CVSPILS", "CVSpilsGetNumRhsEvals", MSGS_LMEM_NULL);
+    return(CVSPILS_LMEM_NULL);
+  }
+  cvspils_mem = (CVSpilsMem) lmem;
+
+  *nfevalsLS = nfes;
+
+  return(CVSPILS_SUCCESS);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVSpilsGetLastFlag
+ * -----------------------------------------------------------------
+ */
+
+int CVSpilsGetLastFlag(void *cvode_mem, int *flag)
+{
+  CVodeMem cv_mem;
+  CVSpilsMem cvspils_mem;
+
+  /* Return immediately if cvode_mem is NULL */
+  if (cvode_mem == NULL) {
+    CVProcessError(NULL, CVSPILS_MEM_NULL, "CVSPILS", "CVSpilsGetLastFlag", MSGS_CVMEM_NULL);
+    return(CVSPILS_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;
+
+  if (lmem == NULL) {
+    CVProcessError(cv_mem, CVSPILS_LMEM_NULL, "CVSPILS", "CVSpilsGetLastFlag", MSGS_LMEM_NULL);
+    return(CVSPILS_LMEM_NULL);
+  }
+  cvspils_mem = (CVSpilsMem) lmem;
+
+  *flag = last_flag;
+
+  return(CVSPILS_SUCCESS);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVSpilsGetReturnFlagName
+ * -----------------------------------------------------------------
+ */
+
+char *CVSpilsGetReturnFlagName(int flag)
+{
+  char *name;
+
+  name = (char *)malloc(30*sizeof(char));
+
+  switch(flag) {
+  case CVSPILS_SUCCESS:
+    sprintf(name,"CVSPILS_SUCCESS");
+    break;    
+  case CVSPILS_MEM_NULL:
+    sprintf(name,"CVSPILS_MEM_NULL");
+    break;
+  case CVSPILS_LMEM_NULL:
+    sprintf(name,"CVSPILS_LMEM_NULL");
+    break;
+  case CVSPILS_ILL_INPUT:
+    sprintf(name,"CVSPILS_ILL_INPUT");
+    break;
+  case CVSPILS_MEM_FAIL:
+    sprintf(name,"CVSPILS_MEM_FAIL");
+    break;
+  case CVSPILS_ADJMEM_NULL:
+    sprintf(name,"CVSPILS_ADJMEM_NULL");
+    break;
+  case CVSPILS_LMEMB_NULL:
+    sprintf(name,"CVSPILS_LMEMB_NULL");
+    break;
+  default:
+    sprintf(name,"NONE");
+  }
+
+  return(name);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVSPILS private functions
+ * -----------------------------------------------------------------
+ */
+
+
+/* Additional readability Replacements */
+
+#define pretype (cvspils_mem->s_pretype)
+#define delt    (cvspils_mem->s_delt)
+#define maxl    (cvspils_mem->s_maxl)
+#define psolve  (cvspils_mem->s_psolve)
+#define P_data  (cvspils_mem->s_P_data)
+#define jtimes  (cvspils_mem->s_jtimes)
+#define j_data  (cvspils_mem->s_j_data)
+
+/*
+ * -----------------------------------------------------------------
+ * CVSpilsAtimes
+ * -----------------------------------------------------------------
+ * This routine generates the matrix-vector product z = Mv, where
+ * M = I - gamma*J. The product J*v is obtained by calling the jtimes 
+ * routine. It is then scaled by -gamma and added to v to obtain M*v.
+ * The return value is the same as the value returned by jtimes --
+ * 0 if successful, nonzero otherwise.
+ * -----------------------------------------------------------------
+ */
+
+int CVSpilsAtimes(void *cvode_mem, N_Vector v, N_Vector z)
+{
+  CVodeMem   cv_mem;
+  CVSpilsMem cvspils_mem;
+  int retval;
+
+  cv_mem = (CVodeMem) cvode_mem;
+  cvspils_mem = (CVSpilsMem) lmem;
+
+  retval = jtimes(v, z, tn, ycur, fcur, j_data, ytemp);
+  njtimes++;
+  if (retval != 0) return(retval);
+
+  N_VLinearSum(ONE, v, -gamma, z, z);
+
+  return(0);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVSpilsPSolve
+ * -----------------------------------------------------------------
+ * This routine interfaces between the generic SpgmrSolve routine and
+ * the user's psolve routine.  It passes to psolve all required state 
+ * information from cvode_mem.  Its return value is the same as that
+ * returned by psolve. Note that the generic SPGMR solver guarantees
+ * that CVSpilsPSolve will not be called in the case in which
+ * preconditioning is not done. This is the only case in which the
+ * user's psolve routine is allowed to be NULL.
+ * -----------------------------------------------------------------
+ */
+
+int CVSpilsPSolve(void *cvode_mem, N_Vector r, N_Vector z, int lr)
+{
+  CVodeMem   cv_mem;
+  CVSpilsMem cvspils_mem;
+  int retval;
+
+  cv_mem = (CVodeMem) cvode_mem;
+  cvspils_mem = (CVSpilsMem)lmem;
+
+  /* This call is counted in nps within the CVSp***Solve routine */
+  retval = psolve(tn, ycur, fcur, r, z, gamma, delta, lr, P_data, ytemp);
+
+  return(retval);     
+}
+
+/*
+ * -----------------------------------------------------------------
+ * CVSpilsDQJtimes
+ * -----------------------------------------------------------------
+ * This routine generates a difference quotient approximation to
+ * the Jacobian times vector f_y(t,y) * v. The approximation is 
+ * Jv = vnrm[f(y + v/vnrm) - f(y)], where vnrm = (WRMS norm of v) is
+ * input, i.e. the WRMS norm of v/vnrm is 1.
+ * -----------------------------------------------------------------
+ */
+
+int CVSpilsDQJtimes(N_Vector v, N_Vector Jv, realtype t, 
+                    N_Vector y, N_Vector fy,
+                    void *jac_data, N_Vector work)
+{
+  CVodeMem cv_mem;
+  CVSpilsMem cvspils_mem;
+  realtype sig, siginv;
+  int iter, retval;
+
+  /* jac_data is cvode_mem */
+  cv_mem = (CVodeMem) jac_data;
+  cvspils_mem = (CVSpilsMem) lmem;
+
+  /* Initialize perturbation to 1/||v|| */
+  sig = ONE/N_VWrmsNorm(v, ewt);
+
+  for (iter=0; iter<MAX_ITERS; iter++) {
+
+    /* Set work = y + sig*v */
+    N_VLinearSum(sig, v, ONE, y, work);
+
+    /* Set Jv = f(tn, y+sig*v) */
+    retval = f(t, work, Jv, f_data); 
+    nfes++;
+    if (retval == 0) break;
+    if (retval < 0)  return(-1);
+
+    sig *= PT25;
+  }
+
+  if (retval > 0) return(+1);
+
+  /* Replace Jv by (Jv - fy)/sig */
+  siginv = ONE/sig;
+  N_VLinearSum(siginv, Jv, -siginv, fy, Jv);
+
+  return(0);
+}
+
+/* 
+ * ================================================================
+ *
+ *                   PART II - backward problems
+ *
+ * ================================================================
+ */
+
+/* Readability replacements */
+
+#define ytmp        (ca_mem->ca_ytmp)
+#define getY        (ca_mem->ca_getY)
+#define lmemB       (ca_mem->ca_lmemB)
+
+#define pset_B      (cvspilsB_mem->s_psetB)
+#define psolve_B    (cvspilsB_mem->s_psolveB)
+#define jtimes_B    (cvspilsB_mem->s_jtimesB)
+#define P_data_B    (cvspilsB_mem->s_P_dataB)
+#define jac_data_B  (cvspilsB_mem->s_jac_dataB)
+
+/*
+ * -----------------------------------------------------------------
+ * OPTIONAL INPUT and OUTPUT FUNCTIONS
+ * -----------------------------------------------------------------
+ */
+
+int CVSpilsSetPrecTypeB(void *cvadj_mem, int pretypeB)
+{
+  CVadjMem ca_mem;
+  CVodeMem cvB_mem;
+  int flag;
+
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CVSPILS_ADJMEM_NULL, "CVSPILS", "CVSpilsSetPrecTypeB", MSGS_CAMEM_NULL);
+    return(CVSPILS_ADJMEM_NULL);
+  }
+  ca_mem = (CVadjMem) cvadj_mem;
+
+  cvB_mem = ca_mem->cvb_mem;
+
+  flag = CVSpilsSetPrecType(cvB_mem, pretypeB);
+
+  return(flag);
+}
+
+int CVSpilsSetGSTypeB(void *cvadj_mem, int gstypeB)
+{
+  CVadjMem ca_mem;
+  CVodeMem cvB_mem;
+  int flag;
+
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CVSPILS_ADJMEM_NULL, "CVSPILS", "CVSpilsSetGSTypeB", MSGS_CAMEM_NULL);
+    return(CVSPILS_ADJMEM_NULL);
+  }
+  ca_mem = (CVadjMem) cvadj_mem;
+
+  cvB_mem = ca_mem->cvb_mem;
+
+  flag = CVSpilsSetGSType(cvB_mem,gstypeB);
+
+  return(flag);
+}
+
+int CVSpilsSetDeltB(void *cvadj_mem, realtype deltB)
+{
+  CVadjMem ca_mem;
+  CVodeMem cvB_mem;
+  int flag;
+
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CVSPILS_ADJMEM_NULL, "CVSPILS", "CVSpilsSetDeltB", MSGS_CAMEM_NULL);
+    return(CVSPILS_ADJMEM_NULL);
+  }
+  ca_mem = (CVadjMem) cvadj_mem;
+
+  cvB_mem = ca_mem->cvb_mem;
+
+  flag = CVSpilsSetDelt(cvB_mem,deltB);
+
+  return(flag);
+}
+
+int CVSpilsSetMaxlB(void *cvadj_mem, int maxlB)
+{
+  CVadjMem ca_mem;
+  CVodeMem cvB_mem;
+  int flag;
+
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CVSPILS_ADJMEM_NULL, "CVSPILS", "CVSpilsSetMaxlB", MSGS_CAMEM_NULL);
+    return(CVSPILS_ADJMEM_NULL);
+  }
+  ca_mem = (CVadjMem) cvadj_mem;
+
+  cvB_mem = ca_mem->cvb_mem;
+
+  flag = CVSpilsSetMaxl(cvB_mem,maxlB);
+
+  return(flag);
+}
+
+int CVSpilsSetPreconditionerB(void *cvadj_mem, CVSpilsPrecSetupFnB psetB,
+                              CVSpilsPrecSolveFnB psolveB, void *P_dataB)
+{
+  CVadjMem ca_mem;
+  CVSpilsMemB cvspilsB_mem; 
+  CVodeMem cvB_mem;
+  int flag;
+
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CVSPILS_ADJMEM_NULL, "CVSPILS", "CVSpilsSetPreconditionerB", MSGS_CAMEM_NULL);
+    return(CVSPILS_ADJMEM_NULL);
+  }
+  ca_mem = (CVadjMem) cvadj_mem;
+
+  cvB_mem = ca_mem->cvb_mem;
+
+  if (lmemB == NULL) {
+    CVProcessError(cvB_mem, CVSPILS_LMEMB_NULL, "CVSPILS", "CVSpilsSetPreconditonerB", MSGS_LMEMB_NULL);
+    return(CVSPILS_LMEMB_NULL);
+  }
+  cvspilsB_mem = (CVSpilsMemB) lmemB;
+
+  pset_B   = psetB;
+  psolve_B = psolveB;
+  P_data_B = P_dataB;
+
+  flag = CVSpilsSetPreconditioner(cvB_mem, CVAspilsPrecSetup, CVAspilsPrecSolve, cvadj_mem);
+
+  return(flag);
+}
+
+int CVSpilsSetJacTimesVecFnB(void *cvadj_mem, CVSpilsJacTimesVecFnB jtimesB,
+                             void *jac_dataB)
+{
+  CVadjMem ca_mem;
+  CVSpilsMemB cvspilsB_mem; 
+  CVodeMem cvB_mem;
+  int flag;
+
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CVSPILS_ADJMEM_NULL, "CVSPILS", "CVSpilsSetJacTimesVecFnB", MSGS_CAMEM_NULL);
+    return(CVSPILS_ADJMEM_NULL);
+  }
+  ca_mem = (CVadjMem) cvadj_mem;
+
+  cvB_mem = ca_mem->cvb_mem;
+
+  if (lmemB == NULL) {
+    CVProcessError(cvB_mem, CVSPILS_LMEMB_NULL, "CVSPILS", "CVSpilsSetJacTimesVecFnB", MSGS_LMEMB_NULL);
+    return(CVSPILS_LMEMB_NULL);
+  }
+  cvspilsB_mem = (CVSpilsMemB) lmemB;
+
+  jtimes_B   = jtimesB;
+  jac_data_B = jac_dataB;
+
+  flag = CVSpilsSetJacTimesVecFn(cvB_mem, CVAspilsJacTimesVec, cvadj_mem);
+
+  return(flag);
+}
+
+
+/*
+ * -----------------------------------------------------------------
+ * CVSPILS private functions
+ * -----------------------------------------------------------------
+ */
+
+/*
+ * CVAspilsPrecSetup
+ *
+ * This routine interfaces to the CVSpilsPrecSetupFnB routine 
+ * provided by the user.
+ * NOTE: p_data actually contains cvadj_mem
+ */
+
+int CVAspilsPrecSetup(realtype t, N_Vector yB, 
+                      N_Vector fyB, booleantype jokB, 
+                      booleantype *jcurPtrB, realtype gammaB,
+                      void *cvadj_mem,
+                      N_Vector tmp1B, N_Vector tmp2B, N_Vector tmp3B)
+{
+  CVadjMem ca_mem;
+  CVodeMem cvB_mem;
+  CVSpilsMemB cvspilsB_mem;
+  int retval, flag;
+
+  ca_mem = (CVadjMem) cvadj_mem;
+  cvB_mem = ca_mem->cvb_mem;
+  cvspilsB_mem = (CVSpilsMemB) lmemB;
+
+  /* Forward solution from interpolation */
+  flag = getY(ca_mem, t, ytmp);
+  if (flag != CV_SUCCESS) {
+    CVProcessError(cvB_mem, -1, "CVSPILS", "CVAspilsPrecSetup", MSGS_BAD_T);
+    return(-1);
+  } 
+
+  /* Call user's adjoint precondB routine */
+  retval = pset_B(t, ytmp, yB, fyB, jokB, jcurPtrB, gammaB,
+                  P_data_B, tmp1B, tmp2B, tmp3B);
+
+  return(retval);
+}
+
+
+/*
+ * CVAspilsPrecSolve
+ *
+ * This routine interfaces to the CVSpilsPrecSolveFnB routine 
+ * provided by the user.
+ * NOTE: p_data actually contains cvadj_mem
+ */
+
+int CVAspilsPrecSolve(realtype t, N_Vector yB, N_Vector fyB,
+                      N_Vector rB, N_Vector zB,
+                      realtype gammaB, realtype deltaB,
+                      int lrB, void *cvadj_mem, N_Vector tmpB)
+{
+  CVadjMem ca_mem;
+  CVodeMem cvB_mem;
+  CVSpilsMemB cvspilsB_mem;
+  int retval, flag;
+
+  ca_mem = (CVadjMem) cvadj_mem;
+  cvB_mem = ca_mem->cvb_mem;
+  cvspilsB_mem = (CVSpilsMemB) lmemB;
+
+  /* Forward solution from interpolation */
+  flag = getY(ca_mem, t, ytmp);
+  if (flag != CV_SUCCESS) {
+    CVProcessError(cvB_mem, -1, "CVSPILS", "CVAspilsPrecSolve", MSGS_BAD_T);
+    return(-1);
+  }
+
+  /* Call user's adjoint psolveB routine */
+  retval = psolve_B(t, ytmp, yB, fyB, rB, zB, gammaB, deltaB, 
+                    lrB, P_data_B, tmpB);
+
+  return(retval);
+}
+
+
+/*
+ * CVAspilsJacTimesVec
+ *
+ * This routine interfaces to the CVSpilsJacTimesVecFnB routine 
+ * provided by the user.
+ * NOTE: jac_data actually contains cvadj_mem
+ */
+
+int CVAspilsJacTimesVec(N_Vector vB, N_Vector JvB, realtype t, 
+                        N_Vector yB, N_Vector fyB, 
+                        void *cvadj_mem, N_Vector tmpB)
+{
+  CVadjMem ca_mem;
+  CVodeMem cvB_mem;
+  CVSpilsMemB cvspilsB_mem;
+  int retval, flag;
+
+  ca_mem = (CVadjMem) cvadj_mem;
+  cvB_mem = ca_mem->cvb_mem;
+  cvspilsB_mem = (CVSpilsMemB) lmemB;
+
+  /* Forward solution from interpolation */
+  flag = getY(ca_mem, t, ytmp);
+  if (flag != CV_SUCCESS) {
+    CVProcessError(cvB_mem, -1, "CVSPILS", "CVAspilsJacTimesVec", MSGS_BAD_T);
+    return(-1);
+  } 
+
+  /* Call user's adjoint jtimesB routine */
+  retval = jtimes_B(vB, JvB, t, ytmp, yB, fyB, jac_data_B, tmpB);
+
+  return(retval);
+}
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_spils_impl.h b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_spils_impl.h
new file mode 100644
index 0000000000000000000000000000000000000000..2f6f7058de19decd4222622c9cfada5fc186dae5
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_spils_impl.h	
@@ -0,0 +1,212 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * ----------------------------------------------------------------- 
+ * Programmer(s): Radu Serban @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2005, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * Common implementation header file for the scaled, preconditioned
+ * iterative linear solvers
+ * -----------------------------------------------------------------
+ */
+
+#ifndef _CVSSPILS_IMPL_H
+#define _CVSSPILS_IMPL_H
+
+#ifdef __cplusplus  /* wrapper to enable C++ usage */
+extern "C" {
+#endif
+
+#include <cvodes/cvodes_spils.h>
+
+  /* Types of iterative linear solvers */
+
+#define SPILS_SPGMR   1
+#define SPILS_SPBCG   2
+#define SPILS_SPTFQMR 3
+
+
+  /* 
+   * -----------------------------------------------------------------
+   * PART I - forward problems
+   * -----------------------------------------------------------------
+   */
+
+  /*
+   * -----------------------------------------------------------------
+   * Types : CVSpilsMemRec, CVSpilsMem
+   * -----------------------------------------------------------------
+   * The type CVSpilsMem is pointer to a CVSpilsMemRec.
+   * -----------------------------------------------------------------
+   */
+
+  typedef struct {
+
+    int s_type;           /* type of scaled preconditioned iterative LS   */
+
+    int  s_pretype;       /* type of preconditioning                      */
+    int  s_gstype;        /* type of Gram-Schmidt orthogonalization       */
+    realtype s_sqrtN;     /* sqrt(N)                                      */
+    realtype s_delt;      /* delt = user specified or DELT_DEFAULT        */
+    realtype s_deltar;    /* deltar = delt * tq4                          */
+    realtype s_delta;     /* delta = deltar * sqrtN                       */
+    int  s_maxl;          /* maxl = maximum dimension of the Krylov space */
+
+    long int s_nstlpre;   /* value of nst at the last pset call           */
+    long int s_npe;       /* npe = total number of pset calls             */
+    long int s_nli;       /* nli = total number of linear iterations      */
+    long int s_nps;       /* nps = total number of psolve calls           */
+    long int s_ncfl;      /* ncfl = total number of convergence failures  */
+    long int s_njtimes;   /* njtimes = total number of calls to jtimes    */
+    long int s_nfes;      /* nfeSG = total number of calls to f for     
+                             difference quotient Jacobian-vector products */
+
+    N_Vector s_ytemp;     /* temp vector passed to jtimes and psolve      */
+    N_Vector s_x;         /* temp vector used by CVSpilsSolve             */
+    N_Vector s_ycur;      /* CVODE current y vector in Newton Iteration   */
+    N_Vector s_fcur;      /* fcur = f(tn, ycur)                           */
+
+    CVSpilsPrecSetupFn s_pset; 
+    /* pset = user-supplied routine to compute      */
+    /* a preconditioner                             */
+
+    CVSpilsPrecSolveFn s_psolve;   
+    /* psolve = user-supplied routine to solve      */
+    /* preconditioner linear system                 */
+
+    void *s_P_data;       /* P_data passed to psolve and pset             */
+
+    void* s_spils_mem;    /* memory used by the generic solver            */
+
+    CVSpilsJacTimesVecFn s_jtimes;  
+    /* jtimes = Jacobian * vector routine           */
+    void *s_j_data;       /* j_data is passed to jtimes                   */
+
+    int s_last_flag;      /* last error flag returned by any function     */
+
+  } CVSpilsMemRec, *CVSpilsMem;
+
+  /*
+   * -----------------------------------------------------------------
+   * Prototypes of internal functions
+   * -----------------------------------------------------------------
+   */
+
+  /* Atimes and PSolve routines called by generic solver */
+
+  int CVSpilsAtimes(void *cv_mem, N_Vector v, N_Vector z);
+
+  int CVSpilsPSolve(void *cv_mem, N_Vector r, N_Vector z, int lr);
+
+  /* Difference quotient approximation for Jac times vector */
+
+  int CVSpilsDQJtimes(N_Vector v, N_Vector Jv, realtype t,
+                      N_Vector y, N_Vector fy, void *jac_data,
+                      N_Vector work);
+
+
+  /*
+   * -----------------------------------------------------------------
+   * Error Messages
+   * -----------------------------------------------------------------
+   */
+
+#define MSGS_CVMEM_NULL  "Integrator memory is NULL."
+#define MSGS_MEM_FAIL    "A memory request failed."
+#define MSGS_BAD_NVECTOR "A required vector operation is not implemented."
+#define MSGS_BAD_LSTYPE  "Incompatible linear solver type."
+#define MSGS_BAD_PRETYPE "Illegal value for pretype. Legal values are PREC_NONE, PREC_LEFT, PREC_RIGHT, and PREC_BOTH."
+#define MSGS_PSOLVE_REQ  "pretype != PREC_NONE, but PSOLVE = NULL is illegal."
+#define MSGS_LMEM_NULL   "Linear solver memory is NULL."
+#define MSGS_BAD_GSTYPE  "Illegal value for gstype. Legal values are MODIFIED_GS and CLASSICAL_GS."
+#define MSGS_BAD_DELT    "delt < 0 illegal."
+  
+#define MSGS_PSET_FAILED "The preconditioner setup routine failed in an unrecoverable manner."
+#define MSGS_PSOLVE_FAILED "The preconditioner solve routine failed in an unrecoverable manner."
+#define MSGS_JTIMES_FAILED "The Jacobian x vector routine failed in an unrecoverable manner."
+
+
+  /* 
+   * -----------------------------------------------------------------
+   * PART II - backward problems
+   * -----------------------------------------------------------------
+   */
+
+  /*
+   * -----------------------------------------------------------------
+   * Types : CVSpilsMemRecB, CVSpilsMemB       
+   * -----------------------------------------------------------------
+   * CVSpgmrB, CVSpbcgB, and CVSptfqmr attach such a structure to the 
+   * lmemB filed of CVadjMem
+   * -----------------------------------------------------------------
+   */
+
+  typedef struct {
+
+    CVSpilsJacTimesVecFnB s_jtimesB;
+    CVSpilsPrecSetupFnB s_psetB;
+    CVSpilsPrecSolveFnB s_psolveB;
+    void *s_P_dataB;
+    void *s_jac_dataB;
+
+  } CVSpilsMemRecB, *CVSpilsMemB;
+
+
+  /*
+   * ------------------------------------------------
+   * Wrapper functions for using the iterative linear 
+   * solvers on adjoint (backward) problems
+   * ------------------------------------------------
+   */
+
+  /* 
+   * CVAspilsPrecSetup has type CVSpilsPrecSetupFn
+   * It wraps around the user-provided function of type CVSpilsPrecSetupFnB
+   */
+
+  int CVAspilsPrecSetup(realtype t, N_Vector yB, 
+                        N_Vector fyB, booleantype jokB, 
+                        booleantype *jcurPtrB, realtype gammaB,
+                        void *cvadj_mem,
+                        N_Vector tmp1B, N_Vector tmp2B, N_Vector tmp3B);
+
+  /* 
+   * CVAspilsPrecSolve has type CVSpilsPrecSolveFn 
+   * It wraps around the user-provided function of type CVSpilsPrecSolveFnB
+   */
+
+  int CVAspilsPrecSolve(realtype t, N_Vector yB, N_Vector fyB,
+                        N_Vector rB, N_Vector zB,
+                        realtype gammaB, realtype deltaB,
+                        int lrB, void *cvadj_mem, N_Vector tmpB);
+  
+  /* 
+   * CVAspilsJacTimesVec has type CVSpilsJacTimesVecFn 
+   * It wraps around the user-provided function of type CVSpilsJacTimesVecFnB
+   */
+
+  int CVAspilsJacTimesVec(N_Vector vB, N_Vector JvB, realtype t, 
+                          N_Vector yB, N_Vector fyB, 
+                          void *cvadj_mem, N_Vector tmpB);
+
+  /*
+   * -----------------------------------------------------------------
+   * Error Messages 
+   * -----------------------------------------------------------------
+   */
+
+#define MSGS_CAMEM_NULL "cvadj_mem = NULL illegal."
+#define MSGS_LMEMB_NULL "Linear solver memory is NULL for the backward integration."
+#define MSGS_BAD_T      "Bad t for interpolation."
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_sptfqmr.c b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_sptfqmr.c
new file mode 100644
index 0000000000000000000000000000000000000000..ea1efd1e1c25c82b377f8050eb79d7802dc8df34
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/cvodes_sptfqmr.c	
@@ -0,0 +1,547 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * ----------------------------------------------------------------- 
+ * Programmer(s): Aaron Collier and Radu Serban @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2005, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This is the implementation file for the CVSPTFQMR linear solver.
+ * -----------------------------------------------------------------
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <cvodes/cvodes_sptfqmr.h>
+#include "cvodes_spils_impl.h"
+#include "cvodes_impl.h"
+
+#include <sundials/sundials_sptfqmr.h>
+#include <sundials/sundials_math.h>
+
+/* Constants */
+
+#define ZERO RCONST(0.0)
+#define ONE  RCONST(1.0)
+
+/* CVSPTFQMR linit, lsetup, lsolve, and lfree routines */
+
+static int CVSptfqmrInit(CVodeMem cv_mem);
+
+static int CVSptfqmrSetup(CVodeMem cv_mem, int convfail, N_Vector ypred,
+			  N_Vector fpred, booleantype *jcurPtr, N_Vector vtemp1,
+			  N_Vector vtemp2, N_Vector vtemp3);
+
+static int CVSptfqmrSolve(CVodeMem cv_mem, N_Vector b, N_Vector weight,
+			  N_Vector ynow, N_Vector fnow);
+
+static void CVSptfqmrFree(CVodeMem cv_mem);
+
+/* CVSPTFQMR lfreeB function */
+
+static void CVSptfqmrFreeB(CVadjMem ca_mem);
+
+/* 
+ * ================================================================
+ *
+ *                   PART I - forward problems
+ *
+ * ================================================================
+ */
+
+/* Readability Replacements */
+
+#define tq           (cv_mem->cv_tq)
+#define nst          (cv_mem->cv_nst)
+#define tn           (cv_mem->cv_tn)
+#define gamma        (cv_mem->cv_gamma)
+#define gammap       (cv_mem->cv_gammap)
+#define f            (cv_mem->cv_f)
+#define f_data       (cv_mem->cv_f_data)
+#define ewt          (cv_mem->cv_ewt)
+#define errfp        (cv_mem->cv_errfp)
+#define mnewt        (cv_mem->cv_mnewt)
+#define linit        (cv_mem->cv_linit)
+#define lsetup       (cv_mem->cv_lsetup)
+#define lsolve       (cv_mem->cv_lsolve)
+#define lfree        (cv_mem->cv_lfree)
+#define lmem         (cv_mem->cv_lmem)
+#define vec_tmpl     (cv_mem->cv_tempv)
+#define setupNonNull (cv_mem->cv_setupNonNull)
+
+#define sqrtN       (cvspils_mem->s_sqrtN)   
+#define ytemp       (cvspils_mem->s_ytemp)
+#define x           (cvspils_mem->s_x)
+#define ycur        (cvspils_mem->s_ycur)
+#define fcur        (cvspils_mem->s_fcur)
+#define delta       (cvspils_mem->s_delta)
+#define deltar      (cvspils_mem->s_deltar)
+#define npe         (cvspils_mem->s_npe)
+#define nli         (cvspils_mem->s_nli)
+#define nps         (cvspils_mem->s_nps)
+#define ncfl        (cvspils_mem->s_ncfl)
+#define nstlpre     (cvspils_mem->s_nstlpre)
+#define njtimes     (cvspils_mem->s_njtimes)
+#define nfes        (cvspils_mem->s_nfes)
+#define spils_mem   (cvspils_mem->s_spils_mem)
+#define last_flag   (cvspils_mem->s_last_flag)
+
+/*
+ * -----------------------------------------------------------------
+ * Function : CVSptfqmr
+ * -----------------------------------------------------------------
+ * This routine initializes the memory record and sets various function
+ * fields specific to the Sptfqmr linear solver module. CVSptfqmr first
+ * calls the existing lfree routine if this is not NULL. It then sets
+ * the cv_linit, cv_lsetup, cv_lsolve, cv_lfree fields in (*cvode_mem)
+ * to be CVSptfqmrInit, CVSptfqmrSetup, CVSptfqmrSolve, and CVSptfqmrFree,
+ * respectively. It allocates memory for a structure of type
+ * CVSpilsMemRec and sets the cv_lmem field in (*cvode_mem) to the
+ * address of this structure. It sets setupNonNull in (*cvode_mem),
+ * and sets the following fields in the CVSpilsMemRec structure:
+ *
+ *   s_pretype   = pretype
+ *   s_maxl      = CVSPILS_MAXL  if maxl <= 0
+ *               = maxl          if maxl >  0
+ *   s_delt      = CVSPILS_DELT
+ *   s_P_data    = NULL
+ *   s_pset      = NULL
+ *   s_psolve    = NULL
+ *   s_jtimes    = CVSpilsDQJtimes
+ *   s_j_data    = cvode_mem
+ *   s_last_flag = CVSPILS_SUCCESS
+ *
+ * Finally, CVSptfqmr allocates memory for ytemp and x, and calls
+ * SptfqmrMalloc to allocate memory for the Sptfqmr solver.
+ * -----------------------------------------------------------------
+ */
+
+int CVSptfqmr(void *cvode_mem, int pretype, int maxl)
+{
+  CVodeMem cv_mem;
+  CVSpilsMem cvspils_mem;
+  SptfqmrMem sptfqmr_mem;
+  int mxl;
+
+  /* Return immediately if cvode_mem is NULL */
+  if (cvode_mem == NULL) {
+    CVProcessError(NULL, CVSPILS_MEM_NULL, "CVSPTFQMR", "CVSptfqmr", MSGS_CVMEM_NULL);
+    return(CVSPILS_MEM_NULL);
+  }
+  cv_mem = (CVodeMem) cvode_mem;
+
+  /* Check if N_VDotProd is present */
+  if (vec_tmpl->ops->nvdotprod == NULL) {
+    CVProcessError(cv_mem, CVSPILS_ILL_INPUT, "CVSPTFQMR", "CVSptfqmr", MSGS_BAD_NVECTOR);
+    return(CVSPILS_ILL_INPUT);
+  }
+
+  if (lfree != NULL) lfree(cv_mem);
+
+  /* Set four main function fields in cv_mem */
+  linit  = CVSptfqmrInit;
+  lsetup = CVSptfqmrSetup;
+  lsolve = CVSptfqmrSolve;
+  lfree  = CVSptfqmrFree;
+
+  /* Get memory for CVSpilsMemRec */
+  cvspils_mem = NULL;
+  cvspils_mem = (CVSpilsMem) malloc(sizeof(CVSpilsMemRec));
+  if (cvspils_mem == NULL) {
+    CVProcessError(cv_mem, CVSPILS_MEM_FAIL, "CVSPTFQMR", "CVSptfqmr", MSGS_MEM_FAIL);
+    return(CVSPILS_MEM_FAIL);
+  }
+
+  /* Set ILS type */
+  cvspils_mem->s_type = SPILS_SPTFQMR;
+
+  /* Set Sptfqmr parameters that have been passed in call sequence */
+  cvspils_mem->s_pretype = pretype;
+  mxl = cvspils_mem->s_maxl = (maxl <= 0) ? CVSPILS_MAXL : maxl;
+
+  /* Set default values for the rest of the Sptfqmr parameters */
+  cvspils_mem->s_delt      = CVSPILS_DELT;
+  cvspils_mem->s_P_data    = NULL;
+  cvspils_mem->s_pset      = NULL;
+  cvspils_mem->s_psolve    = NULL;
+  cvspils_mem->s_jtimes    = CVSpilsDQJtimes;
+  cvspils_mem->s_j_data    = cvode_mem;
+  cvspils_mem->s_last_flag = CVSPILS_SUCCESS;
+
+  setupNonNull = FALSE;
+
+  /* Check for legal pretype */ 
+  if ((pretype != PREC_NONE) && (pretype != PREC_LEFT) &&
+      (pretype != PREC_RIGHT) && (pretype != PREC_BOTH)) {
+    CVProcessError(cv_mem, CVSPILS_ILL_INPUT, "CVSPTFQMR", "CVSptfqmr", MSGS_BAD_PRETYPE);
+    return(CVSPILS_ILL_INPUT);
+  }
+
+  /* Allocate memory for ytemp and x */
+  ytemp = NULL;
+  ytemp = N_VClone(vec_tmpl);
+  if (ytemp == NULL) {
+    CVProcessError(cv_mem, CVSPILS_MEM_FAIL, "CVSPTFQMR", "CVSptfqmr", MSGS_MEM_FAIL);
+    free(cvspils_mem); cvspils_mem = NULL;
+    return(CVSPILS_MEM_FAIL);
+  }
+  x = NULL;
+  x = N_VClone(vec_tmpl);
+  if (x == NULL) {
+    CVProcessError(cv_mem, CVSPILS_MEM_FAIL, "CVSPTFQMR", "CVSptfqmr", MSGS_MEM_FAIL);
+    N_VDestroy(ytemp);
+    free(cvspils_mem); cvspils_mem = NULL;
+    return(CVSPILS_MEM_FAIL);
+  }
+
+  /* Compute sqrtN from a dot product */
+  N_VConst(ONE, ytemp);
+  sqrtN = RSqrt(N_VDotProd(ytemp, ytemp));
+
+  /* Call SptfqmrMalloc to allocate workspace for Sptfqmr */
+  sptfqmr_mem = NULL;
+  sptfqmr_mem = SptfqmrMalloc(mxl, vec_tmpl);
+  if (sptfqmr_mem == NULL) {
+    CVProcessError(cv_mem, CVSPILS_MEM_FAIL, "CVSPTFQMR", "CVSptfqmr", MSGS_MEM_FAIL);
+    N_VDestroy(ytemp);
+    N_VDestroy(x);
+    free(cvspils_mem); cvspils_mem = NULL;
+    return(CVSPILS_MEM_FAIL);
+  }
+  
+  /* Attach SPTFQMR memory to spils memory structure */
+  spils_mem = (void *) sptfqmr_mem;
+
+  /* Attach linear solver memory to integrator memory */
+  lmem = cvspils_mem;
+
+  return(CVSPILS_SUCCESS);
+}
+
+/* Additional readability replacements */
+
+#define pretype (cvspils_mem->s_pretype)
+#define delt    (cvspils_mem->s_delt)
+#define maxl    (cvspils_mem->s_maxl)
+#define psolve  (cvspils_mem->s_psolve)
+#define pset    (cvspils_mem->s_pset)
+#define P_data  (cvspils_mem->s_P_data)
+#define jtimes  (cvspils_mem->s_jtimes)
+#define j_data  (cvspils_mem->s_j_data)
+
+/*
+ * -----------------------------------------------------------------
+ * Function : CVSptfqmrInit
+ * -----------------------------------------------------------------
+ * This routine does remaining initializations specific to the Sptfqmr
+ * linear solver.
+ * -----------------------------------------------------------------
+ */
+
+static int CVSptfqmrInit(CVodeMem cv_mem)
+{
+  CVSpilsMem cvspils_mem;
+  SptfqmrMem sptfqmr_mem;
+
+  cvspils_mem = (CVSpilsMem) lmem;
+  sptfqmr_mem = (SptfqmrMem) spils_mem;
+
+  /* Initialize counters */
+  npe = nli = nps = ncfl = nstlpre = 0;
+  njtimes = nfes = 0;
+
+  /* Check for legal combination pretype - psolve */
+  if ((pretype != PREC_NONE) && (psolve == NULL)) {
+    CVProcessError(cv_mem, -1, "CVSPTFQMR", "CVSptfqmrInit", MSGS_PSOLVE_REQ);
+    last_flag = CVSPILS_ILL_INPUT;
+    return(-1);
+  }
+
+  /* Set setupNonNull = TRUE iff there is preconditioning
+     (pretype != PREC_NONE)  and there is a preconditioning
+     setup phase (pset != NULL) */
+  setupNonNull = (pretype != PREC_NONE) && (pset != NULL);
+
+  /* If jtimes is NULL at this time, set it to DQ */
+  if (jtimes == NULL) {
+    jtimes = CVSpilsDQJtimes;
+    j_data = cv_mem;
+  }
+
+  /*  Set maxl in the SPTFQMR memory in case it was changed by the user */
+  sptfqmr_mem->l_max  = maxl;
+
+  last_flag = CVSPILS_SUCCESS;
+  return(0);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * Function : CVSptfqmrSetup
+ * -----------------------------------------------------------------
+ * This routine does the setup operations for the Sptfqmr linear solver.
+ * It makes a decision as to whether or not to signal for reevaluation
+ * of Jacobian data in the pset routine, based on various state
+ * variables, then it calls pset. If we signal for reevaluation,
+ * then we reset jcur = *jcurPtr to TRUE, regardless of the pset output.
+ * In any case, if jcur == TRUE, we increment npe and save nst in nstlpre.
+ * -----------------------------------------------------------------
+ */
+
+static int CVSptfqmrSetup(CVodeMem cv_mem, int convfail, N_Vector ypred,
+			  N_Vector fpred, booleantype *jcurPtr, N_Vector vtemp1,
+			  N_Vector vtemp2, N_Vector vtemp3)
+{
+  booleantype jbad, jok;
+  realtype dgamma;
+  int  retval;
+  CVSpilsMem cvspils_mem;
+
+  cvspils_mem = (CVSpilsMem) lmem;
+
+  /* Use nst, gamma/gammap, and convfail to set J eval. flag jok */
+  dgamma = ABS((gamma/gammap) - ONE);
+  jbad = (nst == 0) || (nst > nstlpre + CVSPILS_MSBPRE) ||
+      ((convfail == CV_FAIL_BAD_J) && (dgamma < CVSPILS_DGMAX)) ||
+      (convfail == CV_FAIL_OTHER);
+  *jcurPtr = jbad;
+  jok = !jbad;
+
+  /* Call pset routine and possibly reset jcur */
+  retval = pset(tn, ypred, fpred, jok, jcurPtr, gamma, P_data, 
+                vtemp1, vtemp2, vtemp3);
+  if (retval < 0) {
+    CVProcessError(cv_mem, SPTFQMR_PSET_FAIL_UNREC, "CVSPTFQMR", "CVSptfqmrSetup", MSGS_PSET_FAILED);
+    last_flag = SPTFQMR_PSET_FAIL_UNREC;
+  }
+  if (retval > 0) {
+    last_flag = SPTFQMR_PSET_FAIL_REC;
+  }
+
+  if (jbad) *jcurPtr = TRUE;
+
+  /* If jcur = TRUE, increment npe and save nst value */
+  if (*jcurPtr) {
+    npe++;
+    nstlpre = nst;
+  }
+
+  last_flag = SPTFQMR_SUCCESS;
+
+  /* Return the same value that pset returned */
+  return(retval);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * Function : CVSptfqmrSolve
+ * -----------------------------------------------------------------
+ * This routine handles the call to the generic solver SptfqmrSolve
+ * for the solution of the linear system Ax = b with the SPTFQMR method.
+ * The solution x is returned in the vector b.
+ *
+ * If the WRMS norm of b is small, we return x = b (if this is the first
+ * Newton iteration) or x = 0 (if a later Newton iteration).
+ *
+ * Otherwise, we set the tolerance parameter and initial guess (x = 0),
+ * call SptfqmrSolve, and copy the solution x into b. The x-scaling and
+ * b-scaling arrays are both equal to weight.
+ *
+ * The counters nli, nps, and ncfl are incremented, and the return value
+ * is set according to the success of SptfqmrSolve. The success flag is
+ * returned if SptfqmrSolve converged, or if this is the first Newton
+ * iteration and the residual norm was reduced below its initial value.
+ * -----------------------------------------------------------------
+ */
+
+static int CVSptfqmrSolve(CVodeMem cv_mem, N_Vector b, N_Vector weight,
+			  N_Vector ynow, N_Vector fnow)
+{
+  realtype bnorm, res_norm;
+  CVSpilsMem cvspils_mem;
+  SptfqmrMem sptfqmr_mem;
+  int nli_inc, nps_inc, retval;
+  
+  cvspils_mem = (CVSpilsMem) lmem;
+
+  sptfqmr_mem = (SptfqmrMem) spils_mem;
+
+  /* Test norm(b); if small, return x = 0 or x = b */
+  deltar = delt * tq[4]; 
+
+  bnorm = N_VWrmsNorm(b, weight);
+  if (bnorm <= deltar) {
+    if (mnewt > 0) N_VConst(ZERO, b); 
+    return(0);
+  }
+
+  /* Set vectors ycur and fcur for use by the Atimes and Psolve routines */
+  ycur = ynow;
+  fcur = fnow;
+
+  /* Set inputs delta and initial guess x = 0 to SptfqmrSolve */  
+  delta = deltar * sqrtN;
+  N_VConst(ZERO, x);
+  
+  /* Call SptfqmrSolve and copy x to b */
+  retval = SptfqmrSolve(sptfqmr_mem, cv_mem, x, b, pretype, delta,
+                        cv_mem, weight, weight, CVSpilsAtimes, CVSpilsPSolve,
+                        &res_norm, &nli_inc, &nps_inc);
+
+  N_VScale(ONE, x, b);
+  
+  /* Increment counters nli, nps, and ncfl */
+  nli += nli_inc;
+  nps += nps_inc;
+  if (retval != SPTFQMR_SUCCESS) ncfl++;
+
+  /* Interpret return value from SpgmrSolve */
+
+  last_flag = retval;
+
+  switch(retval) {
+
+  case SPTFQMR_SUCCESS:
+    return(0);
+    break;
+  case SPTFQMR_RES_REDUCED:
+    if (mnewt == 0) return(0);
+    else            return(1);
+    break;
+  case SPTFQMR_CONV_FAIL:
+    return(1);
+    break;
+  case SPTFQMR_PSOLVE_FAIL_REC:
+    return(1);
+    break;
+  case SPTFQMR_ATIMES_FAIL_REC:
+    return(1);
+    break;
+  case SPTFQMR_MEM_NULL:
+    return(-1);
+    break;
+  case SPTFQMR_ATIMES_FAIL_UNREC:
+    CVProcessError(cv_mem, SPTFQMR_ATIMES_FAIL_UNREC, "CVSPTFQMR", "CVSptfqmrSolve", MSGS_JTIMES_FAILED);    
+    return(-1);
+    break;
+  case SPTFQMR_PSOLVE_FAIL_UNREC:
+    CVProcessError(cv_mem, SPTFQMR_PSOLVE_FAIL_UNREC, "CVSPTFQMR", "CVSptfqmrSolve", MSGS_PSOLVE_FAILED);
+    return(-1);
+    break;
+  }
+
+  return(0);  
+
+}
+
+/*
+ * -----------------------------------------------------------------
+ * Function : CVSptfqmrFree
+ * -----------------------------------------------------------------
+ * This routine frees memory specific to the Sptfqmr linear solver.
+ * -----------------------------------------------------------------
+ */
+
+static void CVSptfqmrFree(CVodeMem cv_mem)
+{
+  CVSpilsMem cvspils_mem;
+  SptfqmrMem sptfqmr_mem;
+    
+  cvspils_mem = (CVSpilsMem) lmem;
+
+  sptfqmr_mem = (SptfqmrMem) spils_mem;
+
+  N_VDestroy(ytemp);
+  N_VDestroy(x);
+  SptfqmrFree(sptfqmr_mem);
+  free(cvspils_mem); cvspils_mem = NULL;
+
+  return;
+}
+
+/* 
+ * ================================================================
+ *
+ *                   PART II - backward problems
+ *
+ * ================================================================
+ */
+      
+/* Additional readability replacements */
+
+#define lmemB       (ca_mem->ca_lmemB)
+#define lfreeB      (ca_mem->ca_lfreeB)
+
+#define pset_B      (cvspilsB_mem->s_psetB)
+#define psolve_B    (cvspilsB_mem->s_psolveB)
+#define jtimes_B    (cvspilsB_mem->s_jtimesB)
+#define P_data_B    (cvspilsB_mem->s_P_dataB)
+#define jac_data_B  (cvspilsB_mem->s_jac_dataB)
+
+/*
+ * CVSptfqmrB
+ *
+ * Wrapper for the backward phase
+ */
+
+int CVSptfqmrB(void *cvadj_mem, int pretypeB, int maxlB)
+{
+  CVadjMem ca_mem;
+  CVSpilsMemB cvspilsB_mem;
+  CVodeMem cvB_mem;
+  int flag;
+
+  if (cvadj_mem == NULL) {
+    CVProcessError(NULL, CVSPILS_ADJMEM_NULL, "CVSPTFQMR", "CVSptfqmrB", MSGS_CAMEM_NULL);
+    return(CVSPILS_ADJMEM_NULL);
+  }
+  ca_mem = (CVadjMem) cvadj_mem;
+
+  cvB_mem = ca_mem->cvb_mem;
+  
+  /* Get memory for CVSpilsMemRecB */
+  cvspilsB_mem = NULL;
+  cvspilsB_mem = (CVSpilsMemB) malloc(sizeof(CVSpilsMemRecB));
+  if (cvspilsB_mem == NULL) {
+    CVProcessError(cvB_mem, CVSPILS_MEM_FAIL, "CVSPTFQMR", "CVSptfqmrB", MSGS_MEM_FAIL);
+    return(CVSPILS_MEM_FAIL);
+  }
+
+  pset_B = NULL;
+  psolve_B = NULL;
+  jtimes_B = NULL;
+  P_data_B = NULL;
+  jac_data_B = NULL;
+
+  /* attach lmemB and lfreeB */
+  lmemB = cvspilsB_mem;
+  lfreeB = CVSptfqmrFreeB;
+
+  flag = CVSptfqmr(cvB_mem, pretypeB, maxlB);
+
+  if (flag != CVSPILS_SUCCESS) {
+    free(cvspilsB_mem); 
+    cvspilsB_mem = NULL;
+  }
+
+  return(flag);
+}
+
+/*
+ * CVSptfqmrFreeB 
+ */
+
+
+static void CVSptfqmrFreeB(CVadjMem ca_mem)
+{
+  CVSpilsMemB cvspilsB_mem;
+
+  cvspilsB_mem = (CVSpilsMemB) lmemB;
+
+  free(cvspilsB_mem);
+}
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/fnvector_parallel.c_does_not_need_to_be_compiled_for_SBT2 b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/fnvector_parallel.c_does_not_need_to_be_compiled_for_SBT2
new file mode 100644
index 0000000000000000000000000000000000000000..7ce300f72cece7d850703227e54dd35b151c735f
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/fnvector_parallel.c_does_not_need_to_be_compiled_for_SBT2	
@@ -0,0 +1,182 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * ----------------------------------------------------------------- 
+ * Programmer(s): Radu Serban @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2002, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This file (companion of nvector_parallel.h) contains the 
+ * implementation needed for the Fortran initialization of parallel 
+ * vector operations.
+ * -----------------------------------------------------------------
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "fnvector_parallel.h"
+
+/* Define global vector variables */
+
+N_Vector F2C_CVODE_vec;
+N_Vector F2C_CVODE_vecQ;
+N_Vector *F2C_CVODE_vecS;
+N_Vector F2C_CVODE_vecB;
+N_Vector F2C_CVODE_vecQB;
+
+N_Vector F2C_IDA_vec;
+N_Vector F2C_IDA_vecQ;
+N_Vector *F2C_IDA_vecS;
+N_Vector F2C_IDA_vecB;
+N_Vector F2C_IDA_vecQB;
+
+N_Vector F2C_KINSOL_vec;
+
+#ifndef SUNDIALS_MPI_COMM_F2C
+#define MPI_Fint int
+#endif
+
+/* Fortran callable interfaces */
+
+void FNV_INITP(MPI_Fint *comm, int *code, long int *L, long int *N, int *ier)
+{
+  MPI_Comm F2C_comm;
+
+#ifdef SUNDIALS_MPI_COMM_F2C
+  F2C_comm = MPI_Comm_f2c(*comm);
+#else
+  F2C_comm = MPI_COMM_WORLD;
+#endif
+
+  *ier = 0;
+
+  switch(*code) {
+  case FCMIX_CVODE:
+    F2C_CVODE_vec = NULL;
+    F2C_CVODE_vec = N_VNewEmpty_Parallel(F2C_comm, *L, *N);
+    if (F2C_CVODE_vec == NULL) *ier = -1;
+    break;
+  case FCMIX_IDA:
+    F2C_IDA_vec = NULL;
+    F2C_IDA_vec = N_VNewEmpty_Parallel(F2C_comm, *L, *N);
+    if (F2C_IDA_vec == NULL) *ier = -1;
+    break;
+  case FCMIX_KINSOL:
+    F2C_KINSOL_vec = NULL;
+    F2C_KINSOL_vec = N_VNewEmpty_Parallel(F2C_comm, *L, *N);
+    if (F2C_KINSOL_vec == NULL) *ier = -1;
+    break;
+  default:
+    *ier = -1;
+  }
+}
+
+void FNV_INITP_Q(MPI_Fint *comm, int *code, long int *Lq, long int *Nq, int *ier)
+{
+  MPI_Comm F2C_comm;
+
+#ifdef SUNDIALS_MPI_COMM_F2C
+  F2C_comm = MPI_Comm_f2c(*comm);
+#else
+  F2C_comm = MPI_COMM_WORLD;
+#endif
+
+  *ier = 0;
+
+  switch(*code) {
+  case FCMIX_CVODE:
+    F2C_CVODE_vecQ = NULL;
+    F2C_CVODE_vecQ = N_VNewEmpty_Parallel(F2C_comm, *Lq, *Nq);
+    if (F2C_CVODE_vecQ == NULL) *ier = -1;
+    break;
+  case FCMIX_IDA:
+    F2C_IDA_vecQ = NULL;
+    F2C_IDA_vecQ = N_VNewEmpty_Parallel(F2C_comm, *Lq, *Nq);
+    if (F2C_IDA_vecQ == NULL) *ier = -1;
+    break;
+  default:
+    *ier = -1;
+  }
+}
+
+void FNV_INITP_B(MPI_Fint *comm, int *code, long int *LB, long int *NB, int *ier)
+{
+  MPI_Comm F2C_comm;
+
+#ifdef SUNDIALS_MPI_COMM_F2C
+  F2C_comm = MPI_Comm_f2c(*comm);
+#else
+  F2C_comm = MPI_COMM_WORLD;
+#endif
+
+  *ier = 0;
+
+  switch(*code) {
+  case FCMIX_CVODE:
+    F2C_CVODE_vecB = NULL;
+    F2C_CVODE_vecB = N_VNewEmpty_Parallel(F2C_comm, *LB, *NB);
+    if (F2C_CVODE_vecB == NULL) *ier = -1;
+    break;
+  case FCMIX_IDA:
+    F2C_IDA_vecB = NULL;
+    F2C_IDA_vecB = N_VNewEmpty_Parallel(F2C_comm, *LB, *NB);
+    if (F2C_IDA_vecB == NULL) *ier = -1;
+    break;
+  default:
+    *ier = -1;
+  }
+}
+
+void FNV_INITP_QB(MPI_Fint *comm, int *code, long int *LqB, long int *NqB, int *ier)
+{
+  MPI_Comm F2C_comm;
+
+#ifdef SUNDIALS_MPI_COMM_F2C
+  F2C_comm = MPI_Comm_f2c(*comm);
+#else
+  F2C_comm = MPI_COMM_WORLD;
+#endif
+
+
+  *ier = 0;
+
+  switch(*code) {
+  case FCMIX_CVODE:
+    F2C_CVODE_vecQB = NULL;
+    F2C_CVODE_vecQB = N_VNewEmpty_Parallel(F2C_comm, *LqB, *NqB);
+    if (F2C_CVODE_vecQB == NULL) *ier = -1;
+    break;
+  case FCMIX_IDA:
+    F2C_IDA_vecQB = NULL;
+    F2C_IDA_vecQB = N_VNewEmpty_Parallel(F2C_comm, *LqB, *NqB);
+    if (F2C_IDA_vecQB == NULL) *ier = -1;
+    break;
+  default:
+    *ier = -1;
+  }
+}
+
+void FNV_INITP_S(int *code, int *Ns, int *ier)
+{
+  *ier = 0;
+
+  switch(*code) {
+  case FCMIX_CVODE:
+    F2C_CVODE_vecS = NULL;
+    F2C_CVODE_vecS = (N_Vector *) N_VCloneVectorArrayEmpty_Parallel(*Ns, F2C_CVODE_vec);
+    if (F2C_CVODE_vecS == NULL) *ier = -1;
+    break;
+  case FCMIX_IDA:
+    F2C_IDA_vecS = NULL;
+    F2C_IDA_vecS = (N_Vector *) N_VCloneVectorArrayEmpty_Parallel(*Ns, F2C_IDA_vec);
+    if (F2C_IDA_vecS == NULL) *ier = -1;
+    break;
+  default:
+    *ier = -1;
+  }
+}
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/fnvector_parallel.h b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/fnvector_parallel.h
new file mode 100644
index 0000000000000000000000000000000000000000..c90689bfe3fc954f4b2d2378be573a80a2174f6b
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/fnvector_parallel.h	
@@ -0,0 +1,128 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * ----------------------------------------------------------------- 
+ * Programmer(s): Radu Serban and Aaron Collier @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2002, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This file (companion of nvector_parallel.c) contains the
+ * definitions needed for the initialization of parallel
+ * vector operations in Fortran.
+ * -----------------------------------------------------------------
+ */
+
+#ifndef _FNVECTOR_PARALLEL_H
+#define _FNVECTOR_PARALLEL_H
+
+#ifdef __cplusplus  /* wrapper to enable C++ usage */
+extern "C" {
+#endif
+
+#include <nvector/nvector_parallel.h>  
+#include <sundials/sundials_fnvector.h>
+
+#if defined(F77_FUNC)
+
+#define FNV_INITP    F77_FUNC(fnvinitp, FNVINITP)
+#define FNV_INITP_Q  F77_FUNC_(fnvinitp_q, FNVINITP_Q)
+#define FNV_INITP_S  F77_FUNC_(fnvinitp_s, FNVINITP_S)
+#define FNV_INITP_B  F77_FUNC_(fnvinitp_b, FNVINITP_B)
+#define FNV_INITP_QB F77_FUNC_(fnvinitp_qb, FNVINITP_QB)
+
+#elif defined(SUNDIALS_UNDERSCORE_NONE) && defined(SUNDIALS_CASE_LOWER)
+
+#define FNV_INITP    fnvinitp
+#define FNV_INITP_Q  fnvinitp_q
+#define FNV_INITP_S  fnvinitp_s
+#define FNV_INITP_B  fnvinitp_b
+#define FNV_INITP_QB fnvinitp_qb
+
+#elif defined(SUNDIALS_UNDERSCORE_NONE) && defined(SUNDIALS_CASE_UPPER)
+
+#define FNV_INITP    FNVINITP
+#define FNV_INITP_Q  FNVINITP_Q
+#define FNV_INITP_S  FNVINITP_S
+#define FNV_INITP_B  FNVINITP_B
+#define FNV_INITP_QB FNVINITP_QB
+
+#elif defined(SUNDIALS_UNDERSCORE_ONE) && defined(SUNDIALS_CASE_LOWER)
+
+#define FNV_INITP    fnvinitp_
+#define FNV_INITP_Q  fnvinitp_q_
+#define FNV_INITP_S  fnvinitp_s_
+#define FNV_INITP_B  fnvinitp_b_
+#define FNV_INITP_QB fnvinitp_qb_
+
+#elif defined(SUNDIALS_UNDERSCORE_ONE) && defined(SUNDIALS_CASE_UPPER)
+
+#define FNV_INITP    FNVINITP_
+#define FNV_INITP_Q  FNVINITP_Q_
+#define FNV_INITP_S  FNVINITP_S_
+#define FNV_INITP_B  FNVINITP_B_
+#define FNV_INITP_QB FNVINITP_QB_
+
+#elif defined(SUNDIALS_UNDERSCORE_TWO) && defined(SUNDIALS_CASE_LOWER)
+
+#define FNV_INITP    fnvinitp__
+#define FNV_INITP_Q  fnvinitp_q__
+#define FNV_INITP_S  fnvinitp_s__
+#define FNV_INITP_B  fnvinitp_b__
+#define FNV_INITP_QB fnvinitp_qb__
+
+#elif defined(SUNDIALS_UNDERSCORE_TWO) && defined(SUNDIALS_CASE_UPPER)
+
+#define FNV_INITP    FNVINITP__
+#define FNV_INITP_Q  FNVINITP_Q__
+#define FNV_INITP_S  FNVINITP_S__
+#define FNV_INITP_B  FNVINITP_B__
+#define FNV_INITP_QB FNVINITP_QB__
+
+#endif
+
+  /* Declarations of global variables */
+
+  extern N_Vector F2C_CVODE_vec;
+  extern N_Vector F2C_CVODE_vecQ;
+  extern N_Vector *F2C_CVODE_vecS;
+  extern N_Vector F2C_CVODE_vecB;
+  extern N_Vector F2C_CVODE_vecQB;
+
+  extern N_Vector F2C_IDA_vec;
+  extern N_Vector F2C_IDA_vecQ;
+  extern N_Vector *F2C_IDA_vecS;
+  extern N_Vector F2C_IDA_vecB;
+  extern N_Vector F2C_IDA_vecQB;
+
+  extern N_Vector F2C_KINSOL_vec;
+
+  /* 
+   * Prototypes of exported functions 
+   *
+   * FNV_INITP    - initializes parallel vector operations for main problem
+   * FNV_INITP_Q  - initializes parallel vector operations for quadratures
+   * FNV_INITP_S  - initializes parallel vector operations for sensitivities
+   * FNV_INITP_B  - initializes parallel vector operations for adjoint problem
+   * FNV_INITP_QB - initializes parallel vector operations for adjoint quadratures
+   *
+   */
+
+#ifndef SUNDIALS_MPI_COMM_F2C
+#define MPI_Fint int
+#endif
+
+  void FNV_INITP(MPI_Fint *comm, int *code, long int *L, long int *N, int *ier);
+  void FNV_INITP_Q(MPI_Fint *comm, int *code, long int *Lq, long int *Nq, int *ier);
+  void FNV_INITP_B(MPI_Fint *comm, int *code, long int *LB, long int *NB, int *ier);
+  void FNV_INITP_QB(MPI_Fint *comm, int *code, long int *LqB, long int *NqB, int *ier);
+  void FNV_INITP_S(int *code, int *Ns, int *ier);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/fnvector_serial.c b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/fnvector_serial.c
new file mode 100644
index 0000000000000000000000000000000000000000..efd39922461755243f352111651dfad16e2e6714
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/fnvector_serial.c	
@@ -0,0 +1,147 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * ----------------------------------------------------------------- 
+ * Programmer(s): Radu Serban @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2002, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This file (companion of nvector_serial.h) contains the
+ * implementation needed for the Fortran initialization of serial
+ * vector operations.
+ * -----------------------------------------------------------------
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "fnvector_serial.h"
+
+/* Define global vector variables */
+
+N_Vector F2C_CVODE_vec;
+N_Vector F2C_CVODE_vecQ;
+N_Vector *F2C_CVODE_vecS;
+N_Vector F2C_CVODE_vecB;
+N_Vector F2C_CVODE_vecQB;
+
+N_Vector F2C_IDA_vec;
+N_Vector F2C_IDA_vecQ;
+N_Vector *F2C_IDA_vecS;
+N_Vector F2C_IDA_vecB;
+N_Vector F2C_IDA_vecQB;
+
+N_Vector F2C_KINSOL_vec;
+
+/* Fortran callable interfaces */
+
+void FNV_INITS(int *code, long int *N, int *ier)
+{
+  *ier = 0;
+
+  switch(*code) {
+  case FCMIX_CVODE:
+    F2C_CVODE_vec = NULL;
+    F2C_CVODE_vec = N_VNewEmpty_Serial(*N);
+    if (F2C_CVODE_vec == NULL) *ier = -1;
+    break;
+  case FCMIX_IDA:
+    F2C_IDA_vec = NULL;
+    F2C_IDA_vec = N_VNewEmpty_Serial(*N);
+    if (F2C_IDA_vec == NULL) *ier = -1;
+    break;
+  case FCMIX_KINSOL:
+    F2C_KINSOL_vec = NULL;
+    F2C_KINSOL_vec = N_VNewEmpty_Serial(*N);
+    if (F2C_KINSOL_vec == NULL) *ier = -1;
+    break;
+  default:
+    *ier = -1;
+  }
+}
+
+void FNV_INITS_Q(int *code, long int *Nq, int *ier)
+{
+  *ier = 0;
+
+  switch(*code) {
+  case FCMIX_CVODE:
+    F2C_CVODE_vecQ = NULL;
+    F2C_CVODE_vecQ = N_VNewEmpty_Serial(*Nq);
+    if (F2C_CVODE_vecQ == NULL) *ier = -1;
+    break;
+  case FCMIX_IDA:
+    F2C_IDA_vecQ = NULL;
+    F2C_IDA_vecQ = N_VNewEmpty_Serial(*Nq);
+    if (F2C_IDA_vecQ == NULL) *ier = -1;
+    break;
+  default:
+    *ier = -1;
+  }
+}
+
+void FNV_INITS_B(int *code, long int *NB, int *ier)
+{
+  *ier = 0;
+
+  switch(*code) {
+  case FCMIX_CVODE:
+    F2C_CVODE_vecB = NULL;
+    F2C_CVODE_vecB = N_VNewEmpty_Serial(*NB);
+    if (F2C_CVODE_vecB == NULL) *ier = -1;
+    break;
+  case FCMIX_IDA:
+    F2C_IDA_vecB = NULL;
+    F2C_IDA_vecB = N_VNewEmpty_Serial(*NB);
+    if (F2C_IDA_vecB == NULL) *ier = -1;
+    break;
+  default:
+    *ier = -1;
+  }
+}
+
+void FNV_INITS_QB(int *code, long int *NqB, int *ier)
+{
+  *ier = 0;
+
+  switch(*code) {
+  case FCMIX_CVODE:
+    F2C_CVODE_vecQB = NULL;
+    F2C_CVODE_vecQB = N_VNewEmpty_Serial(*NqB);
+    if (F2C_CVODE_vecQB == NULL) *ier = -1;
+    break;
+  case FCMIX_IDA:
+    F2C_IDA_vecQB = NULL;
+    F2C_IDA_vecQB = N_VNewEmpty_Serial(*NqB);
+    if (F2C_IDA_vecQB == NULL) *ier = -1;
+    break;
+  default:
+    *ier = -1;
+  }
+}
+
+void FNV_INITS_S(int *code, int *Ns, int *ier)
+{
+  *ier = 0;
+
+  switch(*code) {
+  case FCMIX_CVODE:
+    F2C_CVODE_vecS = NULL;
+    F2C_CVODE_vecS = (N_Vector *) N_VCloneVectorArrayEmpty_Serial(*Ns, F2C_CVODE_vec);
+    if (F2C_CVODE_vecS == NULL) *ier = -1;
+    break;
+  case FCMIX_IDA:
+    F2C_IDA_vecS = NULL;
+    F2C_IDA_vecS = (N_Vector *) N_VCloneVectorArrayEmpty_Serial(*Ns, F2C_IDA_vec);
+    if (F2C_IDA_vecS == NULL) *ier = -1;
+    break;
+  default:
+    *ier = -1;
+  }
+}
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/fnvector_serial.h b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/fnvector_serial.h
new file mode 100644
index 0000000000000000000000000000000000000000..cff3b8813df6f9c6ff7134dc16646eeb98c4a563
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/fnvector_serial.h	
@@ -0,0 +1,124 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * ----------------------------------------------------------------- 
+ * Programmer(s): Radu Serban and Aaron Collier @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2002, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This file (companion of nvector_serial.h) contains the
+ * definitions needed for the initialization of serial
+ * vector operations in Fortran.
+ * -----------------------------------------------------------------
+ */
+
+#ifndef _FNVECTOR_SERIAL_H
+#define _FNVECTOR_SERIAL_H
+
+#ifdef __cplusplus  /* wrapper to enable C++ usage */
+extern "C" {
+#endif
+
+#include <nvector/nvector_serial.h>  
+#include <sundials/sundials_fnvector.h>
+
+#if defined(F77_FUNC)
+
+#define FNV_INITS    F77_FUNC(fnvinits, FNVINITS)
+#define FNV_INITS_Q  F77_FUNC_(fnvinits_q, FNVINITS_Q)
+#define FNV_INITS_S  F77_FUNC_(fnvinits_s, FNVINITS_S)
+#define FNV_INITS_B  F77_FUNC_(fnvinits_b, FNVINITS_B)
+#define FNV_INITS_QB F77_FUNC_(fnvinits_qb, FNVINITS_QB)
+
+#elif defined(SUNDIALS_UNDERSCORE_NONE) && defined(SUNDIALS_CASE_LOWER)
+
+#define FNV_INITS    fnvinits
+#define FNV_INITS_Q  fnvinits_q
+#define FNV_INITS_S  fnvinits_s
+#define FNV_INITS_B  fnvinits_b
+#define FNV_INITS_QB fnvinits_qb
+
+#elif defined(SUNDIALS_UNDERSCORE_NONE) && defined(SUNDIALS_CASE_UPPER)
+
+#define FNV_INITS    FNVINITS
+#define FNV_INITS_Q  FNVINITS_Q
+#define FNV_INITS_S  FNVINITS_S
+#define FNV_INITS_B  FNVINITS_B
+#define FNV_INITS_QB FNVINITS_QB
+
+#elif defined(SUNDIALS_UNDERSCORE_ONE) && defined(SUNDIALS_CASE_LOWER)
+
+#define FNV_INITS    fnvinits_
+#define FNV_INITS_Q  fnvinits_q_
+#define FNV_INITS_S  fnvinits_s_
+#define FNV_INITS_B  fnvinits_b_
+#define FNV_INITS_QB fnvinits_qb_
+
+#elif defined(SUNDIALS_UNDERSCORE_ONE) && defined(SUNDIALS_CASE_UPPER)
+
+#define FNV_INITS    FNVINITS_
+#define FNV_INITS_Q  FNVINITS_Q_
+#define FNV_INITS_S  FNVINITS_S_
+#define FNV_INITS_B  FNVINITS_B_
+#define FNV_INITS_QB FNVINITS_QB_
+
+#elif defined(SUNDIALS_UNDERSCORE_TWO) && defined(SUNDIALS_CASE_LOWER)
+
+#define FNV_INITS    fnvinits__
+#define FNV_INITS_Q  fnvinits_q__
+#define FNV_INITS_S  fnvinits_s__
+#define FNV_INITS_B  fnvinits_b__
+#define FNV_INITS_QB fnvinits_qb__
+
+#elif defined(SUNDIALS_UNDERSCORE_TWO) && defined(SUNDIALS_CASE_UPPER)
+
+#define FNV_INITS    FNVINITS__
+#define FNV_INITS_Q  FNVINITS_Q__
+#define FNV_INITS_S  FNVINITS_S__
+#define FNV_INITS_B  FNVINITS_B__
+#define FNV_INITS_QB FNVINITS_QB__
+
+#endif
+
+  /* Declarations of global variables */
+
+  extern N_Vector F2C_CVODE_vec;
+  extern N_Vector F2C_CVODE_vecQ;
+  extern N_Vector *F2C_CVODE_vecS;
+  extern N_Vector F2C_CVODE_vecB;
+  extern N_Vector F2C_CVODE_vecQB;
+
+  extern N_Vector F2C_IDA_vec;
+  extern N_Vector F2C_IDA_vecQ;
+  extern N_Vector *F2C_IDA_vecS;
+  extern N_Vector F2C_IDA_vecB;
+  extern N_Vector F2C_IDA_vecQB;
+
+  extern N_Vector F2C_KINSOL_vec;
+
+  /* 
+   * Prototypes of exported functions 
+   *
+   * FNV_INITS    - initializes serial vector operations for main problem
+   * FNV_INITS_Q  - initializes serial vector operations for quadratures
+   * FNV_INITS_S  - initializes serial vector operations for sensitivities
+   * FNV_INITS_B  - initializes serial vector operations for adjoint problem
+   * FNV_INITS_QB - initializes serial vector operations for adjoint quadratures
+   *
+   */
+
+  void FNV_INITS(int *code, long int *neq, int *ier);
+  void FNV_INITS_Q(int *code, long int *Nq, int *ier);
+  void FNV_INITS_S(int *code, int *Ns, int *ier);
+  void FNV_INITS_B(int *code, long int *NB, int *ier);
+  void FNV_INITS_QB(int *code, long int *NqB, int *ier);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/nvector_serial.c b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/nvector_serial.c
new file mode 100644
index 0000000000000000000000000000000000000000..1766b833b9fc162afb4ad3c4189787c3fb15b0fd
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/nvector_serial.c	
@@ -0,0 +1,1034 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * ----------------------------------------------------------------- 
+ * Programmer(s): Scott D. Cohen, Alan C. Hindmarsh, Radu Serban,
+ *                and Aaron Collier @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2002, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This is the implementation file for a serial implementation
+ * of the NVECTOR package.
+ * -----------------------------------------------------------------
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <nvector/nvector_serial.h>
+#include <sundials/sundials_math.h>
+
+#define ZERO   RCONST(0.0)
+#define HALF   RCONST(0.5)
+#define ONE    RCONST(1.0)
+#define ONEPT5 RCONST(1.5)
+
+/* Private function prototypes */
+/* z=x */
+static void VCopy_Serial(N_Vector x, N_Vector z);
+/* z=x+y */
+static void VSum_Serial(N_Vector x, N_Vector y, N_Vector z);
+/* z=x-y */
+static void VDiff_Serial(N_Vector x, N_Vector y, N_Vector z);
+/* z=-x */
+static void VNeg_Serial(N_Vector x, N_Vector z);
+/* z=c(x+y) */
+static void VScaleSum_Serial(realtype c, N_Vector x, N_Vector y, N_Vector z);
+/* z=c(x-y) */
+static void VScaleDiff_Serial(realtype c, N_Vector x, N_Vector y, N_Vector z); 
+/* z=ax+y */
+static void VLin1_Serial(realtype a, N_Vector x, N_Vector y, N_Vector z);
+/* z=ax-y */
+static void VLin2_Serial(realtype a, N_Vector x, N_Vector y, N_Vector z);
+/* y <- ax+y */
+static void Vaxpy_Serial(realtype a, N_Vector x, N_Vector y);
+/* x <- ax */
+static void VScaleBy_Serial(realtype a, N_Vector x);
+
+/*
+ * -----------------------------------------------------------------
+ * exported functions
+ * -----------------------------------------------------------------
+ */
+
+/* ----------------------------------------------------------------------------
+ * Function to create a new empty serial vector 
+ */
+
+N_Vector N_VNewEmpty_Serial(long int length)
+{
+  N_Vector v;
+  N_Vector_Ops ops;
+  N_VectorContent_Serial content;
+
+  /* Create vector */
+  v = NULL;
+  v = (N_Vector) malloc(sizeof *v);
+  if (v == NULL) return(NULL);
+  
+  /* Create vector operation structure */
+  ops = NULL;
+  ops = (N_Vector_Ops) malloc(sizeof(struct _generic_N_Vector_Ops));
+  if (ops == NULL) { free(v); return(NULL); }
+
+  ops->nvclone           = N_VClone_Serial;
+  ops->nvcloneempty      = N_VCloneEmpty_Serial;
+  ops->nvdestroy         = N_VDestroy_Serial;
+  ops->nvspace           = N_VSpace_Serial;
+  ops->nvgetarraypointer = N_VGetArrayPointer_Serial;
+  ops->nvsetarraypointer = N_VSetArrayPointer_Serial;
+  ops->nvlinearsum       = N_VLinearSum_Serial;
+  ops->nvconst           = N_VConst_Serial;
+  ops->nvprod            = N_VProd_Serial;
+  ops->nvdiv             = N_VDiv_Serial;
+  ops->nvscale           = N_VScale_Serial;
+  ops->nvabs             = N_VAbs_Serial;
+  ops->nvinv             = N_VInv_Serial;
+  ops->nvaddconst        = N_VAddConst_Serial;
+  ops->nvdotprod         = N_VDotProd_Serial;
+  ops->nvmaxnorm         = N_VMaxNorm_Serial;
+  ops->nvwrmsnormmask    = N_VWrmsNormMask_Serial;
+  ops->nvwrmsnorm        = N_VWrmsNorm_Serial;
+  ops->nvmin             = N_VMin_Serial;
+  ops->nvwl2norm         = N_VWL2Norm_Serial;
+  ops->nvl1norm          = N_VL1Norm_Serial;
+  ops->nvcompare         = N_VCompare_Serial;
+  ops->nvinvtest         = N_VInvTest_Serial;
+  ops->nvconstrmask      = N_VConstrMask_Serial;
+  ops->nvminquotient     = N_VMinQuotient_Serial;
+
+  /* Create content */
+  content = NULL;
+  content = (N_VectorContent_Serial) malloc(sizeof(struct _N_VectorContent_Serial));
+  if (content == NULL) { free(ops); free(v); return(NULL); }
+
+  content->length   = length;
+  content->own_data = FALSE;
+  content->data     = NULL;
+
+  /* Attach content and ops */
+  v->content = content;
+  v->ops     = ops;
+
+  return(v);
+}
+
+/* ----------------------------------------------------------------------------
+ * Function to create a new serial vector 
+ */
+
+N_Vector N_VNew_Serial(long int length)
+{
+  N_Vector v;
+  realtype *data;
+
+  v = NULL;
+  v = N_VNewEmpty_Serial(length);
+  if (v == NULL) return(NULL);
+
+  /* Create data */
+  if (length > 0) {
+
+    /* Allocate memory */
+    data = NULL;
+    data = (realtype *) malloc(length * sizeof(realtype));
+    if(data == NULL) { N_VDestroy_Serial(v); return(NULL); }
+
+    /* Attach data */
+    NV_OWN_DATA_S(v) = TRUE;
+    NV_DATA_S(v)     = data;
+
+  }
+
+  return(v);
+}
+
+/* ----------------------------------------------------------------------------
+ * Function to create a serial N_Vector with user data component 
+ */
+
+N_Vector N_VMake_Serial(long int length, realtype *v_data)
+{
+  N_Vector v;
+
+  v = NULL;
+  v = N_VNewEmpty_Serial(length);
+  if (v == NULL) return(NULL);
+
+  if (length > 0) {
+    /* Attach data */
+    NV_OWN_DATA_S(v) = FALSE;
+    NV_DATA_S(v)     = v_data;
+  }
+
+  return(v);
+}
+
+/* ----------------------------------------------------------------------------
+ * Function to create an array of new serial vectors. 
+ */
+
+N_Vector *N_VCloneVectorArray_Serial(int count, N_Vector w)
+{
+  N_Vector *vs;
+  int j;
+
+  if (count <= 0) return(NULL);
+
+  vs = NULL;
+  vs = (N_Vector *) malloc(count * sizeof(N_Vector));
+  if(vs == NULL) return(NULL);
+
+  for (j = 0; j < count; j++) {
+    vs[j] = NULL;
+    vs[j] = N_VClone_Serial(w);
+    if (vs[j] == NULL) {
+      N_VDestroyVectorArray_Serial(vs, j-1);
+      return(NULL);
+    }
+  }
+
+  return(vs);
+}
+
+/* ----------------------------------------------------------------------------
+ * Function to create an array of new serial vectors with NULL data array. 
+ */
+
+N_Vector *N_VCloneVectorArrayEmpty_Serial(int count, N_Vector w)
+{
+  N_Vector *vs;
+  int j;
+
+  if (count <= 0) return(NULL);
+
+  vs = NULL;
+  vs = (N_Vector *) malloc(count * sizeof(N_Vector));
+  if(vs == NULL) return(NULL);
+
+  for (j = 0; j < count; j++) {
+    vs[j] = NULL;
+    vs[j] = N_VCloneEmpty_Serial(w);
+    if (vs[j] == NULL) {
+      N_VDestroyVectorArray_Serial(vs, j-1);
+      return(NULL);
+    }
+  }
+
+  return(vs);
+}
+
+/* ----------------------------------------------------------------------------
+ * Function to free an array created with N_VCloneVectorArray_Serial
+ */
+
+void N_VDestroyVectorArray_Serial(N_Vector *vs, int count)
+{
+  int j;
+
+  for (j = 0; j < count; j++) N_VDestroy_Serial(vs[j]);
+
+  free(vs); vs = NULL;
+
+  return;
+}
+
+/* ----------------------------------------------------------------------------
+ * Function to print the a serial vector 
+ */
+ 
+void N_VPrint_Serial(N_Vector x)
+{
+  long int i, N;
+  realtype *xd;
+
+  xd = NULL;
+
+  N  = NV_LENGTH_S(x);
+  xd = NV_DATA_S(x);
+
+  for (i = 0; i < N; i++) {
+#if defined(SUNDIALS_EXTENDED_PRECISION)
+    printf("%11.8Lg\n", xd[i]);
+#elif defined(SUNDIALS_DOUBLE_PRECISION)
+    printf("%11.8lg\n", xd[i]);
+#else
+    printf("%11.8g\n", xd[i]);
+#endif
+  }
+  printf("\n");
+
+  return;
+}
+
+/*
+ * -----------------------------------------------------------------
+ * implementation of vector operations
+ * -----------------------------------------------------------------
+ */
+
+N_Vector N_VCloneEmpty_Serial(N_Vector w)
+{
+  N_Vector v;
+  N_Vector_Ops ops;
+  N_VectorContent_Serial content;
+
+  if (w == NULL) return(NULL);
+
+  /* Create vector */
+  v = NULL;
+  v = (N_Vector) malloc(sizeof *v);
+  if (v == NULL) return(NULL);
+
+  /* Create vector operation structure */
+  ops = NULL;
+  ops = (N_Vector_Ops) malloc(sizeof(struct _generic_N_Vector_Ops));
+  if (ops == NULL) { free(v); return(NULL); }
+  
+  ops->nvclone           = w->ops->nvclone;
+  ops->nvcloneempty      = w->ops->nvcloneempty;
+  ops->nvdestroy         = w->ops->nvdestroy;
+  ops->nvspace           = w->ops->nvspace;
+  ops->nvgetarraypointer = w->ops->nvgetarraypointer;
+  ops->nvsetarraypointer = w->ops->nvsetarraypointer;
+  ops->nvlinearsum       = w->ops->nvlinearsum;
+  ops->nvconst           = w->ops->nvconst;  
+  ops->nvprod            = w->ops->nvprod;   
+  ops->nvdiv             = w->ops->nvdiv;
+  ops->nvscale           = w->ops->nvscale; 
+  ops->nvabs             = w->ops->nvabs;
+  ops->nvinv             = w->ops->nvinv;
+  ops->nvaddconst        = w->ops->nvaddconst;
+  ops->nvdotprod         = w->ops->nvdotprod;
+  ops->nvmaxnorm         = w->ops->nvmaxnorm;
+  ops->nvwrmsnormmask    = w->ops->nvwrmsnormmask;
+  ops->nvwrmsnorm        = w->ops->nvwrmsnorm;
+  ops->nvmin             = w->ops->nvmin;
+  ops->nvwl2norm         = w->ops->nvwl2norm;
+  ops->nvl1norm          = w->ops->nvl1norm;
+  ops->nvcompare         = w->ops->nvcompare;    
+  ops->nvinvtest         = w->ops->nvinvtest;
+  ops->nvconstrmask      = w->ops->nvconstrmask;
+  ops->nvminquotient     = w->ops->nvminquotient;
+
+  /* Create content */
+  content = NULL;
+  content = (N_VectorContent_Serial) malloc(sizeof(struct _N_VectorContent_Serial));
+  if (content == NULL) { free(ops); free(v); return(NULL); }
+
+  content->length   = NV_LENGTH_S(w);
+  content->own_data = FALSE;
+  content->data     = NULL;
+
+  /* Attach content and ops */
+  v->content = content;
+  v->ops     = ops;
+
+  return(v);
+}
+
+N_Vector N_VClone_Serial(N_Vector w)
+{
+  N_Vector v;
+  realtype *data;
+  long int length;
+
+  v = NULL;
+  v = N_VCloneEmpty_Serial(w);
+  if (v == NULL) return(NULL);
+
+  length = NV_LENGTH_S(w);
+
+  /* Create data */
+  if (length > 0) {
+
+    /* Allocate memory */
+    data = NULL;
+    data = (realtype *) malloc(length * sizeof(realtype));
+    if(data == NULL) { N_VDestroy_Serial(v); return(NULL); }
+
+    /* Attach data */
+    NV_OWN_DATA_S(v) = TRUE;
+    NV_DATA_S(v)     = data;
+
+  }
+
+  return(v);
+}
+
+void N_VDestroy_Serial(N_Vector v)
+{
+  if (NV_OWN_DATA_S(v) == TRUE) {
+    free(NV_DATA_S(v));
+    NV_DATA_S(v) = NULL;
+  }
+  free(v->content); v->content = NULL;
+  free(v->ops); v->ops = NULL;
+  free(v); v = NULL;
+
+  return;
+}
+
+void N_VSpace_Serial(N_Vector v, long int *lrw, long int *liw)
+{
+  *lrw = NV_LENGTH_S(v);
+  *liw = 1;
+
+  return;
+}
+
+realtype *N_VGetArrayPointer_Serial(N_Vector v)
+{
+  return((realtype *) NV_DATA_S(v));
+}
+
+void N_VSetArrayPointer_Serial(realtype *v_data, N_Vector v)
+{
+  if (NV_LENGTH_S(v) > 0) NV_DATA_S(v) = v_data;
+
+  return;
+}
+
+void N_VLinearSum_Serial(realtype a, N_Vector x, realtype b, N_Vector y, N_Vector z)
+{
+  long int i, N;
+  realtype c, *xd, *yd, *zd;
+  N_Vector v1, v2;
+  booleantype test;
+
+  xd = yd = zd = NULL;
+
+  if ((b == ONE) && (z == y)) {    /* BLAS usage: axpy y <- ax+y */
+    Vaxpy_Serial(a,x,y);
+    return;
+  }
+
+  if ((a == ONE) && (z == x)) {    /* BLAS usage: axpy x <- by+x */
+    Vaxpy_Serial(b,y,x);
+    return;
+  }
+
+  /* Case: a == b == 1.0 */
+
+  if ((a == ONE) && (b == ONE)) {
+    VSum_Serial(x, y, z);
+    return;
+  }
+
+  /* Cases: (1) a == 1.0, b = -1.0, (2) a == -1.0, b == 1.0 */
+
+  if ((test = ((a == ONE) && (b == -ONE))) || ((a == -ONE) && (b == ONE))) {
+    v1 = test ? y : x;
+    v2 = test ? x : y;
+    VDiff_Serial(v2, v1, z);
+    return;
+  }
+
+  /* Cases: (1) a == 1.0, b == other or 0.0, (2) a == other or 0.0, b == 1.0 */
+  /* if a or b is 0.0, then user should have called N_VScale */
+
+  if ((test = (a == ONE)) || (b == ONE)) {
+    c  = test ? b : a;
+    v1 = test ? y : x;
+    v2 = test ? x : y;
+    VLin1_Serial(c, v1, v2, z);
+    return;
+  }
+
+  /* Cases: (1) a == -1.0, b != 1.0, (2) a != 1.0, b == -1.0 */
+
+  if ((test = (a == -ONE)) || (b == -ONE)) {
+    c = test ? b : a;
+    v1 = test ? y : x;
+    v2 = test ? x : y;
+    VLin2_Serial(c, v1, v2, z);
+    return;
+  }
+
+  /* Case: a == b */
+  /* catches case both a and b are 0.0 - user should have called N_VConst */
+
+  if (a == b) {
+    VScaleSum_Serial(a, x, y, z);
+    return;
+  }
+
+  /* Case: a == -b */
+
+  if (a == -b) {
+    VScaleDiff_Serial(a, x, y, z);
+    return;
+  }
+
+  /* Do all cases not handled above:
+     (1) a == other, b == 0.0 - user should have called N_VScale
+     (2) a == 0.0, b == other - user should have called N_VScale
+     (3) a,b == other, a !=b, a != -b */
+  
+  N  = NV_LENGTH_S(x);
+  xd = NV_DATA_S(x);
+  yd = NV_DATA_S(y);
+  zd = NV_DATA_S(z);
+
+  for (i = 0; i < N; i++)
+    zd[i] = (a*xd[i])+(b*yd[i]);
+
+  return;
+}
+
+void N_VConst_Serial(realtype c, N_Vector z)
+{
+  long int i, N;
+  realtype *zd;
+
+  zd = NULL;
+
+  N  = NV_LENGTH_S(z);
+  zd = NV_DATA_S(z);
+
+  for (i = 0; i < N; i++) zd[i] = c;
+
+  return;
+}
+
+void N_VProd_Serial(N_Vector x, N_Vector y, N_Vector z)
+{
+  long int i, N;
+  realtype *xd, *yd, *zd;
+
+  xd = yd = zd = NULL;
+
+  N  = NV_LENGTH_S(x);
+  xd = NV_DATA_S(x);
+  yd = NV_DATA_S(y);
+  zd = NV_DATA_S(z);
+
+  for (i = 0; i < N; i++)
+    zd[i] = xd[i]*yd[i];
+
+  return;
+}
+
+void N_VDiv_Serial(N_Vector x, N_Vector y, N_Vector z)
+{
+  long int i, N;
+  realtype *xd, *yd, *zd;
+
+  xd = yd = zd = NULL;
+
+  N  = NV_LENGTH_S(x);
+  xd = NV_DATA_S(x);
+  yd = NV_DATA_S(y);
+  zd = NV_DATA_S(z);
+
+  for (i = 0; i < N; i++)
+    zd[i] = xd[i]/yd[i];
+
+  return;
+}
+
+void N_VScale_Serial(realtype c, N_Vector x, N_Vector z)
+{
+  long int i, N;
+  realtype *xd, *zd;
+
+  xd = zd = NULL;
+
+  if (z == x) {  /* BLAS usage: scale x <- cx */
+    VScaleBy_Serial(c, x);
+    return;
+  }
+
+  if (c == ONE) {
+    VCopy_Serial(x, z);
+  } else if (c == -ONE) {
+    VNeg_Serial(x, z);
+  } else {
+    N  = NV_LENGTH_S(x);
+    xd = NV_DATA_S(x);
+    zd = NV_DATA_S(z);
+    for (i = 0; i < N; i++) 
+      zd[i] = c*xd[i];
+  }
+
+  return;
+}
+
+void N_VAbs_Serial(N_Vector x, N_Vector z)
+{
+  long int i, N;
+  realtype *xd, *zd;
+
+  xd = zd = NULL;
+
+  N  = NV_LENGTH_S(x);
+  xd = NV_DATA_S(x);
+  zd = NV_DATA_S(z);
+
+  for (i = 0; i < N; i++)
+    zd[i] = ABS(xd[i]);
+
+  return;
+}
+
+void N_VInv_Serial(N_Vector x, N_Vector z)
+{
+  long int i, N;
+  realtype *xd, *zd;
+
+  xd = zd = NULL;
+
+  N  = NV_LENGTH_S(x);
+  xd = NV_DATA_S(x);
+  zd = NV_DATA_S(z);
+
+  for (i = 0; i < N; i++)
+    zd[i] = ONE/xd[i];
+
+  return;
+}
+
+void N_VAddConst_Serial(N_Vector x, realtype b, N_Vector z)
+{
+  long int i, N;
+  realtype *xd, *zd;
+
+  xd = zd = NULL;
+
+  N  = NV_LENGTH_S(x);
+  xd = NV_DATA_S(x);
+  zd = NV_DATA_S(z);
+
+  for (i = 0; i < N; i++) 
+    zd[i] = xd[i]+b;
+
+  return;
+}
+
+realtype N_VDotProd_Serial(N_Vector x, N_Vector y)
+{
+  long int i, N;
+  realtype sum, *xd, *yd;
+
+  sum = ZERO;
+  xd = yd = NULL;
+
+  N  = NV_LENGTH_S(x);
+  xd = NV_DATA_S(x);
+  yd = NV_DATA_S(y);
+
+  for (i = 0; i < N; i++)
+    sum += xd[i]*yd[i];
+  
+  return(sum);
+}
+
+realtype N_VMaxNorm_Serial(N_Vector x)
+{
+  long int i, N;
+  realtype max, *xd;
+
+  max = ZERO;
+  xd = NULL;
+
+  N  = NV_LENGTH_S(x);
+  xd = NV_DATA_S(x);
+
+  for (i = 0; i < N; i++) {
+    if (ABS(xd[i]) > max) max = ABS(xd[i]);
+  }
+
+  return(max);
+}
+
+realtype N_VWrmsNorm_Serial(N_Vector x, N_Vector w)
+{
+  long int i, N;
+  realtype sum, prodi, *xd, *wd;
+
+  sum = ZERO;
+  xd = wd = NULL;
+
+  N  = NV_LENGTH_S(x);
+  xd = NV_DATA_S(x);
+  wd = NV_DATA_S(w);
+
+  for (i = 0; i < N; i++) {
+    prodi = xd[i]*wd[i];
+    sum += SQR(prodi);
+  }
+
+  return(RSqrt(sum/N));
+}
+
+realtype N_VWrmsNormMask_Serial(N_Vector x, N_Vector w, N_Vector id)
+{
+  long int i, N;
+  realtype sum, prodi, *xd, *wd, *idd;
+
+  sum = ZERO;
+  xd = wd = idd = NULL;
+
+  N  = NV_LENGTH_S(x);
+  xd  = NV_DATA_S(x);
+  wd  = NV_DATA_S(w);
+  idd = NV_DATA_S(id);
+
+  for (i = 0; i < N; i++) {
+    if (idd[i] > ZERO) {
+      prodi = xd[i]*wd[i];
+      sum += SQR(prodi);
+    }
+  }
+
+  return(RSqrt(sum / N));
+}
+
+realtype N_VMin_Serial(N_Vector x)
+{
+  long int i, N;
+  realtype min, *xd;
+
+  xd = NULL;
+
+  N  = NV_LENGTH_S(x);
+  xd = NV_DATA_S(x);
+
+  min = xd[0];
+
+  for (i = 1; i < N; i++) {
+    if (xd[i] < min) min = xd[i];
+  }
+
+  return(min);
+}
+
+realtype N_VWL2Norm_Serial(N_Vector x, N_Vector w)
+{
+  long int i, N;
+  realtype sum, prodi, *xd, *wd;
+
+  sum = ZERO;
+  xd = wd = NULL;
+
+  N  = NV_LENGTH_S(x);
+  xd = NV_DATA_S(x);
+  wd = NV_DATA_S(w);
+
+  for (i = 0; i < N; i++) {
+    prodi = xd[i]*wd[i];
+    sum += SQR(prodi);
+  }
+
+  return(RSqrt(sum));
+}
+
+realtype N_VL1Norm_Serial(N_Vector x)
+{
+  long int i, N;
+  realtype sum, *xd;
+
+  sum = ZERO;
+  xd = NULL;
+
+  N  = NV_LENGTH_S(x);
+  xd = NV_DATA_S(x);
+  
+  for (i = 0; i<N; i++)  
+    sum += ABS(xd[i]);
+
+  return(sum);
+}
+
+void N_VCompare_Serial(realtype c, N_Vector x, N_Vector z)
+{
+  long int i, N;
+  realtype *xd, *zd;
+
+  xd = zd = NULL;
+
+  N  = NV_LENGTH_S(x);
+  xd = NV_DATA_S(x);
+  zd = NV_DATA_S(z);
+
+  for (i = 0; i < N; i++) {
+    zd[i] = (ABS(xd[i]) >= c) ? ONE : ZERO;
+  }
+
+  return;
+}
+
+booleantype N_VInvTest_Serial(N_Vector x, N_Vector z)
+{
+  long int i, N;
+  realtype *xd, *zd;
+
+  xd = zd = NULL;
+
+  N  = NV_LENGTH_S(x);
+  xd = NV_DATA_S(x);
+  zd = NV_DATA_S(z);
+
+  for (i = 0; i < N; i++) {
+    if (xd[i] == ZERO) return(FALSE);
+    zd[i] = ONE/xd[i];
+  }
+
+  return(TRUE);
+}
+
+booleantype N_VConstrMask_Serial(N_Vector c, N_Vector x, N_Vector m)
+{
+  long int i, N;
+  booleantype test;
+  realtype *cd, *xd, *md;
+
+  cd = xd = md = NULL;
+
+  N  = NV_LENGTH_S(x);
+  xd = NV_DATA_S(x);
+  cd = NV_DATA_S(c);
+  md = NV_DATA_S(m);
+
+  test = TRUE;
+
+  for (i = 0; i < N; i++) {
+    md[i] = ZERO;
+    if (cd[i] == ZERO) continue;
+    if (cd[i] > ONEPT5 || cd[i] < -ONEPT5) {
+      if ( xd[i]*cd[i] <= ZERO) { test = FALSE; md[i] = ONE; }
+      continue;
+    }
+    if ( cd[i] > HALF || cd[i] < -HALF) {
+      if (xd[i]*cd[i] < ZERO ) { test = FALSE; md[i] = ONE; }
+    }
+  }
+
+  return(test);
+}
+
+realtype N_VMinQuotient_Serial(N_Vector num, N_Vector denom)
+{
+  booleantype notEvenOnce;
+  long int i, N;
+  realtype *nd, *dd, min;
+
+  nd = dd = NULL;
+
+  N  = NV_LENGTH_S(num);
+  nd = NV_DATA_S(num);
+  dd = NV_DATA_S(denom);
+
+  notEvenOnce = TRUE;
+  min = BIG_REAL;
+
+  for (i = 0; i < N; i++) {
+    if (dd[i] == ZERO) continue;
+    else {
+      if (!notEvenOnce) min = MIN(min, nd[i]/dd[i]);
+      else {
+	min = nd[i]/dd[i];
+        notEvenOnce = FALSE;
+      }
+    }
+  }
+
+  return(min);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * private functions
+ * -----------------------------------------------------------------
+ */
+
+static void VCopy_Serial(N_Vector x, N_Vector z)
+{
+  long int i, N;
+  realtype *xd, *zd;
+
+  xd = zd = NULL;
+
+  N  = NV_LENGTH_S(x);
+  xd = NV_DATA_S(x);
+  zd = NV_DATA_S(z);
+
+  for (i = 0; i < N; i++)
+    zd[i] = xd[i]; 
+
+  return;
+}
+
+static void VSum_Serial(N_Vector x, N_Vector y, N_Vector z)
+{
+  long int i, N;
+  realtype *xd, *yd, *zd;
+
+  xd = yd = zd = NULL;
+
+  N  = NV_LENGTH_S(x);
+  xd = NV_DATA_S(x);
+  yd = NV_DATA_S(y);
+  zd = NV_DATA_S(z);
+
+  for (i = 0; i < N; i++)
+    zd[i] = xd[i]+yd[i];
+
+  return;
+}
+
+static void VDiff_Serial(N_Vector x, N_Vector y, N_Vector z)
+{
+  long int i, N;
+  realtype *xd, *yd, *zd;
+
+  xd = yd = zd = NULL;
+
+  N  = NV_LENGTH_S(x);
+  xd = NV_DATA_S(x);
+  yd = NV_DATA_S(y);
+  zd = NV_DATA_S(z);
+
+  for (i = 0; i < N; i++)
+    zd[i] = xd[i]-yd[i];
+
+  return;
+}
+
+static void VNeg_Serial(N_Vector x, N_Vector z)
+{
+  long int i, N;
+  realtype *xd, *zd;
+
+  xd = zd = NULL;
+
+  N  = NV_LENGTH_S(x);
+  xd = NV_DATA_S(x);
+  zd = NV_DATA_S(z);
+  
+  for (i = 0; i < N; i++)
+    zd[i] = -xd[i];
+
+  return;
+}
+
+static void VScaleSum_Serial(realtype c, N_Vector x, N_Vector y, N_Vector z)
+{
+  long int i, N;
+  realtype *xd, *yd, *zd;
+
+  xd = yd = zd = NULL;
+
+  N  = NV_LENGTH_S(x);
+  xd = NV_DATA_S(x);
+  yd = NV_DATA_S(y);
+  zd = NV_DATA_S(z);
+
+  for (i = 0; i < N; i++)
+    zd[i] = c*(xd[i]+yd[i]);
+
+  return;
+}
+
+static void VScaleDiff_Serial(realtype c, N_Vector x, N_Vector y, N_Vector z)
+{
+  long int i, N;
+  realtype *xd, *yd, *zd;
+
+  xd = yd = zd = NULL;
+
+  N  = NV_LENGTH_S(x);
+  xd = NV_DATA_S(x);
+  yd = NV_DATA_S(y);
+  zd = NV_DATA_S(z);
+
+  for (i = 0; i < N; i++)
+    zd[i] = c*(xd[i]-yd[i]);
+
+  return;
+}
+
+static void VLin1_Serial(realtype a, N_Vector x, N_Vector y, N_Vector z)
+{
+  long int i, N;
+  realtype *xd, *yd, *zd;
+
+  xd = yd = zd = NULL;
+
+  N  = NV_LENGTH_S(x);
+  xd = NV_DATA_S(x);
+  yd = NV_DATA_S(y);
+  zd = NV_DATA_S(z);
+
+  for (i = 0; i < N; i++)
+    zd[i] = (a*xd[i])+yd[i];
+
+  return;
+}
+
+static void VLin2_Serial(realtype a, N_Vector x, N_Vector y, N_Vector z)
+{
+  long int i, N;
+  realtype *xd, *yd, *zd;
+
+  xd = yd = zd = NULL;
+
+  N  = NV_LENGTH_S(x);
+  xd = NV_DATA_S(x);
+  yd = NV_DATA_S(y);
+  zd = NV_DATA_S(z);
+
+  for (i = 0; i < N; i++)
+    zd[i] = (a*xd[i])-yd[i];
+
+  return;
+}
+
+static void Vaxpy_Serial(realtype a, N_Vector x, N_Vector y)
+{
+  long int i, N;
+  realtype *xd, *yd;
+
+  xd = yd = NULL;
+
+  N  = NV_LENGTH_S(x);
+  xd = NV_DATA_S(x);
+  yd = NV_DATA_S(y);
+
+  if (a == ONE) {
+    for (i = 0; i < N; i++)
+      yd[i] += xd[i];
+    return;
+  }
+
+  if (a == -ONE) {
+    for (i = 0; i < N; i++)
+      yd[i] -= xd[i];
+    return;
+  }    
+
+  for (i = 0; i < N; i++)
+    yd[i] += a*xd[i];
+
+  return;
+}
+
+static void VScaleBy_Serial(realtype a, N_Vector x)
+{
+  long int i, N;
+  realtype *xd;
+
+  xd = NULL;
+
+  N  = NV_LENGTH_S(x);
+  xd = NV_DATA_S(x);
+
+  for (i = 0; i < N; i++)
+    xd[i] *= a;
+
+  return;
+}
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/source_SUNDIALS_CVODES b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/source_SUNDIALS_CVODES
new file mode 100644
index 0000000000000000000000000000000000000000..2675704d64f6f4294fabf95a19beb4b5dd177701
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/source_SUNDIALS_CVODES	
@@ -0,0 +1,959 @@
+/*
+ * interfaceSER.c: MEX/CVODES Interface
+ *
+ * SBPD 
+ * Copyright 2006 by Fraunhofer-Chalmers Research Centre, Gothenburg, Sweden
+ * All rights reserved.me
+ *
+ * The main author of SBaddon is Henning Schmidt (henning@sbtoolbox.org). 
+ */
+
+/* General includes */
+#include <stddef.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+/* MEX file inculde */
+#include <mex.h>
+#include <matrix.h>
+
+/* CVODES relevant includes */
+#include <cvodes/cvodes.h>
+#include <nvector/nvector_serial.h>
+#include <sundials/sundials_types.h>
+#include <sundials/sundials_math.h>
+
+/* Include file for this interface */
+#include "interfaceSER.h"
+
+/* CVODES related contstants */
+#define ATOL  1.0e-6  /* default absolute tolerance */
+#define RTOL  1.0e-6  /* default relative tolerance */
+
+/* Accessor macros */
+#define Ith(v,i) NV_Ith_S(v,i-1)
+
+/* Help function to add a row vector to a matrix */
+static void includeVectorInMatrix(double *matrix, double *rowvector, int row, int nrows, int ncols);
+
+/* Function(s) Called by the Solver */
+static void f(double time, N_Vector u, N_Vector udot, void *f_data);
+static void g(double time, N_Vector y, double *gout, void *g_data);
+
+/* Error Function */
+static void error(char *text);
+
+/* All Variables */
+    /* Input variables */
+    mxArray *timevectorMX = NULL;
+    mxArray *parametervectorMX = NULL;
+    mxArray *initialconditionsMX = NULL;
+    mxArray *optionsMX = NULL;
+    mxArray *minstepMX = NULL;
+    mxArray *maxstepMX = NULL;
+    mxArray *maxnumstepsMX = NULL;
+    mxArray *methodMX = NULL;
+    mxArray *reltolMX = NULL;
+    mxArray *abstolMX = NULL;
+    mxArray *simdataMX = NULL;
+    mxArray *sensitivityMX = NULL;
+    mxArray *sensparamMX = NULL;
+    mxArray *sensstatesMX = NULL;
+    mxArray *senstypeMX = NULL;
+    mxArray *senserrorMX = NULL;
+    mxArray *sensparamscalingMX = NULL;
+    double *timevector = NULL;
+    int numbertimesteps;
+    double *parametervector = NULL;
+    double *parametervectorCVODE = NULL; /* parameters for right hand side. in case of sensitivity analysis eventually augmented by states */
+    double *initialconditions = NULL;
+    double minstep;
+    double maxstep;
+    long int maxnumsteps;
+    int method;
+    double reltol;
+    double abstol;
+    int simdata;
+    int sensitivity;
+    int senstype;
+    booleantype senserror;
+    int *sensparamstates;
+    /* Output variables */
+    mxArray *outputMX = NULL;
+    mxArray *statevaluesMX = NULL;
+    mxArray *variablevaluesMX = NULL;
+    mxArray *reactionvaluesMX = NULL;
+    mxArray *statesMX = NULL;
+    mxArray *variablesMX = NULL;
+    mxArray *reactionsMX = NULL;
+    mxArray *eventsMX = NULL;
+    mxArray *eventtimesMX = NULL;
+    mxArray *eventflagsMX = NULL;
+    double *output = NULL;
+    double *statevalues = NULL;
+    double *variablevalues = NULL;
+    double *reactionvalues = NULL;
+    double *eventtimes = NULL;
+    double *eventflags = NULL;
+    /* Help variables */
+    int ncols, nrows, inputStringLength;
+    int k,k2;
+    /* Model Data */
+    ModelData modeldata;
+    /* CVODE IVP related variables */
+    N_Vector u;
+    void *cvode_mem;
+    int flag, flagr;
+    double treturn;
+    /* Simulation related variables */
+    double tendstep;
+    double *statevector = NULL;
+    double *variablevector = NULL;
+    double *reactionvector = NULL;
+    int *eventvector = NULL;
+    double *oldeventvalues = NULL;
+    int numberevents;
+    double *eventflagscollect = NULL;
+    double checkeventcorrect;
+    /* Sensitivity related variables */
+    int nrsensparam;
+    int sensparamdefault;
+    int sensstatesdefault;
+    double *sensparamdouble = NULL;
+    int nrsensstates;
+    double *sensstatesdouble = NULL;
+    double *sensparamscaling = NULL;
+    double *sensparamscalingdata = NULL;
+    N_Vector *uS = NULL;
+    double *sensvector = NULL;
+    double **sensitivitydataparam = NULL;
+    double **sensitivitydatastates = NULL;
+    mxArray **sensitivitydataparamMX = NULL;
+    mxArray **sensitivitydatastatesMX = NULL;
+    mxArray *sensparamoutMX = NULL;
+    mxArray *sensitivityparamdataoutMX = NULL;
+    mxArray *sensstatesoutMX = NULL;
+    mxArray *sensitivitystatesdataoutMX = NULL;
+    /* Output function related */
+    mxArray *outputfunctionMX = NULL;
+    mxArray *checkoutputfunctionMX = NULL;
+    mxArray **outputfunctionRHS = NULL;
+    char outputfunction[100];
+    double *checkoutputfunction = NULL;
+    bool outputfunctionFlag;
+    /* whatever */
+    double *temp;
+    double timestepout;
+    char buffer[250];
+    
+/*
+ *========================================================================
+ * MEX interface to MATLAB
+ *========================================================================
+ */
+void interfaceSER(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
+{
+    /*
+     * ==============================================
+     * HANDLE VARIABLE INPUT ARGUMENTS
+     * ==============================================
+     */
+    if (nrhs == 0) {
+        /* In the case of no input argument the default initial conditions
+           of the model are returned. */
+        outputMX = mxCreateDoubleMatrix(NRSTATES, 1, mxREAL);
+        output = mxGetPr(outputMX);
+        for (k=0; k<NRSTATES; k++) output[k] = initialconditionsDefault[k];
+        plhs[0] = outputMX;
+        return;
+    } else if (nrhs == 1) {
+        /*
+           In the case of a single input argument the following cases exist:
+           1) arg = 'states' => output = species names in cell-array
+           2) arg = 'parameters' => output = parameter names in cell-array
+           3) arg = 'parametervalues' => output = parameter values in column vector
+           4) arg = [timevector] => do simulation, output = data structure
+           We start by checking if input argument is a string
+         */
+        if (mxIsChar(prhs[0])) {
+            /*
+               Get the length of the input string
+               Comparison of the string lengths instead of the string itself
+               (easier, faster, etc.)
+             */
+            inputStringLength = (mxGetM(prhs[0]) * mxGetN(prhs[0]));
+            if (inputStringLength == 6) {       /* "states" */
+                /* Return cellarray containing the state names */
+                outputMX = mxCreateCellMatrix(NRSTATES, 1);
+                for (k=0; k<NRSTATES; k++) mxSetCell(outputMX,k,mxCreateString(statenames[k]));
+                plhs[0] = outputMX;
+                return;
+            }
+            else if (inputStringLength == 10) { /* "parameters" */
+                /* Return cellarray containing the parameter names */
+                outputMX = mxCreateCellMatrix(NRPARAMETERS, 1);
+                for (k=0; k<NRPARAMETERS; k++) mxSetCell(outputMX,k,mxCreateString(parameternames[k]));
+                plhs[0] = outputMX;
+                return;
+            }
+            else if (inputStringLength == 15) { /* "parametervalues" */
+                /* Return vector containing the parameter values */
+                outputMX = mxCreateDoubleMatrix(NRPARAMETERS, 1, mxREAL);
+                output = mxGetPr(outputMX);
+                for (k=0; k<NRPARAMETERS; k++) output[k] = parametervectorDefault[k];
+                plhs[0] = outputMX;
+                return;
+            } else error("Incorrect input argument.");
+        } else {
+            /* Input argument is not a string. Check if it contains doubles, if not display error message and exit.*/
+            if (!mxIsDouble(prhs[0])) error("Check 'timevector' input argument.");
+            /*
+               Input argument is a double ... assume it is the timevector (checked later)
+               Get the timevector and set all other optional data to NULL
+             */
+            timevectorMX = (mxArray *) prhs[0];
+            parametervectorMX = NULL;
+            initialconditionsMX = NULL;
+            optionsMX = NULL;
+        }
+    } else if (nrhs == 2) {
+        /* check if timevector is a double */
+        if (!mxIsDouble(prhs[0])) error("Check 'timevector' input argument.");
+        timevectorMX = (mxArray *) prhs[0];
+        /* check if initialconditions is a double or empty */
+        if (!mxIsDouble(prhs[1]) && !mxIsEmpty(prhs[1])) error("Check 'initialconditions' input argument.");
+        initialconditionsMX = (mxArray *) prhs[1];
+        parametervectorMX = NULL;
+        optionsMX = NULL;
+    } else if (nrhs == 3) {
+        /* check if timevector is a double */
+        if (!mxIsDouble(prhs[0])) error("Check 'timevector' input argument.");
+        timevectorMX = (mxArray *) prhs[0];
+        /* check if initialconditions is a double */
+        if (!mxIsDouble(prhs[1]) && !mxIsEmpty(prhs[1])) error("Check 'initialconditions' input argument.");
+        initialconditionsMX = (mxArray *) prhs[1];
+        /* check if parametervector  is a double */
+        if (!mxIsDouble(prhs[2]) && !mxIsEmpty(prhs[1])) error("Check 'parametervector' input argument.");
+        parametervectorMX = (mxArray *) prhs[2];
+        optionsMX = NULL;
+    } else if (nrhs == 4) {
+        /* check if timevector is a double */
+        if (!mxIsDouble(prhs[0])) error("Check 'timevector' input argument.");
+        timevectorMX = (mxArray *) prhs[0];
+        /* check if initialconditions is a double */
+        if (!mxIsDouble(prhs[1]) && !mxIsEmpty(prhs[1])) error("Check 'initialconditions' input argument.");
+        initialconditionsMX = (mxArray *) prhs[1];
+        /* check if parametervector  is a double */
+        if (!mxIsDouble(prhs[2]) && !mxIsEmpty(prhs[1])) error("Check 'parametervector' input argument.");
+        parametervectorMX = (mxArray *) prhs[2];
+        /* check if options is a structure (empty [] is allowed) */
+        if (!mxIsStruct(prhs[3]) && !mxIsEmpty(prhs[3])) error("Check 'options' input argument.");
+        optionsMX = (mxArray *) prhs[3];
+    } else {
+        error("Incorrect number of input arguments.");
+    }
+    /*
+       Check if the time vector is a vector. If not then display an error message.
+       Otherwise get the timevector data
+     */
+    ncols = mxGetN(timevectorMX);
+    nrows = mxGetM(timevectorMX);
+    if (ncols*nrows == 1 || (nrows > 1 && ncols > 1)) error("'timevector' input argument needs to be a vector.");
+    timevector = mxGetPr(timevectorMX);
+    numbertimesteps = ncols*nrows;
+    /*
+       Check if initialconditions is a vector of correct length. If not then display error.
+       Otherwise get the initialconditions data
+     */
+    initialconditions = (double *) mxCalloc(NRSTATES,sizeof(double));
+    if (initialconditions == NULL) error("Memory allocation for initial conditions failed.");
+    for (k=0;k<NRSTATES;k++) initialconditions[k] = initialconditionsDefault[k];
+    if (initialconditionsMX != NULL) {
+        if (!mxIsEmpty(initialconditionsMX)) {
+            ncols = mxGetN(initialconditionsMX);
+            nrows = mxGetM(initialconditionsMX);
+            if (ncols*nrows != NRSTATES || (nrows > 1 && ncols > 1)) error("'initialconditions' needs to be a vector of 'number states' length.");
+            /* Need to duplicate the initial condition MX array */
+            initialconditions = mxGetPr(mxDuplicateArray(initialconditionsMX));
+        }
+    }
+    /*
+       Check if parametervector is a vector of correct length. If not then display error.
+       Otherwise get the parametervector data
+     */
+    parametervector = parametervectorDefault;
+    if (parametervectorMX != NULL) {
+        if (!mxIsEmpty(parametervectorMX)) {
+            ncols = mxGetN(parametervectorMX);
+            nrows = mxGetM(parametervectorMX);
+            if (ncols*nrows != NRPARAMETERS || (nrows > 1 && ncols > 1)) error("'parametervector' needs to be a vector of 'number parameters' length.");
+            parametervector = mxGetPr(parametervectorMX);
+        }
+    }
+    /*
+       Check if options is not empty and a structure. If not then use default values.
+       Otherwise get the options data. Set first the default values:
+     */
+    minstep = -1;
+    maxstep = -1;
+    maxnumsteps = -1; /* max number internal steps <0 => default (500) */
+    method = 0;     /* 0 = stiff, 1 = nonstiff, default: 0 */
+    reltol = RTOL;  /* default values for relative tolerance */
+    abstol = ATOL;  /* default values for absolute tolerance */
+    simdata = 0;    /* 0 = 'states', 1 = 'all', default: 0 */
+    sensitivity = 0;  /* 0 = no sensitivity computation, 1 = sensitivity computation */
+    senstype = CV_SIMULTANEOUS;     /* 1 = simultaneous, 2 = staggered, 3 = staggered1 */
+    senserror = false;    /* TRUE = full, FALSE = partial */
+    sensparamstates = NULL; /* default: all parameters */
+    sensparamscalingdata = NULL;
+    outputfunctionFlag = false;
+    if (optionsMX != NULL) {
+        if (!mxIsEmpty(optionsMX)) {
+            /* read out the options structure */
+            /*  1) simulation related */
+            minstepMX = mxGetField(optionsMX, 0, "minstep");
+            maxstepMX = mxGetField(optionsMX, 0, "maxstep");
+            maxnumstepsMX = mxGetField(optionsMX, 0, "maxnumsteps");
+            methodMX = mxGetField(optionsMX, 0, "method");
+            reltolMX = mxGetField(optionsMX, 0, "reltol");
+            abstolMX = mxGetField(optionsMX, 0, "abstol");
+            simdataMX = mxGetField(optionsMX, 0, "simdata");
+            /*  2) sensitivity related */
+            sensitivityMX = mxGetField(optionsMX, 0, "sensitivity");
+            sensparamMX = mxGetField(optionsMX, 0, "sensparams");
+            sensstatesMX = mxGetField(optionsMX, 0, "sensstates");
+            senstypeMX = mxGetField(optionsMX, 0, "senstype");
+            senserrorMX = mxGetField(optionsMX, 0, "senserror");
+            sensparamscalingMX = mxGetField(optionsMX, 0, "sensparamscaling");
+            /*  3) output function related */
+            outputfunctionMX = mxGetField(optionsMX, 0, "outputfunction");
+            /* get the values of the fields now */
+            if (minstepMX != NULL) if (mxIsDouble(minstepMX)) minstep = mxGetScalar(minstepMX); else error("'options.minstep' wrongly defined.");
+            if (maxstepMX != NULL) if (mxIsDouble(maxstepMX)) maxstep = mxGetScalar(maxstepMX); else error("'options.maxstep' wrongly defined.");
+            if (maxnumstepsMX != NULL) if (mxIsDouble(maxnumstepsMX)) maxnumsteps = (long int)mxGetScalar(maxnumstepsMX); else error("'options.maxnumsteps' wrongly defined.");
+            if (methodMX != NULL) {
+                if (mxIsChar(methodMX)) {
+                    if (mxGetM(methodMX) * mxGetN(methodMX) == 8) {
+                        method = 1; /* "nonstiff" method */
+                    } else if (mxGetM(methodMX) * mxGetN(methodMX) == 5) {
+                        method = 0; /* "stiff method */
+                    } else {
+                        error("'options.method' wrongly defined.");
+                    }
+                } else {
+                    error("'options.method' wrongly defined.");
+                }
+            }
+            if (reltolMX != NULL) if (mxIsDouble(reltolMX)) reltol = mxGetScalar(reltolMX); else error("'options.reltol' wrongly defined.");
+            if (abstolMX != NULL) if (mxIsDouble(abstolMX)) abstol = mxGetScalar(abstolMX); else error("'options.abstol' wrongly defined.");
+            if (simdataMX != NULL) {
+                if (mxIsChar(simdataMX)) {
+                    if (mxGetM(simdataMX) * mxGetN(simdataMX) == 3) {
+                        simdata = 1; /* "all" */
+                    } else if (mxGetM(simdataMX) * mxGetN(simdataMX) == 6) {
+                        simdata = 0; /* "states" */
+                    } else {
+                        error("'options.simdata' wrongly defined.");
+                    }
+                } else {
+                    error("'options.simdata' wrongly defined.");
+                }
+            }
+            /* handle sensitivity related options */
+            if (sensitivityMX != NULL) {
+                if (mxIsChar(sensitivityMX)) {
+                    if (mxGetM(sensitivityMX) * mxGetN(sensitivityMX) == 3) {
+                        sensitivity = 1; /* "yes" */
+                    } else if (mxGetM(sensitivityMX) * mxGetN(sensitivityMX) == 2) {
+                        sensitivity = 0; /* "no" */
+                    } else {
+                        error("'options.sensitivity' wrongly defined ('yes' or 'no').");
+                    }
+                } else {
+                    error("'options.sensitivity' wrongly defined ('yes' or 'no').");
+                }
+            }
+            if (senstypeMX != NULL && sensitivity == 1) {
+                if (mxIsChar(senstypeMX)) {
+                    if (mxGetM(senstypeMX) * mxGetN(senstypeMX) == 12) {
+                        senstype = CV_SIMULTANEOUS; /* "simultaneous" */
+                    } else if (mxGetM(senstypeMX) * mxGetN(senstypeMX) == 9) {
+                        senstype = CV_STAGGERED; /* "staggered" */
+                    } else if (mxGetM(senstypeMX) * mxGetN(senstypeMX) == 10) {
+                        senstype = CV_STAGGERED1; /* "staggered1" */
+                    } else {
+                        error("'options.senstype' wrongly defined ('simultaneous' or 'staggered' or 'staggered1').");
+                    }
+                } else {
+                    error("'options.senstype' wrongly defined ('simultaneous' or 'staggered' or 'staggered1').");
+                }
+            }
+            if (senserrorMX != NULL && sensitivity == 1) {
+                if (mxIsChar(senserrorMX)) {
+                    if (mxGetM(senserrorMX) * mxGetN(senserrorMX) == 4) {
+                        senserror = true; /* "full" */
+                    } else if (mxGetM(senserrorMX) * mxGetN(senserrorMX) == 7) {
+                        senserror = false; /* "partial" */
+                    } else {
+                        error("'options.senserror' wrongly defined ('full' or 'partial').");
+                    }
+                } else {
+                    error("'options.senserror' wrongly defined ('full' or 'partial').");
+                }
+            }
+            if (sensparamMX != NULL && sensitivity == 1) {
+                if (mxIsEmpty(sensparamMX)) sensparamMX = NULL;
+                else {
+                    if (!mxIsDouble(sensparamMX)) error("Check 'options.sensparams' input argument.");
+                    sensparamdouble = mxGetPr(sensparamMX);
+                }
+            }
+            if (sensstatesMX != NULL && sensitivity == 1) {
+                if (mxIsEmpty(sensstatesMX)) sensstatesMX = NULL;
+                else {
+                    if (!mxIsDouble(sensstatesMX)) error("Check 'options.sensstates' input argument.");
+                    sensstatesdouble = mxGetPr(sensstatesMX);
+                }
+            }
+            if (sensparamscalingMX != NULL && sensitivity == 1) {
+                if (!mxIsDouble(sensparamscalingMX)) error("Check 'options.sensparamscaling' input argument.");
+                sensparamscalingdata = mxGetPr(sensparamscalingMX);
+            }
+            if (sensparamMX != NULL && sensparamscalingMX != NULL) {
+                if (mxGetM(sensparamMX)*mxGetN(sensparamMX) == 0)
+                    error("No parameters for sensitivity analysis are defined.");
+                if (mxGetM(sensparamMX)*mxGetN(sensparamMX) != mxGetM(sensparamscalingMX)*mxGetN(sensparamscalingMX))
+                    error("Different number of 'sensparamstates' and 'sensparamscaling' elements.");
+            }
+            if (sensparamMX == NULL && sensparamscalingMX != NULL) {
+                if (mxGetM(sensparamscalingMX)*mxGetN(sensparamscalingMX) != NRPARAMETERS)
+                    error("Please specify 'options.sensparamscaling' for all parameters in the model.");
+            }
+            if (outputfunctionMX != NULL) {
+                if (!mxIsEmpty(outputfunctionMX)) {
+                    if (!mxIsChar(outputfunctionMX)) error("Check 'options.outputfunction' input argument.");
+                    /* Check if given string determines an existing function in matlab */
+                    mexCallMATLAB(1, &checkoutputfunctionMX, 1, &outputfunctionMX, "exist");
+                    checkoutputfunction = (double *) mxGetData(checkoutputfunctionMX);
+                    if (checkoutputfunction[0] != 2 && checkoutputfunction[0] != 3)
+                        error("Defined output function does not exist in MATLAB path! Check 'options.outputfunction' input argument.");
+                    mxGetString(outputfunctionMX, outputfunction, (mxGetM(outputfunctionMX) * mxGetN(outputfunctionMX) * sizeof(mxChar)) + 1);
+                    outputfunctionFlag = true;
+                }
+            }
+        }
+    }
+    
+    /*
+     * ==============================================
+     * ALLOCATE MEMORY FOR THE SIMULATION
+     * ==============================================
+     */
+    /* statevalues is a 2 dimensional array with NRSTATES columns and nrtimesteps rows */
+    statevaluesMX = mxCreateDoubleMatrix(numbertimesteps, NRSTATES, mxREAL);
+    if (statevaluesMX == NULL) error("Memory allocation for state values failed.");
+    statevalues = mxGetPr(statevaluesMX);
+    /* if simdata = 1 then do allocate memory for additional simulation results */
+    if (simdata == 1) {
+        if (NRVARIABLES > 0) {
+            /* allocate memory for the variablevector */
+            variablevector = (double *) mxCalloc(NRVARIABLES, sizeof(double));
+            if (variablevector == NULL) error("Memory allocation for variable vector failed.");
+            /* variablevalues is a 2 dimensional array with NRVARIABLES columns and nrtimesteps rows */
+            variablevaluesMX = mxCreateDoubleMatrix(numbertimesteps, NRVARIABLES, mxREAL);
+            if (variablevaluesMX == NULL) error("Memory allocation for variable values failed.");
+            variablevalues = mxGetPr(variablevaluesMX);
+        }
+        if (NRREACTIONS > 0) {
+            /* allocate memory for the reactionvector */
+            reactionvector = (double *) mxCalloc(NRREACTIONS, sizeof(double));
+            if (reactionvector == NULL) error("Memory allocation for reaction vector failed.");
+            /* reactionvalues is a 2 dimensional array with NRVARIABLES columns and nrtimesteps rows */
+            reactionvaluesMX = mxCreateDoubleMatrix(numbertimesteps, NRREACTIONS, mxREAL);
+            if (reactionvaluesMX == NULL) error("Memory allocation for reaction values failed.");
+            reactionvalues = mxGetPr(reactionvaluesMX);
+        }
+    }
+    /* Allocate memory for the eventvector array */
+    if (NREVENTS > 0) {
+        eventvector = (int *) mxCalloc(NREVENTS, sizeof(int));
+        if (eventvector == NULL) error("Memory allocation for eventvector vector failed.");
+        oldeventvalues = (double *) mxCalloc(NREVENTS, sizeof(double));
+        if (oldeventvalues == NULL) error("Memory allocation for oldeventvalues vector failed.");
+    }
+    if (sensitivity == 1) {
+        /* Allocate memory for index list of sensitivity parameters (parameters + initial conditions) */
+        /* parameters */
+        if (sensparamMX == NULL) { nrsensparam = NRPARAMETERS; sensparamdefault = 1; }
+        else { nrsensparam = mxGetM(sensparamMX) * mxGetN(sensparamMX);  sensparamdefault = 0; }
+        
+        /* states (initial conditions) */
+        if (sensstatesMX == NULL) { nrsensstates = NRSTATES; sensstatesdefault = 1; }
+        else { nrsensstates = mxGetM(sensstatesMX) * mxGetN(sensstatesMX); sensstatesdefault = 0; }
+        /* sensparamstates' includes both parameter and state indices */
+        sensparamstates = (int *) mxCalloc(nrsensparam+nrsensstates, sizeof(int));
+        if (sensparamstates == NULL) error("Memory allocation for sensparamstates vector failed.");
+        /* Check the number of parameters and states to use in computation */
+        if (nrsensparam == 0 && nrsensstates == 0) error("No parameters or states specified. Sensitivity analysis does not make sense!");
+        /* Allocate memory for scaling factors of sensitivity parameters (if needed) */
+        sensparamscaling = (double *) mxCalloc(nrsensparam+nrsensstates, sizeof(double));
+        if (sensparamscaling == NULL) error("Memory allocation for sensparamscaling failed.");
+        /* Allocate memory for sensitivity data pointers */
+        sensitivitydataparam = (double **) mxCalloc(nrsensparam, sizeof(double *));
+        if (sensitivitydataparam == NULL) error("Memory allocation for sensitivitydataparam failed.");
+        sensitivitydatastates = (double **) mxCalloc(nrsensstates, sizeof(double *));
+        if (sensitivitydatastates == NULL) error("Memory allocation for sensitivitydatastates failed.");
+        /* Allocate memory for sensitivity data mxArrays */
+        sensitivitydataparamMX = (mxArray **) mxCalloc(nrsensparam, sizeof(mxArray *));
+        if (sensitivitydataparamMX == NULL) error("Memory allocation for sensitivitydataparamMX failed.");
+        sensitivitydatastatesMX = (mxArray **) mxCalloc(nrsensstates, sizeof(mxArray *));
+        if (sensitivitydatastatesMX == NULL) error("Memory allocation for sensitivitydatastatesMX failed.");
+        /* Allocate memory for sensitivity trajectories */
+        for (k=0; k<nrsensparam; k++) {
+            sensitivitydataparamMX[k] = (mxArray *) mxCreateDoubleMatrix(numbertimesteps, NRSTATES, mxREAL);
+            if (sensitivitydataparamMX[k] == NULL) error("Memory allocation for sensitivity data failed.");
+            sensitivitydataparam[k] = mxGetPr(sensitivitydataparamMX[k]);
+        }
+        for (k=0; k<nrsensstates; k++) {
+            sensitivitydatastatesMX[k] = (mxArray *) mxCreateDoubleMatrix(numbertimesteps, NRSTATES, mxREAL);
+            if (sensitivitydatastatesMX[k] == NULL) error("Memory allocation for sensitivity data failed.");
+            sensitivitydatastates[k] = mxGetPr(sensitivitydatastatesMX[k]);
+        }
+    }
+    
+    /*
+     * ==============================================
+     * SET THE MODEL DATA (PARAMETERS)
+     * In the case of sensitivity analysis also with respect to initial conditions
+     * the parameter vector needs to be augmented by the number of states
+     * ==============================================
+     */
+    if (sensitivity == 1) {
+        /* get augmented memory for right hand side parameter vector */
+        parametervectorCVODE = (double *) mxCalloc(NRPARAMETERS+NRSTATES, sizeof(double));
+        if (parametervectorCVODE == NULL) error("Memory allocation for parametervectorCVODE failed.");
+        /* copy parameter values from parametervector the values corresponding to the states are arbitrary since not used in the model */
+        for (k=0; k<NRPARAMETERS; k++) parametervectorCVODE[k] = parametervector[k];
+        for (k=NRPARAMETERS; k<NRSTATES+NRPARAMETERS; k++) parametervectorCVODE[k] = 1.0;
+        modeldata.parametervector = parametervectorCVODE;
+    }
+    else {
+        /* If no sensitivity calculations the non augmented parametervector can be used */
+        modeldata.parametervector = parametervector;
+    }
+    
+    /*
+     * ==============================================
+     * INITIALIZE CVODE (INTEGRATION)
+     * ==============================================
+     */
+    u = NULL;
+    cvode_mem = NULL;
+    /* Create serial vector and initialize it with the initial conditions */
+    u = N_VMake_Serial(NRSTATES,initialconditions);
+    /* Call CvodeCreate to create integrator memory */
+    if (method == 0) cvode_mem = CVodeCreate(CV_BDF, CV_NEWTON);    /* default (stiff) */
+    else cvode_mem = CVodeCreate(CV_ADAMS, CV_FUNCTIONAL);          /* nonstiff */
+    if (cvode_mem == NULL) error("Error: CVodeCreate.");
+    /*
+       Call CVodeMalloc to initialize the integrator memory:
+       cvode_mem is the pointer to the integrator memory returned by CVodeCreate
+       f       is the user's right hand side function in y'=f(t,y)
+       T0      is the initial time
+       u       is the initial dependent variable vector
+       CV_SS   specifies scalar relative and absolute tolerances
+       reltol  is the scalar relative tolerance
+       &abstol is a pointer to the scalar absolute tolerance
+     */
+    flag = CVodeMalloc(cvode_mem, f, timevector[0], u, CV_SS, reltol, &abstol);
+    if (flag < 0) error("Error: CVodeMalloc.");
+    /* Add the root finding function in case that events are present */
+    if (NREVENTS > 0) {
+        flag = CVodeRootInit(cvode_mem, NREVENTS, g, &modeldata);
+        if (flag < 0) error("Error: CVodeRootInit.");
+    }
+    /* Set the pointer to modeldata */
+    flag = CVodeSetFdata(cvode_mem, &modeldata);
+    if(flag < 0) error("Error: CVodeSetFdata.");
+    /* Set min and max steps if given by user */
+    if (minstep > 0) {
+        flag = CVodeSetMinStep(cvode_mem, minstep);
+        if (flag < 0) error("Error: CVodeSetMinStep.");
+    }
+    if (maxstep > 0) {
+        flag = CVodeSetMaxStep(cvode_mem, maxstep);
+        if (flag < 0) error("Error: CVodeSetMaxStep.");
+    }
+    if (maxnumsteps > 0) {
+        flag = CVodeSetMaxNumSteps(cvode_mem, maxnumsteps);
+        if (flag < 0) error("Error: CVodeSetMaxNumSteps.");
+    }
+    /* Call CVDense to specify the CVDense band linear solver */
+    flag = CVDense(cvode_mem,NRSTATES);
+    if (flag < 0) error("Error: CVDense.");
+    /*
+     * ==============================================
+     * INITIALIZE CVODE (SENSITIVITY)
+     * ==============================================
+     */
+    if (sensitivity) {
+        /* fill the sensparamstates vector with the indices of the parameters and states that are to be considered */
+        /* nrsensparams needs to be added to the state indices */
+        if (sensparamdefault) {
+            /* per default use all parameters in same order as in model */
+            for(k=0; k<nrsensparam; k++) sensparamstates[k] = k+1;
+        } else {
+            /* if parameter indices given then convert them from double to int */
+            for (k=0; k<nrsensparam; k++) sensparamstates[k] = (int)sensparamdouble[k];
+        }
+        if (sensstatesdefault) {
+        /* per default use all states in same order as in model */
+            for(k=0; k<nrsensstates; k++) sensparamstates[nrsensparam+k] = NRPARAMETERS+k+1;
+        } else {
+        /* if state indices given then convert them from double to int */
+            for (k=0; k<nrsensstates; k++) sensparamstates[nrsensparam+k] = NRPARAMETERS+(int)sensstatesdouble[k];
+        }
+        /* Assign scaling factors for each sensitivity parameter (for ics values are arbitrary) */
+        if (sensparamscalingdata == NULL) for(k=0; k<nrsensparam+nrsensstates; k++) sensparamscaling[k] = 1.0;
+        else {
+            for(k=0; k<nrsensparam; k++) sensparamscaling[k] = sensparamscalingdata[k];
+            for(k=nrsensparam; k<nrsensparam+nrsensstates; k++) sensparamscaling[k] = 1.0;
+        }
+        /* Initial conditions for sensitivities (0 for parameters and 1 for states) */
+        uS = N_VCloneVectorArray_Serial(nrsensparam+nrsensstates,u);
+        for(k=0;k<nrsensparam;k++) N_VConst(0.0, uS[k]);    /* parameters */
+        for(k=0; k<nrsensstates; k++) {
+            N_VConst(0.0, uS[k+nrsensparam]); /* states ics */
+            Ith(uS[k+nrsensparam],sensparamstates[k+nrsensparam]-NRPARAMETERS) = 1.0; /* set ics for icstate trajectories to identity matrix */
+        }
+        /* Initialize memory for sensitivity computation */
+        flag = CVodeSensMalloc(cvode_mem, nrsensparam+nrsensstates, senstype, uS);
+        if (flag < 0) error("Error: CVodeSensMalloc.");
+        /* Set error control method */
+        flag = CVodeSetSensErrCon(cvode_mem, senserror);
+        if (flag < 0) error("Error: CVodeSetSensErrCon.");
+        /* Set parameter information */
+        flag = CVodeSetSensParams(cvode_mem, modeldata.parametervector, sensparamscaling, sensparamstates);
+        if (flag < 0) error("Error: CVodeSetSensParams.");
+    }
+    /*
+     * ==============================================
+     * PERFORM THE INTEGRATION
+     * ==============================================
+     */
+    /* Add initial conditions as first entry to simulation results (statevalues) */
+    includeVectorInMatrix(statevalues,initialconditions,0,numbertimesteps,NRSTATES);
+    if (sensitivity) {
+    /* Add initial conditions for initial condition sensitivities (identity matrix) */
+    /* The parameter sensitivities have zero initial conditions and thus do not need to be set (already zero) */
+        for (k=0; k<nrsensstates; k++) {
+            sensvector = NV_DATA_S(uS[nrsensparam+k]);
+            includeVectorInMatrix(sensitivitydatastates[k], sensvector, 0, numbertimesteps, NRSTATES);
+        }
+    }
+    /* If simdata = 1 then determine variables and reactions for initialconditions */
+    if (simdata == 1) {
+        model(timevector[0], initialconditions, NULL, &modeldata, CVODE_VARREAC, variablevector, reactionvector,NULL,NULL);
+        /* Add data to simulation results */
+        if (NRVARIABLES > 0) includeVectorInMatrix(variablevalues,variablevector,0,numbertimesteps,NRVARIABLES);
+        if (NRREACTIONS > 0) includeVectorInMatrix(reactionvalues,reactionvector,0,numbertimesteps,NRREACTIONS);
+    }
+    if (NREVENTS > 0) {
+        /*
+           If events are present in the model then determine the
+           event evaluation vector for last successful step
+           This will be needed to determine directions of events
+           (only from negative to positive zero crossings are valid events)
+         */
+        model(timevector[0], initialconditions, NULL, &modeldata, CVODE_EVENTS, NULL, NULL, oldeventvalues, NULL);
+    }
+    /* Loop over the time vector */
+    k = 1;
+    tendstep = timevector[k]; /* Define first desired endstep */
+    numberevents = 0; /* initialize saying no event found so far */
+    while(1) {
+        /* integrate the time step */
+        flag = CVode(cvode_mem, tendstep, u, &treturn, CV_NORMAL);
+
+        sprintf(buffer, "%f\n",tendstep);
+        mexPrintf(buffer);
+        
+        if (flag < 0) {
+            if (flag == CV_TOO_MUCH_WORK) error("Error: CVode. To large time steps in timevector and/or to small value of 'maxnumsteps' options.");
+            else if (flag == CV_TOO_MUCH_ACC) error("Error: CVode. Given tolerances could not be met.");
+            else if (flag == CV_ERR_FAILURE || flag == CV_CONV_FAILURE) error("Error: CVode. Error or convergence test fails to often or minimum step size reached.");
+            else {
+                sprintf(buffer, "Error: CVode. You might want to try different tolerances, steps, method. %d",flag);
+                error(buffer);
+            }
+        }
+        /* Get new statevector */
+        statevector = NV_DATA_S(u);
+        /* CHECK IF RETURNED FROM AN EVENT */
+        if (flag == CV_ROOT_RETURN) {
+            /* Handle the event */
+            flagr = CVodeGetRootInfo(cvode_mem, eventvector);
+            if (flagr < 0) error("Error: CVodeGetRootInfo.");
+            /* call the model to determine new statevector */
+            checkeventcorrect = 0;
+            model(treturn, statevector, &checkeventcorrect, &modeldata, CVODE_EVENTASSIGNMENT, NULL, NULL, oldeventvalues, eventvector);
+            /* reinitialize CVODE */
+            flag = CVodeReInit(cvode_mem, f, treturn, u, CV_SS, reltol, &abstol);
+            if (flag < 0) error("Error: CVodeReInit.");
+            /* if event was correct then add it to output variable */
+            if (checkeventcorrect > 0) {
+                numberevents += 1;  /* increase counter */
+                /* add event time to vector and reallocate memory */
+                if (numberevents == 1) {
+                    /* allocate memory for saving event information (only for first step) */
+                    eventtimes = (double *) mxCalloc(1, sizeof(double));
+                    eventflagscollect = (double *) mxCalloc(NREVENTS, sizeof(double));
+                } else {
+                    /* reallocate memory for saving event information (only for first step) */
+                    eventtimes = (double *) mxRealloc((void *) eventtimes, numberevents*sizeof(double));
+                    eventflagscollect = (double *) mxRealloc((void *) eventflagscollect, NREVENTS*numberevents*sizeof(double));
+                }
+                eventtimes[numberevents-1] = treturn;
+                for (k2=0;k2<NREVENTS;k2++) eventflagscollect[NREVENTS*(numberevents-1)+k2] = (double)eventvector[k2];
+            }
+            /* Leave tendstep and k unchanged */
+        }
+        if (tendstep == treturn) { /* it can happen that an event happens exactly on a time step */
+            includeVectorInMatrix(statevalues,statevector,k,numbertimesteps,NRSTATES);
+            /*
+               If simdata = 1 then determine variables and reactions for current step
+               and include the results in the result matrices.
+             */
+            if (simdata == 1) {
+                model(tendstep, statevector, NULL, &modeldata, CVODE_VARREAC, variablevector, reactionvector, NULL, NULL);
+                if (NRVARIABLES > 0) includeVectorInMatrix(variablevalues,variablevector,k,numbertimesteps,NRVARIABLES);
+                if (NRREACTIONS > 0) includeVectorInMatrix(reactionvalues,reactionvector,k,numbertimesteps,NRREACTIONS);
+            }
+            /* Get sensitivities and save them for output */
+            if (sensitivity) {
+                if (CVodeGetSens(cvode_mem, treturn, uS) < 0) error("Error: CVodeGetSens.");
+                /* parameters */
+                for (k2=0; k2<nrsensparam; k2++) {
+                    sensvector = NV_DATA_S(uS[k2]);
+                    includeVectorInMatrix(sensitivitydataparam[k2], sensvector, k, numbertimesteps, NRSTATES);
+                }
+                /* states */
+                for (k2=0; k2<nrsensstates; k2++) {
+                    sensvector = NV_DATA_S(uS[nrsensparam+k2]);
+                    includeVectorInMatrix(sensitivitydatastates[k2], sensvector, k, numbertimesteps, NRSTATES);
+                }
+            }
+            /* Handle output function if specified */
+            if (outputfunctionFlag) {
+                outputfunctionRHS = (mxArray **) mxCalloc(4, sizeof(mxArray *));
+                /* Check if given string determines an existing function in matlab */
+                timestepout = tendstep;
+                outputfunctionRHS[0] = mxCreateDoubleScalar(timestepout);
+                outputfunctionRHS[1] = mxCreateDoubleMatrix(NRSTATES, 1, mxREAL);
+                temp = mxGetPr(outputfunctionRHS[1]);
+                for (k2=0;k2<NRSTATES;k2++) temp[k2] = statevector[k2];
+                if (simdata == 1) {
+                    outputfunctionRHS[2] = mxCreateDoubleMatrix(NRVARIABLES, 1, mxREAL);
+                    temp = mxGetPr(outputfunctionRHS[2]);
+                    for (k2=0;k2<NRVARIABLES;k2++) temp[k2] = variablevector[k2];
+                    outputfunctionRHS[3] = mxCreateDoubleMatrix(NRREACTIONS, 1, mxREAL);
+                    temp = mxGetPr(outputfunctionRHS[3]);
+                    for (k2=0;k2<NRREACTIONS;k2++) temp[k2] = reactionvector[k2];
+                }
+                else {
+                    outputfunctionRHS[2] = mxCreateDoubleMatrix(NRVARIABLES, 0, mxREAL);
+                    outputfunctionRHS[3] = mxCreateDoubleMatrix(NRREACTIONS, 0, mxREAL);
+                }
+                mexCallMATLAB(0, NULL, 4, outputfunctionRHS, outputfunction);
+                mxDestroyArray(outputfunctionRHS[0]);
+                mxDestroyArray(outputfunctionRHS[1]);
+                mxDestroyArray(outputfunctionRHS[2]);
+                mxDestroyArray(outputfunctionRHS[3]);
+            }
+            /* increase k and set new tendstep - leave loop if last timestep reached */
+            k = k+1;
+            if (k < numbertimesteps) tendstep = timevector[k];
+            else break; /* leave the integration loop when end time reached */
+        }
+        if (NREVENTS > 0) {
+            /*
+               If events are present in the model then determine the
+               event evaluation vector for last successful step
+               This will be needed to determine directions of events
+               (only from negative to positive zero crossings are valid events)
+             */
+            model(treturn, statevector, NULL, &modeldata, CVODE_EVENTS, NULL, NULL, oldeventvalues, NULL);
+        }
+    }
+    /*
+     * ==============================================
+     * FREE CVODE RELATED VARIABLES
+     * ==============================================
+     */
+    N_VDestroy_Serial(u);  /* Free the u vector */
+    if (sensitivity) {
+        N_VDestroyVectorArray_Serial(uS,nrsensparam);
+        mxFree(sensparamscaling);
+        mxFree(parametervectorCVODE);
+    }
+    CVodeFree(cvode_mem);  /* Free the integrator memory */
+    /*
+     * ==============================================
+     * CONSTRUCT OUTPUT VARIABLE
+     * ==============================================
+     */
+    outputMX = mxCreateStructMatrix(1,1,0,NULL);
+    /* Create fields in output structure */
+    mxAddField(outputMX,"time");
+    mxAddField(outputMX,"states");
+    mxAddField(outputMX,"statevalues");
+    /* If simdata = 1, add variables and reactions to the structure */
+    if (simdata == 1) {
+        mxAddField(outputMX,"variables");
+        mxAddField(outputMX,"variablevalues");
+        mxAddField(outputMX,"reactions");
+        mxAddField(outputMX,"reactionvalues");
+    }
+    if (NREVENTS > 0) {
+        mxAddField(outputMX,"events");
+        mxAddField(outputMX,"eventtimes");
+        mxAddField(outputMX,"eventflags");
+    }
+    if (sensitivity) {
+        mxAddField(outputMX,"sensparameters");
+        mxAddField(outputMX,"sensparamtrajectories");
+        mxAddField(outputMX,"sensicstates");
+        mxAddField(outputMX,"sensicstatetrajectories");
+    }
+    /* Add numeric information to output structure */
+    mxSetField(outputMX, 0, "time", mxDuplicateArray(timevectorMX));
+    mxSetField(outputMX, 0, "statevalues", statevaluesMX);
+    /* If simdata = 1, add variables and reactions to the structure */
+    if (simdata == 1) {
+        if (NRVARIABLES > 0) mxSetField(outputMX, 0, "variablevalues", variablevaluesMX);
+        if (NRREACTIONS > 0) mxSetField(outputMX, 0, "reactionvalues", reactionvaluesMX);
+    }
+    /* Construct state name cell array */
+    statesMX = mxCreateCellMatrix(1, NRSTATES);
+    for (k=0;k<NRSTATES;k++) mxSetCell(statesMX,k,mxCreateString(statenames[k]));
+    mxSetField(outputMX, 0, "states", statesMX);
+    /* If simdata = 1, add variables and reactions to the structure */
+    if (simdata == 1) {
+        /* Construct variable name cell array */
+        if (NRVARIABLES > 0) {
+            variablesMX = mxCreateCellMatrix(1, NRVARIABLES);
+            for (k=0;k<NRVARIABLES;k++) mxSetCell(variablesMX,k,mxCreateString(variablenames[k]));
+            mxSetField(outputMX, 0, "variables", variablesMX);
+        }
+        /* Construct reaction name cell array */
+        if (NRREACTIONS > 0) {
+            reactionsMX = mxCreateCellMatrix(1, NRREACTIONS);
+            for (k=0;k<NRREACTIONS;k++) mxSetCell(reactionsMX,k,mxCreateString(reactionnames[k]));
+            mxSetField(outputMX, 0, "reactions", reactionsMX);
+        }
+    }
+    if (NREVENTS > 0) {
+        eventsMX = mxCreateCellMatrix(1, NREVENTS);
+        for (k=0;k<NREVENTS;k++) mxSetCell(eventsMX,k,mxCreateString(eventnames[k]));
+        mxSetField(outputMX, 0, "events", eventsMX);
+        if (numberevents > 0) {
+            eventtimesMX = mxCreateDoubleMatrix(1,numberevents,mxREAL);
+            mxSetData(eventtimesMX, eventtimes);
+            mxSetField(outputMX, 0, "eventtimes", eventtimesMX);
+            eventflagsMX = mxCreateDoubleMatrix(NREVENTS,numberevents,mxREAL);
+            mxSetData(eventflagsMX, eventflagscollect);
+            mxSetField(outputMX, 0, "eventflags", eventflagsMX);
+        }
+    }
+    if (sensitivity) {
+        sensparamoutMX = mxCreateCellMatrix(1, nrsensparam);
+        sensitivityparamdataoutMX = mxCreateCellMatrix(1, nrsensparam);
+        for (k=0;k<nrsensparam;k++) {
+            mxSetCell(sensparamoutMX,k,mxCreateString(parameternames[sensparamstates[k]-1]));
+            mxSetCell(sensitivityparamdataoutMX,k,sensitivitydataparamMX[k]);
+        }
+        mxSetField(outputMX, 0, "sensparameters", sensparamoutMX);
+        mxSetField(outputMX, 0, "sensparamtrajectories", sensitivityparamdataoutMX);
+        sensstatesoutMX = mxCreateCellMatrix(1, nrsensstates);
+        sensitivitystatesdataoutMX = mxCreateCellMatrix(1, nrsensstates);
+        for (k=0;k<nrsensstates;k++) {
+            mxSetCell(sensstatesoutMX,k,mxCreateString(statenames[sensparamstates[nrsensparam+k]-1-NRPARAMETERS]));
+            mxSetCell(sensitivitystatesdataoutMX,k,sensitivitydatastatesMX[k]);
+        }
+        mxSetField(outputMX, 0, "sensicstatetrajectories", sensitivitystatesdataoutMX);
+        mxSetField(outputMX, 0, "sensicstates", sensstatesoutMX);
+    }
+    /* Return the output argument 'outputMX' */
+    plhs[0] = outputMX;
+}
+
+/*
+ *========================================================================
+ * Help function to add a row vector to a matrix
+ *========================================================================
+ */
+static void includeVectorInMatrix(double *matrix, double *rowvector, int row, int nrows, int ncols)
+{
+    int k;
+    for (k=0;k<ncols;k++) {
+        matrix[row+k*nrows] = rowvector[k];
+    }
+}
+
+/*
+ *========================================================================
+ * RHS function f(t,u) (INTERFACE TO CVODE)
+ *========================================================================
+ */
+static int f(double time, N_Vector u, N_Vector udot, void *f_data)
+{
+    double *statevector, *ODERHSvector;
+    
+int k;
+    
+    ModelData *modeldataPtr;
+    /* get pointer to modeldata */
+    modeldataPtr = (ModelData*) f_data;
+    /* connect input and output data */
+    statevector = NV_DATA_S(u);
+    ODERHSvector = NV_DATA_S(udot);
+    /* run the model */
+    model(time, statevector, ODERHSvector, modeldataPtr, CVODE_RHS, NULL, NULL, NULL, NULL);
+    
+for (k=0; k<9; k++) {
+    mexPrintf("%f: %f\n",statevector[k],ODERHSvector[k]);
+}
+    
+    return(0);
+}
+
+/*
+ *========================================================================
+ * Event function (INTERFACE TO CVODE)
+ *========================================================================
+ */
+static void g(double time, N_Vector y, double *gout, void *g_data)
+{
+    double *statevector;
+    ModelData *modeldataPtr;
+    /* get pointer to model data */
+    modeldataPtr = (ModelData*) g_data;
+    /* connect input data */
+    statevector = NV_DATA_S(y);
+    /* run the event function */
+    model(time, statevector, NULL, modeldataPtr, CVODE_EVENTS, NULL, NULL, gout, NULL);
+}
+
+/*
+ *========================================================================
+ * Error function ... 
+ *========================================================================
+ */
+static void error(char *text)
+{
+    mexErrMsgTxt(text);
+}
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/source_SUNDIALS_CVODES_25 b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/source_SUNDIALS_CVODES_25
new file mode 100644
index 0000000000000000000000000000000000000000..46b85751162bf1d89f21cdabf02833cccf2b983d
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/source_SUNDIALS_CVODES_25	
@@ -0,0 +1,572 @@
+/*
+ * CVODEmex25.c: MEX/CVODES Interface for Sundials CVODES version 2.5
+ *
+ * Information:
+ * ============
+ * SBPD Package - Systems Biology Parameter Determination Package
+ * Copyright 2008 by Henning Schmidt, henning@sbtoolbox2.org
+ */
+
+#include <mex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <string.h>
+#include <matrix.h>
+#include <math.h>
+
+/* CVODES includes */
+#include <cvodes/cvodes.h>
+#include <nvector/nvector_serial.h>
+#include <sundials/sundials_types.h>
+#include <sundials/sundials_math.h>
+#include "CVODEmex25.h"
+
+/* Definitions for CVODES */
+#define ABSTOL  1.0e-6  
+#define RELTOL  1.0e-6  
+#define Ith(v,i) NV_Ith_S(v,i-1)
+
+/* Initialize functions */
+static void resetDelayInformation();
+static mxArray* handleInputArguments(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]);
+static mxArray* doXdotCalc();
+static void allocSimMemory();
+static void initCVODE();
+static void integrate();
+static mxArray* constructOutput();
+static void addVec2Mat(double *matrix, double *rowvector, int row, int nrows, int ncols);
+static int f(double time, N_Vector u, N_Vector udot, void *f_data);
+static int g(double time, N_Vector y, double *gout, void *g_data);
+static void errorMsg(char *text);
+static void freeMem();
+
+/* Some global variables for the interface */
+int k,k2;   /* some loop variables */
+
+int length2check;
+
+char stringbuffer[256];
+
+mxArray *timesimvectorMX = NULL;
+double *timesimvector = NULL;
+
+mxArray *parametervectorMX = NULL;
+double *parametervector = NULL;
+double *parametervectorCVODES = NULL; 
+
+mxArray *initialconditionsMX = NULL;
+double *initialconditions = NULL;
+
+mxArray *optionsMX = NULL;
+
+mxArray *minstepMX = NULL;
+double minstep;
+
+mxArray *maxstepMX = NULL;
+double maxstep;
+
+mxArray *maxnumstepsMX = NULL;
+long int maxnumsteps;
+
+mxArray *reltolMX = NULL;
+double reltol;
+
+mxArray *abstolMX = NULL;
+double abstol;
+
+mxArray *xdotcalcMX = NULL;
+double xdotcalc;
+
+int numbertimesteps;
+
+mxArray *resultMX = NULL;
+double *result = NULL;
+
+mxArray *statesMX = NULL;
+
+mxArray *statevaluesMX = NULL;
+double *statevalues = NULL;
+
+mxArray *variablesMX = NULL;
+
+mxArray *variablevaluesMX = NULL;
+double *variablevalues = NULL;
+
+mxArray *reactionsMX = NULL;
+
+mxArray *reactionvaluesMX = NULL;
+double *reactionvalues = NULL;
+
+mxArray *eventsMX = NULL;
+
+mxArray *eventtimesMX = NULL;
+double *eventtimes = NULL;
+
+mxArray *eventflagsMX = NULL;
+double *eventflags = NULL;
+
+/* CVODES needed data */
+ParamData modeldata;
+N_Vector u = NULL;
+void *cvode_mem;
+int flag, flagroot;
+double treturn;
+double tendstep;
+
+/* Interface to model RHS */
+double *statevec = NULL;
+double *variablevec = NULL;
+double *reactionvec = NULL;
+int *eventvec = NULL;
+double *eventdataold = NULL;
+int nreventshappend;
+double *eventflagsdata = NULL;
+double eventcorrecttest;
+
+/* Error Flags */
+int timevectorEmpty = 0;
+int timevectorNotVector = 0;
+  
+/*
+ *========================================================================
+ * MEX INTERFACE FOR MEX SIMULATION MODELS
+ *========================================================================
+ */
+void CVODEmex25(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
+{
+    /* Handle variable input arguments */
+    resultMX = handleInputArguments(nlhs, plhs, nrhs, prhs);
+    if (resultMX != NULL) {
+        /* No integration requested */
+        plhs[0] = resultMX;
+        return;
+    }
+    /* check if integration or xdot calculation */
+    if (xdotcalc != 0) {
+        /* return the RHS of the ODEs at given state and parameter values */
+        resultMX = doXdotCalc();
+        plhs[0] = resultMX;
+        return;
+    }
+    /* Do error checks ... timevector needs to be defined if integration is to be done! */
+    if (timevectorEmpty == 1) mexErrMsgTxt("Timevector is empty.");
+    if (timevectorNotVector == 1) mexErrMsgTxt("'timevector' input argument needs to be a vector.");
+    /* Otherwise do the integration */
+    /* Allocate memory for the simulation */
+    allocSimMemory();
+    /* Initialize CVODES */
+    initCVODE();
+    /* Integrate */
+    integrate();
+    /* Construct result */
+    plhs[0] = constructOutput();
+    /* Free allocated memory */
+    freeMem();
+}
+
+/*
+ *========================================================================
+ * Reset delay information
+ *========================================================================
+ */
+static void resetDelayInformation()
+{
+    for (k=0; k<NRDELAYS; k++) {
+        delaydataMX[k] = NULL;
+        delaytimeMX[k] = NULL;
+        delaytimearraylengths[k] = 0;
+    }
+}
+
+/*
+ *========================================================================
+ * Help function to add a row vector to a matrix
+ *========================================================================
+ */
+static void addVec2Mat(double *matrix, double *rowvector, int row, int nrrows, int nrcols)
+{
+    int k;
+    for (k=0;k<nrcols;k++) {
+        matrix[row+k*nrrows] = rowvector[k];
+    }
+}
+
+/*
+ *========================================================================
+ * RHS function f(t,u) 
+ *========================================================================
+ */
+static int f(double time, N_Vector u, N_Vector udot, void *f_data)
+{
+    double *statevec, *DDTvector;
+    ParamData *paramdataPtr;
+    /* get pointer to modeldata */
+    paramdataPtr = (ParamData*) f_data;
+    /* connect input and result data */
+    statevec = NV_DATA_S(u);
+    DDTvector = NV_DATA_S(udot);
+    /* run the model */
+    model(time, statevec, DDTvector, paramdataPtr, DOFLAG_DDT, NULL, NULL, NULL, NULL);
+    return(0);
+}
+
+/*
+ *========================================================================
+ * Event function 
+ *========================================================================
+ */
+static int g(double time, N_Vector y, double *gout, void *g_data)
+{
+    double *statevec;
+    ParamData *paramdataPtr;
+    /* get pointer to model data */
+    paramdataPtr = (ParamData*) g_data;
+    /* connect input data */
+    statevec = NV_DATA_S(y);
+    /* run the event function */
+    model(time, statevec, NULL, paramdataPtr, DOFLAG_EVENTS, NULL, NULL, gout, NULL);
+    return(0);
+}
+
+/*
+ *========================================================================
+ * Error function 
+ *========================================================================
+ */
+static void errorMsg(char *text)
+{
+    /* First free the allocated memory */
+    freeMem();
+    /* Then print error message and exit */
+    mexErrMsgTxt(text);
+}
+
+/*
+ *========================================================================
+ * Free the memory 
+ *========================================================================
+ */
+static void freeMem()
+{
+    /* Free all CVODE related memory */
+    N_VDestroy_Serial(u);  /* Free the u vector */
+    CVodeFree(&cvode_mem);  /* Free the integrator memory */
+    /* Free delay related memory if allocated */
+    for (k=0; k<NRDELAYS; k++) {
+        if (delaydataMX[k] != NULL) { mxDestroyArray(delaydataarrays[k]); delaydataMX[k] = NULL; }
+        if (delaytimeMX[k] != NULL) { mxDestroyArray(delaytimearrays[k]); delaytimeMX[k] = NULL; }
+    }
+}
+
+    /*
+     * ==============================================
+     * HANDLE THE VARIABLE INPUT ARGUMENTS
+     * ==============================================
+     */
+static mxArray* handleInputArguments(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
+{
+    if (nrhs == 0) {
+        resultMX = mxCreateDoubleMatrix(NRSTATES, 1, mxREAL);
+        result = mxGetPr(resultMX);
+        for (k=0; k<NRSTATES; k++) result[k] = defaultICs[k];
+        return resultMX;
+    } else if (nrhs == 1) {
+        if (mxIsEmpty(prhs[0])) {
+            mexErrMsgTxt("Timevector is empty.");
+        } 
+        if (mxIsChar(prhs[0])) {
+            length2check = (mxGetM(prhs[0]) * mxGetN(prhs[0]));
+            if (length2check == 6) {       
+                resultMX = mxCreateCellMatrix(NRSTATES, 1);
+                for (k=0; k<NRSTATES; k++) mxSetCell(resultMX,k,mxCreateString(stateNames[k]));
+                return resultMX;
+            }
+            else if (length2check == 10) { 
+                resultMX = mxCreateCellMatrix(NRPARAMETERS, 1);
+                for (k=0; k<NRPARAMETERS; k++) mxSetCell(resultMX,k,mxCreateString(parameterNames[k]));
+                return resultMX;
+            }
+            else if (length2check == 15) { 
+                resultMX = mxCreateDoubleMatrix(NRPARAMETERS, 1, mxREAL);
+                result = mxGetPr(resultMX);
+                for (k=0; k<NRPARAMETERS; k++) result[k] = defaultParam[k];
+                return resultMX;
+            } else mexErrMsgTxt("Incorrect input argument.");
+        } else {
+            if (!mxIsDouble(prhs[0])) mexErrMsgTxt("Check the 'timevector' (first) input argument.");
+            /* if no error then the first argument is the timevector for simulation */
+            timesimvectorMX = (mxArray *) prhs[0];
+        }
+    } else {
+        if (!mxIsDouble(prhs[0])) mexErrMsgTxt("Check 'timevector' (first) input argument.");
+        timesimvectorMX = (mxArray *) prhs[0];
+        if (nrhs >= 2) {
+            if (!mxIsDouble(prhs[1]) && !mxIsEmpty(prhs[1])) mexErrMsgTxt("Check 'initialconditions' (second) input argument.");
+            initialconditionsMX = (mxArray *) prhs[1];
+        }
+        if (nrhs >= 3) {
+            if (!mxIsDouble(prhs[2]) && !mxIsEmpty(prhs[2])) mexErrMsgTxt("Check 'parametervector' (third) input argument.");
+            parametervectorMX = (mxArray *) prhs[2];
+        } 
+        if (nrhs >= 4) {
+            if (!mxIsStruct(prhs[3]) && !mxIsEmpty(prhs[3])) mexErrMsgTxt("Check 'options' (fourth) input argument.");
+            optionsMX = (mxArray *) prhs[3];
+        }
+        if (nrhs >= 5) {
+            mexErrMsgTxt("Incorrect number of input arguments.");
+        }
+    }
+    /* process timevector only if not empty */
+    if (!mxIsEmpty(timesimvectorMX)) {
+        numbertimesteps = mxGetM(timesimvectorMX)*mxGetN(timesimvectorMX);
+        if (numbertimesteps == 1 || (mxGetN(timesimvectorMX) > 1 && mxGetM(timesimvectorMX) > 1)) timevectorNotVector = 1;
+        else timesimvector = mxGetPr(timesimvectorMX);
+    } else {
+        /* set error flag for simulation case */
+        timevectorEmpty = 1;
+    }
+    /* process initial conditions */
+    initialconditions = (double *) mxCalloc(NRSTATES,sizeof(double));
+    for (k=0;k<NRSTATES;k++) initialconditions[k] = defaultICs[k];
+    if (initialconditionsMX != NULL) {
+        if (!mxIsEmpty(initialconditionsMX)) {
+            if (mxGetN(initialconditionsMX)*mxGetM(initialconditionsMX) != NRSTATES || (mxGetN(initialconditionsMX) > 1 && mxGetM(initialconditionsMX) > 1)) mexErrMsgTxt("'initialconditions' needs to be a vector of 'number states' length.");
+            initialconditions = mxGetPr(mxDuplicateArray(initialconditionsMX));
+        }
+    }
+    /* check parametervector */
+    parametervector = defaultParam;
+    if (parametervectorMX != NULL) {
+        if (!mxIsEmpty(parametervectorMX)) {
+            if (mxGetN(parametervectorMX)*mxGetM(parametervectorMX) != NRPARAMETERS || (mxGetN(parametervectorMX) > 1 && mxGetM(parametervectorMX) > 1)) mexErrMsgTxt("'parametervector' needs to be a vector of 'number parameters' length.");
+            parametervector = mxGetPr(parametervectorMX);
+        }
+    }
+    /* assign parametervector to modeldata struct */
+    modeldata.parametervector = parametervector;
+    /* check options */
+    minstep = -1;
+    maxstep = -1;
+    maxnumsteps = -1; 
+    reltol = RELTOL;  
+    abstol = ABSTOL;  
+    xdotcalc = 0;
+    if (optionsMX != NULL) {
+        if (!mxIsEmpty(optionsMX)) {
+            minstepMX = mxGetField(optionsMX, 0, "minstep");
+            if (minstepMX != NULL) 
+                if (mxIsDouble(minstepMX)) 
+                    minstep = mxGetScalar(minstepMX); 
+                else 
+                    mexErrMsgTxt("'options.minstep' wrongly defined.");
+            maxstepMX = mxGetField(optionsMX, 0, "maxstep");
+            if (maxstepMX != NULL) 
+                if (mxIsDouble(maxstepMX)) 
+                    maxstep = mxGetScalar(maxstepMX); 
+                else 
+                    mexErrMsgTxt("'options.maxstep' wrongly defined.");
+            maxnumstepsMX = mxGetField(optionsMX, 0, "maxnumsteps");
+            if (maxnumstepsMX != NULL) 
+                if (mxIsDouble(maxnumstepsMX)) 
+                    maxnumsteps = (long int)mxGetScalar(maxnumstepsMX); 
+                else 
+                    mexErrMsgTxt("'options.maxnumsteps' wrongly defined.");
+            reltolMX = mxGetField(optionsMX, 0, "reltol");
+            if (reltolMX != NULL) 
+                if (mxIsDouble(reltolMX)) 
+                    reltol = mxGetScalar(reltolMX); 
+                else 
+                    mexErrMsgTxt("'options.reltol' wrongly defined.");
+            abstolMX = mxGetField(optionsMX, 0, "abstol");
+            if (abstolMX != NULL) 
+                if (mxIsDouble(abstolMX)) 
+                    abstol = mxGetScalar(abstolMX); 
+                else 
+                    mexErrMsgTxt("'options.abstol' wrongly defined.");
+            xdotcalcMX = mxGetField(optionsMX, 0, "xdotcalc");
+            if (xdotcalcMX != NULL) 
+                if (mxIsDouble(xdotcalcMX)) 
+                    xdotcalc = mxGetScalar(xdotcalcMX); 
+                else 
+                    mexErrMsgTxt("'options.xdotcalc' wrongly defined.");
+        }
+    }
+    return NULL;
+}
+
+    /*
+     * ==============================================
+     * GET RHS OF ODEs (fir time = 0)
+     * ==============================================
+     */
+static mxArray* doXdotCalc()
+{
+    resultMX = mxCreateDoubleMatrix(NRSTATES, 1, mxREAL);
+    result = mxGetPr(resultMX);
+    model(0.0, initialconditions, result, &modeldata, DOFLAG_DDT, NULL, NULL, NULL, NULL);
+    return resultMX;
+}
+
+    /*
+     * ==============================================
+     * ALLOCATE MEMORY 
+     * ==============================================
+     */
+static void allocSimMemory()
+{
+    statevaluesMX = mxCreateDoubleMatrix(numbertimesteps, NRSTATES, mxREAL);
+    statevalues = mxGetPr(statevaluesMX);
+    if (NRVARIABLES > 0) {
+        variablevec = (double *) mxCalloc(NRVARIABLES, sizeof(double));
+        variablevaluesMX = mxCreateDoubleMatrix(numbertimesteps, NRVARIABLES, mxREAL);
+        variablevalues = mxGetPr(variablevaluesMX);
+    }
+    if (NRREACTIONS > 0) {
+        reactionvec = (double *) mxCalloc(NRREACTIONS, sizeof(double));
+        reactionvaluesMX = mxCreateDoubleMatrix(numbertimesteps, NRREACTIONS, mxREAL);
+        reactionvalues = mxGetPr(reactionvaluesMX);
+    }
+    if (NREVENTS > 0) {
+        eventvec = (int *) mxCalloc(NREVENTS, sizeof(int));
+        eventdataold = (double *) mxCalloc(NREVENTS, sizeof(double));
+    }
+}
+    
+    /*
+     * ==============================================
+     * INITIALIZE INTEGRATOR
+     * ==============================================
+     */
+static void initCVODE()
+{
+    u = N_VMake_Serial(NRSTATES,initialconditions);
+    cvode_mem = CVodeCreate(CV_BDF, CV_NEWTON);
+    CVodeMalloc(cvode_mem, f, timesimvector[0], u, CV_SS, reltol, &abstol);
+    if (NREVENTS > 0) {
+        CVodeRootInit(cvode_mem, NREVENTS, g, &modeldata);
+    }
+    CVodeSetFdata(cvode_mem, &modeldata);
+    if (minstep > 0) CVodeSetMinStep(cvode_mem, minstep);
+    if (maxstep > 0) CVodeSetMaxStep(cvode_mem, maxstep);
+    if (maxnumsteps > 0) CVodeSetMaxNumSteps(cvode_mem, maxnumsteps);
+	CVDense(cvode_mem,NRSTATES);
+}
+
+    /*
+     * ==============================================
+     * DO THE INTEGRATION
+     * ==============================================
+     */
+static void integrate()
+{
+    addVec2Mat(statevalues,initialconditions,0,numbertimesteps,NRSTATES);
+    model(timesimvector[0], initialconditions, NULL, &modeldata, DOFLAG_VARREAC, variablevec, reactionvec,NULL,NULL);
+    if (NRVARIABLES > 0) addVec2Mat(variablevalues,variablevec,0,numbertimesteps,NRVARIABLES);
+    if (NRREACTIONS > 0) addVec2Mat(reactionvalues,reactionvec,0,numbertimesteps,NRREACTIONS);
+    if (NREVENTS > 0) /* determine eventdataold to be able to detect directions of events */
+        model(timesimvector[0], initialconditions, NULL, &modeldata, DOFLAG_EVENTS, NULL, NULL, eventdataold, NULL);
+    k = 1;
+    tendstep = timesimvector[k]; 
+    nreventshappend = 0; 
+    while(1) {
+        flag = CVode(cvode_mem, tendstep, u, &treturn, CV_NORMAL);
+        if (flag < 0) {
+            if (flag == CV_TOO_MUCH_WORK) errorMsg("CVODE Error: CV_TOO_MUCH_WORK");
+            else if (flag == CV_TOO_MUCH_ACC) errorMsg("CVODE Error: CV_TOO_MUCH_ACC");
+            else if (flag == CV_ERR_FAILURE || flag == CV_CONV_FAILURE) errorMsg("CVODE Error: CV_ERR_FAILURE");
+            else {
+                sprintf(stringbuffer, "CVODE Error Flag: %d",flag);
+                errorMsg(stringbuffer);
+            }
+        }
+        statevec = NV_DATA_S(u);
+        if (flag == CV_ROOT_RETURN) {
+            /* Event happened */
+            CVodeGetRootInfo(cvode_mem, eventvec);
+            eventcorrecttest = 0;
+            model(treturn, statevec, &eventcorrecttest, &modeldata, DOFLAG_EVENTASSIGN, NULL, NULL, eventdataold, eventvec);
+            flag = CVodeReInit(cvode_mem, f, treturn, u, CV_SS, reltol, &abstol);
+            if (eventcorrecttest > 0) {
+                nreventshappend += 1;  
+                if (nreventshappend == 1) {
+                    eventtimes = (double *) mxCalloc(1, sizeof(double));
+                    eventflagsdata = (double *) mxCalloc(NREVENTS, sizeof(double));
+                } else {
+                    eventtimes = (double *) mxRealloc((void *) eventtimes, nreventshappend*sizeof(double));
+                    eventflagsdata = (double *) mxRealloc((void *) eventflagsdata, NREVENTS*nreventshappend*sizeof(double));
+                }
+                eventtimes[nreventshappend-1] = treturn;
+                for (k2=0;k2<NREVENTS;k2++) eventflagsdata[NREVENTS*(nreventshappend-1)+k2] = (double)eventvec[k2];
+            }
+        }
+        if (tendstep == treturn) { 
+            addVec2Mat(statevalues,statevec,k,numbertimesteps,NRSTATES);
+            model(tendstep, statevec, NULL, &modeldata, DOFLAG_VARREAC, variablevec, reactionvec, NULL, NULL);
+            if (NRVARIABLES > 0) addVec2Mat(variablevalues,variablevec,k,numbertimesteps,NRVARIABLES);
+            if (NRREACTIONS > 0) addVec2Mat(reactionvalues,reactionvec,k,numbertimesteps,NRREACTIONS);
+            k = k+1;
+            if (k < numbertimesteps) 
+                tendstep = timesimvector[k];
+            else 
+                break; 
+        }
+        if (NREVENTS > 0) /* determine eventdataold to be able to detect directions of events */
+            model(treturn, statevec, NULL, &modeldata, DOFLAG_EVENTS, NULL, NULL, eventdataold, NULL);
+    }
+}
+
+    /*
+     * ==============================================
+     * CONSTRUCT OUTPUT VARIABLE
+     * ==============================================
+     */
+static mxArray* constructOutput()
+{
+    resultMX = mxCreateStructMatrix(1,1,0,NULL);
+    /* Create fields in result structure */
+    mxAddField(resultMX,"time");
+    mxAddField(resultMX,"states");
+    mxAddField(resultMX,"statevalues");
+    mxAddField(resultMX,"variables");
+    mxAddField(resultMX,"variablevalues");
+    mxAddField(resultMX,"reactions");
+    mxAddField(resultMX,"reactionvalues");
+    if (NREVENTS > 0) {
+        mxAddField(resultMX,"events");
+        mxAddField(resultMX,"eventtimes");
+        mxAddField(resultMX,"eventflags");
+    }
+    mxSetField(resultMX, 0, "time", mxDuplicateArray(timesimvectorMX));
+    mxSetField(resultMX, 0, "statevalues", statevaluesMX);
+    if (NRVARIABLES > 0) mxSetField(resultMX, 0, "variablevalues", variablevaluesMX);
+    if (NRREACTIONS > 0) mxSetField(resultMX, 0, "reactionvalues", reactionvaluesMX);
+    statesMX = mxCreateCellMatrix(1, NRSTATES);
+    for (k=0;k<NRSTATES;k++) mxSetCell(statesMX,k,mxCreateString(stateNames[k]));
+    mxSetField(resultMX, 0, "states", statesMX);
+    if (NRVARIABLES > 0) {
+        variablesMX = mxCreateCellMatrix(1, NRVARIABLES);
+        for (k=0;k<NRVARIABLES;k++) mxSetCell(variablesMX,k,mxCreateString(variableNames[k]));
+        mxSetField(resultMX, 0, "variables", variablesMX);
+    }
+    if (NRREACTIONS > 0) {
+        reactionsMX = mxCreateCellMatrix(1, NRREACTIONS);
+        for (k=0;k<NRREACTIONS;k++) mxSetCell(reactionsMX,k,mxCreateString(reactionNames[k]));
+        mxSetField(resultMX, 0, "reactions", reactionsMX);
+    }
+    if (NREVENTS > 0) {
+        eventsMX = mxCreateCellMatrix(1, NREVENTS);
+        for (k=0;k<NREVENTS;k++) mxSetCell(eventsMX,k,mxCreateString(eventNames[k]));
+        mxSetField(resultMX, 0, "events", eventsMX);
+        if (nreventshappend > 0) {
+            eventtimesMX = mxCreateDoubleMatrix(1,nreventshappend,mxREAL);
+            mxSetData(eventtimesMX, eventtimes);
+            mxSetField(resultMX, 0, "eventtimes", eventtimesMX);
+            eventflagsMX = mxCreateDoubleMatrix(NREVENTS,nreventshappend,mxREAL);
+            mxSetData(eventflagsMX, eventflagsdata);
+            mxSetField(resultMX, 0, "eventflags", eventflagsMX);
+        }
+    }
+    return resultMX;
+}
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/sundials_band.c b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/sundials_band.c
new file mode 100644
index 0000000000000000000000000000000000000000..956e884fa8520a5bae78c20e579ee262027d28fb
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/sundials_band.c	
@@ -0,0 +1,371 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * -----------------------------------------------------------------
+ * Programmer(s): Alan C. Hindmarsh and Radu Serban @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2002, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This is the implementation file for a generic BAND linear
+ * solver package.
+ * -----------------------------------------------------------------
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sundials/sundials_band.h>
+#include <sundials/sundials_math.h>
+
+#define ZERO RCONST(0.0)
+#define ONE  RCONST(1.0)
+
+#define ROW(i,j,smu) (i-j+smu)
+
+/* Implementation */
+
+BandMat BandAllocMat(long int N, long int mu, long int ml, long int smu)
+{
+  BandMat A;
+
+  if (N <= 0) return(NULL);
+  
+  A = NULL;
+  A = (BandMat) malloc(sizeof *A);
+  if (A == NULL) return (NULL);
+
+  A->data = NULL;
+  A->data = bandalloc(N, smu, ml);
+  if (A->data == NULL) {
+    free(A); A = NULL;
+    return(NULL);
+  }
+  
+  A->size = N;
+  A->mu = mu;
+  A->ml = ml;
+  A->smu = smu;
+
+  return(A);
+}
+
+long int *BandAllocPiv(long int N)
+{
+  return(bandallocpiv(N));
+}
+
+long int BandGBTRF(BandMat A, long int *p)
+{
+  return(bandGBTRF(A->data, A->size, A->mu, A->ml, A->smu, p));
+}
+
+void BandGBTRS(BandMat A, long int *p, realtype *b)
+{
+  bandGBTRS(A->data, A->size, A->smu, A->ml, p, b);
+}
+
+void BandZero(BandMat A)
+{
+  bandzero(A->data, A->size, A->mu, A->ml, A->smu);
+}
+
+void BandCopy(BandMat A, BandMat B, long int copymu, 
+              long int copyml)
+{
+  bandcopy(A->data, B->data, A->size, A->smu, B->smu, copymu, copyml);
+}
+
+void BandScale(realtype c, BandMat A)
+{
+  bandscale(c, A->data, A->size, A->mu, A->ml, A->smu);
+}
+
+void BandAddI(BandMat A)
+{
+  bandaddI(A->data, A->size, A->smu);
+}
+
+void BandFreeMat(BandMat A)
+{
+  bandfree(A->data);
+  free(A); A = NULL;
+}
+
+void BandFreePiv(long int *p)
+{ 
+  bandfreepiv(p);
+}
+
+void BandPrint(BandMat A)
+{
+  bandprint(A->data, A->size, A->mu, A->ml, A->smu);
+}
+
+realtype **bandalloc(long int n, long int smu, long int ml)
+{
+  realtype **a;
+  long int j, colSize;
+
+  if (n <= 0) return(NULL);
+
+  a = NULL;
+  a = (realtype **) malloc(n * sizeof(realtype *));
+  if (a == NULL) return(NULL);
+
+  colSize = smu + ml + 1;
+  a[0] = NULL;
+  a[0] = (realtype *) malloc(n * colSize * sizeof(realtype));
+  if (a[0] == NULL) {
+    free(a); a = NULL;
+    return(NULL);
+  }
+
+  for (j=1; j < n; j++) a[j] = a[0] + j * colSize;
+
+  return(a);
+}
+
+long int *bandallocpiv(long int n)
+{
+  long int *piv;
+
+  if (n <= 0) return(NULL);
+
+  piv = NULL;
+  piv = (long int *) malloc(n * sizeof(long int));
+  if (piv == NULL) return(NULL);
+
+  return(piv);
+}
+
+long int bandGBTRF(realtype **a, long int n, long int mu, long int ml, 
+                   long int smu, long int *p)
+{
+  long int c, r, num_rows;
+  long int i, j, k, l, storage_l, storage_k, last_col_k, last_row_k;
+  realtype *a_c, *col_k, *diag_k, *sub_diag_k, *col_j, *kptr, *jptr;
+  realtype max, temp, mult, a_kj;
+  booleantype swap;
+
+  /* zero out the first smu - mu rows of the rectangular array a */
+
+  num_rows = smu - mu;
+  if (num_rows > 0) {
+    for (c=0; c < n; c++) {
+      a_c = a[c];
+      for (r=0; r < num_rows; r++) {
+	a_c[r] = ZERO;
+      }
+    }
+  }
+
+  /* k = elimination step number */
+
+  for (k=0; k < n-1; k++, p++) {
+    
+    col_k     = a[k];
+    diag_k    = col_k + smu;
+    sub_diag_k = diag_k + 1;
+    last_row_k = MIN(n-1,k+ml);
+
+    /* find l = pivot row number */
+
+    l=k;
+    max = ABS(*diag_k);
+    for (i=k+1, kptr=sub_diag_k; i <= last_row_k; i++, kptr++) { 
+      if (ABS(*kptr) > max) {
+	l=i;
+	max = ABS(*kptr);
+      }
+    }
+    storage_l = ROW(l, k, smu);
+    *p = l;
+    
+    /* check for zero pivot element */
+
+    if (col_k[storage_l] == ZERO) return(k+1);
+    
+    /* swap a(l,k) and a(k,k) if necessary */
+    
+    if ( (swap = (l != k) )) {
+      temp = col_k[storage_l];
+      col_k[storage_l] = *diag_k;
+      *diag_k = temp;
+    }
+
+    /* Scale the elements below the diagonal in         */
+    /* column k by -1.0 / a(k,k). After the above swap, */
+    /* a(k,k) holds the pivot element. This scaling     */
+    /* stores the pivot row multipliers -a(i,k)/a(k,k)  */
+    /* in a(i,k), i=k+1, ..., MIN(n-1,k+ml).            */
+    
+    mult = -ONE / (*diag_k);
+    for (i=k+1, kptr = sub_diag_k; i <= last_row_k; i++, kptr++)
+      (*kptr) *= mult;
+
+    /* row_i = row_i - [a(i,k)/a(k,k)] row_k, i=k+1, ..., MIN(n-1,k+ml) */
+    /* row k is the pivot row after swapping with row l.                */
+    /* The computation is done one column at a time,                    */
+    /* column j=k+1, ..., MIN(k+smu,n-1).                               */
+    
+    last_col_k = MIN(k+smu,n-1);
+    for (j=k+1; j <= last_col_k; j++) {
+      
+      col_j = a[j];
+      storage_l = ROW(l,j,smu); 
+      storage_k = ROW(k,j,smu); 
+      a_kj = col_j[storage_l];
+
+      /* Swap the elements a(k,j) and a(k,l) if l!=k. */
+      
+      if (swap) {
+	col_j[storage_l] = col_j[storage_k];
+	col_j[storage_k] = a_kj;
+      }
+
+      /* a(i,j) = a(i,j) - [a(i,k)/a(k,k)]*a(k,j) */
+      /* a_kj = a(k,j), *kptr = - a(i,k)/a(k,k), *jptr = a(i,j) */
+
+      if (a_kj != ZERO) {
+	for (i=k+1, kptr=sub_diag_k, jptr=col_j+ROW(k+1,j,smu);
+	     i <= last_row_k;
+	     i++, kptr++, jptr++)
+	  (*jptr) += a_kj * (*kptr);
+      }
+    }    
+  }
+  
+  /* set the last pivot row to be n-1 and check for a zero pivot */
+
+  *p = n-1; 
+  if (a[n-1][smu] == ZERO) return(n);
+
+  /* return 0 to indicate success */
+
+  return(0);
+}
+
+void bandGBTRS(realtype **a, long int n, long int smu, long int ml, 
+               long int *p, realtype *b)
+{
+  long int k, l, i, first_row_k, last_row_k;
+  realtype mult, *diag_k;
+  
+  /* Solve Ly = Pb, store solution y in b */
+  
+  for (k=0; k < n-1; k++) {
+    l = p[k];
+    mult = b[l];
+    if (l != k) {
+      b[l] = b[k];
+      b[k] = mult;
+    }
+    diag_k = a[k]+smu;
+    last_row_k = MIN(n-1,k+ml);
+    for (i=k+1; i <= last_row_k; i++)
+      b[i] += mult * diag_k[i-k];
+  }
+  
+  /* Solve Ux = y, store solution x in b */
+  
+  for (k=n-1; k >= 0; k--) {
+    diag_k = a[k]+smu;
+    first_row_k = MAX(0,k-smu);
+    b[k] /= (*diag_k);
+    mult = -b[k];
+    for (i=first_row_k; i <= k-1; i++)
+      b[i] += mult*diag_k[i-k];
+  }
+}
+
+void bandzero(realtype **a, long int n, long int mu, long int ml, 
+              long int smu)
+{
+  long int i, j, colSize;
+  realtype *col_j;
+
+  colSize = mu + ml + 1;
+  for (j=0; j < n; j++) {
+    col_j = a[j]+smu-mu;
+    for (i=0; i < colSize; i++)
+      col_j[i] = ZERO;
+  }
+}
+
+void bandcopy(realtype **a, realtype **b, long int n, long int a_smu, 
+              long int b_smu, long int copymu, long int copyml)
+{
+  long int i, j, copySize;
+  realtype *a_col_j, *b_col_j;
+
+  copySize = copymu + copyml + 1;
+ 
+  for (j=0; j < n; j++) {
+    a_col_j = a[j]+a_smu-copymu;
+    b_col_j = b[j]+b_smu-copymu;
+    for (i=0; i < copySize; i++)
+      b_col_j[i] = a_col_j[i];
+  }
+}
+
+void bandscale(realtype c, realtype **a, long int n, long int mu, 
+               long int ml, long int smu)
+{
+  long int i, j, colSize;
+  realtype *col_j;
+
+  colSize = mu + ml + 1;
+
+  for(j=0; j < n; j++) {
+    col_j = a[j]+smu-mu;
+    for (i=0; i < colSize; i++)
+      col_j[i] *= c;
+  }
+}
+
+void bandaddI(realtype **a, long int n, long int smu)
+{
+  long int j;
+ 
+  for(j=0; j < n; j++)
+    a[j][smu] += ONE;
+}
+
+void bandfreepiv(long int *p)
+{
+  free(p); p = NULL;
+}
+
+void bandfree(realtype **a)
+{
+  free(a[0]); a[0] = NULL;
+  free(a); a = NULL;
+}
+
+void bandprint(realtype **a, long int n, long int mu, long int ml, 
+               long int smu)
+{
+  long int i, j, start, finish;
+ 
+  printf("\n");
+  for (i=0; i < n; i++) {
+    start = MAX(0,i-ml);
+    finish = MIN(n-1,i+mu);
+    for (j=0; j < start; j++) printf("%12s  ","");
+    for (j=start; j <= finish; j++) {
+#if defined(SUNDIALS_EXTENDED_PRECISION)
+      printf("%12Lg  ", a[j][i-j+smu]);
+#elif defined(SUNDIALS_DOUBLE_PRECISION)
+      printf("%12lg  ", a[j][i-j+smu]);
+#else
+      printf("%12g  ", a[j][i-j+smu]);
+#endif
+    }
+    printf("\n");
+  }
+  printf("\n");
+}
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/sundials_dense.c b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/sundials_dense.c
new file mode 100644
index 0000000000000000000000000000000000000000..3a52a3853f59915933afcbcca1558f58d94b2221
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/sundials_dense.c	
@@ -0,0 +1,102 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * -----------------------------------------------------------------
+ * Programmer(s): Scott D. Cohen, Alan C. Hindmarsh and
+ *                Radu Serban @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2002, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This is the implementation file for a generic package of dense
+ * matrix operations.
+ * -----------------------------------------------------------------
+ */ 
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sundials/sundials_dense.h>
+#include <sundials/sundials_math.h>
+
+#define ZERO RCONST(0.0)
+#define ONE  RCONST(1.0)
+
+/* Implementation */
+
+DenseMat DenseAllocMat(long int M, long int N)
+{
+  DenseMat A;
+
+  /* Note that M and N are tested in denalloc */
+
+  A = NULL;
+  A = (DenseMat) malloc(sizeof *A);
+  if (A==NULL) return (NULL);
+  
+  A->data = NULL;
+  A->data = denalloc(M, N);
+  if (A->data == NULL) {
+    free(A); A = NULL;
+    return(NULL);
+  }
+
+  A->M = M;
+  A->N = N;
+
+  return(A);
+}
+
+long int *DenseAllocPiv(long int N)
+{
+  return(denallocpiv(N));
+}
+
+long int DenseGETRF(DenseMat A, long int *p)
+{
+  return(denGETRF(A->data, A->M, A->N, p));
+}
+
+void DenseGETRS(DenseMat A, long int *p, realtype *b)
+{
+  denGETRS(A->data, A->N, p, b);
+}
+
+void DenseZero(DenseMat A)
+{
+  denzero(A->data, A->M, A->N);
+}
+
+void DenseCopy(DenseMat A, DenseMat B)
+{
+  dencopy(A->data, B->data, A->M, A->N);
+}
+
+void DenseScale(realtype c, DenseMat A)
+{
+  denscale(c, A->data, A->M, A->N);
+}
+
+void DenseAddI(DenseMat A)
+{
+  denaddI(A->data, A->N);
+}
+
+void DenseFreeMat(DenseMat A)
+{
+  denfree(A->data);
+  free(A); A = NULL;
+}
+
+void DenseFreePiv(long int *p)
+{  
+  denfreepiv(p);
+}
+
+void DensePrint(DenseMat A)
+{
+  denprint(A->data, A->M, A->N);
+}
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/sundials_iterative.c b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/sundials_iterative.c
new file mode 100644
index 0000000000000000000000000000000000000000..36a17c76b6699d3cf6f6feacbea15830ec3a50c3
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/sundials_iterative.c	
@@ -0,0 +1,288 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * ----------------------------------------------------------------- 
+ * Programmer(s): Scott D. Cohen, Alan C. Hindmarsh and
+ *                Radu Serban @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2002, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This is the implementation file for the iterative.h header
+ * file. It contains the implementation of functions that may be
+ * useful for many different iterative solvers of A x = b.
+ * -----------------------------------------------------------------
+ */
+
+#include <stdio.h>
+
+#include <sundials/sundials_iterative.h>
+#include <sundials/sundials_math.h>
+
+#define FACTOR RCONST(1000.0)
+#define ZERO   RCONST(0.0)
+#define ONE    RCONST(1.0)
+
+/*
+ * -----------------------------------------------------------------
+ * Function : ModifiedGS
+ * -----------------------------------------------------------------
+ * This implementation of ModifiedGS is a slight modification of a
+ * previous modified Gram-Schmidt routine (called mgs) written by
+ * Milo Dorr.
+ * -----------------------------------------------------------------
+ */
+ 
+int ModifiedGS(N_Vector *v, realtype **h, int k, int p, 
+               realtype *new_vk_norm)
+{
+  int  i, k_minus_1, i0;
+  realtype new_norm_2, new_product, vk_norm, temp;
+  
+  vk_norm = RSqrt(N_VDotProd(v[k],v[k]));
+  k_minus_1 = k - 1;
+  i0 = MAX(k-p, 0);
+  
+  /* Perform modified Gram-Schmidt */
+  
+  for (i=i0; i < k; i++) {
+    h[i][k_minus_1] = N_VDotProd(v[i], v[k]);
+    N_VLinearSum(ONE, v[k], -h[i][k_minus_1], v[i], v[k]);
+  }
+
+  /* Compute the norm of the new vector at v[k] */
+
+  *new_vk_norm = RSqrt(N_VDotProd(v[k], v[k]));
+
+  /* If the norm of the new vector at v[k] is less than
+     FACTOR (== 1000) times unit roundoff times the norm of the
+     input vector v[k], then the vector will be reorthogonalized
+     in order to ensure that nonorthogonality is not being masked
+     by a very small vector length. */
+
+  temp = FACTOR * vk_norm;
+  if ((temp + (*new_vk_norm)) != temp) return(0);
+  
+  new_norm_2 = ZERO;
+
+  for (i=i0; i < k; i++) {
+    new_product = N_VDotProd(v[i], v[k]);
+    temp = FACTOR * h[i][k_minus_1];
+    if ((temp + new_product) == temp) continue;
+    h[i][k_minus_1] += new_product;
+    N_VLinearSum(ONE, v[k],-new_product, v[i], v[k]);
+    new_norm_2 += SQR(new_product);
+  }
+
+  if (new_norm_2 != ZERO) {
+    new_product = SQR(*new_vk_norm) - new_norm_2;
+    *new_vk_norm = (new_product > ZERO) ? RSqrt(new_product) : ZERO;
+  }
+
+  return(0);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * Function : ClassicalGS
+ * -----------------------------------------------------------------
+ * This implementation of ClassicalGS was contributed by Homer Walker
+ * and Peter Brown.
+ * -----------------------------------------------------------------
+ */
+
+int ClassicalGS(N_Vector *v, realtype **h, int k, int p, 
+                realtype *new_vk_norm, N_Vector temp, realtype *s)
+{
+  int  i, k_minus_1, i0;
+  realtype vk_norm;
+
+  k_minus_1 = k - 1;
+  
+  /* Perform Classical Gram-Schmidt */
+
+  vk_norm = RSqrt(N_VDotProd(v[k], v[k]));
+
+  i0 = MAX(k-p, 0);
+  for (i=i0; i < k; i++) {
+    h[i][k_minus_1] = N_VDotProd(v[i], v[k]);
+  }
+
+  for (i=i0; i < k; i++) {
+    N_VLinearSum(ONE, v[k], -h[i][k_minus_1], v[i], v[k]);
+  }
+
+  /* Compute the norm of the new vector at v[k] */
+
+  *new_vk_norm = RSqrt(N_VDotProd(v[k], v[k]));
+
+  /* Reorthogonalize if necessary */
+
+  if ((FACTOR * (*new_vk_norm)) < vk_norm) {
+
+    for (i=i0; i < k; i++) {
+      s[i] = N_VDotProd(v[i], v[k]);
+    }
+
+    if (i0 < k) {
+      N_VScale(s[i0], v[i0], temp);
+      h[i0][k_minus_1] += s[i0];
+    }
+    for (i=i0+1; i < k; i++) {
+      N_VLinearSum(s[i], v[i], ONE, temp, temp);
+      h[i][k_minus_1] += s[i];
+    }
+    N_VLinearSum(ONE, v[k], -ONE, temp, v[k]);
+
+    *new_vk_norm = RSqrt(N_VDotProd(v[k],v[k]));
+  }
+
+  return(0);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * Function : QRfact
+ * -----------------------------------------------------------------
+ * This implementation of QRfact is a slight modification of a
+ * previous routine (called qrfact) written by Milo Dorr.
+ * -----------------------------------------------------------------
+ */
+
+int QRfact(int n, realtype **h, realtype *q, int job)
+{
+  realtype c, s, temp1, temp2, temp3;
+  int i, j, k, q_ptr, n_minus_1, code=0;
+
+  switch (job) {
+  case 0:
+
+    /* Compute a new factorization of H */
+
+    code = 0;
+    for (k=0; k < n; k++) {
+      
+      /* Multiply column k by the previous k-1 Givens rotations */
+
+      for (j=0; j < k-1; j++) {
+	i = 2*j;
+	temp1 = h[j][k];
+	temp2 = h[j+1][k];
+	c = q[i];
+	s = q[i+1];
+	h[j][k] = c*temp1 - s*temp2;
+	h[j+1][k] = s*temp1 + c*temp2;
+      }
+      
+      /* Compute the Givens rotation components c and s */
+
+      q_ptr = 2*k;
+      temp1 = h[k][k];
+      temp2 = h[k+1][k];
+      if( temp2 == ZERO) {
+	c = ONE;
+	s = ZERO;
+      } else if (ABS(temp2) >= ABS(temp1)) {
+	temp3 = temp1/temp2;
+	s = -ONE/RSqrt(ONE+SQR(temp3));
+	c = -s*temp3;
+      } else {
+	temp3 = temp2/temp1;
+	c = ONE/RSqrt(ONE+SQR(temp3));
+	s = -c*temp3;
+      }
+      q[q_ptr] = c;
+      q[q_ptr+1] = s;
+      if( (h[k][k] = c*temp1 - s*temp2) == ZERO) code = k+1;
+    }
+    break;
+
+  default:
+
+    /* Update the factored H to which a new column has been added */
+
+    n_minus_1 = n - 1;
+    code = 0;
+    
+    /* Multiply the new column by the previous n-1 Givens rotations */
+
+    for (k=0; k < n_minus_1; k++) {
+      i = 2*k;
+      temp1 = h[k][n_minus_1];
+      temp2 = h[k+1][n_minus_1];
+      c = q[i];
+      s = q[i+1];
+      h[k][n_minus_1] = c*temp1 - s*temp2;
+      h[k+1][n_minus_1] = s*temp1 + c*temp2;
+    }
+    
+    /* Compute new Givens rotation and multiply it times the last two
+       entries in the new column of H.  Note that the second entry of 
+       this product will be 0, so it is not necessary to compute it. */
+
+    temp1 = h[n_minus_1][n_minus_1];
+    temp2 = h[n][n_minus_1];
+    if (temp2 == ZERO) {
+      c = ONE;
+      s = ZERO;
+    } else if (ABS(temp2) >= ABS(temp1)) {
+      temp3 = temp1/temp2;
+      s = -ONE/RSqrt(ONE+SQR(temp3));
+      c = -s*temp3;
+    } else {
+      temp3 = temp2/temp1;
+      c = ONE/RSqrt(ONE+SQR(temp3));
+      s = -c*temp3;
+    }
+    q_ptr = 2*n_minus_1;
+    q[q_ptr] = c;
+    q[q_ptr+1] = s;
+    if ((h[n_minus_1][n_minus_1] = c*temp1 - s*temp2) == ZERO)
+      code = n;
+  }
+  
+  return (code);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * Function : QRsol
+ * -----------------------------------------------------------------
+ * This implementation of QRsol is a slight modification of a
+ * previous routine (called qrsol) written by Milo Dorr.
+ * -----------------------------------------------------------------
+ */
+
+int QRsol(int n, realtype **h, realtype *q, realtype *b)
+{
+  realtype c, s, temp1, temp2;
+  int i, k, q_ptr, code=0;
+
+  /* Compute Q*b */
+  
+  for (k=0; k < n; k++) {
+    q_ptr = 2*k;
+    c = q[q_ptr];
+    s = q[q_ptr+1];
+    temp1 = b[k];
+    temp2 = b[k+1];
+    b[k] = c*temp1 - s*temp2;
+    b[k+1] = s*temp1 + c*temp2;
+  }
+
+  /* Solve  R*x = Q*b */
+
+  for (k=n-1; k >= 0; k--) {
+    if (h[k][k] == ZERO) {
+      code = k + 1;
+      break;
+    }
+    b[k] /= h[k][k];
+    for (i=0; i < k; i++) b[i] -= b[k]*h[i][k];
+  }
+  
+  return (code);
+}
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/sundials_math.c b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/sundials_math.c
new file mode 100644
index 0000000000000000000000000000000000000000..9ca8d36fe0a92f9f1bcfc01ee069e8239f71dba7
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/sundials_math.c	
@@ -0,0 +1,94 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * -----------------------------------------------------------------
+ * Programmer(s): Scott D. Cohen, Alan C. Hindmarsh and
+ *                Aaron Collier @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2002, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This is the implementation file for a simple C-language math
+ * library.
+ * -----------------------------------------------------------------
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include <sundials/sundials_math.h>
+
+#define ZERO RCONST(0.0)
+#define ONE  RCONST(1.0)
+
+realtype RPowerI(realtype base, int exponent)
+{
+  int i, expt;
+  realtype prod;
+
+  prod = ONE;
+  expt = abs(exponent);
+  for(i = 1; i <= expt; i++) prod *= base;
+  if (exponent < 0) prod = ONE/prod;
+  return(prod);
+}
+
+realtype RPowerR(realtype base, realtype exponent)
+{
+  if (base <= ZERO) return(ZERO);
+
+#if defined(SUNDIALS_USE_GENERIC_MATH)
+  return((realtype) pow((double) base, (double) exponent));
+#elif defined(SUNDIALS_DOUBLE_PRECISION)
+  return(pow(base, exponent));
+#elif defined(SUNDIALS_SINGLE_PRECISION)
+  return(powf(base, exponent));
+#elif defined(SUNDIALS_EXTENDED_PRECISION)
+  return(powl(base, exponent));
+#endif
+}
+
+realtype RSqrt(realtype x)
+{
+  if (x <= ZERO) return(ZERO);
+
+#if defined(SUNDIALS_USE_GENERIC_MATH)
+  return((realtype) sqrt((double) x));
+#elif defined(SUNDIALS_DOUBLE_PRECISION)
+  return(sqrt(x));
+#elif defined(SUNDIALS_SINGLE_PRECISION)
+  return(sqrtf(x));
+#elif defined(SUNDIALS_EXTENDED_PRECISION)
+  return(sqrtl(x));
+#endif
+}
+
+realtype RAbs(realtype x)
+{
+#if defined(SUNDIALS_USE_GENERIC_MATH)
+  return((realtype) fabs((double) x));
+#elif defined(SUNDIALS_DOUBLE_PRECISION)
+  return(fabs(x));
+#elif defined(SUNDIALS_SINGLE_PRECISION)
+  return(fabsf(x));
+#elif defined(SUNDIALS_EXTENDED_PRECISION)
+  return(fabsl(x));
+#endif
+}
+
+realtype RExp(realtype x)
+{
+#if defined(SUNDIALS_USE_GENERIC_MATH)
+  return((realtype) exp((double) x));
+#elif defined(SUNDIALS_DOUBLE_PRECISION)
+  return(exp(x));
+#elif defined(SUNDIALS_SINGLE_PRECISION)
+  return(expf(x));
+#elif defined(SUNDIALS_EXTENDED_PRECISION)
+  return(expl(x));
+#endif
+}
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/sundials_nvector.c b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/sundials_nvector.c
new file mode 100644
index 0000000000000000000000000000000000000000..fcf938f5a458b82af55cc15b1d35306cfa97d05a
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/sundials_nvector.c	
@@ -0,0 +1,230 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * ----------------------------------------------------------------- 
+ * Programmer(s): Radu Serban and Aaron Collier @ LLNL                               
+ * -----------------------------------------------------------------
+ * Copyright (c) 2002, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This is the implementation file for a generic NVECTOR package.
+ * It contains the implementation of the N_Vector operations listed
+ * in nvector.h.
+ * -----------------------------------------------------------------
+ */
+
+#include <stdlib.h>
+
+#include <sundials/sundials_nvector.h>
+
+/*
+ * -----------------------------------------------------------------
+ * Functions in the 'ops' structure
+ * -----------------------------------------------------------------
+ */
+
+N_Vector N_VClone(N_Vector w)
+{
+  return(w->ops->nvclone(w));
+}
+
+N_Vector N_VCloneEmpty(N_Vector w)
+{
+  return(w->ops->nvcloneempty(w));
+}
+
+void N_VDestroy(N_Vector v)
+{
+  v->ops->nvdestroy(v);
+  return;
+}
+
+void N_VSpace(N_Vector v, long int *lrw, long int *liw)
+{
+  v->ops->nvspace(v, lrw, liw);
+  return;
+}
+
+realtype *N_VGetArrayPointer(N_Vector v)
+{
+  return((realtype *) v->ops->nvgetarraypointer(v));
+}
+
+void N_VSetArrayPointer(realtype *v_data, N_Vector v)
+{
+  v->ops->nvsetarraypointer(v_data, v);
+  return;
+}
+
+void N_VLinearSum(realtype a, N_Vector x, realtype b, N_Vector y, N_Vector z)
+{
+  z->ops->nvlinearsum(a, x, b, y, z);
+  return;
+}
+
+void N_VConst(realtype c, N_Vector z)
+{
+  z->ops->nvconst(c, z);
+  return;
+}
+
+void N_VProd(N_Vector x, N_Vector y, N_Vector z)
+{
+  z->ops->nvprod(x, y, z);
+  return;
+}
+
+void N_VDiv(N_Vector x, N_Vector y, N_Vector z)
+{
+  z->ops->nvdiv(x, y, z);
+  return;
+}
+
+void N_VScale(realtype c, N_Vector x, N_Vector z) 
+{
+  z->ops->nvscale(c, x, z);
+  return;
+}
+
+void N_VAbs(N_Vector x, N_Vector z)
+{
+  z->ops->nvabs(x, z);
+  return;
+}
+
+void N_VInv(N_Vector x, N_Vector z)
+{
+  z->ops->nvinv(x, z);
+  return;
+}
+
+void N_VAddConst(N_Vector x, realtype b, N_Vector z)
+{
+  z->ops->nvaddconst(x, b, z);
+  return;
+}
+
+realtype N_VDotProd(N_Vector x, N_Vector y)
+{
+  return((realtype) y->ops->nvdotprod(x, y));
+}
+
+realtype N_VMaxNorm(N_Vector x)
+{
+  return((realtype) x->ops->nvmaxnorm(x));
+}
+
+realtype N_VWrmsNorm(N_Vector x, N_Vector w)
+{
+  return((realtype) x->ops->nvwrmsnorm(x, w));
+}
+
+realtype N_VWrmsNormMask(N_Vector x, N_Vector w, N_Vector id)
+{
+  return((realtype) x->ops->nvwrmsnormmask(x, w, id));
+}
+
+realtype N_VMin(N_Vector x)
+{
+  return((realtype) x->ops->nvmin(x));
+}
+
+realtype N_VWL2Norm(N_Vector x, N_Vector w)
+{
+  return((realtype) x->ops->nvwl2norm(x, w));
+}
+
+realtype N_VL1Norm(N_Vector x)
+{
+  return((realtype) x->ops->nvl1norm(x));
+}
+
+void N_VCompare(realtype c, N_Vector x, N_Vector z)
+{
+  z->ops->nvcompare(c, x, z);
+  return;
+}
+
+booleantype N_VInvTest(N_Vector x, N_Vector z)
+{
+  return((booleantype) z->ops->nvinvtest(x, z));
+}
+
+booleantype N_VConstrMask(N_Vector c, N_Vector x, N_Vector m)
+{
+  return((booleantype) x->ops->nvconstrmask(c, x, m));
+}
+
+realtype N_VMinQuotient(N_Vector num, N_Vector denom)
+{
+  return((realtype) num->ops->nvminquotient(num, denom));
+}
+
+/*
+ * -----------------------------------------------------------------
+ * Additional functions exported by the generic NVECTOR:
+ *   N_VCloneEmptyVectorArray
+ *   N_VCloneVectorArray
+ *   N_VDestroyVectorArray
+ * -----------------------------------------------------------------
+ */
+
+N_Vector *N_VCloneEmptyVectorArray(int count, N_Vector w)
+{
+  N_Vector *vs;
+  int j;
+
+  if (count <= 0) return(NULL);
+
+  vs = NULL;
+  vs = (N_Vector *) malloc(count * sizeof(N_Vector));
+  if(vs == NULL) return(NULL);
+
+  for (j = 0; j < count; j++) {
+    vs[j] = NULL;
+    vs[j] = N_VCloneEmpty(w);
+    if (vs[j] == NULL) {
+      N_VDestroyVectorArray(vs, j-1);
+      return(NULL);
+    }
+  }
+
+  return(vs);
+}
+
+N_Vector *N_VCloneVectorArray(int count, N_Vector w)
+{
+  N_Vector *vs;
+  int j;
+
+  if (count <= 0) return(NULL);
+
+  vs = NULL;
+  vs = (N_Vector *) malloc(count * sizeof(N_Vector));
+  if(vs == NULL) return(NULL);
+
+  for (j = 0; j < count; j++) {
+    vs[j] = NULL;
+    vs[j] = N_VClone(w);
+    if (vs[j] == NULL) {
+      N_VDestroyVectorArray(vs, j-1);
+      return(NULL);
+    }
+  }
+
+  return(vs);
+}
+
+void N_VDestroyVectorArray(N_Vector *vs, int count)
+{
+  int j;
+
+  for (j = 0; j < count; j++) N_VDestroy(vs[j]);
+
+  free(vs); vs = NULL;
+
+  return;
+}
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/sundials_smalldense.c b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/sundials_smalldense.c
new file mode 100644
index 0000000000000000000000000000000000000000..4abb9424b500b322835fb2ecb7a8ddb1944a7972
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/sundials_smalldense.c	
@@ -0,0 +1,233 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * -----------------------------------------------------------------
+ * Programmer: Radu Serban @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2006, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This is the implementation file for a generic DENSE linear
+ * solver package, intended for small dense matrices.
+ * -----------------------------------------------------------------
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sundials/sundials_smalldense.h>
+#include <sundials/sundials_math.h>
+
+#define ZERO RCONST(0.0)
+#define ONE  RCONST(1.0)
+
+/* Implementation */
+
+
+realtype **denalloc(long int m, long int n)
+{
+  long int j;
+  realtype **a;
+
+  if ( (n <= 0) || (m <= 0) ) return(NULL);
+
+  a = NULL;
+  a = (realtype **) malloc(n * sizeof(realtype *));
+  if (a == NULL) return(NULL);
+
+  a[0] = NULL;
+  a[0] = (realtype *) malloc(m * n * sizeof(realtype));
+  if (a[0] == NULL) {
+    free(a); a = NULL;
+    return(NULL);
+  }
+
+  for (j=1; j < n; j++) a[j] = a[0] + j * m;
+
+  return(a);
+}
+
+long int *denallocpiv(long int n)
+{
+  long int *piv;
+
+  if (n <= 0) return(NULL);
+
+  piv = NULL;
+  piv = (long int *) malloc(n * sizeof(long int));
+
+  return(piv);
+}
+
+long int denGETRF(realtype **a, long int m, long int n, long int *p)
+{
+  long int i, j, k, l;
+  realtype *col_j, *col_k;
+  realtype temp, mult, a_kj;
+
+  /* k-th elimination step number */
+  for (k=0; k < n; k++) {
+
+    col_k  = a[k];
+
+    /* find l = pivot row number */
+    l=k;
+    for (i=k+1; i < m; i++)
+      if (ABS(col_k[i]) > ABS(col_k[l])) l=i;
+    p[k] = l;
+
+    /* check for zero pivot element */
+    if (col_k[l] == ZERO) return(k+1);
+    
+    /* swap a(k,1:n) and a(l,1:n) if necessary */    
+    if ( l!= k ) {
+      for (i=0; i<n; i++) {
+        temp = a[i][l];
+        a[i][l] = a[i][k];
+        a[i][k] = temp;
+      }
+    }
+
+    /* Scale the elements below the diagonal in
+     * column k by 1.0/a(k,k). After the above swap
+     * a(k,k) holds the pivot element. This scaling
+     * stores the pivot row multipliers a(i,k)/a(k,k)
+     * in a(i,k), i=k+1, ..., m-1.                      
+     */
+    mult = ONE/col_k[k];
+    for(i=k+1; i < m; i++) col_k[i] *= mult;
+
+    /* row_i = row_i - [a(i,k)/a(k,k)] row_k, i=k+1, ..., m-1 */
+    /* row k is the pivot row after swapping with row l.      */
+    /* The computation is done one column at a time,          */
+    /* column j=k+1, ..., n-1.                                */
+
+    for (j=k+1; j < n; j++) {
+
+      col_j = a[j];
+      a_kj = col_j[k];
+
+      /* a(i,j) = a(i,j) - [a(i,k)/a(k,k)]*a(k,j)  */
+      /* a_kj = a(k,j), col_k[i] = - a(i,k)/a(k,k) */
+
+      if (a_kj != ZERO) {
+	for (i=k+1; i < m; i++)
+	  col_j[i] -= a_kj * col_k[i];
+      }
+    }
+  }
+
+  /* return 0 to indicate success */
+
+  return(0);
+}
+
+void denGETRS(realtype **a, long int n, long int *p, realtype *b)
+{
+  long int i, k, pk;
+  realtype *col_k, tmp;
+
+  /* Permute b, based on pivot information in p */
+  for (k=0; k<n; k++) {
+    pk = p[k];
+    if(pk != k) {
+      tmp = b[k];
+      b[k] = b[pk];
+      b[pk] = tmp;
+    }
+  }
+
+  /* Solve Ly = b, store solution y in b */
+  for (k=0; k<n-1; k++) {
+    col_k = a[k];
+    for (i=k+1; i<n; i++) b[i] -= col_k[i]*b[k];
+  }
+
+  /* Solve Ux = y, store solution x in b */
+  for (k = n-1; k > 0; k--) {
+    col_k = a[k];
+    b[k] /= col_k[k];
+    for (i=0; i<k; i++) b[i] -= col_k[i]*b[k];
+  }
+  b[0] /= a[0][0];
+
+}
+
+void denzero(realtype **a, long int m, long int n)
+{
+  long int i, j;
+  realtype *col_j;
+
+  for (j=0; j < n; j++) {
+    col_j = a[j];
+    for (i=0; i < m; i++)
+      col_j[i] =  ZERO;
+  }
+}
+
+void dencopy(realtype **a, realtype **b, long int m, long int n)
+{
+  long int i, j;
+  realtype *a_col_j, *b_col_j;
+
+  for (j=0; j < n; j++) {
+    a_col_j = a[j];
+    b_col_j = b[j];
+    for (i=0; i < m; i++)
+      b_col_j[i] = a_col_j[i];
+  }
+
+}
+
+void denscale(realtype c, realtype **a, long int m, long int n)
+{
+  long int i, j;
+  realtype *col_j;
+
+  for (j=0; j < n; j++) {
+    col_j = a[j];
+    for (i=0; i < m; i++)
+      col_j[i] *= c;
+  }
+}
+
+void denaddI(realtype **a, long int n)
+{
+  long int i;
+  
+  for (i=0; i < n; i++) a[i][i] += ONE;
+}
+
+void denfreepiv(long int *p)
+{
+  free(p); p = NULL;
+}
+
+void denfree(realtype **a)
+{
+  free(a[0]); a[0] = NULL;
+  free(a); a = NULL;
+}
+
+void denprint(realtype **a, long int m, long int n)
+{
+  long int i, j;
+
+  printf("\n");
+  for (i=0; i < m; i++) {
+    for (j=0; j < n; j++) {
+#if defined(SUNDIALS_EXTENDED_PRECISION)
+      printf("%12Lg  ", a[j][i]);
+#elif defined(SUNDIALS_DOUBLE_PRECISION)
+      printf("%12lg  ", a[j][i]);
+#else
+      printf("%12g  ", a[j][i]);
+#endif
+    }
+    printf("\n");
+  }
+  printf("\n");
+}
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/sundials_spbcgs.c b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/sundials_spbcgs.c
new file mode 100644
index 0000000000000000000000000000000000000000..9dad08dc9d353e4b0cf79eba5b7b5f994e149399
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/sundials_spbcgs.c	
@@ -0,0 +1,386 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * -----------------------------------------------------------------
+ * Programmer(s): Peter Brown and Aaron Collier @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2004, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This is the implementation file for the scaled, preconditioned
+ * Bi-CGSTAB (SPBCG) iterative linear solver.
+ * -----------------------------------------------------------------
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sundials/sundials_spbcgs.h>
+#include <sundials/sundials_math.h>
+
+/*
+ * -----------------------------------------------------------------
+ * private constants
+ * -----------------------------------------------------------------
+ */
+
+#define ZERO RCONST(0.0)
+#define ONE  RCONST(1.0)
+
+/*
+ * -----------------------------------------------------------------
+ * Function : SpbcgMalloc
+ * -----------------------------------------------------------------
+ */
+
+SpbcgMem SpbcgMalloc(int l_max, N_Vector vec_tmpl)
+{
+  SpbcgMem mem;
+  N_Vector r_star, r, p, q, u, Ap, vtemp;
+
+  /* Check the input parameters */
+
+  if (l_max <= 0) return(NULL);
+
+  /* Get arrays to hold temporary vectors */
+
+  r_star = NULL;
+  r_star = N_VClone(vec_tmpl);
+  if (r_star == NULL) {
+    return(NULL);
+  }
+
+  r = NULL;
+  r = N_VClone(vec_tmpl);
+  if (r == NULL) {
+    N_VDestroy(r_star);
+    return(NULL);
+  }
+
+  p = NULL;
+  p = N_VClone(vec_tmpl);
+  if (p == NULL) {
+    N_VDestroy(r_star);
+    N_VDestroy(r);
+    return(NULL);
+  }
+
+  q = NULL;
+  q = N_VClone(vec_tmpl);
+  if (q == NULL) {
+    N_VDestroy(r_star);
+    N_VDestroy(r);
+    N_VDestroy(p);
+    return(NULL);
+  }
+
+  u = NULL;
+  u = N_VClone(vec_tmpl);
+  if (u == NULL) {
+    N_VDestroy(r_star);
+    N_VDestroy(r);
+    N_VDestroy(p);
+    N_VDestroy(q);
+    return(NULL);
+  }
+
+  Ap = NULL;
+  Ap = N_VClone(vec_tmpl);
+  if (Ap == NULL) {
+    N_VDestroy(r_star);
+    N_VDestroy(r);
+    N_VDestroy(p);
+    N_VDestroy(q);
+    N_VDestroy(u);
+    return(NULL);
+  }
+
+  vtemp = NULL;
+  vtemp = N_VClone(vec_tmpl);
+  if (vtemp == NULL) {
+    N_VDestroy(r_star);
+    N_VDestroy(r);
+    N_VDestroy(p);
+    N_VDestroy(q);
+    N_VDestroy(u);
+    N_VDestroy(Ap);
+    return(NULL);
+  }
+
+  /* Get memory for an SpbcgMemRec containing SPBCG matrices and vectors */
+
+  mem = NULL;
+  mem = (SpbcgMem) malloc(sizeof(SpbcgMemRec));
+  if (mem == NULL) {
+    N_VDestroy(r_star);
+    N_VDestroy(r);
+    N_VDestroy(p);
+    N_VDestroy(q);
+    N_VDestroy(u);
+    N_VDestroy(Ap);
+    N_VDestroy(vtemp);
+    return(NULL);
+  }
+
+  /* Set the fields of mem */
+
+  mem->l_max  = l_max;
+  mem->r_star = r_star;
+  mem->r      = r;
+  mem->p      = p;
+  mem->q      = q;
+  mem->u      = u;
+  mem->Ap     = Ap;
+  mem->vtemp  = vtemp;
+
+  /* Return the pointer to SPBCG memory */
+
+  return(mem);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * Function : SpbcgSolve
+ * -----------------------------------------------------------------
+ */
+
+int SpbcgSolve(SpbcgMem mem, void *A_data, N_Vector x, N_Vector b,
+               int pretype, realtype delta, void *P_data, N_Vector sx,
+               N_Vector sb, ATimesFn atimes, PSolveFn psolve,
+               realtype *res_norm, int *nli, int *nps)
+{
+  realtype alpha, beta, omega, omega_denom, beta_num, beta_denom, r_norm, rho;
+  N_Vector r_star, r, p, q, u, Ap, vtemp;
+  booleantype preOnLeft, preOnRight, scale_x, scale_b, converged;
+  int l, l_max, ier;
+
+  if (mem == NULL) return(SPBCG_MEM_NULL);
+
+  /* Make local copies of mem variables */
+
+  l_max  = mem->l_max;
+  r_star = mem->r_star;
+  r      = mem->r;
+  p      = mem->p;
+  q      = mem->q;
+  u      = mem->u;
+  Ap     = mem->Ap;
+  vtemp  = mem->vtemp;
+
+  *nli = *nps = 0;    /* Initialize counters */
+  converged = FALSE;  /* Initialize converged flag */
+
+  if ((pretype != PREC_LEFT) && (pretype != PREC_RIGHT) && (pretype != PREC_BOTH)) pretype = PREC_NONE;
+
+  preOnLeft  = ((pretype == PREC_BOTH) || (pretype == PREC_LEFT));
+  preOnRight = ((pretype == PREC_BOTH) || (pretype == PREC_RIGHT));
+
+  scale_x = (sx != NULL);
+  scale_b = (sb != NULL);
+
+  /* Set r_star to initial (unscaled) residual r_0 = b - A*x_0 */
+
+  if (N_VDotProd(x, x) == ZERO) N_VScale(ONE, b, r_star);
+  else {
+    ier = atimes(A_data, x, r_star);
+    if (ier != 0)
+      return((ier < 0) ? SPBCG_ATIMES_FAIL_UNREC : SPBCG_ATIMES_FAIL_REC);
+    N_VLinearSum(ONE, b, -ONE, r_star, r_star);
+  }
+
+  /* Apply left preconditioner and b-scaling to r_star = r_0 */
+
+  if (preOnLeft) {
+    ier = psolve(P_data, r_star, r, PREC_LEFT);
+    (*nps)++;
+    if (ier != 0) return((ier < 0) ? SPBCG_PSOLVE_FAIL_UNREC : SPBCG_PSOLVE_FAIL_REC);
+  }
+  else N_VScale(ONE, r_star, r);
+
+  if (scale_b) N_VProd(sb, r, r_star);
+  else N_VScale(ONE, r, r_star);
+
+  /* Initialize beta_denom to the dot product of r0 with r0 */
+
+  beta_denom = N_VDotProd(r_star, r_star);
+
+  /* Set r_norm to L2 norm of r_star = sb P1_inv r_0, and
+     return if small */
+
+  *res_norm = r_norm = rho = RSqrt(beta_denom);
+  if (r_norm <= delta) return(SPBCG_SUCCESS);
+
+  /* Copy r_star to r and p */
+
+  N_VScale(ONE, r_star, r);
+  N_VScale(ONE, r_star, p);
+
+  /* Begin main iteration loop */
+
+  for(l = 0; l < l_max; l++) {
+
+    (*nli)++;
+
+    /* Generate Ap = A-tilde p, where A-tilde = sb P1_inv A P2_inv sx_inv */
+
+    /*   Apply x-scaling: vtemp = sx_inv p */
+
+    if (scale_x) N_VDiv(p, sx, vtemp);
+    else N_VScale(ONE, p, vtemp);
+
+    /*   Apply right preconditioner: vtemp = P2_inv sx_inv p */
+
+    if (preOnRight) {
+      N_VScale(ONE, vtemp, Ap);
+      ier = psolve(P_data, Ap, vtemp, PREC_RIGHT);
+      (*nps)++;
+      if (ier != 0) return((ier < 0) ? SPBCG_PSOLVE_FAIL_UNREC : SPBCG_PSOLVE_FAIL_REC);
+    }
+
+    /*   Apply A: Ap = A P2_inv sx_inv p */
+
+    ier = atimes(A_data, vtemp, Ap );
+    if (ier != 0)
+      return((ier < 0) ? SPBCG_ATIMES_FAIL_UNREC : SPBCG_ATIMES_FAIL_REC);
+
+    /*   Apply left preconditioner: vtemp = P1_inv A P2_inv sx_inv p */
+
+    if (preOnLeft) {
+      ier = psolve(P_data, Ap, vtemp, PREC_LEFT);
+      (*nps)++;
+      if (ier != 0) return((ier < 0) ? SPBCG_PSOLVE_FAIL_UNREC : SPBCG_PSOLVE_FAIL_REC);
+    }
+    else N_VScale(ONE, Ap, vtemp);
+
+    /*   Apply b-scaling: Ap = sb P1_inv A P2_inv sx_inv p */
+
+    if (scale_b) N_VProd(sb, vtemp, Ap);
+    else N_VScale(ONE, vtemp, Ap);
+
+
+    /* Calculate alpha = <r,r_star>/<Ap,r_star> */
+
+    alpha = ((N_VDotProd(r, r_star) / N_VDotProd(Ap, r_star)));
+
+    /* Update q = r - alpha*Ap = r - alpha*(sb P1_inv A P2_inv sx_inv p) */
+
+    N_VLinearSum(ONE, r, -alpha, Ap, q);
+
+    /* Generate u = A-tilde q */
+
+    /*   Apply x-scaling: vtemp = sx_inv q */
+
+    if (scale_x) N_VDiv(q, sx, vtemp);
+    else N_VScale(ONE, q, vtemp);
+
+    /*   Apply right preconditioner: vtemp = P2_inv sx_inv q */
+
+    if (preOnRight) {
+      N_VScale(ONE, vtemp, u);
+      ier = psolve(P_data, u, vtemp, PREC_RIGHT);
+      (*nps)++;
+      if (ier != 0) return((ier < 0) ? SPBCG_PSOLVE_FAIL_UNREC : SPBCG_PSOLVE_FAIL_REC);
+    }
+
+    /*   Apply A: u = A P2_inv sx_inv u */
+
+    ier = atimes(A_data, vtemp, u );
+    if (ier != 0)
+      return((ier < 0) ? SPBCG_ATIMES_FAIL_UNREC : SPBCG_ATIMES_FAIL_REC);
+
+    /*   Apply left preconditioner: vtemp = P1_inv A P2_inv sx_inv p */
+
+    if (preOnLeft) {
+      ier = psolve(P_data, u, vtemp, PREC_LEFT);
+      (*nps)++;
+      if (ier != 0) return((ier < 0) ? SPBCG_PSOLVE_FAIL_UNREC : SPBCG_PSOLVE_FAIL_REC);
+    }
+    else N_VScale(ONE, u, vtemp);
+
+    /*   Apply b-scaling: u = sb P1_inv A P2_inv sx_inv u */
+
+    if (scale_b) N_VProd(sb, vtemp, u);
+    else N_VScale(ONE, vtemp, u);
+
+
+    /* Calculate omega = <u,q>/<u,u> */
+
+    omega_denom = N_VDotProd(u, u);
+    if (omega_denom == ZERO) omega_denom = ONE;
+    omega = (N_VDotProd(u, q) / omega_denom);
+
+    /* Update x = x + alpha*p + omega*q */
+
+    N_VLinearSum(alpha, p, omega, q, vtemp);
+    N_VLinearSum(ONE, x, ONE, vtemp, x);
+
+    /* Update the residual r = q - omega*u */
+
+    N_VLinearSum(ONE, q, -omega, u, r);
+
+    /* Set rho = norm(r) and check convergence */
+
+    *res_norm = rho = RSqrt(N_VDotProd(r, r));
+    if (rho <= delta) {
+      converged = TRUE;
+      break;
+    }
+
+    /* Not yet converged, continue iteration */
+    /* Update beta = <rnew,r_star> / <rold,r_start> * alpha / omega */
+
+    beta_num = N_VDotProd(r, r_star);
+    beta = ((beta_num / beta_denom) * (alpha / omega));
+    beta_denom = beta_num;
+
+    /* Update p = r + beta*(p - omega*Ap) */
+
+    N_VLinearSum(ONE, p, -omega, Ap, vtemp);
+    N_VLinearSum(ONE, r, beta, vtemp, p);
+
+  }
+
+  /* Main loop finished */
+
+  if ((converged == TRUE) || (rho < r_norm)) {
+
+    /* Apply the x-scaling and right preconditioner: x = P2_inv sx_inv x */
+
+    if (scale_x) N_VDiv(x, sx, x);
+    if (preOnRight) {
+      ier = psolve(P_data, x, vtemp, PREC_RIGHT);
+      (*nps)++;
+      if (ier != 0) return((ier < 0) ? SPBCG_PSOLVE_FAIL_UNREC : SPBCG_PSOLVE_FAIL_REC);
+      N_VScale(ONE, vtemp, x);
+    }
+
+    if (converged == TRUE) return(SPBCG_SUCCESS);
+    else return(SPBCG_RES_REDUCED);
+  }
+  else return(SPBCG_CONV_FAIL);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * Function : SpbcgFree
+ * -----------------------------------------------------------------
+ */
+
+void SpbcgFree(SpbcgMem mem)
+{
+
+  if (mem == NULL) return;
+
+  N_VDestroy(mem->r_star);
+  N_VDestroy(mem->r);
+  N_VDestroy(mem->p);
+  N_VDestroy(mem->q);
+  N_VDestroy(mem->u);
+  N_VDestroy(mem->Ap);
+  N_VDestroy(mem->vtemp);
+
+  free(mem); mem = NULL;
+}
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/sundials_spgmr.c b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/sundials_spgmr.c
new file mode 100644
index 0000000000000000000000000000000000000000..78b3c8c235c0982a0926370ae0eef730d91a52c8
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/sundials_spgmr.c	
@@ -0,0 +1,461 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * -----------------------------------------------------------------
+ * Programmer(s): Scott D. Cohen, Alan C. Hindmarsh and
+ *                Radu Serban @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2002, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This is the implementation file for the scaled preconditioned
+ * GMRES (SPGMR) iterative linear solver.
+ * -----------------------------------------------------------------
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sundials/sundials_spgmr.h>
+#include <sundials/sundials_math.h>
+
+/*
+ * -----------------------------------------------------------------
+ * private constants
+ * -----------------------------------------------------------------
+ */
+
+#define ZERO RCONST(0.0)
+#define ONE  RCONST(1.0)
+
+/*
+ * -----------------------------------------------------------------
+ * Function : SpgmrMalloc
+ * -----------------------------------------------------------------
+ */
+
+SpgmrMem SpgmrMalloc(int l_max, N_Vector vec_tmpl)
+{
+  SpgmrMem mem;
+  N_Vector *V, xcor, vtemp;
+  realtype **Hes, *givens, *yg;
+  int k, i;
+ 
+  /* Check the input parameters. */
+
+  if (l_max <= 0) return(NULL);
+
+  /* Get memory for the Krylov basis vectors V[0], ..., V[l_max]. */
+
+  V = NULL;
+  V = N_VCloneVectorArray(l_max+1, vec_tmpl);
+  if (V == NULL) return(NULL);
+
+  /* Get memory for the Hessenberg matrix Hes. */
+
+  Hes = NULL;
+  Hes = (realtype **) malloc((l_max+1)*sizeof(realtype *)); 
+  if (Hes == NULL) {
+    N_VDestroyVectorArray(V, l_max+1);
+    return(NULL);
+  }
+
+  for (k = 0; k <= l_max; k++) {
+    Hes[k] = NULL;
+    Hes[k] = (realtype *) malloc(l_max*sizeof(realtype));
+    if (Hes[k] == NULL) {
+      for (i = 0; i < k; i++) {free(Hes[i]); Hes[i] = NULL;}
+      free(Hes); Hes = NULL;
+      N_VDestroyVectorArray(V, l_max+1);
+      return(NULL);
+    }
+  }
+  
+  /* Get memory for Givens rotation components. */
+  
+  givens = NULL;
+  givens = (realtype *) malloc(2*l_max*sizeof(realtype));
+  if (givens == NULL) {
+    for (i = 0; i <= l_max; i++) {free(Hes[i]); Hes[i] = NULL;}
+    free(Hes); Hes = NULL;
+    N_VDestroyVectorArray(V, l_max+1);
+    return(NULL);
+  }
+
+  /* Get memory to hold the correction to z_tilde. */
+
+  xcor = NULL;
+  xcor = N_VClone(vec_tmpl);
+  if (xcor == NULL) {
+    free(givens); givens = NULL;
+    for (i = 0; i <= l_max; i++) {free(Hes[i]); Hes[i] = NULL;}
+    free(Hes); Hes = NULL;
+    N_VDestroyVectorArray(V, l_max+1);
+    return(NULL);
+  }
+
+  /* Get memory to hold SPGMR y and g vectors. */
+
+  yg = NULL;
+  yg = (realtype *) malloc((l_max+1)*sizeof(realtype));
+  if (yg == NULL) {
+    N_VDestroy(xcor);
+    free(givens); givens = NULL;
+    for (i = 0; i <= l_max; i++) {free(Hes[i]); Hes[i] = NULL;}
+    free(Hes); Hes = NULL;
+    N_VDestroyVectorArray(V, l_max+1);
+    return(NULL);
+  }
+
+  /* Get an array to hold a temporary vector. */
+
+  vtemp = NULL;
+  vtemp = N_VClone(vec_tmpl);
+  if (vtemp == NULL) {
+    free(yg); yg = NULL;
+    N_VDestroy(xcor);
+    free(givens); givens = NULL;
+    for (i = 0; i <= l_max; i++) {free(Hes[i]); Hes[i] = NULL;}
+    free(Hes); Hes = NULL;
+    N_VDestroyVectorArray(V, l_max+1);
+    return(NULL);
+  }
+
+  /* Get memory for an SpgmrMemRec containing SPGMR matrices and vectors. */
+
+  mem = NULL;
+  mem = (SpgmrMem) malloc(sizeof(SpgmrMemRec));
+  if (mem == NULL) {
+    N_VDestroy(vtemp);
+    free(yg); yg = NULL;
+    N_VDestroy(xcor);
+    free(givens); givens = NULL;
+    for (i = 0; i <= l_max; i++) {free(Hes[i]); Hes[i] = NULL;}
+    free(Hes); Hes = NULL;
+    N_VDestroyVectorArray(V, l_max+1);
+    return(NULL); 
+  }
+
+  /* Set the fields of mem. */
+
+  mem->l_max = l_max;
+  mem->V = V;
+  mem->Hes = Hes;
+  mem->givens = givens;
+  mem->xcor = xcor;
+  mem->yg = yg;
+  mem->vtemp = vtemp;
+
+  /* Return the pointer to SPGMR memory. */
+
+  return(mem);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * Function : SpgmrSolve
+ * -----------------------------------------------------------------
+ */
+
+int SpgmrSolve(SpgmrMem mem, void *A_data, N_Vector x, N_Vector b,
+               int pretype, int gstype, realtype delta, int max_restarts,
+               void *P_data, N_Vector s1, N_Vector s2, ATimesFn atimes,
+               PSolveFn psolve, realtype *res_norm, int *nli, int *nps)
+{
+  N_Vector *V, xcor, vtemp;
+  realtype **Hes, *givens, *yg;
+  realtype beta, rotation_product, r_norm, s_product, rho;
+  booleantype preOnLeft, preOnRight, scale2, scale1, converged;
+  int i, j, k, l, l_plus_1, l_max, krydim, ier, ntries;
+
+  if (mem == NULL) return(SPGMR_MEM_NULL);
+
+  /* Initialize some variables */
+
+  l_plus_1 = 0;
+  krydim = 0;
+
+  /* Make local copies of mem variables. */
+
+  l_max  = mem->l_max;
+  V      = mem->V;
+  Hes    = mem->Hes;
+  givens = mem->givens;
+  xcor   = mem->xcor;
+  yg     = mem->yg;
+  vtemp  = mem->vtemp;
+
+  *nli = *nps = 0;    /* Initialize counters */
+  converged = FALSE;  /* Initialize converged flag */
+
+  if (max_restarts < 0) max_restarts = 0;
+
+  if ((pretype != PREC_LEFT) && (pretype != PREC_RIGHT) && (pretype != PREC_BOTH))
+    pretype = PREC_NONE;
+  
+  preOnLeft  = ((pretype == PREC_LEFT) || (pretype == PREC_BOTH));
+  preOnRight = ((pretype == PREC_RIGHT) || (pretype == PREC_BOTH));
+  scale1 = (s1 != NULL);
+  scale2 = (s2 != NULL);
+
+  /* Set vtemp and V[0] to initial (unscaled) residual r_0 = b - A*x_0. */
+
+  if (N_VDotProd(x, x) == ZERO) {
+    N_VScale(ONE, b, vtemp);
+  } else {
+    ier = atimes(A_data, x, vtemp);
+    if (ier != 0)
+      return((ier < 0) ? SPGMR_ATIMES_FAIL_UNREC : SPGMR_ATIMES_FAIL_REC);
+    N_VLinearSum(ONE, b, -ONE, vtemp, vtemp);
+  }
+  N_VScale(ONE, vtemp, V[0]);
+
+  /* Apply left preconditioner and left scaling to V[0] = r_0. */
+  
+  if (preOnLeft) {
+    ier = psolve(P_data, V[0], vtemp, PREC_LEFT);
+    (*nps)++;
+    if (ier != 0)
+      return((ier < 0) ? SPGMR_PSOLVE_FAIL_UNREC : SPGMR_PSOLVE_FAIL_REC);
+  } else {
+    N_VScale(ONE, V[0], vtemp);
+  }
+  
+  if (scale1) {
+    N_VProd(s1, vtemp, V[0]);   
+  } else {
+    N_VScale(ONE, vtemp, V[0]);
+  }
+
+  /* Set r_norm = beta to L2 norm of V[0] = s1 P1_inv r_0, and
+     return if small.  */
+
+  *res_norm = r_norm = beta = RSqrt(N_VDotProd(V[0], V[0])); 
+  if (r_norm <= delta)
+    return(SPGMR_SUCCESS);
+
+  /* Initialize rho to avoid compiler warning message */
+
+  rho = beta;
+
+  /* Set xcor = 0. */
+
+  N_VConst(ZERO, xcor);
+
+
+  /* Begin outer iterations: up to (max_restarts + 1) attempts. */
+  
+  for (ntries = 0; ntries <= max_restarts; ntries++) {
+    
+    /* Initialize the Hessenberg matrix Hes and Givens rotation
+       product.  Normalize the initial vector V[0].             */
+    
+    for (i = 0; i <= l_max; i++)
+      for (j = 0; j < l_max; j++)
+        Hes[i][j] = ZERO;
+    
+    rotation_product = ONE;
+    
+    N_VScale(ONE/r_norm, V[0], V[0]);
+    
+    /* Inner loop: generate Krylov sequence and Arnoldi basis. */
+    
+    for (l = 0; l < l_max; l++) {
+      
+      (*nli)++;
+      
+      krydim = l_plus_1 = l + 1;
+      
+      /* Generate A-tilde V[l], where A-tilde = s1 P1_inv A P2_inv s2_inv. */
+      
+      /* Apply right scaling: vtemp = s2_inv V[l]. */
+
+      if (scale2) N_VDiv(V[l], s2, vtemp);
+      else N_VScale(ONE, V[l], vtemp);
+      
+      /* Apply right preconditioner: vtemp = P2_inv s2_inv V[l]. */ 
+
+      if (preOnRight) {
+        N_VScale(ONE, vtemp, V[l_plus_1]);
+        ier = psolve(P_data, V[l_plus_1], vtemp, PREC_RIGHT);
+        (*nps)++;
+        if (ier != 0)
+          return((ier < 0) ? SPGMR_PSOLVE_FAIL_UNREC : SPGMR_PSOLVE_FAIL_REC);
+      }
+      
+      /* Apply A: V[l+1] = A P2_inv s2_inv V[l]. */
+
+      ier = atimes(A_data, vtemp, V[l_plus_1] );
+      if (ier != 0)
+        return((ier < 0) ? SPGMR_ATIMES_FAIL_UNREC : SPGMR_ATIMES_FAIL_REC);
+      
+      /* Apply left preconditioning: vtemp = P1_inv A P2_inv s2_inv V[l]. */
+
+      if (preOnLeft) {
+        ier = psolve(P_data, V[l_plus_1], vtemp, PREC_LEFT);
+        (*nps)++;
+        if (ier != 0)
+          return((ier < 0) ? SPGMR_PSOLVE_FAIL_UNREC : SPGMR_PSOLVE_FAIL_REC);
+      } else {
+        N_VScale(ONE, V[l_plus_1], vtemp);
+      }
+      
+      /* Apply left scaling: V[l+1] = s1 P1_inv A P2_inv s2_inv V[l]. */
+
+      if (scale1) {
+        N_VProd(s1, vtemp, V[l_plus_1]);
+      } else {
+        N_VScale(ONE, vtemp, V[l_plus_1]);
+      }
+      
+      /*  Orthogonalize V[l+1] against previous V[i]: V[l+1] = w_tilde. */
+      
+      if (gstype == CLASSICAL_GS) {
+        if (ClassicalGS(V, Hes, l_plus_1, l_max, &(Hes[l_plus_1][l]),
+                        vtemp, yg) != 0)
+          return(SPGMR_GS_FAIL);
+      } else {
+        if (ModifiedGS(V, Hes, l_plus_1, l_max, &(Hes[l_plus_1][l])) != 0) 
+          return(SPGMR_GS_FAIL);
+      }
+      
+      /*  Update the QR factorization of Hes. */
+      
+      if(QRfact(krydim, Hes, givens, l) != 0 )
+        return(SPGMR_QRFACT_FAIL);
+      
+      /*  Update residual norm estimate; break if convergence test passes. */
+      
+      rotation_product *= givens[2*l+1];
+      *res_norm = rho = ABS(rotation_product*r_norm);
+      
+      if (rho <= delta) { converged = TRUE; break; }
+      
+      /* Normalize V[l+1] with norm value from the Gram-Schmidt routine. */
+
+      N_VScale(ONE/Hes[l_plus_1][l], V[l_plus_1], V[l_plus_1]);
+    }
+    
+    /* Inner loop is done.  Compute the new correction vector xcor. */
+    
+    /* Construct g, then solve for y. */
+
+    yg[0] = r_norm;
+    for (i = 1; i <= krydim; i++) yg[i]=ZERO;
+    if (QRsol(krydim, Hes, givens, yg) != 0)
+      return(SPGMR_QRSOL_FAIL);
+    
+    /* Add correction vector V_l y to xcor. */
+
+    for (k = 0; k < krydim; k++)
+      N_VLinearSum(yg[k], V[k], ONE, xcor, xcor);
+    
+    /* If converged, construct the final solution vector x and return. */
+
+    if (converged) {
+      
+      /* Apply right scaling and right precond.: vtemp = P2_inv s2_inv xcor. */
+      
+      if (scale2) N_VDiv(xcor, s2, xcor);
+      if (preOnRight) {
+        ier = psolve(P_data, xcor, vtemp, PREC_RIGHT);
+        (*nps)++;
+        if (ier != 0)
+          return((ier < 0) ? SPGMR_PSOLVE_FAIL_UNREC : SPGMR_PSOLVE_FAIL_REC);
+      } else {
+        N_VScale(ONE, xcor, vtemp);
+      }
+      
+      /* Add vtemp to initial x to get final solution x, and return */
+
+      N_VLinearSum(ONE, x, ONE, vtemp, x);
+      
+      return(SPGMR_SUCCESS);
+    }
+    
+    /* Not yet converged; if allowed, prepare for restart. */
+    
+    if (ntries == max_restarts) break;
+    
+    /* Construct last column of Q in yg. */
+
+    s_product = ONE;
+    for (i = krydim; i > 0; i--) {
+      yg[i] = s_product*givens[2*i-2];
+      s_product *= givens[2*i-1];
+    }
+    yg[0] = s_product;
+    
+    /* Scale r_norm and yg. */
+    r_norm *= s_product;
+    for (i = 0; i <= krydim; i++)
+      yg[i] *= r_norm;
+    r_norm = ABS(r_norm);
+    
+    /* Multiply yg by V_(krydim+1) to get last residual vector; restart. */
+    N_VScale(yg[0], V[0], V[0]);
+    for (k = 1; k <= krydim; k++)
+      N_VLinearSum(yg[k], V[k], ONE, V[0], V[0]);
+    
+  }
+  
+  /* Failed to converge, even after allowed restarts.
+     If the residual norm was reduced below its initial value, compute
+     and return x anyway.  Otherwise return failure flag. */
+
+  if (rho < beta) {
+    
+    /* Apply right scaling and right precond.: vtemp = P2_inv s2_inv xcor. */
+    
+    if (scale2) N_VDiv(xcor, s2, xcor);
+    if (preOnRight) {
+      ier = psolve(P_data, xcor, vtemp, PREC_RIGHT);
+      (*nps)++;
+      if (ier != 0)
+        return((ier < 0) ? SPGMR_PSOLVE_FAIL_UNREC : SPGMR_PSOLVE_FAIL_REC);
+      } else {
+      N_VScale(ONE, xcor, vtemp);
+    }
+
+    /* Add vtemp to initial x to get final solution x, and return. */
+
+    N_VLinearSum(ONE, x, ONE, vtemp, x);
+    
+    return(SPGMR_RES_REDUCED);
+  }
+
+  return(SPGMR_CONV_FAIL); 
+}
+
+/*
+ * -----------------------------------------------------------------
+ * Function : SpgmrFree
+ * -----------------------------------------------------------------
+ */
+
+void SpgmrFree(SpgmrMem mem)
+{
+  int i, l_max;
+  realtype **Hes, *givens, *yg;
+  
+  if (mem == NULL) return;
+
+  l_max  = mem->l_max;
+  Hes    = mem->Hes;
+  givens = mem->givens;
+  yg     = mem->yg;
+
+  for (i = 0; i <= l_max; i++) {free(Hes[i]); Hes[i] = NULL;}
+  free(Hes); Hes = NULL;
+  free(mem->givens); givens = NULL; 
+  free(mem->yg); yg = NULL;
+
+  N_VDestroyVectorArray(mem->V, l_max+1);
+  N_VDestroy(mem->xcor);
+  N_VDestroy(mem->vtemp);
+
+  free(mem); mem = NULL;
+}
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/sundials_sptfqmr.c b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/sundials_sptfqmr.c
new file mode 100644
index 0000000000000000000000000000000000000000..b4cf2aa4545eb5d98167667113974bfdfdf2c317
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/CVODEMEX/src/source_SUNDIALS_CVODES_25/sundials_sptfqmr.c	
@@ -0,0 +1,525 @@
+/*
+ * -----------------------------------------------------------------
+ * $Revision: 749 $
+ * $Date: 2011-06-22 14:49:10 +0200 (Wed, 22 Jun 2011) $
+ * -----------------------------------------------------------------
+ * Programmer(s): Aaron Collier @ LLNL
+ * -----------------------------------------------------------------
+ * Copyright (c) 2005, The Regents of the University of California.
+ * Produced at the Lawrence Livermore National Laboratory.
+ * All rights reserved.
+ * For details, see the LICENSE file.
+ * -----------------------------------------------------------------
+ * This is the implementation file for the scaled preconditioned
+ * Transpose-Free Quasi-Minimal Residual (SPTFQMR) linear solver.
+ * -----------------------------------------------------------------
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sundials/sundials_sptfqmr.h>
+#include <sundials/sundials_math.h>
+
+/*
+ * -----------------------------------------------------------------
+ * private constants
+ * -----------------------------------------------------------------
+ */
+
+#define ZERO RCONST(0.0)
+#define ONE  RCONST(1.0)
+
+/*
+ * -----------------------------------------------------------------
+ * Function : SptfqmrMalloc
+ * -----------------------------------------------------------------
+ */
+
+SptfqmrMem SptfqmrMalloc(int l_max, N_Vector vec_tmpl)
+{
+  SptfqmrMem mem;
+  N_Vector *r;
+  N_Vector q, d, v, p, u;
+  N_Vector r_star, vtemp1, vtemp2, vtemp3;
+
+  /* Check the input parameters */
+  if ((l_max <= 0) || (vec_tmpl == NULL)) return(NULL);
+
+  /* Allocate space for vectors */
+  r_star = NULL;
+  r_star = N_VClone(vec_tmpl);
+  if (r_star == NULL) return(NULL);
+
+  q = NULL;
+  q = N_VClone(vec_tmpl);
+  if (q == NULL) {
+    N_VDestroy(r_star);
+    return(NULL);
+  }
+
+  d = NULL;
+  d = N_VClone(vec_tmpl);
+  if (d == NULL) {
+    N_VDestroy(r_star);
+    N_VDestroy(q);
+    return(NULL);
+  }
+
+  v = NULL;
+  v = N_VClone(vec_tmpl);
+  if (v == NULL) {
+    N_VDestroy(r_star);
+    N_VDestroy(q);
+    N_VDestroy(d);
+    return(NULL);
+  }
+
+  p = NULL;
+  p = N_VClone(vec_tmpl);
+  if (p == NULL) {
+    N_VDestroy(r_star);
+    N_VDestroy(q);
+    N_VDestroy(d);
+    N_VDestroy(v);
+    return(NULL);
+  }
+
+  r = NULL;
+  r = N_VCloneVectorArray(2, vec_tmpl);
+  if (r == NULL) {
+    N_VDestroy(r_star);
+    N_VDestroy(q);
+    N_VDestroy(d);
+    N_VDestroy(v);
+    N_VDestroy(p);
+    return(NULL);
+  }
+
+  u = NULL;
+  u = N_VClone(vec_tmpl);
+  if (u == NULL) {
+    N_VDestroy(r_star);
+    N_VDestroy(q);
+    N_VDestroy(d);
+    N_VDestroy(v);
+    N_VDestroy(p);
+    N_VDestroyVectorArray(r, 2);
+    return(NULL);
+  }
+
+  vtemp1 = NULL;
+  vtemp1 = N_VClone(vec_tmpl);
+  if (vtemp1 == NULL) {
+    N_VDestroy(r_star);
+    N_VDestroy(q);
+    N_VDestroy(d);
+    N_VDestroy(v);
+    N_VDestroy(p);
+    N_VDestroyVectorArray(r, 2);
+    N_VDestroy(u);
+    return(NULL);
+  }
+
+  vtemp2 = NULL;
+  vtemp2 = N_VClone(vec_tmpl);
+  if (vtemp2 == NULL) {
+    N_VDestroy(r_star);
+    N_VDestroy(q);
+    N_VDestroy(d);
+    N_VDestroy(v);
+    N_VDestroy(p);
+    N_VDestroyVectorArray(r, 2);
+    N_VDestroy(u);
+    N_VDestroy(vtemp1);
+    return(NULL);
+  }
+
+  vtemp3 = NULL;
+  vtemp3 = N_VClone(vec_tmpl);
+  if (vtemp3 == NULL) {
+    N_VDestroy(r_star);
+    N_VDestroy(q);
+    N_VDestroy(d);
+    N_VDestroy(v);
+    N_VDestroy(p);
+    N_VDestroyVectorArray(r, 2);
+    N_VDestroy(u);
+    N_VDestroy(vtemp1);
+    N_VDestroy(vtemp2);
+    return(NULL);
+  }
+
+  /* Allocate memory for SptfqmrMemRec */
+  mem = NULL;
+  mem = (SptfqmrMem) malloc(sizeof(SptfqmrMemRec));
+  if (mem == NULL) {
+    N_VDestroy(r_star);
+    N_VDestroy(q);
+    N_VDestroy(d);
+    N_VDestroy(v);
+    N_VDestroy(p);
+    N_VDestroyVectorArray(r, 2);
+    N_VDestroy(u);
+    N_VDestroy(vtemp1);
+    N_VDestroy(vtemp2);
+    N_VDestroy(vtemp3);
+    return(NULL);
+  }
+
+  /* Intialize SptfqmrMemRec data structure */
+  mem->l_max  = l_max;
+  mem->r_star = r_star;
+  mem->q      = q;
+  mem->d      = d;
+  mem->v      = v;
+  mem->p      = p;
+  mem->r      = r;
+  mem->u      = u;
+  mem->vtemp1 = vtemp1;
+  mem->vtemp2 = vtemp2;
+  mem->vtemp3 = vtemp3;
+
+  /* Return pointer to SPTFQMR memory block */
+  return(mem);
+}
+
+#define l_max  (mem->l_max)
+#define r_star (mem->r_star)
+#define q_     (mem->q)
+#define d_     (mem->d)
+#define v_     (mem->v)
+#define p_     (mem->p)
+#define r_     (mem->r)
+#define u_     (mem->u)
+#define vtemp1 (mem->vtemp1)
+#define vtemp2 (mem->vtemp2)
+#define vtemp3 (mem->vtemp3)
+
+/*
+ * -----------------------------------------------------------------
+ * Function : SptfqmrSolve
+ * -----------------------------------------------------------------
+ */
+
+int SptfqmrSolve(SptfqmrMem mem, void *A_data, N_Vector x, N_Vector b,
+		 int pretype, realtype delta, void *P_data, N_Vector sx,
+		 N_Vector sb, ATimesFn atimes, PSolveFn psolve,
+		 realtype *res_norm, int *nli, int *nps)
+{
+  realtype alpha, tau, eta, beta, c, sigma, v_bar, omega;
+  realtype rho[2];
+  realtype r_init_norm, r_curr_norm;
+  realtype temp_val;
+  booleantype preOnLeft, preOnRight, scale_x, scale_b, converged;
+  booleantype b_ok;
+  int n, m, ier;
+
+  /* Exit immediately if memory pointer is NULL */
+  if (mem == NULL) return(SPTFQMR_MEM_NULL);
+
+  temp_val = r_curr_norm = -ONE;  /* Initialize to avoid compiler warnings */
+
+  *nli = *nps = 0;    /* Initialize counters */
+  converged = FALSE;  /* Initialize convergence flag */
+  b_ok = FALSE;
+
+  if ((pretype != PREC_LEFT)  &&
+      (pretype != PREC_RIGHT) &&
+      (pretype != PREC_BOTH)) pretype = PREC_NONE;
+
+  preOnLeft  = ((pretype == PREC_BOTH) || (pretype == PREC_LEFT));
+  preOnRight = ((pretype == PREC_BOTH) || (pretype == PREC_RIGHT));
+
+  scale_x = (sx != NULL);
+  scale_b = (sb != NULL);
+
+  /* Set r_star to initial (unscaled) residual r_star = r_0 = b - A*x_0 */
+  /* NOTE: if x == 0 then just set residual to b and continue */
+  if (N_VDotProd(x, x) == ZERO) N_VScale(ONE, b, r_star);
+  else {
+    ier = atimes(A_data, x, r_star);
+    if (ier != 0)
+      return((ier < 0) ? SPTFQMR_ATIMES_FAIL_UNREC : SPTFQMR_ATIMES_FAIL_REC);
+    N_VLinearSum(ONE, b, -ONE, r_star, r_star);
+  }
+
+  /* Apply left preconditioner and b-scaling to r_star (or really just r_0) */
+  if (preOnLeft) {
+    ier = psolve(P_data, r_star, vtemp1, PREC_LEFT);
+    (*nps)++;
+    if (ier != 0)
+      return((ier < 0) ? SPTFQMR_PSOLVE_FAIL_UNREC : SPTFQMR_PSOLVE_FAIL_REC);
+  }
+  else N_VScale(ONE, r_star, vtemp1);
+  if (scale_b) N_VProd(sb, vtemp1, r_star);
+  else N_VScale(ONE, vtemp1, r_star);
+
+  /* Initialize rho[0] */
+  /* NOTE: initialized here to reduce number of computations - avoid need
+           to compute r_star^T*r_star twice, and avoid needlessly squaring
+           values */
+  rho[0] = N_VDotProd(r_star, r_star);
+
+  /* Compute norm of initial residual (r_0) to see if we really need
+     to do anything */
+  *res_norm = r_init_norm = RSqrt(rho[0]);
+  if (r_init_norm <= delta) return(SPTFQMR_SUCCESS);
+
+  /* Set v_ = A*r_0 (preconditioned and scaled) */
+  if (scale_x) N_VDiv(r_star, sx, vtemp1);
+  else N_VScale(ONE, r_star, vtemp1);
+  if (preOnRight) {
+    N_VScale(ONE, vtemp1, v_);
+    ier = psolve(P_data, v_, vtemp1, PREC_RIGHT);
+    (*nps)++;
+    if (ier != 0) return((ier < 0) ? SPTFQMR_PSOLVE_FAIL_UNREC : SPTFQMR_PSOLVE_FAIL_REC);
+  }
+  ier = atimes(A_data, vtemp1, v_);
+  if (ier != 0)
+    return((ier < 0) ? SPTFQMR_ATIMES_FAIL_UNREC : SPTFQMR_ATIMES_FAIL_REC);
+  if (preOnLeft) {
+    ier = psolve(P_data, v_, vtemp1, PREC_LEFT);
+    (*nps)++;
+    if (ier != 0) return((ier < 0) ? SPTFQMR_PSOLVE_FAIL_UNREC : SPTFQMR_PSOLVE_FAIL_REC);
+  }
+  else N_VScale(ONE, v_, vtemp1);
+  if (scale_b) N_VProd(sb, vtemp1, v_);
+  else N_VScale(ONE, vtemp1, v_);
+
+  /* Initialize remaining variables */
+  N_VScale(ONE, r_star, r_[0]);
+  N_VScale(ONE, r_star, u_);
+  N_VScale(ONE, r_star, p_);
+  N_VConst(ZERO, d_);
+
+  tau = r_init_norm;
+  v_bar = eta = ZERO;
+
+  /* START outer loop */
+  for (n = 0; n < l_max; ++n) {
+
+    /* Increment linear iteration counter */
+    (*nli)++;
+
+    /* sigma = r_star^T*v_ */
+    sigma = N_VDotProd(r_star, v_);
+
+    /* alpha = rho[0]/sigma */
+    alpha = rho[0]/sigma;
+
+    /* q_ = u_-alpha*v_ */
+    N_VLinearSum(ONE, u_, -alpha, v_, q_);
+
+    /* r_[1] = r_[0]-alpha*A*(u_+q_) */
+    N_VLinearSum(ONE, u_, ONE, q_, r_[1]);
+    if (scale_x) N_VDiv(r_[1], sx, r_[1]);
+    if (preOnRight) {
+      N_VScale(ONE, r_[1], vtemp1);
+      ier = psolve(P_data, vtemp1, r_[1], PREC_RIGHT);
+      (*nps)++;
+      if (ier != 0) return((ier < 0) ? SPTFQMR_PSOLVE_FAIL_UNREC : SPTFQMR_PSOLVE_FAIL_REC);
+    }
+    ier = atimes(A_data, r_[1], vtemp1);
+    if (ier != 0)
+      return((ier < 0) ? SPTFQMR_ATIMES_FAIL_UNREC : SPTFQMR_ATIMES_FAIL_REC);
+    if (preOnLeft) {
+      ier = psolve(P_data, vtemp1, r_[1], PREC_LEFT);
+      (*nps)++;
+      if (ier != 0) return((ier < 0) ? SPTFQMR_PSOLVE_FAIL_UNREC : SPTFQMR_PSOLVE_FAIL_REC);
+    }
+    else N_VScale(ONE, vtemp1, r_[1]);
+    if (scale_b) N_VProd(sb, r_[1], vtemp1);
+    else N_VScale(ONE, r_[1], vtemp1);
+    N_VLinearSum(ONE, r_[0], -alpha, vtemp1, r_[1]);
+
+    /* START inner loop */
+    for (m = 0; m < 2; ++m) {
+
+      /* d_ = [*]+(v_bar^2*eta/alpha)*d_ */
+      /* NOTES:
+       *   (1) [*] = u_ if m == 0, and q_ if m == 1
+       *   (2) using temp_val reduces the number of required computations
+       *       if the inner loop is executed twice
+       */
+      if (m == 0) {
+	temp_val = RSqrt(N_VDotProd(r_[1], r_[1]));
+	omega = RSqrt(RSqrt(N_VDotProd(r_[0], r_[0]))*temp_val);
+	N_VLinearSum(ONE, u_, SQR(v_bar)*eta/alpha, d_, d_);
+      }
+      else {
+	omega = temp_val;
+	N_VLinearSum(ONE, q_, SQR(v_bar)*eta/alpha, d_, d_);
+      }
+
+      /* v_bar = omega/tau */
+      v_bar = omega/tau;
+
+      /* c = (1+v_bar^2)^(-1/2) */
+      c = ONE / RSqrt(ONE+SQR(v_bar));
+
+      /* tau = tau*v_bar*c */
+      tau = tau*v_bar*c;
+
+      /* eta = c^2*alpha */
+      eta = SQR(c)*alpha;
+
+      /* x = x+eta*d_ */
+      N_VLinearSum(ONE, x, eta, d_, x);
+
+      /* Check for convergence... */
+      /* NOTE: just use approximation to norm of residual, if possible */
+      *res_norm = r_curr_norm = tau*RSqrt(m+1);
+
+      /* Exit inner loop if iteration has converged based upon approximation
+	 to norm of current residual */
+      if (r_curr_norm <= delta) {
+	converged = TRUE;
+	break;
+      }
+
+      /* Decide if actual norm of residual vector should be computed */
+      /* NOTES:
+       *   (1) if r_curr_norm > delta, then check if actual residual norm
+       *       is OK (recall we first compute an approximation)
+       *   (2) if r_curr_norm >= r_init_norm and m == 1 and n == l_max, then
+       *       compute actual residual norm to see if the iteration can be
+       *       saved
+       *   (3) the scaled and preconditioned right-hand side of the given
+       *       linear system (denoted by b) is only computed once, and the
+       *       result is stored in vtemp3 so it can be reused - reduces the
+       *       number of psovles if using left preconditioning
+       */
+      if ((r_curr_norm > delta) ||
+	  (r_curr_norm >= r_init_norm && m == 1 && n == l_max)) {
+
+	/* Compute norm of residual ||b-A*x||_2 (preconditioned and scaled) */
+	if (scale_x) N_VDiv(x, sx, vtemp1);
+	else N_VScale(ONE, x, vtemp1);
+	if (preOnRight) {
+	  ier = psolve(P_data, vtemp1, vtemp2, PREC_RIGHT);
+	  (*nps)++;
+	  if (ier != 0) return((ier < 0) ? SPTFQMR_PSOLVE_FAIL_UNREC : SPTFQMR_PSOLVE_FAIL_UNREC);
+	  N_VScale(ONE, vtemp2, vtemp1);
+	}
+	ier = atimes(A_data, vtemp1, vtemp2);
+        if (ier != 0)
+          return((ier < 0) ? SPTFQMR_ATIMES_FAIL_UNREC : SPTFQMR_ATIMES_FAIL_REC);
+	if (preOnLeft) {
+	  ier = psolve(P_data, vtemp2, vtemp1, PREC_LEFT);
+	  (*nps)++;
+	  if (ier != 0) return((ier < 0) ? SPTFQMR_PSOLVE_FAIL_UNREC : SPTFQMR_PSOLVE_FAIL_REC);
+	}
+	else N_VScale(ONE, vtemp2, vtemp1);
+	if (scale_b) N_VProd(sb, vtemp1, vtemp2);
+	else N_VScale(ONE, vtemp1, vtemp2);
+	/* Only precondition and scale b once (result saved for reuse) */
+	if (!b_ok) {
+	  b_ok = TRUE;
+	  if (preOnLeft) {
+	    ier = psolve(P_data, b, vtemp3, PREC_LEFT);
+	    (*nps)++;
+	    if (ier != 0) return((ier < 0) ? SPTFQMR_PSOLVE_FAIL_UNREC : SPTFQMR_PSOLVE_FAIL_REC);
+	  }
+	  else N_VScale(ONE, b, vtemp3);
+	  if (scale_b) N_VProd(sb, vtemp3, vtemp3);
+	}
+	N_VLinearSum(ONE, vtemp3, -ONE, vtemp2, vtemp1);
+	*res_norm = r_curr_norm = RSqrt(N_VDotProd(vtemp1, vtemp1));
+
+	/* Exit inner loop if inequality condition is satisfied 
+	   (meaning exit if we have converged) */
+	if (r_curr_norm <= delta) {
+	  converged = TRUE;
+	  break;
+	}
+
+      }
+
+    }  /* END inner loop */
+
+    /* If converged, then exit outer loop as well */
+    if (converged == TRUE) break;
+
+    /* rho[1] = r_star^T*r_[1] */
+    rho[1] = N_VDotProd(r_star, r_[1]);
+
+    /* beta = rho[1]/rho[0] */
+    beta = rho[1]/rho[0];
+
+    /* u_ = r_[1]+beta*q_ */
+    N_VLinearSum(ONE, r_[1], beta, q_, u_);
+
+    /* p_ = u_+beta*(q_+beta*p_) */
+    N_VLinearSum(beta, q_, SQR(beta), p_, p_);
+    N_VLinearSum(ONE, u_, ONE, p_, p_);
+
+    /* v_ = A*p_ */
+    if (scale_x) N_VDiv(p_, sx, vtemp1);
+    else N_VScale(ONE, p_, vtemp1);
+    if (preOnRight) {
+      N_VScale(ONE, vtemp1, v_);
+      ier = psolve(P_data, v_, vtemp1, PREC_RIGHT);
+      (*nps)++;
+      if (ier != 0) return((ier < 0) ? SPTFQMR_PSOLVE_FAIL_UNREC : SPTFQMR_PSOLVE_FAIL_REC);
+    }
+    ier = atimes(A_data, vtemp1, v_);
+    if (ier != 0)
+      return((ier < 0) ? SPTFQMR_ATIMES_FAIL_UNREC : SPTFQMR_ATIMES_FAIL_REC);
+    if (preOnLeft) {
+      ier = psolve(P_data, v_, vtemp1, PREC_LEFT);
+      (*nps)++;
+      if (ier != 0) return((ier < 0) ? SPTFQMR_PSOLVE_FAIL_UNREC : SPTFQMR_PSOLVE_FAIL_REC);
+    }
+    else N_VScale(ONE, v_, vtemp1);
+    if (scale_b) N_VProd(sb, vtemp1, v_);
+    else N_VScale(ONE, vtemp1, v_);
+
+    /* Shift variable values */
+    /* NOTE: reduces storage requirements */
+    N_VScale(ONE, r_[1], r_[0]);
+    rho[0] = rho[1];
+
+  }  /* END outer loop */
+
+  /* Determine return value */
+  /* If iteration converged or residual was reduced, then return current iterate (x) */
+  if ((converged == TRUE) || (r_curr_norm < r_init_norm)) {
+    if (scale_x) N_VDiv(x, sx, x);
+    if (preOnRight) {
+      ier = psolve(P_data, x, vtemp1, PREC_RIGHT);
+      (*nps)++;
+      if (ier != 0) return((ier < 0) ? SPTFQMR_PSOLVE_FAIL_UNREC : SPTFQMR_PSOLVE_FAIL_UNREC);
+      N_VScale(ONE, vtemp1, x);
+    }
+    if (converged == TRUE) return(SPTFQMR_SUCCESS);
+    else return(SPTFQMR_RES_REDUCED);
+  }
+  /* Otherwise, return error code */
+  else return(SPTFQMR_CONV_FAIL);
+}
+
+/*
+ * -----------------------------------------------------------------
+ * Function : SptfqmrFree
+ * -----------------------------------------------------------------
+ */
+
+void SptfqmrFree(SptfqmrMem mem)
+{
+
+  if (mem == NULL) return;
+
+  N_VDestroy(r_star);
+  N_VDestroy(q_);
+  N_VDestroy(d_);
+  N_VDestroy(v_);
+  N_VDestroy(p_);
+  N_VDestroyVectorArray(r_, 2);
+  N_VDestroy(u_);
+  N_VDestroy(vtemp1);
+  N_VDestroy(vtemp2);
+  N_VDestroy(vtemp3);
+
+  free(mem); mem = NULL;
+}
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/IQMPsimulate.m b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/IQMPsimulate.m
new file mode 100644
index 0000000000000000000000000000000000000000..6ac2913a6f6837d61f705af798d9abaf42543edd
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/IQMPsimulate.m	
@@ -0,0 +1,211 @@
+function [varargout] = IQMPsimulate(mmodel,varargin)
+% IQMPsimulate: Function allowing to simulate IQMmodels and MEX simulation
+% functions. IQMmodels are first converted to temporary MEX simulation
+% functions, so that a conversion overhead is present.
+%
+% USAGE:
+% ======
+% output = IQMPsimulate(model)
+% output = IQMPsimulate(model, time)
+% output = IQMPsimulate(model, time, ICs)
+% output = IQMPsimulate(model, time, ICs, paramNames, paramValues)
+% output = IQMPsimulate(model, time, ICs, paramNames, paramValues, OPTIONS)
+%
+% model: Name of MEX simulation function OR IQMmodel 
+% time: Either simulation end time (scalar) or simulation time vector.
+% ICs: Vector of initial conditions.
+% paramNames: Cell-array with the names of the parameters for which the
+%             values are to be changed to given values.
+% paramValues: Vector of parameter values for the given parameters.
+% OPTIONS: structure with integrator options.
+%       OPTIONS.showIntegratorStats: =0 (off), =1 shows integrator
+%               statistics in the MATLAB console window
+%       OPTIONS.method:             'stiff' or 'nonstiff' (default: 'stiff')
+%       OPTIONS.abstol:             abs tolerance (default: 1e-6)
+%       OPTIONS.reltol:             rel tolerance (default: 1e-6)
+%       OPTIONS.minstep:            min step-size integrator (default: 0)
+%       OPTIONS.maxstep:            max step-size integrator (default: inf)
+%       OPTIONS.maxnumsteps:        max number of steps between two output
+%                                   points (default: 100000)
+%       OPTIONS.maxerrtestfails:    maximum number of error test failures
+%                                   permitted in attempting one step
+%                                   (default: 50)
+%       OPTIONS.maxorder:           maximum order of the linear multistep
+%                                   method (default: 5 BDF, 12 ADAMS)
+%       OPTIONS.maxconvfails:       maximum number of nonlinear solver convergence 
+%                                   failures permitted during one step
+%                                   (default: 10)
+%       OPTIONS.initstep:           initial step size to be attempted
+%                                   (default: 0)
+%       OPTIONS.maxnonlineariter:   maximum number of nonlinear solver
+%                                   iterations permitted per step 
+%                                   (default: 3)
+%
+% DEFAULT VALUES:
+% ===============
+% time: 20 
+% ICs: values stored in the model
+% paramNames: {}  do not change any parameters
+% paramValues: []   
+%
+% Output Arguments:
+% =================
+% If no output arguments are given, the result of the simulation is plotted
+% after finished simulation.
+%
+% The output of IQMPsimulate is realized as a structure:
+% output.time:              vector with time instants for the results
+% output.states:            cell-array with state names
+% output.statevalues:       matrix with state values. Each row corresponds to
+%                           one time instant
+%
+% output.variables:         cell-array with variable names
+% output.variablevalues:    matrix with variable values. Each row corresponds to
+%                           one time instant
+% output.reactions:         cell-array with reaction names
+% output.reactionvalues:    matrix with reaction values. Each row corresponds to
+%                           one time instant
+%
+% In the case events are present in the model the following fields are
+% present in the output structure additionally:
+% output.events:            cell-arra with the names of the events
+% output.eventtimes:        vector with time instants at which events
+%                           happened
+% output.eventflags:        matrix of dimension: 'number of events' x
+%                           'number of event time instants'. Each column in
+%                           this matrix correponds to one timeinstant in
+%                           the output.eventtimes vector. The row numbers
+%                           correspond to the numbers of the events. A "1"
+%                           element in the matrix indicates that the
+%                           corresponding event has happened at the
+%                           corresponding time. A "0" element tells you
+%                           that the event has not been fired at the
+%                           corresponding instant.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% FIRST CHECK THE GIVEN MODEL
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isIQMmodel(mmodel),
+    % create the MEX simulation function
+    [MEXmodel, MEXmodelfullpath] = IQMmakeTempMEXmodel(mmodel);
+elseif exist(mmodel) == 3,
+    MEXmodel = mmodel;
+    MEXmodelfullpath = '';
+else
+    error('Model input argument is no IQMmodel and no MEX simulation function.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+timevector = [0:0.01:20];  % just the default timevector
+time = [];
+ICs = [];
+paramvec = [];
+paramNames = {};
+OPTIONS = [];
+if nargin<1 || nargin==4 || nargin > 6,
+    error('Incorrect number of input arguments');
+elseif nargin == 2,
+    time = varargin{1};
+elseif nargin == 3,
+    time = varargin{1};
+    ICs = varargin{2};
+elseif nargin == 5,
+    time = varargin{1};
+    ICs = varargin{2};
+    paramNames = varargin{3};
+    paramValues = varargin{4};
+elseif nargin == 6,
+    time = varargin{1};
+    ICs = varargin{2};
+    paramNames = varargin{3};
+    paramValues = varargin{4};
+    OPTIONS = varargin{5};
+end
+
+try OPTIONS.method; catch, OPTIONS.method = 'stiff'; end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS INPUTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(time),
+    if length(time) == 1,
+        timevector = [0:time/1000:time];
+    elseif length(time) > 1,
+        timevector = time;
+    end
+end
+if ~isempty(paramNames),
+    paramvec = makeparamvecIQM(MEXmodel,paramNames,paramValues);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF DELAY PRESENT ... THEN ERROR
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isIQMmodel(mmodel),
+    if usedelayIQM(mmodel),
+        error('The model contains delays. This is not supported for MEX file simulation.');
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% IF EVENTS ARE PRESENT THEN USE A DEFAULT MAXSTEP
+% Only do that in case of an IQMmodel
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isIQMmodel(mmodel),
+    if useeventIQM(mmodel),
+        if ~isfield(OPTIONS,'maxstep'),
+            % change only if not user provided 
+            OPTIONS.maxstep = timevector(end)/1000;
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% RUN THE MEX SIMULATION FUNCTION WITH GIVEN INPUT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+simdata = feval(MEXmodel,timevector,ICs,paramvec,OPTIONS);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE VARIABLE OUTPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargout == 0,
+    % NO OUTPUT => DO PLOT RESULTS
+    time = simdata.time;
+    datanames = {};
+    dataindex = 1;
+    for k = 1:length(simdata.states),
+        datanames{dataindex} = sprintf('%s (state)',simdata.states{k});
+        dataindex = dataindex + 1;
+    end
+    if isfield(simdata,'variables'),
+        for k = 1:length(simdata.variables),
+            datanames{dataindex} = sprintf('%s (variable)',simdata.variables{k});
+            dataindex = dataindex + 1;
+        end
+        for k = 1:length(simdata.reactions),
+            datanames{dataindex} = sprintf('%s (reaction rate)',simdata.reactions{k});
+            dataindex = dataindex + 1;
+        end
+        datavalues = [simdata.statevalues, simdata.variablevalues, simdata.reactionvalues];
+    else
+        datavalues = [simdata.statevalues];
+    end
+    IQMplot(createdatastructIQMplotIQM(time(:),datavalues,datanames));
+elseif nargout == 1,
+    varargout{1} = simdata;
+else 
+    error('Incorrect number of simdata arguments!');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DELETE THE TEMPORARY MEX SIMULATION FUNCTION IF IT HAS BEEN CREATED
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(MEXmodelfullpath),
+    clear mex;
+    delete(MEXmodelfullpath);
+end
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/IQMmakeMEXmodel.m b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/IQMmakeMEXmodel.m
new file mode 100644
index 0000000000000000000000000000000000000000..f9df1235c418b8caa24c1fcf45293b165d467be2
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/IQMmakeMEXmodel.m	
@@ -0,0 +1,1166 @@
+function [] = IQMmakeMEXmodel(model,varargin)
+% IQMmakeMEXmodel: This function converts an IQMmodel to an executable
+% C-code
+% MEX model and links it with the CVODE integrator from SUNDIALS.
+% 
+% USAGE:
+% ======
+% [] = IQMmakeMEXmodel(model)
+% [] = IQMmakeMEXmodel(model, MEXfile)
+% [] = IQMmakeMEXmodel(model, MEXfile, doNOTcompileFlag)
+%
+% model: IQMmodel
+% MEXfile: the name of the MEX file (default: models name)
+% doNOTcompileFlag: =0 (default): create executable MEX simulation file 
+%                   =1: only create the source code but do not compile
+%
+% The calling syntax of the MEX simulation function is the following:
+%           
+%   output = MEXfile()                     % returns vector with initial conditions
+%   output = MEXfile('states')             % returns cell array with state names
+%   output = MEXfile('parameters')         % returns cell array with parameter names
+%   output = MEXfile('parametervalues')    % returns vector with parameter values
+%   output = MEXfile(timevector)
+%   output = MEXfile(timevector, ICs)
+%   output = MEXfile(timevector, ICs, param)
+%   output = MEXfile(timevector, ICs, param, OPTIONS)
+%   
+%   INPUT ARGUMENTS TO 'MEXfile':
+%   timevector: simulation time vector
+%   ICs: full initial condition vector
+%   param: full parametervalue vector
+%   OPTIONS: structure with OPTIONS for the integrator
+%       OPTIONS.showIntegratorStats: =0 (off), =1 shows integrator
+%               statistics in the MATLAB console window
+%       OPTIONS.method:             'stiff' or 'nonstiff' (default: 'stiff')
+%       OPTIONS.abstol:             abs tolerance (default: 1e-6)
+%       OPTIONS.reltol:             rel tolerance (default: 1e-6)
+%       OPTIONS.minstep:            min step-size integrator (default: 0)
+%       OPTIONS.maxstep:            max step-size integrator (default: inf)
+%       OPTIONS.maxnumsteps:        max number of steps between two output
+%                                   points (default: 100000)
+%       OPTIONS.maxerrtestfails:    maximum number of error test failures
+%                                   permitted in attempting one step
+%                                   (default: 50)
+%       OPTIONS.maxorder:           maximum order of the linear multistep
+%                                   method (default: 5 BDF, 12 ADAMS)
+%       OPTIONS.maxconvfails:       maximum number of nonlinear solver convergence 
+%                                   failures permitted during one step
+%                                   (default: 10)
+%       OPTIONS.initstep:           initial step size to be attempted
+%                                   (default: 0)
+%       OPTIONS.maxnonlineariter:   maximum number of nonlinear solver
+%                                   iterations permitted per step 
+%                                   (default: 3)
+%       OPTIONS.xdotcalc: =0: do integration, =1: return RHS of ODEs for
+%                         given state and parameter values. Time information
+%                         is neglected and it is assumed that time=0.
+    
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+global MAX_NRPERROW 
+MAX_NRPERROW = 20;  % Max. number of elements per rows
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GENERATE DELAY BASE NAME
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+global delaycount delaybase
+delaycount = 0;
+[dummy,delaybase] = fileparts(tempname);
+delaybase = char([double('delaybase_') double(delaybase(1:8))]);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GENERATE interpcseIQM, etc. counters
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+global interpcseIQMcount interpcseSlopeIQMcount
+interpcseIQMcount = 0;
+interpcseSlopeIQMcount = 0;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK THE MODEL
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~strcmp('IQMmodel',class(model)),
+    error('Function only defined for IQMmodels.');
+end
+if ~isempty(IQMfunctionsMATLAB(model)),
+    error('Matlab functions present in model. Conversion to MEX simulation file not possible.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% ADD PIECEWISE TRIGGERS AS EVENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+model = addpiecewiseeventsIQM(model);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK IF DELAY PRESENT ... THEN ERROR
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if usedelayIQM(model),
+    error('The model contains delays. This is not supported for MEX file simulation.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET THE UNDERLYING MODEL STRUCTURE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+modelstruct = IQMstruct(model);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DEFAULT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+MEXfile = regexprep(modelstruct.name,'[\W]','');  % name of model as default MEX function name
+doNOTcompileFlag = 0;         % do compile per default
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% TAKE CAR OF VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin < 1 || nargin > 3,
+    error('Incorrect number of input arguments.');
+end
+if nargin == 2,
+    MEXfile = varargin{1};
+elseif nargin == 3,
+    MEXfile = varargin{1};
+    doNOTcompileFlag = varargin{2};
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE AN EVENTUAL FULL PATH (GET PATH AND THE NAME OF THE FUNCTION)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[MEXfunctionPath,MEXfunctionName] = fileparts(MEXfile);
+filenameH = fullfile(MEXfunctionPath,strcat(MEXfunctionName,'.h'));
+filenameC = fullfile(MEXfunctionPath,strcat(MEXfunctionName,'.c'));
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET THE MODELS ELEMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[staten,stateode,stateICs] = IQMstates(model);
+[parametern, parameterv] = IQMparameters(model);
+[variablen, variablef] = IQMvariables(model);
+[reactionn, reactionf] = IQMreactions(model);
+[functionn,functionf,functiona] = IQMfunctions(model);
+[eventn,eventt,eventv,eventf] = IQMevents(model);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET NUMBER OF THE MODELS ELEMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+NRSTATES = length(staten);
+NRPARAMETERS = length(parametern);
+NRVARIABLES = length(variablen);
+NRREACTIONS = length(reactionn);
+NRFUNCTIONS = length(functionn);
+NREVENTS = length(eventn);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EXCHANGE SPECIAL NAMES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Certain reserved element names might have to be exchanged. Example:
+% "default", which is an often used name for the root compartment in SBML,
+% but it is a reserved name in C.
+staten = exchangeNames(staten);
+parametern = exchangeNames(parametern); 
+variablen = exchangeNames(variablen);
+reactionn = exchangeNames(reactionn);
+functionn = exchangeNames(functionn);
+eventn = exchangeNames(eventn); 
+eventt = exchangeNames(eventt);
+for k=1:length(eventn),
+    eventv{k} = exchangeNames(eventv{k});
+end
+functiona = exchangeNames(functiona);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DEAL WITH THE FORMULAS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% For C the double representation needs to be made (1->1.0) ...
+% Furthermore, several other things need to be fixed.
+stateode = dealFormulas(stateode);
+variablef = dealFormulas(variablef); 
+reactionf = dealFormulas(reactionf); 
+functionf = dealFormulas(functionf); 
+eventt = dealFormulas(eventt);
+for k = 1:length(eventf),
+    eventf{k} = dealFormulas(eventf{k});
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% WRITE THE MODEL HEADER FILE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fid = fopen(filenameH,'w');
+fprintf(fid,'#include "mex.h"\n\n');
+fprintf(fid,'const int NRSTATES = %d;\n',NRSTATES);
+fprintf(fid,'const int NRPARAMETERS = %d;\n',NRPARAMETERS);
+fprintf(fid,'const int NRVARIABLES = %d;\n',NRVARIABLES);
+fprintf(fid,'const int NRREACTIONS = %d;\n',NRREACTIONS);
+fprintf(fid,'const int NREVENTS = %d;\n',NREVENTS);
+fprintf(fid,'\n');
+% add flag for numeric or non-numeric ICs
+if hasonlynumericICsIQM(model),
+    fprintf(fid,'const int hasOnlyNumericICs = 1;\n');
+    outputHeaderData(fid,'defaultICs_num',NRSTATES,stateICs)
+    fprintf(fid,'char *defaultICs_nonnum[1];\n');    
+else
+    fprintf(fid,'const int hasOnlyNumericICs = 0;\n');
+    fprintf(fid,'double defaultICs_num[1];\n');    
+    outputHeaderData(fid,'defaultICs_nonnum',NRSTATES,stateICs)
+end
+fprintf(fid,'\n');
+if isempty(parameterv), parameterv = []; end
+outputHeaderData(fid,'defaultParam',NRPARAMETERS,parameterv)
+outputHeaderData(fid,'stateNames',NRSTATES,staten)
+outputHeaderData(fid,'parameterNames',NRPARAMETERS,parametern)
+outputHeaderData(fid,'variableNames',NRVARIABLES,variablen)
+outputHeaderData(fid,'variableFormulas',NRVARIABLES,variablef)
+outputHeaderData(fid,'reactionNames',NRREACTIONS,reactionn)
+outputHeaderData(fid,'eventNames',NREVENTS,eventn)
+fprintf(fid,'\n');
+fprintf(fid,'void model(double time, double *stateVector, double *DDTvector, ParamData *paramdataPtr, int DOflag, double *variableVector, double *reactionVector, double *gout, int *eventVector);\n');
+fprintf(fid,'void calc_ic_model(double *icVector, ParamData *paramdataPtr);\n\n');
+fprintf(fid,'void CVODEmex25(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]);\n');
+fprintf(fid,'void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])\n');
+fprintf(fid,'{\n    CVODEmex25(nlhs, plhs, nrhs, prhs);\n}\n');
+fclose(fid);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% WRITE THE MODEL C FILE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fid = fopen(filenameC,'w');
+fprintf(fid,'#include "stddef.h"\n');
+fprintf(fid,'#include "stdarg.h"\n');
+fprintf(fid,'#include "math.h"\n');
+fprintf(fid,'#include "CVODEmex25.h"\n');
+fprintf(fid,'#include "%s"\n',strcat(MEXfunctionName,'.h'));
+fprintf(fid,'#include "mexsplineaddon.h"\n');
+fprintf(fid,'#include "mexmathaddon.h"\n');
+fprintf(fid,'#include "kineticformulas.h"\n\n');
+fprintf(fid,'double time;\n\n');
+% First define the functions
+for k = 1:NRFUNCTIONS,
+    % write declaration
+    fprintf(fid,'static double %s(',functionn{k});
+    % write arguments
+    arguments = explodePCIQM(functiona{k},','); for k2 = 1:length(arguments), if k2 < length(arguments), fprintf(fid,'double %s,',arguments{k2}); else fprintf(fid,'double %s)\n',arguments{k2}); end; end
+    % write forumla and return
+    fprintf(fid,'{\n'); fprintf(fid,'    return %s;\n',functionf{k}); fprintf(fid,'}\n'); fprintf(fid,'\n');
+end
+% Define the model function
+fprintf(fid,'void model(double time_local, double *stateVector, double *DDTvector, ParamData *paramdataPtr, int DOflag, double *variableVector, double *reactionVector, double *gout, int *eventVector)\n');
+fprintf(fid,'{\n');
+outputDeclarationData(fid,NRSTATES,staten)
+outputDeclarationData(fid,NRPARAMETERS,parametern)
+outputDeclarationData(fid,NRVARIABLES,variablen)
+outputDeclarationData(fid,NRREACTIONS,reactionn)
+eventassignn = {};
+for k=1:NREVENTS,
+    eventassignformulak = eventf{k};
+    for k2=1:length(eventassignformulak),
+        eventassignn{end+1} = sprintf('eventassign_%d_%d',k,k2);
+    end
+end
+outputDeclarationData(fid,length(eventassignn),eventassignn)
+fprintf(fid,'\n');
+fprintf(fid,'    time = time_local;\n');
+fprintf(fid,'\n');
+for k=1:NRSTATES, fprintf(fid,'    %s = stateVector[%d];\n',staten{k},k-1); end
+for k=1:NRPARAMETERS, fprintf(fid,'    %s = paramdataPtr->parametervector[%d]; /* %g */\n',parametern{k},k-1,parameterv(k)); end
+%for k=1:NRVARIABLES, fprintf(fid,'    %s = %s;\n',variablen{k},variablef{k}); end
+%for k=1:NRREACTIONS, fprintf(fid,'    %s = %s;\n',reactionn{k},reactionf{k}); end
+for k=1:NRVARIABLES, writeOutFormulasConvertPiecewise(fid,variablen{k},variablef{k},sprintf('\t')); end
+for k=1:NRREACTIONS, writeOutFormulasConvertPiecewise(fid,reactionn{k},reactionf{k},sprintf('\t')); end
+for k=1:NREVENTS,
+    eventassignformulak = eventf{k};
+    for k2=1:length(eventassignformulak),
+        namevar = sprintf('eventassign_%d_%d',k,k2);
+        fprintf(fid,'    %s = %s;\n',namevar,eventassignformulak{k2}); 
+    end
+end
+fprintf(fid,'    if (DOflag == DOFLAG_DDT) {\n');
+%for k=1:NRSTATES, fprintf(fid,'        DDTvector[%d] = %s;\n',k-1,stateode{k}); end
+for k=1:NRSTATES, writeOutFormulasConvertPiecewise(fid,sprintf('\tDDTvector[%d]',k-1),stateode{k},sprintf('\t\t')); end
+fprintf(fid,'    } else if (DOflag == DOFLAG_VARREAC) {\n');
+for k=1:NRVARIABLES, fprintf(fid,'        variableVector[%d] = %s;\n',k-1,variablen{k}); end
+for k=1:NRREACTIONS, fprintf(fid,'        reactionVector[%d] = %s;\n',k-1,reactionn{k}); end
+fprintf(fid,'    } else if (DOflag == DOFLAG_EVENTS) {\n');
+for k = 1:NREVENTS,
+    tExpr = getTriggerExpression(eventt{k});
+    fprintf(fid,'        gout[%d] = %s;\n',k-1,tExpr);
+end
+fprintf(fid,'    } else if (DOflag == DOFLAG_EVENTASSIGN) {\n');
+for k = 1:NREVENTS,
+    fprintf(fid,'        if (eventVector[%d] == 1 && gout[%d] < 0) {\n',k-1,k-1);
+    fprintf(fid,'            DDTvector[0] = 1;\n');
+    vars = eventv{k};
+    for k2 = 1:length(vars),
+        index = strmatchIQM(vars{k2},staten,'exact')-1;
+        if ~isempty(index),
+            fprintf(fid,'            stateVector[%d] = eventassign_%d_%d;\n',index,k,k2);
+        end
+        index = strmatchIQM(vars{k2},parametern,'exact')-1;
+        if ~isempty(index),
+            fprintf(fid,'            paramdataPtr->parametervector[%d] = eventassign_%d_%d;\n',index,k,k2);
+        end
+    end
+    fprintf(fid,'        }\n');
+end
+fprintf(fid,'    }\n');
+fprintf(fid,'}\n');
+fprintf(fid,'\n');
+fprintf(fid,'\n');
+fprintf(fid,'/* Function for initial condition calculation */\n');
+fprintf(fid,'void calc_ic_model(double *icVector, ParamData *paramdataPtr)\n');
+fprintf(fid,'{\n');
+outputDeclarationData(fid,NRSTATES,staten)
+outputDeclarationData(fid,NRPARAMETERS,parametern)
+outputDeclarationData(fid,NRVARIABLES,variablen)
+% Parameters
+for k=1:NRPARAMETERS, fprintf(fid,'    %s = paramdataPtr->parametervector[%d]; /* %g */\n',parametern{k},k-1,parameterv(k)); end
+% Variables
+for k=1:NRVARIABLES, fprintf(fid,'    %s = %s;\n',variablen{k},variablef{k}); end
+modelics = IQMinitialconditions(model);
+for k = 1:NRSTATES,
+    if hasonlynumericICsIQM(model),
+        value = modelics(k);
+    else
+        value = modelics{k};
+    end
+    if isnumeric(value),
+        value = sprintf('%g',value);
+    end
+    stateIC = dealFormulas({value});
+    fprintf(fid,'    %s = %s;\n',staten{k},stateIC{1});
+end
+for k = 1:NRSTATES,
+    fprintf(fid,'    icVector[%d] = %s;\n',k-1,staten{k});
+end
+fprintf(fid,'}\n');
+fprintf(fid,'\n');
+fclose(fid);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% COMPILE THE MEX MODEL
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~doNOTcompileFlag,
+    mexcompileIQM(MEXfunctionName);
+    delete(filenameC);
+    delete(filenameH);
+end
+
+clear delaycount delaybase interpcseIQMcount interpcseSlopeIQMcount
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% WRITING OUT FORMULAS AND REPLACING PIECEWISEIQM BY IF THEN ELSE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [] = writeOutFormulasConvertPiecewise(fid,lhs,rhs,pretext)
+% check if rhs starts with a piecewiseIQM expression
+rhs = strtrim(rhs);
+% Search for both the normal and the T0 type of piecewise expressions
+index1 = strfind(rhs,'piecewiseIQM(');
+index2 = strfind(rhs,'piecewiseT0IQM(');
+index = [index1(:)', index2(:)'];
+if isempty(index),
+    % not a piecewise expression
+    fprintf(fid,'    %s = %s;\n',lhs,rhs); 
+    return
+elseif length(index) > 1,
+    % more than one piecewise expression
+    fprintf(fid,'    %s = %s;\n',lhs,rhs); 
+    return
+elseif index ~= 1,
+    % does not start with a piecewise expression
+    fprintf(fid,'    %s = %s;\n',lhs,rhs); 
+    return
+end
+% At this point the rhs has a single piecewiseIQM or piecewiseT0IQM expression and starts with
+% it. We only need to check if after the piecewiseIQM expression there are
+% other components in the rhs.
+parOpen = 1;
+if ~isempty(index1),
+    indexStart = length('piecewiseIQM(')+1; 
+else
+    indexStart = length('piecewiseT0IQM(')+1; 
+end    
+indexEnd   = indexStart;
+while parOpen ~= 0,
+    indexEnd = indexEnd + 1;
+    if rhs(indexEnd) == '(',
+        parOpen = parOpen + 1;
+    elseif rhs(indexEnd) == ')',
+        parOpen = parOpen - 1;
+    end
+end
+if ~isempty(rhs(indexEnd+1:end)),
+    % piecewiseIQM expression is not the single component on the RHS => not if then else
+    fprintf(fid,'    %s = %s;\n',lhs,rhs); 
+    return
+end
+% Finally we are left with only the rhs which only contain a single piecewise expression
+% that easily can be represented in terms of if else if else if else ...
+% Get only the arguments as comma separated list
+arguments = rhs(indexStart:indexEnd-1);
+% Explode to get the terms
+terms = explodePCIQM(arguments);
+% First term gives the number of arguments. Needs to be an odd number,
+% because otherwise the default value is missing and this is not good :)
+% We still do not use the number ... since the length-1 gives the same
+% result.
+n = length(terms)-1;
+% Check if n is odd 
+if 2*round(n/2) == n,
+    error('All piecewise expressions need an odd number of arguments to specify also a default value.');
+end
+% Construct the if statement and write it out
+terms = terms(2:end);
+for k=2:2:n-1,
+    if k==2,
+        fprintf(fid,'%sif (%s) {\n',pretext,terms{k});
+    else
+        fprintf(fid,'%s} else if (%s) {\n',pretext,terms{k});
+    end
+    fprintf(fid,'%s\t%s = %s;\n',pretext,lhs,terms{k-1});
+end
+fprintf(fid,'%s} else {\n',pretext);
+fprintf(fid,'%s\t%s = %s;\n%s}\n',pretext,lhs,terms{n},pretext);
+return
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DETERMINE THE TRIGGER EXPRESSION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [tExpr] = getTriggerExpression(data)
+tExpr = sprintf('%s-0.5',data);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% OUTPUT HEADER DATA
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [] = outputHeaderData(fid,name,NR,data)
+global MAX_NRPERROW 
+if NR == 0,
+    if iscell(data),
+        fprintf(fid,'char *%s[1];\n',name);
+    else
+        fprintf(fid,'double %s[1];\n',name);
+    end
+else
+    if iscell(data),
+        fprintf(fid,'char *%s[%d] = {\n\t',name,NR);
+    else
+        fprintf(fid,'double %s[%d] = {\n\t',name,NR);
+    end        
+    nrperrow = 0;
+    for k=1:NR,
+        if nrperrow == MAX_NRPERROW, fprintf(fid,'\n\t'); nrperrow = 0; end
+        if iscell(data),   
+            if ~isnumeric(data{k}),
+                if k<NR, fprintf(fid,'"%s",',data{k}); else fprintf(fid,'"%s"',data{k}); end
+            else
+                % handling numeric entries in cell-arrays: happening if
+                % non-numeric ICs
+                if k<NR, fprintf(fid,'"%g",',data{k}); else fprintf(fid,'"%g"',data{k}); end
+            end
+        else
+            if k<NR, fprintf(fid,'%g,',data(k)); else fprintf(fid,'%g',data(k)); end
+        end
+        nrperrow = nrperrow + 1;
+    end
+    fprintf(fid,'};\n');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% OUTPUT DECLARATION DATA
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [] = outputDeclarationData(fid,NR,data)
+global MAX_NRPERROW 
+nrperrow = 0;
+for k=1:NR,
+    if nrperrow==0, fprintf(fid,'    double '); end
+    if k<NR && nrperrow<MAX_NRPERROW-1, fprintf(fid,'%s,',data{k}); else fprintf(fid,'%s',data{k}); end
+    nrperrow = nrperrow + 1;
+    if nrperrow == MAX_NRPERROW, fprintf(fid,';\n'); nrperrow = 0; end
+end
+if nrperrow ~= 0, fprintf(fid,';\n'); end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EXCHANGE THE NAMES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [names] = exchangeNames(names)
+if isempty(names), return; end
+% do not allow "default" being used as component name!!!
+if ~isempty(strmatchIQM('default',names,'exact')),
+    error(sprintf('The name "default" is not allowed to be used in an IQMmodel when you want\nto create MEX simulation functions. The reason is that "default" is a reserved\n"C" word. Of course this is the case also for all other reserved "C" words.\nPlease rename the "default" component in your model with another name!\n'));
+end
+oldText = {}; 
+newText = {};
+names = regexprep(names,oldText,newText);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE INTERP1IQM (LOOKUP TABLE W/ LINEAR INTERPOLATION)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [textnew] = exchangeInterp1IQM(text)
+textnew = text;
+indexstart = strfind(text,'interp1IQM(')+length('interp1IQM(');
+if length(indexstart) > 1,
+    error('The ''interp1IQM'' function is only allowed to be present once in each formula.');
+end
+if ~isempty(indexstart),
+    % interp1IQM found ... handle it
+    % cut out the content using the parentheses
+    % Get the end index of the k-th statement (closing parentheses
+    % belonging to the opening)
+    % count parentheses
+    pc = 1;
+    cstart = indexstart;
+    cend = cstart;
+    while pc ~= 0,
+        cend = cend + 1;
+        if textnew(cend) == '(',
+            pc = pc+1;
+        elseif textnew(cend) == ')',
+            pc = pc-1;
+        end
+    end
+    indexend = cend-1;
+    indexafter = indexend+1;
+    % indexstart/indexend identify the content in the parentheses to be
+    % processed and replaced
+    textinside = textnew(indexstart:indexend);
+    terms = explodePCIQM(textinside,',',{'(','['},{')',']'});
+    % fine so far. We need now to make sure that the elements in the
+    % vectors are separated using commata (otherwise big problem)!
+    xtermstring = terms{1};
+    ytermstring = terms{2};
+    % remove parentheses
+    xtermstring = xtermstring(2:end-1);
+    ytermstring = ytermstring(2:end-1);
+    % get single elements
+    xtermelements = explodePCIQM(xtermstring);
+    ytermelements = explodePCIQM(ytermstring);
+    if length(xtermelements) == 1,
+        error(sprintf('The elements of the lookup table using the interp1IQM function need to be separated by commata!\nAre you sure you have done that correctly?'));
+    end
+    if length(xtermelements) ~= length(ytermelements),
+        error('x and y arguments for interp1IQM function do not have same number of elements.');
+    end
+    pwText = sprintf('%s,lt(%s,%s),',ytermelements{1},terms{3},xtermelements{1});
+    for k=1:length(xtermelements)-1,
+        pwText = sprintf('%s(%s-(%s))/(%s-(%s))*(%s-(%s))+(%s)',pwText,ytermelements{k+1},ytermelements{k},xtermelements{k+1},xtermelements{k},terms{3},xtermelements{k},ytermelements{k});
+        if k<length(xtermelements)-1,
+            pwText = sprintf('%s,andIQM(lt(%s,%s),ge(%s,%s)),',pwText,terms{3},xtermelements{k+1},terms{3},xtermelements{k});
+        end
+    end
+    pwText = sprintf('%s,andIQM(lt(%s,%s),ge(%s,%s)),%s',pwText,terms{3},xtermelements{end},terms{3},xtermelements{end-1},ytermelements{end});
+    textnew = [text(1:indexstart-1) pwText text(indexend+1:end)];
+    textnew = strrep(textnew,'interp1IQM','piecewiseIQM');
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE INTERP0IQM (LOOKUP TABLE W/ ZERO-ORDER INTERPOLATION)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [textnew] = exchangeInterp0IQM(text)
+textnew = text;
+indexstart = strfind(text,'interp0IQM(')+length('interp0IQM(');
+if length(indexstart) > 1,
+    error('The ''interp0IQM'' function is only allowed to be present once in each formula.');
+end
+if ~isempty(indexstart),
+    % interp0IQM found ... handle it
+    % cut out the content using the parentheses
+    % Get the end index of the k-th statement (closing parentheses
+    % belonging to the opening)
+    % count parentheses
+    pc = 1;
+    cstart = indexstart;
+    cend = cstart;
+    while pc ~= 0,
+        cend = cend + 1;
+        if textnew(cend) == '(',
+            pc = pc+1;
+        elseif textnew(cend) == ')',
+            pc = pc-1;
+        end
+    end
+    indexend = cend-1;
+    indexafter = indexend+1;
+    % indexstart/indexend identify the content in the parentheses to be
+    % processed and replaced
+    textinside = textnew(indexstart:indexend);
+    terms = explodePCIQM(textinside,',',{'(','['},{')',']'});
+    % fine so far. We need now to make sure that the elements in the
+    % vectors are separated using commata (otherwise big problem)!
+    xtermstring = terms{1};
+    ytermstring = terms{2};
+    % remove parentheses
+    xtermstring = xtermstring(2:end-1);
+    ytermstring = ytermstring(2:end-1);
+    % get single elements
+    xtermelements = explodePCIQM(xtermstring);
+    ytermelements = explodePCIQM(ytermstring);
+    if length(xtermelements) == 1,
+        error(sprintf('The elements of the lookup table using the interp0IQM function need to be separated by commata!\nAre you sure you have done that correctly?'));
+    end
+    if length(xtermelements) == 2,
+        error('The interp0IQM function requires at least 3 points on the x and y axis.');
+    end
+    if length(xtermelements) ~= length(ytermelements),
+        error('x and y arguments for interp0IQM function do not have same number of elements.');
+    end
+    pwText = sprintf('%s,lt(%s,%s),',ytermelements{1},terms{3},xtermelements{2});
+    for k=2:length(xtermelements)-1,
+        pwText = sprintf('%s(%s)',pwText,ytermelements{k});
+        if k<length(xtermelements)-1,
+            pwText = sprintf('%s,andIQM(lt(%s,%s),ge(%s,%s)),',pwText,terms{3},xtermelements{k+1},terms{3},xtermelements{k});
+        end
+    end
+    pwText = sprintf('%s,andIQM(lt(%s,%s),ge(%s,%s)),%s',pwText,terms{3},xtermelements{end},terms{3},xtermelements{end-1},ytermelements{end});
+    textnew = [text(1:indexstart-1) pwText text(indexend+1:end)];
+    textnew = strrep(textnew,'interp0IQM','piecewiseIQM');
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE INTERPCSIQM (LOOKUP TABLE W/ CUBIC SPLINE INTERPOLATION)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [textnew] = exchangeInterpcsIQM(text)
+textnew = text;
+indexbefore = strfind(text,'interpcsIQM(');
+indexstart = indexbefore+length('interpcsIQM(');
+if length(indexstart) > 1,
+    error('The ''interpcsIQM'' function is only allowed to be present once in each formula.');
+end
+if ~isempty(indexstart),
+    % interpcsIQM found ... handle it
+    % cut out the content using the parentheses
+    % Get the end index of the k-th statement (closing parentheses
+    % belonging to the opening)
+    % count parentheses
+    pc = 1;
+    cstart = indexstart;
+    cend = cstart;
+    while pc ~= 0,
+        cend = cend + 1;
+        if textnew(cend) == '(',
+            pc = pc+1;
+        elseif textnew(cend) == ')',
+            pc = pc-1;
+        end
+    end
+    indexend = cend-1;
+    indexafter = indexend+1;
+    % indexstart/indexend identify the content in the parentheses to be
+    % processed and replaced
+    textinside = textnew(indexstart:indexend);
+    terms = explodePCIQM(textinside,',',{'(','['},{')',']'});
+    if length(terms) ~= 3, 
+        error('interpcsIQM function has wrong number of input arguments.');
+    end
+    % fine so far. We need now to make sure that the elements in the
+    % vectors are separated using commata (otherwise big problem)!
+    xtermstring = terms{1};
+    ytermstring = terms{2};
+    % remove parentheses
+    xtermstring = xtermstring(2:end-1);
+    ytermstring = ytermstring(2:end-1);
+    % get single elements
+    xtermelements = explodePCIQM(xtermstring);
+    ytermelements = explodePCIQM(ytermstring);
+    if length(xtermelements) == 1,
+        error(sprintf('The elements of the lookup table using the interpcsIQM function need to be separated by commata!\nAre you sure you have done that correctly?'));
+    end
+    if length(xtermelements) ~= length(ytermelements),
+        error('x and y arguments for interpcsIQM function do not have same number of elements.');
+    end
+    newexpr = sprintf('%d,%s',length(xtermelements),terms{3});
+    newexpr = strcat('interpcsIQM(',newexpr,',',xtermstring,',',ytermstring,')');
+    textnew = strcat(text(1:indexbefore-1),newexpr,text(indexend+2:end));
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE INTERPCSeIQM (LOOKUP TABLE W/ CUBIC SPLINE INTERPOLATION and
+% possible endpoint-slope definition
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [textnew] = exchangeInterpcseIQM(text)
+global interpcseIQMcount
+
+% Determine the number of required replacements (number of interpcseIQM functions)
+nrRep = length(strfind(text,'interpcseIQM('));
+% Create new text string from input string
+textnew = text;
+
+% Replace on after the other expression sequentially
+% if interpcseIQM not present then nothing is done ... simple
+for k=1:nrRep,
+    % Find start of interpcseIQM in modified string
+    indexbefore = strfind(textnew,'interpcseIQM(');
+    % Get the start index for modification for the k-th modification
+    indexbefore = indexbefore(k);
+    indexstart = indexbefore+length('interpcseIQM(');
+    % Get the end index of the k-th statement (closing parentheses
+    % belonging to the opening)
+    % count parentheses
+    pc = 1;
+    cstart = indexstart;
+    cend = cstart;
+    while pc ~= 0,
+        cend = cend + 1;
+        if textnew(cend) == '(',
+            pc = pc+1;
+        elseif textnew(cend) == ')',
+            pc = pc-1;
+        end
+    end
+    indexend = cend-1;
+    indexafter = indexend+1;
+    % indexstart/indexend identify the content in the parentheses to be
+    % processed and replaced
+    textinside = textnew(indexstart:indexend);
+    terms = explodePCIQM(textinside,',',{'(','['},{')',']'});
+    nterms = length(terms);
+    if nterms ~= 3 && nterms ~= 5, 
+        error('interpcseIQM function has wrong number of input arguments.');
+    end
+    % fine so far. We need now to make sure that the elements in the
+    % vectors are separated using commata (otherwise big problem)!
+    xtermstring = terms{1};
+    ytermstring = terms{2};
+    % remove parentheses
+    xtermstring = xtermstring(2:end-1);
+    ytermstring = ytermstring(2:end-1);
+    % get single elements
+    xtermelements = explodePCIQM(xtermstring);
+    ytermelements = explodePCIQM(ytermstring);
+    if length(xtermelements) == 1,
+        error(sprintf('The elements of the lookup table using the interpcseIQM function need to be separated by commata!\nAre you sure you have done that correctly?'));
+    end
+    if length(xtermelements) ~= length(ytermelements),
+        error('x and y arguments for interpcseIQM function do not have same number of elements.');
+    end
+    % construct the text to replace with
+    if nterms == 3,
+        reptextnew = [sprintf('interpcseIQM(%d,%d',interpcseIQMcount,length(xtermelements)),',',terms{3} ',',xtermstring,',',ytermstring,')'];
+    else
+        reptextnew = [sprintf('interpcseIQM(%d,%d',interpcseIQMcount,length(xtermelements)),',',terms{3},',',terms{4},',',terms{5} ',',xtermstring,',',ytermstring,')'];
+    end
+    % get the text to replace
+    reptextold = textnew(indexbefore:indexafter);
+    % do a simple strrep operation
+    textnew = strrep(textnew,reptextold,reptextnew);
+    % increment the interpcseIQM counter
+    interpcseIQMcount = interpcseIQMcount + 1;
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE INTERPCSeSlopeIQM (LOOKUP TABLE W/ CUBIC SPLINE INTERPOLATION and
+% possible endpoint-slope definition - DERIVATIVE)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [textnew] = exchangeInterpcseSlopeIQM(text)
+global interpcseSlopeIQMcount
+
+% Determine the number of required replacements (number of interpcseSlopeIQM functions)
+nrRep = length(strfind(text,'interpcseSlopeIQM('));
+% Create new text string from input string
+textnew = text;
+
+% Replace on after the other expression sequentially
+% if interpcseSlopeIQM not present then nothing is done ... simple
+for k=1:nrRep,
+    % Find start of interpcseSlopeIQM in modified string
+    indexbefore = strfind(textnew,'interpcseSlopeIQM(');
+    % Get the start index for modification for the k-th modification
+    indexbefore = indexbefore(k);
+    indexstart = indexbefore+length('interpcseSlopeIQM(');
+    % Get the end index of the k-th statement (closing parentheses
+    % belonging to the opening)
+    % count parentheses
+    pc = 1;
+    cstart = indexstart;
+    cend = cstart;
+    while pc ~= 0,
+        cend = cend + 1;
+        if textnew(cend) == '(',
+            pc = pc+1;
+        elseif textnew(cend) == ')',
+            pc = pc-1;
+        end
+    end
+    indexend = cend-1;
+    indexafter = indexend+1;
+    % indexstart/indexend identify the content in the parentheses to be
+    % processed and replaced
+    textinside = textnew(indexstart:indexend);
+    terms = explodePCIQM(textinside,',',{'(','['},{')',']'});
+    nterms = length(terms);
+    if nterms ~= 3 && nterms ~= 5, 
+        error('interpcseSlopeIQM function has wrong number of input arguments.');
+    end
+    % fine so far. We need now to make sure that the elements in the
+    % vectors are separated using commata (otherwise big problem)!
+    xtermstring = terms{1};
+    ytermstring = terms{2};
+    % remove parentheses
+    xtermstring = xtermstring(2:end-1);
+    ytermstring = ytermstring(2:end-1);
+    % get single elements
+    xtermelements = explodePCIQM(xtermstring);
+    ytermelements = explodePCIQM(ytermstring);
+    if length(xtermelements) == 1,
+        error(sprintf('The elements of the lookup table using the interpcseSlopeIQM function need to be separated by commata!\nAre you sure you have done that correctly?'));
+    end
+    if length(xtermelements) ~= length(ytermelements),
+        error('x and y arguments for interpcseSlopeIQM function do not have same number of elements.');
+    end
+    % construct the text to replace with
+    if nterms == 3,
+        reptextnew = [sprintf('interpcseSlopeIQM(%d,%d',interpcseSlopeIQMcount,length(xtermelements)),',',terms{3} ',',xtermstring,',',ytermstring,')'];
+    else
+        reptextnew = [sprintf('interpcseSlopeIQM(%d,%d',interpcseSlopeIQMcount,length(xtermelements)),',',terms{3},',',terms{4},',',terms{5} ',',xtermstring,',',ytermstring,')'];
+    end
+    % get the text to replace
+    reptextold = textnew(indexbefore:indexafter);
+    % do a simple strrep operation
+    textnew = strrep(textnew,reptextold,reptextnew);
+    % increment the interpcseSlopeIQM counter
+    interpcseSlopeIQMcount = interpcseSlopeIQMcount + 1;
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE INTERPCSexIQM (LOOKUP TABLE W/ CUBIC SPLINE INTERPOLATION and
+% possible endpoint-slope definition
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [textnew] = exchangeInterpcsexIQM(text)
+% Determine the number of required replacements (number of interpcsexIQM functions)
+nrRep = length(strfind(text,'interpcsexIQM('));
+% Create new text string from input string
+textnew = text;
+
+% Replace on after the other expression sequentially
+% if interpcsexIQM not present then nothing is done ... simple
+for k=1:nrRep,
+    % Find start of interpcseIQM in modified string
+    indexbefore = strfind(textnew,'interpcsexIQM(');
+    % Get the start index for modification for the k-th modification
+    indexbefore = indexbefore(k);
+    indexstart = indexbefore+length('interpcsexIQM(');
+    % Get the end index of the k-th statement (closing parentheses
+    % belonging to the opening)
+    % count parentheses
+    pc = 1;
+    cstart = indexstart;
+    cend = cstart;
+    while pc ~= 0,
+        cend = cend + 1;
+        if textnew(cend) == '(',
+            pc = pc+1;
+        elseif textnew(cend) == ')',
+            pc = pc-1;
+        end
+    end
+    indexend = cend-1;
+    indexafter = indexend+1;
+    % indexstart/indexend identify the content in the parentheses to be
+    % processed and replaced
+    textinside = textnew(indexstart:indexend);
+    terms = explodePCIQM(textinside,',',{'(','['},{')',']'});
+    nterms = length(terms);
+    if nterms ~= 3 && nterms ~= 5, 
+        error('interpcsexIQM function has wrong number of input arguments.');
+    end
+    % fine so far. We need now to make sure that the elements in the
+    % vectors are separated using commata (otherwise big problem)!
+    xtermstring = terms{1};
+    ytermstring = terms{2};
+    % remove parentheses
+    xtermstring = xtermstring(2:end-1);
+    ytermstring = ytermstring(2:end-1);
+    % get single elements
+    xtermelements = explodePCIQM(xtermstring);
+    ytermelements = explodePCIQM(ytermstring);
+    if length(xtermelements) == 1,
+        error(sprintf('The elements of the lookup table using the interpcsexIQM function need to be separated by commata!\nAre you sure you have done that correctly?'));
+    end
+    if length(xtermelements) ~= length(ytermelements),
+        error('x and y arguments for interpcsexIQM function do not have same number of elements.');
+    end
+    % construct the text to replace with
+    if nterms == 3,
+        reptextnew = [sprintf('interpcsexIQM(%d',length(xtermelements)) ',',xtermstring,',',ytermstring,',',terms{3},')'];
+    else
+        reptextnew = [sprintf('interpcsexIQM(%d',length(xtermelements)),',',terms{4},',',terms{5} ',',xtermstring,',',ytermstring,',',terms{3},')'];
+    end
+    % get the text to replace
+    reptextold = textnew(indexbefore:indexafter);
+    % do a simple strrep operation
+    textnew = strrep(textnew,reptextold,reptextnew);
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE INTERPCSexIQM (LOOKUP TABLE W/ CUBIC SPLINE INTERPOLATION and
+% possible endpoint-slope definition
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [textnew] = exchangeInterpcsexSlopeIQM(text)
+% Determine the number of required replacements (number of interpcsexSlopeIQM functions)
+nrRep = length(strfind(text,'interpcsexSlopeIQM('));
+% Create new text string from input string
+textnew = text;
+
+% Replace on after the other expression sequentially
+% if interpcsexSlopeIQM not present then nothing is done ... simple
+for k=1:nrRep,
+    % Find start of interpcsexSlopeIQM in modified string
+    indexbefore = strfind(textnew,'interpcsexSlopeIQM(');
+    % Get the start index for modification for the k-th modification
+    indexbefore = indexbefore(k);
+    indexstart = indexbefore+length('interpcsexSlopeIQM(');
+    % Get the end index of the k-th statement (closing parentheses
+    % belonging to the opening)
+    % count parentheses
+    pc = 1;
+    cstart = indexstart;
+    cend = cstart;
+    while pc ~= 0,
+        cend = cend + 1;
+        if textnew(cend) == '(',
+            pc = pc+1;
+        elseif textnew(cend) == ')',
+            pc = pc-1;
+        end
+    end
+    indexend = cend-1;
+    indexafter = indexend+1;
+    % indexstart/indexend identify the content in the parentheses to be
+    % processed and replaced
+    textinside = textnew(indexstart:indexend);
+    terms = explodePCIQM(textinside,',',{'(','['},{')',']'});
+    nterms = length(terms);
+    if nterms ~= 3 && nterms ~= 5, 
+        error('interpcsexSlopeIQM function has wrong number of input arguments.');
+    end
+    % fine so far. We need now to make sure that the elements in the
+    % vectors are separated using commata (otherwise big problem)!
+    xtermstring = terms{1};
+    ytermstring = terms{2};
+    % remove parentheses
+    xtermstring = xtermstring(2:end-1);
+    ytermstring = ytermstring(2:end-1);
+    % get single elements
+    xtermelements = explodePCIQM(xtermstring);
+    ytermelements = explodePCIQM(ytermstring);
+    if length(xtermelements) == 1,
+        error(sprintf('The elements of the lookup table using the interpcsexSlopeIQM function need to be separated by commata!\nAre you sure you have done that correctly?'));
+    end
+    if length(xtermelements) ~= length(ytermelements),
+        error('x and y arguments for interpcsexSlopeIQM function do not have same number of elements.');
+    end
+    % construct the text to replace with
+    if nterms == 3,
+        reptextnew = [sprintf('interpcsexSlopeIQM(%d',length(xtermelements)) ',',xtermstring,',',ytermstring,',',terms{3},')'];
+    else
+        reptextnew = [sprintf('interpcsexSlopeIQM(%d',length(xtermelements)),',',terms{4},',',terms{5} ',',xtermstring,',',ytermstring,',',terms{3},')'];
+    end
+    % get the text to replace
+    reptextold = textnew(indexbefore:indexafter);
+    % do a simple strrep operation
+    textnew = strrep(textnew,reptextold,reptextnew);
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DEAL WITH THE FORMULAS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [newformulaArray] = dealFormulas(formulaArray)
+if isempty(formulaArray),
+    newformulaArray = formulaArray;
+    return
+end
+
+% replace names first (and we do it once more after the handling of the
+% formulas ... at least for power that is necessary)
+oldElements = {'\<nthroot\>','\<and\>','\<or\>','\<power\>','\<abs\>'};
+newElements = {'nthrootIQM','andIQM','orIQM','pow','absIQM'};
+formulaArray = regexprep(formulaArray,oldElements,newElements);
+
+% handle calls with variable number of input arguments (these get the
+% number of input arguments as first (additional) argument).
+checkElements = {'\<indexmaxIQM\>','\<minIQM\>','\<maxIQM\>','\<andIQM\>','\<orIQM\>','\<piecewiseIQM\>','\<interpcsIQM\>','\<interpcseIQM\>','\<interpcsexIQM\>','\<piecewiseT0IQM\>','\<interpcseSlopeIQM\>','\<interpcsexSlopeIQM\>'};
+for k0=1:length(formulaArray),
+    formula = formulaArray{k0};
+    % handle interp1IQM -> piecewiseIQM
+    formula = exchangeInterp1IQM(formula);
+    % handle interp0IQM -> piecewiseIQM
+    formula = exchangeInterp0IQM(formula);
+    % handle interpcsIQM: changing the syntax
+    formula = exchangeInterpcsIQM(formula);
+    % handle interpcseIQM: changing the syntax
+    formula = exchangeInterpcseIQM(formula);
+    % handle interpcseSlopeIQM: changing the syntax
+    formula = exchangeInterpcseSlopeIQM(formula);
+    % handle interpcsexIQM: changing the syntax
+    formula = exchangeInterpcsexIQM(formula);
+    % handle interpcsexSlopeIQM: changing the syntax
+    formula = exchangeInterpcsexSlopeIQM(formula);
+    % handle the power operator
+    formula = convertPowerOperator(formula);
+    % handle delay operator
+%    [formula] = processDelayCallIQM(formula);
+    % fix the c notation of doubles
+    formula = regexprep(formula,'((?<!\d*[eE][-+])(?<!\.)\<\d*\>(?!\.))','$1.0');
+    % delete "." at end
+    formula = regexprep(formula,'([\w])+[.]{1}([\W])','$1$2');
+    formula = regexprep(formula,'([\W])+[.]{1}([\W])','$1$2');
+    % Add number of variable input arguments to function calls as first
+    % input argument (for the functions, defined above)
+    % Add number of variable input arguments to function calls as first
+    % input argument (for the functions, defined above)
+    for k1=1:length(checkElements),
+        index = regexp(formula,checkElements{k1});
+        if ~isempty(index),
+            for k2 = 1:length(index),
+                indexStart = index(k2)+length(checkElements{k1})-4;
+                indexEnd = indexStart;
+                parOpen = 1;
+                while parOpen ~= 0,
+                    indexEnd = indexEnd + 1;
+                    if formula(indexEnd) == '(',
+                        parOpen = parOpen + 1;
+                    elseif formula(indexEnd) == ')',
+                        parOpen = parOpen - 1;
+                    end
+                end
+                oldarguments = formula(indexStart+1:indexEnd-1);
+                newargstring = sprintf('%d,%s',length(explodePCIQM(oldarguments,',')),oldarguments);
+                command = checkElements{k1};
+                oldrep  = [command(3:end-2) '(' oldarguments ')'];
+                newrep = [command(3:end-2) '(' newargstring ')'];
+                formula = strrep(formula,oldrep,newrep);
+                index = index + length(newargstring)-length(oldarguments);
+            end
+        end
+    end
+    formulaArray{k0} = formula;
+end
+
+% replace names again
+oldElements = {'\<nthroot\>','\<and\>','\<or\>','\<power\>','\<abs\>'};
+newElements = {'nthrootIQM','andIQM','orIQM','pow','absIQM'};
+formulaArray = regexprep(formulaArray,oldElements,newElements);
+
+% ready
+newformulaArray = formulaArray;
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE THE POWER OPERATOR
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [formula] = convertPowerOperator(formula)
+% remove whitespaces from formula
+formula = regexprep(formula,'\s','');
+% first fix the simple problem
+formula = regexprep(formula,'([\w]+[.]?[\w]*)\^([\w]+[.]?[\w]*)','power($1,$2)');
+% then do the more complicated stuff
+indices = strfind(formula,'^');
+while ~isempty(indices),
+    index = indices(1);
+    formula1 = strtrim(formula(1:index-1));
+    formula2 = strtrim(formula(index+1:end));
+    % check formula1 from the right
+    firstargument = regexp(formula1,'([\w]+[.]?[\w]*)$','match');
+    if isempty(firstargument),
+        % check if last character is a closing parenthesis
+        if formula1(end) ~= ')',
+            error(sprintf('Error in formula: %s',formula));
+        end
+        % count parentheses
+        pc = 1; 
+        cend = length(formula1);
+        cstart = cend;
+        while pc ~= 0,
+            cstart = cstart - 1;
+            if formula1(cstart) == ')',
+                pc = pc+1;
+            elseif formula1(cstart) == '(',
+                pc = pc-1;
+            end
+        end
+        firstargument = formula1(cstart+1:cend-1);
+    else
+        firstargument = firstargument{1};
+        cstart = length(formula1)-length(firstargument)+1; 
+    end
+    cendfirst = cstart;
+    % check formula2 from the left
+    secondargument = regexp(formula2,'^([\w]+[.]?[\w]*)','match');
+    if isempty(secondargument),
+        % check if first character is an opening parenthesis
+        if formula2(1) ~= '(',
+            error(sprintf('Error in formula: %s',formula));
+        end
+        % count parentheses
+        pc = 1; 
+        cstart = 1;
+        cend = cstart;
+        while pc ~= 0,
+            cend = cend + 1;
+            if formula2(cend) == '(',
+                pc = pc+1;
+            elseif formula2(cend) == ')',
+                pc = pc-1;
+            end
+        end
+        secondargument = formula2(cstart+1:cend-1);
+    else
+        secondargument = secondargument{1};    
+        cend = length(secondargument);
+    end
+    cstartsecond = cend;
+    % construct power expression
+    powerexp = sprintf('pow(%s,%s)',firstargument,secondargument);
+    % construct new formula
+    formula = [formula1(1:cendfirst-1) powerexp formula2(cstartsecond+1:end)];
+    % get new indices for '^' character
+    indices = strfind(formula,'^');
+end
+return
+
+% function [formula] = processDelayCallIQM(formula)
+% global delaycount delaybase
+% count = 1;
+% while 1,
+%     index = strfind(formula,'delayIQM(');
+%     if length(index) < count,
+%         break;
+%     end
+%     indexstart = index(count)+length('delayIQM(');
+%     indexend = indexstart;
+%     
+%     % search the end of the delay argument definition
+%     parOpen = 1;
+%     while parOpen ~= 0,
+%         if formula(indexend) == '(',
+%             parOpen = parOpen + 1;
+%         elseif formula(indexend) == ')',
+%             parOpen = parOpen - 1;
+%         end
+%         indexend = indexend + 1;
+%     end
+%     % check if the delaybasename has to be changed
+%     if length(index) > 1,
+%         delayname = [delaybase '_' sprintf('%d', delaycount) '_' sprintf('%d', count)];
+%     else
+%         delayname = [delaybase '_' sprintf('%d', delaycount)];
+%     end
+%     % add info to delayIQM call
+%     firstpart = formula(1:indexend-2);
+%     lastpart = formula(indexend-1:end);
+%     middlepart = sprintf(',time,"%s"',delayname);
+%     formula = char([double(firstpart) double(middlepart) double(lastpart)]);
+%     % increase counters
+%     count = count + 1;
+%     delaycount = delaycount + 1;
+% end
+% return
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/IQMmakeTempMEXmodel.m b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/IQMmakeTempMEXmodel.m
new file mode 100644
index 0000000000000000000000000000000000000000..b5d1e7ab71860a6d4af62e2eb103ecdedf797301
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/IQMmakeTempMEXmodel.m	
@@ -0,0 +1,43 @@
+function [MEXmodel, MEXmodelfullpath] = IQMmakeTempMEXmodel(model)
+% IQMmakeTempMEXmodel: This function can be used to create a temporary 
+% MEX simulation function. Temporary means that it is created in the 
+% systems temp directory and that no name can be chosen, but that a unique
+% temporary filename is automatically chosen and returned.
+% 
+% USAGE:
+% ======
+% [MEXmodel, MEXmodelfullpath] = IQMmakeTempMEXmodel(model)
+% 
+% model: IQMmodel to convert to a temporary MEX simulation function
+% 
+% OUTPUT ARGUMENTS:
+% =================
+% MEXmodel: name of the MEX simulation function (filename without .mex extension)
+% MEXmodelfullpath: complete path to the created MEX simulation function (including mex extension)
+%                   This information can be used to delete the function as
+%                   soon as it is not needed anymore.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% TEMPDIR 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+addpath(tempdirIQM);   % add it to the path
+returndir = pwd;      % save the current dir to return to it
+cd(tempdirIQM);        % change to tempdir
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CREATE THE MEX SIMULATION FUNCTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET TEMP FILE NAME
+tempfilefullpath = tempnameIQM;
+[pathstr,tempfilename,ext] = fileparts(tempfilefullpath);
+IQMmakeMEXmodel(model,tempfilename);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% RETURN TO THE PREVIOUS DIRECTORY AND CREATE OUTPUT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+cd(returndir);
+MEXmodel = tempfilename;
+MEXmodelfullpath = sprintf('%s.%s',tempfilefullpath,mexext);
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/IQMsensitivity.m b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/IQMsensitivity.m
new file mode 100644
index 0000000000000000000000000000000000000000..41fa97f7b0b098aea5e6938cfe20990a39bc69db
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/IQMsensitivity.m	
@@ -0,0 +1,332 @@
+function [varargout] = IQMsensitivity(model,timevector,varargin)
+% IQMsensitivity: The IQMsensitivity function is able to determine the 
+% sensitivities of states and variables with respect to initial conditions
+% and parameters, using a finite difference approach.
+%
+% USAGE:
+% ======
+% output = IQMsensitivity(model, timevector)
+% output = IQMsensitivity(model, timevector, parameternames)
+% output = IQMsensitivity(model, timevector, parameternames, statenames)
+% output = IQMsensitivity(model, timevector, parameternames, statenames, options)
+% output = IQMsensitivity(model, timevector, parameternames, statenames, options, nomparamvalues, nomicvalues)
+%
+% model: IQMmodel or MEX simulation function
+% timevector: a vector of time steps at which to return the simulation data
+% parameternames: cell-array containing the names of the parameters for which to 
+%       calculate the sensitivities. (default: all parameters
+%       in the model)
+% statenames: cell-array containing the names of the states for whose initial
+%       conditions to calculate the sensitivities. (default: no states)
+% options: structure with options for the integrator and sensitivity
+%          calculation
+%               options.pertfactor: relative perturbation if parameter not
+%                   equal to zero. Otherwise absolute peturbation
+%               options.abstol: absolute tolerance
+%               options.reltol: relative tolerance
+%               options.minstep: minimal integrator step size
+%               options.maxstep: maximal integrator step size
+%               options.maxnumsteps: maximum number of steps to be
+%                   taken by the solver in its attempt to reach the next
+%                   output time 
+% nomparamvalues: vector of nominal parameter values
+% nomicvalues: vector of nominal initial condition values
+%
+% DEFAULT VALUES:
+% ===============
+% parameternames: (all parameters)
+% statenames:     (no states)
+% options.pertfactor: 1e-5 
+% options.abstol: 1e-6
+% options.reltol: 1e-6
+% options.minstep: 0
+% options.maxstep: inf
+% options.maxnumsteps: 500
+% nomparamvalues: parameter values stored in the model
+% nomicvalues: initial condition values stored in the model
+%
+% Output Arguments:
+% =================
+% If no output arguments are given, the result of the simulation is plotted
+% after finished simulation (only states, variables, reactions). The
+% sensitivities are not plotted!
+%
+% The output of IQMsensitivity is realized as a structure:
+% output.time:              vector with time instants for the results
+% output.states:            cell-array with state names
+% output.statevalues:       matrix with state values. Each row corresponds to
+%                           one time instant
+%
+% The following fields are only present in case options.simdata = 'all' is
+% defined.
+% output.variables:         cell-array with variable names
+% output.variablevalues:    matrix with variable values. Each row corresponds to
+%                           one time instant
+% output.reactions:         cell-array with reaction names
+% output.reactionvalues:    matrix with reaction values. Each row corresponds to
+%                           one time instant
+%
+% In the case events are present in the model the following fields are
+% present in the output structure additionally:
+% output.events:            cell-arra with the names of the events
+% output.eventtimes:        vector with time instants at which events
+%                           happened
+% output.eventflags:        matrix of dimension: 'number of events' x
+%                           'number of event time instants'. Each column in
+%                           this matrix correponds to one timeinstant in
+%                           the output.eventtimes vector. The row numbers
+%                           correspond to the numbers of the events. A "1"
+%                           element in the matrix indicates that the
+%                           corresponding event has happened at the
+%                           corresponding time. A "0" element tells you
+%                           that the event has not been fired at the
+%                           corresponding instant.
+%
+% Sensitivity trajectoried are returned as follows:
+% output.sensparameters:         cell-array containing the names of the
+%                                parameters for which sensitivities are determined
+% output.paramtrajectories.states:    cell-array containing one entry for each
+%                                parameter in output.sensparameters (same order).
+%                                Each entry consists of a matrix, where the
+%                                columns correspond to state sensitivities wrt
+%                                to the parameter and the rows correspond to
+%                                the different integration time points, given in
+%                                output.time.
+% output.paramtrajectories.variables: same as above just for variables
+% output.paramtrajectories.reactions: same as above just for reactions
+% output.sensicstates:           cell-array containing the names of the
+%                                states for which initial conditions
+%                                sensitivities are determined
+% output.ictrajectories.states:    cell-array containing one entry for each
+%                                state in output.sensicstates (same order).
+%                                Each entry consists of a matrix, where the
+%                                columns correspond to state sensitivities wrt
+%                                to the initial conditions and the rows correspond to
+%                                the different integration time points, given in
+%                                output.time.
+% output.ictrajectories.variables: same as above just for variables
+% output.ictrajectories.reactions: same as above just for reactions
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+pertfactor = 1e-5;
+% HANDLE NON-NUMERIC INITIAL CONDITIONS
+nomicvalues = IQMcalcICvector(model);
+[dummy,nomparamvalues] = IQMparameters(model);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK TYPE OF MODEL
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isIQMmodel(model) && ~ischar(model),
+    error('Model is not an IQMmodel or the name of a MEX simulation function.');
+end
+if length(timevector) <=1,
+    error('''timevector'' input argument needs to be a vector.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+parameternames = IQMparameters(model);
+statenames = [];
+options = [];
+if nargin >= 3,
+    parameternames = varargin{1};
+    if ischar(parameternames), 
+        parameternames = {parameternames}; 
+    end
+end
+if nargin >= 4,
+    statenames = varargin{2};
+    if ischar(statenames), 
+        statenames = {statenames}; 
+    end
+end
+if nargin >= 5,
+    options = varargin{3};
+    % reset the pertfactor if set in options
+	if isfield(options,'pertfactor')
+        pertfactor = options.pertfactor;
+	end
+end
+if nargin >= 6,
+    nomparamvalues = varargin{4};
+end
+if nargin == 7,
+    nomicvalues = varargin{5};
+end
+if nargin > 7,
+    error('Incorrect number of input arguments');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CREATE THE MEX MODEL
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ischar(model),
+    MEXmodel = model;
+    MEXmodelfullpath = '';
+else
+    [MEXmodel, MEXmodelfullpath] = IQMmakeTempMEXmodel(model);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET NOMINAL VALUES AND INDICES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% nom values for all params and states
+allparamvaluesnom = nomparamvalues;
+allicvaluesnom = nomicvalues;
+% nom values for params and states for which to compute the sensitivities
+paramindices = getparamindicesIQM(model,parameternames);
+paramvaluesnom = allparamvaluesnom(paramindices);
+icindices = getstateindicesIQM(model,statenames);
+icvaluesnom = allicvaluesnom(icindices);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% RUN A NOMINAL SIMULATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+nomsimdata = feval(MEXmodel,timevector,allicvaluesnom,allparamvaluesnom,options);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% RUN THE SENSITIVITY ANALYSIS (PARAMETERS)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+parampertsimdata = {};
+paramdeltapertvalue = [];
+for k=1:length(parameternames),
+    % perturb the parameter
+    paramkindex = paramindices(k);
+    paramk = paramvaluesnom(k);
+    if paramk ~= 0,
+        deltapert = paramk*pertfactor;
+    else
+        deltapert = pertfactor;
+    end
+    paramdeltapertvalue(end+1) = deltapert;
+    pertparamk = paramk + deltapert;
+    % create parameter vector
+    pv = allparamvaluesnom;
+    pv(paramkindex) = pertparamk;
+    % simulate the perturbed model
+    parampertsimdata{end+1} = feval(MEXmodel,timevector,allicvaluesnom,pv,options);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% RUN THE SENSITIVITY ANALYSIS (INITIAL CONDITIONS)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+icpertsimdata = {};
+icdeltapertvalue = [];
+for k=1:length(statenames),
+    % perturb the ic
+    ickindex = icindices(k);
+    ick = icvaluesnom(k);
+    if ick ~= 0,
+        deltapert = ick*pertfactor;
+    else
+        deltapert = pertfactor;
+    end
+    icdeltapertvalue(end+1) = deltapert;
+    pertick = ick + deltapert;
+    % create ic vector
+    ic = allicvaluesnom;
+    ic(ickindex) = pertick;
+    % simulate the perturbed model
+    icpertsimdata{end+1} = feval(MEXmodel,timevector,ic,allparamvaluesnom,options);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DETERMINE SENSITIVITIES (STATES)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+states_sensparamtrajectories = {};
+nomstates = nomsimdata.statevalues;
+for k=1:length(parameternames),
+    parampertstates = parampertsimdata{k}.statevalues;
+    states_sensparamtrajectories{end+1} = (parampertstates-nomstates)/paramdeltapertvalue(k);
+end
+states_sensictrajectories = {};
+for k=1:length(statenames),
+    icpertstates = icpertsimdata{k}.statevalues;
+    states_sensictrajectories{end+1} = (icpertstates-nomstates)/icdeltapertvalue(k);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DETERMINE SENSITIVITIES (VARIABLES)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+variables_sensparamtrajectories = {};
+nomvariables = nomsimdata.variablevalues;
+for k=1:length(parameternames),
+    parampertvariables = parampertsimdata{k}.variablevalues;
+    variables_sensparamtrajectories{end+1} = (parampertvariables-nomvariables)/paramdeltapertvalue(k);
+end
+variables_sensictrajectories = {};
+for k=1:length(statenames),
+    icpertvariables = icpertsimdata{k}.variablevalues;
+    variables_sensictrajectories{end+1} = (icpertvariables-nomvariables)/icdeltapertvalue(k);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DETERMINE SENSITIVITIES (REACTIONS)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+reactions_sensparamtrajectories = {};
+nomreactions = nomsimdata.reactionvalues;
+for k=1:length(parameternames),
+    parampertreactions = parampertsimdata{k}.reactionvalues;
+    reactions_sensparamtrajectories{end+1} = (parampertreactions-nomreactions)/paramdeltapertvalue(k);
+end
+reactions_sensictrajectories = {};
+for k=1:length(statenames),
+    icpertreactions = icpertsimdata{k}.reactionvalues;
+    reactions_sensictrajectories{end+1} = (icpertreactions-nomreactions)/icdeltapertvalue(k);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% BUILD OUTPUT STRUCTURE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+output = nomsimdata;
+output.sensparameters = parameternames;
+output.paramtrajectories.states = states_sensparamtrajectories;
+output.paramtrajectories.variables = variables_sensparamtrajectories;
+output.paramtrajectories.reactions = reactions_sensparamtrajectories;
+output.sensicstates = statenames;
+output.ictrajectories.states = states_sensictrajectories;
+output.ictrajectories.variables = variables_sensictrajectories;
+output.ictrajectories.reactions = reactions_sensictrajectories;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE VARIABLE OUTPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargout == 0,
+    % prepare data for plotting
+    time = output.time;
+    datanames = {};
+    dataindex = 1;
+    for k = 1:length(output.states),
+        datanames{dataindex} = sprintf('%s (state)',output.states{k});
+        dataindex = dataindex + 1;
+    end
+    if isfield(output,'variables'),
+        for k = 1:length(output.variables),
+            datanames{dataindex} = sprintf('%s (variable)',output.variables{k});
+            dataindex = dataindex + 1;
+        end
+        for k = 1:length(output.reactions),
+            datanames{dataindex} = sprintf('%s (reaction rate)',output.reactions{k});
+            dataindex = dataindex + 1;
+        end
+        datavalues = [output.statevalues, output.variablevalues, output.reactionvalues];
+    else
+        datavalues = [output.statevalues];
+    end
+    IQMplot(createdatastructIQMplotIQM(time(:),datavalues,datanames));
+elseif nargout == 1,
+    varargout{1} = output;
+else 
+    error('Incorrect number of output arguments!');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DELETE TEMP MEX MODEL IF CREATED
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(MEXmodelfullpath),
+    clear mex;
+    delete(MEXmodelfullpath);
+end
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/auxiliary/convertNNCa2NANNCaIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/auxiliary/convertNNCa2NANNCaIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..4565049e93b85d15a5eb233a24defd93d75af453
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/auxiliary/convertNNCa2NANNCaIQM.m	
@@ -0,0 +1,19 @@
+function [output] = convertNNCa2NANNCaIQM(input)
+% convertNNCa2NANNCaIQM: complicated name for simple function. This
+% function is called by a MEX simulation function when returning
+% non-numeric initial conditions. input is a cell-array with string
+% entries, defining the initial conditions. some of the strings only
+% contain numeric values. this function here will convert these from
+% strings to numbers. 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+output = {};
+for k=1:length(input),
+    test = str2double(input{k});
+    if isnan(test),
+        output{k} = input{k};
+    else
+        output{k} = test;
+    end
+end
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/auxiliary/getparamindicesIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/auxiliary/getparamindicesIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..aa11aace82e373fe517c5d3783aaab7973cb2189
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/auxiliary/getparamindicesIQM.m	
@@ -0,0 +1,36 @@
+function [output] = getparamindicesIQM(model,parameters)
+% getparamindicesIQM: Determines a vector of model parameter indices, the 
+% order corresponding to the parameters argument.
+% 
+% USAGE:
+% ======
+% [output] = getparamindicesIQM(model,parameters)
+% 
+% model: IQMmodel, ODE file model, or MEX simulation model
+% parameters: Cell-array of parameter names
+% 
+% OUTPUT:
+% =======
+% output: Vector of parameter indices
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+
+% check if parameter names is not a cell array
+if ischar(parameters),
+    parameters = {parameters};
+end
+% Get all parameter names in the order as they are stored in the model
+allnames = IQMparameters(model);
+% Get the indices
+output = zeros(1,length(parameters));
+for k = 1:length(parameters),
+    % get the index
+    index = strmatchIQM(parameters{k},allnames,'exact');
+    % check ... if error then the current parameter does not exist in the model
+    if isempty(index),
+        error('Parameter ''%s'' does not exist in the model.',parameters{k});
+    end
+    output(k) = index;
+end
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/auxiliary/getstateindicesIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/auxiliary/getstateindicesIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..daea8921dee1fe93aaecb83df67001b2c2e58c3f
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/auxiliary/getstateindicesIQM.m	
@@ -0,0 +1,33 @@
+function [output] = getstateindicesIQM(model,statenames)
+% getstateindicesIQM: Determines a vector of model state indices, the 
+% order corresponding to the states argument.
+% 
+% USAGE:
+% ======
+% [output] = getstateindicesIQM(model,states)
+% 
+% model: IQMmodel, ODE file model, or MEX simulation model
+% states: Cell-array of state names
+% 
+% OUTPUT:
+% =======
+% output: Vector of state indices
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Convert to cell array if necessary
+if ischar(statenames),
+    statenames = {statenames};
+end
+% Get all state names in order as stored in the model
+allnames = IQMstates(model);
+% Get the indices
+output = zeros(1,length(statenames));
+for k = 1:length(statenames),
+    index = strmatchIQM(statenames{k},allnames,'exact');
+    if isempty(index),
+        error(sprintf('State ''%s'' does not exist in the model.',statenames{k}));
+    end
+    output(k) = index;
+end
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/auxiliary/makeinicondvectorIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/auxiliary/makeinicondvectorIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..a24552d01a8b83936d920553be70dedfdb024942
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/auxiliary/makeinicondvectorIQM.m	
@@ -0,0 +1,45 @@
+function [icvector] = makeinicondvectorIQM(model,states,statevalues)
+% makeinicondvectorIQM: The mex simulation functions take a full initial
+% condition vector as an input. In order to construct such a vector while
+% changing some but possibly not all IC values this function can be used.
+%
+% This function does handle also non-numeric initial conditions. The
+% default state vector is determined based on the given model. Then the
+% user provided changes are added as given.
+%
+% USAGE:
+% ======
+% [icvector] = makeinicondvectorIQM(model,states,statevalues)
+% 
+% model: IQMmodel, ODE file model, or MEX file model
+% states: Cell-array of state names for which to change the ICs
+% statevalues: Vector with the corresponding values for the ICs of the states.
+% 
+% OUTPUT:
+% =======
+% icvector: Constructed initial condition vector
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+
+% Convert to cell-array if necessary
+if ischar(states),
+    states = {states};
+end
+% State input arguments need to have same length ...
+if length(states) ~= length(statevalues),
+    error('Different numbers of states and statevalues.');
+end
+% Get the initialconditions from the model
+icvector = IQMcalcICvector(model);
+% Get all state names to check against the given state names
+allstates = IQMstates(model);
+% Update the icvector with given values
+for k = 1:length(states),
+    index = strmatchIQM(states{k},allstates,'exact');
+    if isempty(index),
+        error(sprintf('Statename ''%s'' is no state in the model.',states{k}));
+    end
+    icvector(index) = statevalues(k);
+end
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/auxiliary/makeparamvecIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/auxiliary/makeparamvecIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..653b138e44fea06a153c324c571da1b6c593904f
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/auxiliary/makeparamvecIQM.m	
@@ -0,0 +1,38 @@
+function [paramvector] = makeparamvecIQM(model,parameters,parametervalues)
+% makeparamvecIQM: The mex simulation functions take a full parameter value
+% vector as an input. In order to construct such a vector while changing 
+% some but possibly not all parameter values this function can be used.
+% 
+% USAGE:
+% ======
+% [paramvector] = makeparamvecIQM(model,parameters,parametervalues)
+% 
+% model: IQMmodel, ODE file model, or MEX file model
+% parameters: Cell-array of parameter names for which to change the parametervalues
+% parametervalues: Vector with the corresponding values for the parameters 
+% 
+% OUTPUT:
+% =======
+% paramvector: Constructed initial condition vector
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Convert to cell-array if necessary
+if ischar(parameters),
+    parameters = {parameters};
+end
+% Parameter input arguments need to have same length ...
+if length(parameters) ~= length(parametervalues),
+    error('Different numbers of parameters and parametervalues.');
+end
+% Get the parametervalues from the model
+[allParams,paramvector] = IQMparameters(model);
+% Update the paramvector with given values
+for k = 1:length(parameters),
+    index = strmatchIQM(parameters{k},allParams,'exact');
+    if isempty(index),
+        error(sprintf('Parameter name ''%s'' is no parameter in the model.',parameters{k}));
+    end
+    paramvector(index) = parametervalues(k);
+end
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/auxiliary/mexcompileIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/auxiliary/mexcompileIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..949783290091606c98a515ef971a33d34ddf7015
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/auxiliary/mexcompileIQM.m	
@@ -0,0 +1,22 @@
+function [] = mexcompileIQM(filename)
+% mexcompileIQM: Compiles an IQMmodel that has been converted to a mexfile.h 
+% and mexfile.c and links it with the CVODE integrator from the SUNDIALS
+% suite (http://www.llnl.gov/CASC/sundials/). 
+% 
+% USAGE:
+% ======
+% [] = mexcompileIQM(mexfile)
+%
+% mexfile: Basename of the model files (mexfile.c and mexfile.h)  
+    
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+if ~isunix,
+    libpath = which('CVODEmex25.lib');
+else
+    libpath = which('CVODEmex25.a');
+end
+includefolder = fileparts(which('mexmathaddon.h'));
+% do compilation
+eval(sprintf('mex -O -I''%s'' %s.c ''%s'';',includefolder,filename,libpath));
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/auxiliary/updateparamvecIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/auxiliary/updateparamvecIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..10826bdab7a405835d32b8e58a204052b6c29b07
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/01-MEXmodels/auxiliary/updateparamvecIQM.m	
@@ -0,0 +1,43 @@
+function [newparamvector] = updateparamvecIQM(paramnames, oldparamvector, pnames, pvalues)
+% updateparamvecIQM: The mex simulation functions take a full parameter value
+% vector as an input. In order to construct such a vector from an existing 
+% parameter vector while changing some but possibly not all parameter
+% values this function can be used. 
+% 
+% USAGE:
+% ======
+% [newparamvector] = updateparamvecIQM(paramnames, oldparamvector, pnames, pvalues)
+% 
+% paramnames: Cell-array of all model parameter names (in the order as they
+%   appear in the model)
+% oldparamvector: Full parameter vector before the change
+% pnames: Cell-array of parameter names for which to change the
+%   parametervalues 
+% pvalues: Vector with parameter values for the parameters to be changed
+%   (order defined by pnames)
+% 
+% OUTPUT:
+% =======
+% newparamvector: Constructed new parameter vector with changed parameters
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Convert to cell-array if necessary
+if ischar(pnames),
+    pnames = {pnames};
+end
+% Parameter input arguments need to have same length ...
+if length(pnames) ~= length(pvalues),
+    error('Different numbers of parameters and parametervalues to be changed.');
+end
+
+% Update the paramvector with given values
+newparamvector = oldparamvector;
+for k = 1:length(pnames),
+    index = strmatchIQM(pnames{k}, paramnames, 'exact');
+    if isempty(index),
+        disp(sprintf('Parameter name ''%s'' is no parameter in the model.',pnames{k}));
+    end
+    newparamvector(index) = pvalues(k);
+end
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMmanualtuningGUI/IQMmanualtuning.fig b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMmanualtuningGUI/IQMmanualtuning.fig
new file mode 100644
index 0000000000000000000000000000000000000000..f619ddb212bb0aba296a8fbd8f2e65a300638546
Binary files /dev/null and b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMmanualtuningGUI/IQMmanualtuning.fig differ
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMmanualtuningGUI/IQMmanualtuning.m b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMmanualtuningGUI/IQMmanualtuning.m
new file mode 100644
index 0000000000000000000000000000000000000000..81fa2c5c1b105e0a15a00967cd5d3c1458465625
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMmanualtuningGUI/IQMmanualtuning.m	
@@ -0,0 +1,1857 @@
+function varargout = IQMmanualtuning(varargin)
+% IQMmanualtuning: Allows to compare simulated experiments data to
+% measurements and perform manual parameter tuning. Additionally it is
+% possible to run simulations of selected experiments directly from the 
+% IQMmanualtuning window, allowing for a deeper analysis of what happens 
+% in the system.
+%
+% USAGE:
+% ======
+% [project] = IQMmanualtuning(project)
+% [project] = IQMmanualtuning(project,modelindex)
+% [project] = IQMmanualtuning(project,estimation)
+% [project] = IQMmanualtuning(project,modelindex,additionalcomponents)
+% [project] =
+% IQMmanualtuning(project,estimation,additionalcomponents)
+%
+% project: IQMprojectSB to tune manually. 
+% modelindex: The index of the model in the project to use for tuning.
+% estimation: Same structure as used for parameter estimation
+%   (IQMparameterestimation), defining the (global) parameters and their
+%   bounds, and modelindex.
+% additionalcomponents: Cell-array containing the names of components
+%   (states or variables) that have not been measured but which should also
+%   be plotted in IQMmanualtuning.
+%
+% DEFAULT VALUES:
+% ===============
+% modelindex: 1:n, where n is the number of the models in the project. This
+%             means that tuning is carried out for all models in the
+%             project if modelindex is not given
+% estimation: all global parameters and all models, bounds: nominalvalue*[0.01 100]
+% additionalcomponents: {} (none)
+%
+% Output Arguments:
+% =================
+% The manually tuned project is given back.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INITIALIZATION CODE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Begin initialization code - DO NOT EDIT
+gui_Singleton = 1;
+gui_State = struct('gui_Name',       mfilename, ...
+                   'gui_Singleton',  gui_Singleton, ...
+                   'gui_OpeningFcn', @IQMmanualtuning_OpeningFcn, ...
+                   'gui_OutputFcn',  @IQMmanualtuning_OutputFcn, ...
+                   'gui_LayoutFcn',  [] , ...
+                   'gui_Callback',   []);
+if nargin && ischar(varargin{1})
+    gui_State.gui_Callback = str2func(varargin{1});
+end
+if nargout
+    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
+else
+    gui_mainfcn(gui_State, varargin{:});
+end
+% End initialization code - DO NOT EDIT
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INTERFACE FUNCTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% --- Executes just before IQMmanualtuning is made visible.
+function IQMmanualtuning_OpeningFcn(hObject, eventdata, handles, varargin)
+
+% Handle variable input arguments
+estimation = [];
+if nargin >= 4,
+    project = varargin{1};
+    if ~isIQMprojectSB(project), 
+        error('Input argument is not an IQMprojectSB.'); 
+    end
+    projectstruct = IQMstruct(project);
+    modelindex = [1:length(projectstruct.models)];
+end
+if nargin >= 5,
+    if ~isstruct(varargin{2}),
+        modelindex = varargin{2};
+    else
+        estimation = varargin{2};
+        modelindex = 1; % default value
+        try modelindex = estimation.modelindex; catch, end
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        % HANDLE PARAM DATA MATRIX
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        if iscell(estimation.parameters),
+            if ~isempty(estimation.parameters),
+                paramnames = estimation.parameters(:,1);
+                paramlowbounds = cell2mat(estimation.parameters(:,2));
+                paramhighbounds = cell2mat(estimation.parameters(:,3));
+            else
+                paramnames = {};
+                paramlowbounds = [];
+                paramhighbounds = [];
+            end
+            estimation.parameters = [];
+            estimation.parameters.names = paramnames;
+            estimation.parameters.lowbounds = paramlowbounds;
+            estimation.parameters.highbounds = paramhighbounds;
+        end
+        if iscell(estimation.parameterslocal),
+            if ~isempty(estimation.parameterslocal),
+                paramnameslocal = estimation.parameterslocal(:,1);
+                paramlowboundslocal = cell2mat(estimation.parameterslocal(:,2));
+                paramhighboundslocal = cell2mat(estimation.parameterslocal(:,3));
+            else
+                paramnameslocal = {};
+                paramlowboundslocal = [];
+                paramhighboundslocal = [];
+            end
+            estimation.parameterslocal = [];
+            estimation.parameterslocal.names = paramnameslocal;
+            estimation.parameterslocal.lowbounds = paramlowboundslocal;
+            estimation.parameterslocal.highbounds = paramhighboundslocal;
+        end
+        if iscell(estimation.initialconditions),
+            if ~isempty(estimation.initialconditions),
+                icnames = estimation.initialconditions(:,1);
+                iclowbounds = cell2mat(estimation.initialconditions(:,2));
+                ichighbounds = cell2mat(estimation.initialconditions(:,3));
+            else
+                icnames = {};
+                iclowbounds = [];
+                ichighbounds = [];
+            end
+            estimation.initialconditions = [];
+            estimation.initialconditions.names = icnames;
+            estimation.initialconditions.lowbounds = iclowbounds;
+            estimation.initialconditions.highbounds = ichighbounds;
+        end
+    end
+end
+if nargin >= 6,
+    additionalPlotNames = varargin{3};
+else 
+    additionalPlotNames = {};
+end
+% if nargin<3 || nargin>6,
+%     error('Incorrect number of input arguments.');
+% end
+
+% get integrator options
+try
+    OPTIONS = estimation.integrator.options; 
+catch
+    OPTIONS = [];
+end
+
+handles.modelindex = modelindex;
+handles.projectstruct = struct(project);
+handles.estimation = estimation;
+handles.integratoroptions = OPTIONS;
+handles.boundsaxis = NaN;
+set(handles.bounds,'String','Nominal');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Determine ALL parameters changed by events (in all models and in all experiments)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Parameters that are changed by events are not allowed to be changed by the user during tuning
+pnames = {};
+for k=1:length(handles.projectstruct.models),
+    model = handles.projectstruct.models{k};
+    ms = struct(model);
+    pnames = {pnames{:} ms.parameters.name};
+end
+pnames = unique(pnames);
+apnames = {};
+% MODELS FIRST:
+for k1=1:length(handles.projectstruct.models),
+    model = handles.projectstruct.models{k1};
+    ms = struct(model);
+    % collect all assignment variables in all events that are parameters
+    for k=1:length(ms.events),
+        for k2=1:length(ms.events(k).assignment),
+            vname = ms.events(k).assignment(k2).variable;
+            if ~isempty(strmatchIQM(vname,pnames,'exact')),
+                apnames{end+1} = vname;
+            end
+        end
+    end
+end
+% EXPERIMENTS SECOND:
+for k1=1:length(handles.projectstruct.experiments),
+    experiment = handles.projectstruct.experiments(k1).experiment;
+    es = struct(experiment);
+    % collect all assignment variables in all events that are parameters
+    for k=1:length(es.stateevents),
+        for k2=1:length(es.stateevents(k).assignment),
+            vname = es.stateevents(k).assignment(k2).variable;
+            if ~isempty(strmatchIQM(vname,pnames,'exact')),
+                apnames{end+1} = vname;
+            end
+        end
+    end
+end
+% apnames are the names of the parameters that are changed by events.
+% these are not allowed to be tuned
+apnames = unique(apnames);
+% Save the info in the 
+handles.event_param_names = apnames;
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% handle experimentindices
+try 
+    experimentindices = estimation.experiments.indices; 
+catch
+    experimentindices = [1:length(handles.projectstruct.experiments)];
+end
+handles.nrsliders = 7;  % not really used everywhere yet
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% ADD EXTRA PLOT NAMES TO THE MEASUREMENT STRUCTURES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% additionally save the unchanged project structure for output
+handles.saveORIGprojectstruct = handles.projectstruct;
+for e=1:length(handles.projectstruct.experiments),
+    measurements = handles.projectstruct.experiments(e).measurements;
+    for m=1:length(measurements),
+        msm = struct(measurements{m});
+        for k=1:length(additionalPlotNames),
+            % check if additional plot name is already present
+            if isempty(strmatchIQM(additionalPlotNames{k},{msm.data(1:end).name},'exact')),
+                msm.data(end+1).name = additionalPlotNames{k};
+                msm.data(end).notes = 'User-selected additional component for plotting';
+                msm.data(end).values = NaN*ones(length(msm.time),1);
+                msm.data(end).maxvalues = NaN*ones(length(msm.time),1);
+                msm.data(end).minvalues = NaN*ones(length(msm.time),1);
+            end
+        end
+        measurements{m} = IQMmeasurement(msm);
+    end
+    handles.projectstruct.experiments(e).measurements = measurements;
+end
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK WHICH EXPERIMENTS DO NOT HAVE MEASUREMENT DATA ASSIGNED TO
+% THESE ARE SKIPPED FROM THE CONSIDERATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+text = '';
+useexperimentindices = [];
+for e=1:length(experimentindices),
+    if isempty(handles.projectstruct.experiments(experimentindices(e)).measurements),
+        text = sprintf('%sExperiment %d has no measurements assigned to ... not considered here.\n',text,experimentindices(e));
+    else
+        useexperimentindices = [useexperimentindices experimentindices(e)];
+    end
+end
+if ~isempty(text),
+    disp(text);
+end
+if isempty(useexperimentindices),
+    error('No measurements present in the project. No comparison possible.');
+end
+handles.experimentindices = useexperimentindices;
+handles.plotdata = initializePlotdata(handles.projectstruct,modelindex,handles);
+% set modelselection and choose first model
+set(handles.modelselection,'String',{handles.plotdata.model.name});
+set(handles.modelselection,'Value',1);
+% set experimentselection for first model and first experiment
+set(handles.experimentselection,'String',{handles.plotdata.model(1).experiment.name});
+set(handles.experimentselection,'Value',1);
+% set component selection
+set(handles.componentselection,'String',handles.plotdata.model(1).allmeascomponents);
+set(handles.componentselection,'Value',[1:length(handles.plotdata.model(1).allmeascomponents)]);
+% determine parameter data
+handles = getparamdata(handles);
+% set all parameter selection boxes with parameter names (model dependent)
+initializeParameterLists(handles);
+% select plottype
+handles.dataPlotType = 'plot';     
+% set errorbarflag to 1
+handles.errorbars = 1;
+% set legendflag to 1
+handles.legendflag = 1;
+% Initialize export figure handle and grid flag
+handles.exportFigureHandle = [];
+handles.grid = 0;
+% Doing a first plot
+doPlot(handles);
+% Choose default command line output for IQMmanualtuning
+handles.output = hObject;
+% Update handles structure
+guidata(hObject, handles);
+uiwait;
+return
+
+% --- Outputs from this function are returned to the command line.
+function varargout = IQMmanualtuning_OutputFcn(hObject, eventdata, handles) 
+% varargout  cell array for returning output args (see VARARGOUT);
+varargout{1} = handles.output;
+% delete temporary MEX models
+global compiledExpModelsIQMparamestGUI % if not empty then models are precompiled and should not be deleted
+if isempty(compiledExpModelsIQMparamestGUI),
+    clear mex
+    for m=1:length(handles.plotdata.model)
+        for e=1:length(handles.plotdata.model(m).experiment),
+            delete(handles.plotdata.model(m).experiment(e).mexfullpath);
+        end
+    end
+end
+% close the GUI
+delete(hObject);
+return
+
+% --- Closed by user
+function IQMmanualtuning_CloseRequestFcn(hObject, eventdata, handles)
+exit_Callback(hObject, eventdata, handles)
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EXIT IQMmanualtuning CALLBACK
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function exit_Callback(hObject, eventdata, handles)
+    % construct the output (its just an updated IQMprojectSB in which the 
+    % manually tuned parametervalues are entered)
+    % FOR THIS USE THE SAVED ORIG PROJECT!
+    for k=1:length(handles.modelindex),
+        m = handles.modelindex(k);
+        % get model to update
+        model = handles.saveORIGprojectstruct.models{m};
+        % set manually tuned parameters
+        % take away the things that are no parameters
+        noParamIndices = strmatchIQM('No Parameter',handles.parammodel(k).names,'exact');
+        paramIndices = setdiff([1:length(handles.parammodel(k).names)],noParamIndices);
+        paramnames = handles.parammodel(k).names(paramIndices);
+        paramvalues = handles.parammodel(k).values(paramIndices);
+        model = IQMparameters(model,paramnames,paramvalues);
+        % add model to project
+        handles.saveORIGprojectstruct.models{m} = model;
+    end
+    handles.output = IQMprojectSB(handles.saveORIGprojectstruct);
+    % Update handles structure
+    guidata(hObject, handles);
+    uiresume;
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% SIMULATION FUNCTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function handles=doSimAndPlot(handles)
+% get the parameter values to use for simulation
+m = get(handles.modelselection,'Value');
+%pv = handles.parammodel(m).values;
+% run through all experiments and perform them for the parameter settings
+for e = 1:length(handles.plotdata.model(m).experiment),
+    mexmodel = handles.plotdata.model(m).experiment(e).mexmodel;
+    timevector = handles.plotdata.model(m).experiment(e).timevector;
+    ic = handles.plotdata.model(m).experiment(e).initialconditions;
+    % take away the things that are no parameters
+    noParamIndices = strmatchIQM('No Parameter',handles.parammodel(m).names,'exact');
+    paramIndices = setdiff([1:length(handles.parammodel(m).names)],noParamIndices);
+    paramnames = handles.parammodel(m).names(paramIndices);
+    paramvalues = handles.parammodel(m).values(paramIndices);
+    % construct parameter vector for simulation
+    pv = makeparamvecIQM(mexmodel,paramnames,paramvalues);
+    try
+        tmin = timevector(1); tmax = timevector(end);
+        tvec = [tmin:(tmax-tmin)/1000:tmax];
+        simdata = feval(mexmodel,tvec,ic,pv,handles.integratoroptions);        
+    catch
+        simdata = [];
+        break;
+    end
+    stateindices = handles.plotdata.model(m).experiment(e).stateindices;
+    statevalues = simdata.statevalues(:,stateindices);
+    variableindices = handles.plotdata.model(m).experiment(e).variableindices;
+    variablevalues = simdata.variablevalues(:,variableindices);
+    handles.plotdata.model(m).experiment(e).componentvalues = [statevalues variablevalues];
+end
+if ~isempty(simdata),
+    doPlot(handles);
+else
+    errordlg('Parameter setting leads to error.');
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PLOT FUNCTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function doPlot(handles)
+colorvector = {'b','g','r','c','m','y','k'};
+% markervector = {'o','x','+','*','s','d','v','^','<','>','p','h'};
+warning off;
+% get the data to plot
+plotdata = handles.plotdata;
+m = get(handles.modelselection,'Value');
+eall = get(handles.experimentselection,'Value');
+callnames = get(handles.componentselection,'String');
+callselected = get(handles.componentselection,'Value');
+NTOTAL = length(eall);
+NROW = ceil(sqrt(NTOTAL));
+NCOL = ceil(NTOTAL/NROW);
+for sp = 1:NTOTAL,
+    e = eall(sp);
+    subplot(NROW,NCOL,sp,'Parent',handles.plotpanel);
+    edata = plotdata.model(m).experiment(e);
+    % general information
+    titletext = regexprep(edata.name,'_',' ');
+    xlabeltext = 'Time';
+    % simulated data information
+    sim_timevector = edata.timevector;
+    sim_componentnames = edata.componentnames;
+    sim_componentvalues = edata.componentvalues;
+    for k=1:length(edata.componentnames),
+        if isempty(strmatchIQM(edata.componentnames{k},callnames(callselected),'exact')),
+            sim_componentvalues(:,k) = NaN;
+        end
+    end
+    % plot simulated data
+if ~isnan(handles.boundsaxis),
+    [sim_timevector,sim_componentvalues] = stripSmallerTimes(sim_timevector,sim_componentvalues,handles.boundsaxis(1));    
+end
+
+    for kplotsim=1:size(sim_componentvalues,2)
+        feval(handles.dataPlotType,sim_timevector,sim_componentvalues(:,kplotsim),'linewidth',2,'color',colorvector{mod(kplotsim-1,7)+1}); hold on;
+    end
+    
+    
+    % measured data information
+    for meas=1:length(edata.measurement),
+        meas_timevector = edata.measurement(meas).timevector;
+        meas_componentnames = edata.measurement(meas).componentnames;
+        meas_componentvalues = edata.measurement(meas).componentvalues;
+        meas_maxvalues = edata.measurement(meas).maxvalues;
+        meas_minvalues = edata.measurement(meas).minvalues;
+        for k=1:length(edata.measurement(meas).componentnames),
+            if isempty(strmatchIQM(edata.measurement(meas).componentnames{k},callnames(callselected),'exact')),
+                meas_componentvalues(:,k) = NaN;
+                meas_maxvalues(:,k) = NaN;
+                meas_minvalues(:,k) = NaN;
+            end
+        end
+        % continue
+%         marker = markervector{mod(meas-1,length(markervector))+1};
+%         feval(handles.dataPlotType,meas_timevector,meas_componentvalues,['--' marker]); hold on;
+        color4meas = colorvector{mod(meas-1,length(colorvector))+1};
+if ~isnan(handles.boundsaxis),
+    [meas_timevector,meas_componentvalues] = stripSmallerTimes(meas_timevector,meas_componentvalues,handles.boundsaxis(1));   
+end
+
+        for kplotsim=1:size(meas_componentvalues,2)
+            feval(handles.dataPlotType,meas_timevector,meas_componentvalues(:,kplotsim),'*','linewidth',2,'color',colorvector{mod(kplotsim-1,7)+1}); hold on;
+        end
+
+        if handles.errorbars == 1 && strcmp(handles.dataPlotType,'plot'),
+            % plot error bounds
+            for k=1:length(meas_componentnames),
+                color = colorvector{mod(k-1,7)+1};
+%                 for k1 = 1:size(meas_timevector,1),
+                for k1 = 1:length(meas_timevector),
+if ~isnan(handles.boundsaxis),
+    if meas_timevector(k1) >= handles.boundsaxis(1),
+                    feval(handles.dataPlotType,[meas_timevector(k1),meas_timevector(k1)],[meas_minvalues(k1,k),meas_maxvalues(k1,k)],['.:',color]);
+    end
+else
+                    feval(handles.dataPlotType,[meas_timevector(k1),meas_timevector(k1)],[meas_minvalues(k1,k),meas_maxvalues(k1,k)],['.:',color]);
+end
+                end
+            end
+        end
+    end
+    hold off;
+    if handles.legendflag == 1,
+        hlhlx = legend(sim_componentnames);
+        set(hlhlx,'Interpreter','none');
+    end
+    hlhlx = title(titletext);
+    set(hlhlx,'Interpreter','none');
+    hlhlx = xlabel(xlabeltext);
+    set(hlhlx,'Interpreter','none');
+
+if ~isnan(handles.boundsaxis),
+    axis(handles.boundsaxis)
+end
+
+end
+
+
+return
+
+function [t,y] = stripSmallerTimes(t,y,minT)
+    indexdel = find(t<minT);
+    t(indexdel) = [];
+    y(indexdel,:) = [];
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Determine parameter data and save in handles structure
+% Only parameters that appear in all expmmexmodels are considered.
+% Furthermore, they need to have the same values (so that they are not
+% modified due to experimental settings)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function handles = getparamdata(handles)
+if isempty(handles.estimation),
+    for m = 1:length(handles.plotdata.model),
+        % get parameter names that appear in all expmexmodels
+        for e = 1:length(handles.plotdata.model(m).experiment),
+            model = handles.plotdata.model(m).experiment(e).mexmodel;
+            if e == 1,
+                parameters = feval(model,'parameters');
+            else
+                parameters = intersect(parameters, feval(model,'parameters'));
+            end
+        end
+        % keep only those parameters that have the same value (not changed by
+        % experiment or changed equally)
+        indexdelete = [];
+        for e = 1:length(handles.plotdata.model(m).experiment),
+            model = handles.plotdata.model(m).experiment(e).mexmodel;
+            if e == 1,
+                % first run just get the parametervalues
+                parametervalues = IQMparameters(model,parameters);
+            else
+                % subsequent runs ... check if equal and get the indices of the
+                % non equal entries
+                pv = IQMparameters(model,parameters);
+                indexdelete = unique([indexdelete(:)', find(pv(:)'~=parametervalues(:)')]);
+            end
+        end
+        indexkeep = setdiff([1:length(parameters)],indexdelete);
+        parameters = parameters(indexkeep);
+        % FINALLY ALSO REMOVE THE PARAMETERS THAT ARE CHANGED BY EVENTS DURING
+        % THE SIMULATION (DEFINED IN: handles.event_param_names)
+        parameters = setdiff(parameters,handles.event_param_names);
+        parametervalues = IQMparameters(model,parameters);
+        % add param info to structure
+        handles.parammodel(m).names = parameters;
+        handles.parammodel(m).values = parametervalues;
+        handles.parammodel(m).startvalues = parametervalues;
+        max = 100*parametervalues;
+        max(find(max==0)) = 1;
+        handles.parammodel(m).max = max;
+        handles.parammodel(m).startmax = max;
+        handles.parammodel(m).min = 0.01*parametervalues;
+        handles.parammodel(m).startmin = 0.01*parametervalues;
+    end
+else
+    % add param info to structure
+    % directly from estimation structure (just one model possible)
+    model = handles.plotdata.model(1).experiment(1).mexmodel;
+    handles.parammodel.names = handles.estimation.parameters.names;
+    parametervalues = IQMparameters(model,handles.parammodel.names);
+    handles.parammodel.values = parametervalues;
+    handles.parammodel.startvalues = parametervalues;
+    if ~isfield(handles.estimation.parameters,'lowbounds'),
+        handles.estimation.parameters.lowbounds = [];
+    end
+    if ~isfield(handles.estimation.parameters,'highbounds'),
+        handles.estimation.parameters.highbounds = [];
+    end
+    if isempty(handles.estimation.parameters.lowbounds),
+        min = 0.01*parametervalues;
+    else
+        min = handles.estimation.parameters.lowbounds;
+    end
+    if isempty(handles.estimation.parameters.highbounds),
+        max = 100*parametervalues;
+    else
+        max = handles.estimation.parameters.highbounds;
+    end
+    max(find(max==0)) = 1;
+    handles.parammodel.max = max;
+    handles.parammodel.startmax = max;
+    handles.parammodel.min = min;
+    handles.parammodel.startmin = min;
+end
+% if fewer parameters than handles.nrsliders then add dummy ones
+if length(parametervalues) < handles.nrsliders,
+    for k=1:(handles.nrsliders-length(parametervalues)),
+        handles.parammodel.names{end+1} = 'No Parameter';
+        handles.parammodel.values(end+1) = NaN;
+        handles.parammodel.startvalues(end+1) = NaN;
+        handles.parammodel.max(end+1) = NaN;
+        handles.parammodel.startmax(end+1) = NaN;
+        handles.parammodel.min(end+1) = NaN;
+        handles.parammodel.startmin(end+1) = NaN;
+    end
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Initialize parameter lists
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [] = initializeParameterLists(handles,varargin)
+if nargin == 1,
+    i1 = 1;
+    i2 = 2;
+    i3 = 3;
+    i4 = 4;
+    i5 = 5;
+    i6 = 6;
+    i7 = 7;
+elseif nargin == 2,
+    if strcmp(varargin{1},'resetall'),
+        i1 = 1;
+        i2 = 2;
+        i3 = 3;
+        i4 = 4;
+        i5 = 5;
+        i6 = 6;
+        i7 = 7;
+    else
+        i1 = get(handles.manualparam1,'Value');
+        i2 = get(handles.manualparam2,'Value');
+        i3 = get(handles.manualparam3,'Value');
+        i4 = get(handles.manualparam4,'Value');
+        i5 = get(handles.manualparam5,'Value');
+        i6 = get(handles.manualparam6,'Value');
+        i7 = get(handles.manualparam7,'Value');
+    end
+end
+
+m = get(handles.modelselection,'Value');
+% get the models parameters and values
+parameters = handles.parammodel(m).names;
+parametervalues = handles.parammodel(m).values;
+parammax = handles.parammodel(m).max;
+parammin = handles.parammodel(m).min;
+% set the 7 parameter lists (adjust list of parameters)
+nrtakeaway = length(strmatchIQM('No Parameter',parameters,'exact'));
+if nrtakeaway > 0,
+    endindex = handles.nrsliders-nrtakeaway;
+    set(handles.manualparam1,'String',parameters(1:endindex));
+    set(handles.manualparam2,'String',parameters(1:endindex));
+    set(handles.manualparam3,'String',parameters(1:endindex));
+    set(handles.manualparam4,'String',parameters(1:endindex));
+    set(handles.manualparam5,'String',parameters(1:endindex));
+    set(handles.manualparam6,'String',parameters(1:endindex));
+    set(handles.manualparam7,'String',parameters(1:endindex));
+else
+    set(handles.manualparam1,'String',parameters);
+    set(handles.manualparam2,'String',parameters);
+    set(handles.manualparam3,'String',parameters);
+    set(handles.manualparam4,'String',parameters);
+    set(handles.manualparam5,'String',parameters);
+    set(handles.manualparam6,'String',parameters);
+    set(handles.manualparam7,'String',parameters);
+end    
+% set selected values
+set(handles.manualparam1,'Value',i1);
+set(handles.manualparam2,'Value',i2);
+set(handles.manualparam3,'Value',i3);
+set(handles.manualparam4,'Value',i4);
+set(handles.manualparam5,'Value',i5);
+set(handles.manualparam6,'Value',i6);
+set(handles.manualparam7,'Value',i7);
+% set current parameter values
+set(handles.value1,'String',parametervalues(i1));
+set(handles.value2,'String',parametervalues(i2));
+set(handles.value3,'String',parametervalues(i3));
+set(handles.value4,'String',parametervalues(i4));
+set(handles.value5,'String',parametervalues(i5));
+set(handles.value6,'String',parametervalues(i6));
+set(handles.value7,'String',parametervalues(i7));
+% set max and min values per default to *100 / *0.01
+set(handles.manualmax1,'String',parammax(i1));
+set(handles.manualmax2,'String',parammax(i2));
+set(handles.manualmax3,'String',parammax(i3));
+set(handles.manualmax4,'String',parammax(i4));
+set(handles.manualmax5,'String',parammax(i5));
+set(handles.manualmax6,'String',parammax(i6));
+set(handles.manualmax7,'String',parammax(i7));
+set(handles.manualmin1,'String',parammin(i1));
+set(handles.manualmin2,'String',parammin(i2));
+set(handles.manualmin3,'String',parammin(i3));
+set(handles.manualmin4,'String',parammin(i4));
+set(handles.manualmin5,'String',parammin(i5));
+set(handles.manualmin6,'String',parammin(i6));
+set(handles.manualmin7,'String',parammin(i7));
+% set slider min max and value
+set(handles.manualslider1,'Max',101);
+set(handles.manualslider2,'Max',101);
+set(handles.manualslider3,'Max',101);
+set(handles.manualslider4,'Max',101);
+set(handles.manualslider5,'Max',101);
+set(handles.manualslider6,'Max',101);
+set(handles.manualslider7,'Max',101);
+set(handles.manualslider1,'Min',1);
+set(handles.manualslider2,'Min',1);
+set(handles.manualslider3,'Min',1);
+set(handles.manualslider4,'Min',1);
+set(handles.manualslider5,'Min',1);
+set(handles.manualslider6,'Min',1);
+set(handles.manualslider7,'Min',1);
+% construct vectors
+if parammin(i1) > 0,
+    vector1 = logspace(log(parammin(i1))/log(10),log(parammax(i1))/log(10),101);
+else
+    vector1 = [parammin(i1):(parammax(i1)-parammin(i1))/100:parammax(i1)];
+end
+if parammin(i2) > 0,
+    vector2 = logspace(log(parammin(i2))/log(10),log(parammax(i2))/log(10),101);
+else
+    vector2 = [parammin(i2):(parammax(i2)-parammin(i2))/100:parammax(i2)];
+end
+if parammin(i3) > 0,
+    vector3 = logspace(log(parammin(i3))/log(10),log(parammax(i3))/log(10),101);
+else
+    vector3 = [parammin(i3):(parammax(i3)-parammin(i3))/100:parammax(i3)];
+end
+if parammin(i4) > 0,
+    vector4 = logspace(log(parammin(i4))/log(10),log(parammax(i4))/log(10),101);
+else
+    vector4 = [parammin(i4):(parammax(i4)-parammin(i4))/100:parammax(i4)];
+end
+if parammin(i5) > 0,
+    vector5 = logspace(log(parammin(i5))/log(10),log(parammax(i5))/log(10),101);
+else
+    vector5 = [parammin(i5):(parammax(i5)-parammin(i5))/100:parammax(i5)];
+end
+if parammin(i6) > 0,
+    vector6 = logspace(log(parammin(i6))/log(10),log(parammax(i6))/log(10),101);
+else
+    vector6 = [parammin(i6):(parammax(i6)-parammin(i6))/100:parammax(i6)];
+end
+if parammin(i7) > 0,
+    vector7 = logspace(log(parammin(i7))/log(10),log(parammax(i7))/log(10),101);
+else
+    vector7 = [parammin(i7):(parammax(i7)-parammin(i7))/100:parammax(i7)];
+end
+% set sliders
+[dummy,index] = min(abs(vector1-parametervalues(i1)));
+set(handles.manualslider1,'Value',index);
+[dummy,index] = min(abs(vector2-parametervalues(i2)));
+set(handles.manualslider2,'Value',index);
+[dummy,index] = min(abs(vector3-parametervalues(i3)));
+set(handles.manualslider3,'Value',index);
+[dummy,index] = min(abs(vector4-parametervalues(i4)));
+set(handles.manualslider4,'Value',index);
+[dummy,index] = min(abs(vector5-parametervalues(i5)));
+set(handles.manualslider5,'Value',index);
+[dummy,index] = min(abs(vector6-parametervalues(i6)));
+set(handles.manualslider6,'Value',index);
+[dummy,index] = min(abs(vector7-parametervalues(i7)));
+set(handles.manualslider7,'Value',index);
+% set slider steps
+set(handles.manualslider1,'SliderStep',[0.01 0.01]);
+set(handles.manualslider2,'SliderStep',[0.01 0.01]);
+set(handles.manualslider3,'SliderStep',[0.01 0.01]);
+set(handles.manualslider4,'SliderStep',[0.01 0.01]);
+set(handles.manualslider5,'SliderStep',[0.01 0.01]);
+set(handles.manualslider6,'SliderStep',[0.01 0.01]);
+set(handles.manualslider7,'SliderStep',[0.01 0.01]);
+% set Enable to off for the elements
+nrtakeaway = length(strmatchIQM('No Parameter',parameters,'exact'));
+if nrtakeaway >= 7,
+    set(handles.manualslider1,'Enable','off');
+    set(handles.manualmax1,'Enable','off');
+    set(handles.manualmin1,'Enable','off');
+    set(handles.manualparam1,'Enable','off');
+end
+if nrtakeaway >= 6,
+    set(handles.manualslider2,'Enable','off');
+    set(handles.manualmax2,'Enable','off');
+    set(handles.manualmin2,'Enable','off');
+    set(handles.manualparam2,'Enable','off');
+end
+if nrtakeaway >= 5,
+    set(handles.manualslider3,'Enable','off');
+    set(handles.manualmax3,'Enable','off');
+    set(handles.manualmin3,'Enable','off');
+    set(handles.manualparam3,'Enable','off');
+end
+if nrtakeaway >= 4,
+    set(handles.manualslider4,'Enable','off');
+    set(handles.manualmax4,'Enable','off');
+    set(handles.manualmin4,'Enable','off');
+    set(handles.manualparam4,'Enable','off');
+end
+if nrtakeaway >= 3,
+    set(handles.manualslider5,'Enable','off');
+    set(handles.manualmax5,'Enable','off');
+    set(handles.manualmin5,'Enable','off');
+    set(handles.manualparam5,'Enable','off');
+end
+if nrtakeaway >= 2,
+    set(handles.manualslider6,'Enable','off');
+    set(handles.manualmax6,'Enable','off');
+    set(handles.manualmin6,'Enable','off');
+    set(handles.manualparam6,'Enable','off');
+end
+if nrtakeaway >= 1,
+    set(handles.manualslider7,'Enable','off');
+    set(handles.manualmax7,'Enable','off');
+    set(handles.manualmin7,'Enable','off');
+    set(handles.manualparam7,'Enable','off');
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Slider1 handling function
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function slider1_Callback(hObject, eventdata, handles)
+% get slider settings
+v = ceil(get(handles.manualslider1,'Value'));                       %%%
+% get min max settings
+maxV = str2double(get(handles.manualmax1,'String'));                %%%
+minV = str2double(get(handles.manualmin1,'String'));                %%%
+% construct vectors
+if minV > 0,
+    vector = logspace(log(minV)/log(10),log(maxV)/log(10),101);
+else
+    vector = [minV:(maxV-minV)/100:maxV];
+end
+% get paramvalues
+value = vector(v);
+% set parameter value
+set(handles.value1,'String',value);                                 %%%
+% update parameter information structure in handles with new values
+m = get(handles.modelselection,'Value');
+pindex = get(handles.manualparam1,'Value');                         %%%
+handles.parammodel(m).values(pindex) = value;
+% sim and plot
+handles = doSimAndPlot(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Slider2 handling function
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function slider2_Callback(hObject, eventdata, handles)
+% get slider settings
+v = ceil(get(handles.manualslider2,'Value'));                       %%%
+% get min max settings
+maxV = str2double(get(handles.manualmax2,'String'));                %%%
+minV = str2double(get(handles.manualmin2,'String'));                %%%
+% construct vectors
+if minV > 0,
+    vector = logspace(log(minV)/log(10),log(maxV)/log(10),101);
+else
+    vector = [minV:(maxV-minV)/100:maxV];
+end
+% get paramvalues
+value = vector(v);
+% set parameter value
+set(handles.value2,'String',value);                                 %%%
+% update parameter information structure in handles with new values
+m = get(handles.modelselection,'Value');
+pindex = get(handles.manualparam2,'Value');                         %%%
+handles.parammodel(m).values(pindex) = value;
+% sim and plot
+handles = doSimAndPlot(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Slider3 handling function
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function slider3_Callback(hObject, eventdata, handles)
+% get slider settings
+v = ceil(get(handles.manualslider3,'Value'));                       %%%
+% get min max settings
+maxV = str2double(get(handles.manualmax3,'String'));                %%%
+minV = str2double(get(handles.manualmin3,'String'));                %%%
+% construct vectors
+if minV > 0,
+    vector = logspace(log(minV)/log(10),log(maxV)/log(10),101);
+else
+    vector = [minV:(maxV-minV)/100:maxV];
+end
+% get paramvalues
+value = vector(v);
+% set parameter value
+set(handles.value3,'String',value);                                 %%%
+% update parameter information structure in handles with new values
+m = get(handles.modelselection,'Value');
+pindex = get(handles.manualparam3,'Value');                         %%%
+handles.parammodel(m).values(pindex) = value;
+% sim and plot
+handles = doSimAndPlot(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Slider4 handling function
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function slider4_Callback(hObject, eventdata, handles)
+% get slider settings
+v = ceil(get(handles.manualslider4,'Value'));                       %%%
+% get min max settings
+maxV = str2double(get(handles.manualmax4,'String'));                %%%
+minV = str2double(get(handles.manualmin4,'String'));                %%%
+% construct vectors
+if minV > 0,
+    vector = logspace(log(minV)/log(10),log(maxV)/log(10),101);
+else
+    vector = [minV:(maxV-minV)/100:maxV];
+end
+% get paramvalues
+value = vector(v);
+% set parameter value
+set(handles.value4,'String',value);                                 %%%
+% update parameter information structure in handles with new values
+m = get(handles.modelselection,'Value');
+pindex = get(handles.manualparam4,'Value');                         %%%
+handles.parammodel(m).values(pindex) = value;
+% sim and plot
+handles = doSimAndPlot(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Slider5 handling function
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function slider5_Callback(hObject, eventdata, handles)
+% get slider settings
+v = ceil(get(handles.manualslider5,'Value'));                       %%%
+% get min max settings
+maxV = str2double(get(handles.manualmax5,'String'));                %%%
+minV = str2double(get(handles.manualmin5,'String'));                %%%
+% construct vectors
+if minV > 0,
+    vector = logspace(log(minV)/log(10),log(maxV)/log(10),101);
+else
+    vector = [minV:(maxV-minV)/100:maxV];
+end
+% get paramvalues
+value = vector(v);
+% set parameter value
+set(handles.value5,'String',value);                                 %%%
+% update parameter information structure in handles with new values
+m = get(handles.modelselection,'Value');
+pindex = get(handles.manualparam5,'Value');                         %%%
+handles.parammodel(m).values(pindex) = value;
+% sim and plot
+handles = doSimAndPlot(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Slider6 handling function
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function slider6_Callback(hObject, eventdata, handles)
+% get slider settings
+v = ceil(get(handles.manualslider6,'Value'));                       %%%
+% get min max settings
+maxV = str2double(get(handles.manualmax6,'String'));                %%%
+minV = str2double(get(handles.manualmin6,'String'));                %%%
+% construct vectors
+if minV > 0,
+    vector = logspace(log(minV)/log(10),log(maxV)/log(10),101);
+else
+    vector = [minV:(maxV-minV)/100:maxV];
+end
+% get paramvalues
+value = vector(v);
+% set parameter value
+set(handles.value6,'String',value);                                 %%%
+% update parameter information structure in handles with new values
+m = get(handles.modelselection,'Value');
+pindex = get(handles.manualparam6,'Value');                         %%%
+handles.parammodel(m).values(pindex) = value;
+% sim and plot
+handles = doSimAndPlot(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Slider7 handling function
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function slider7_Callback(hObject, eventdata, handles)
+% get slider settings
+v = ceil(get(handles.manualslider7,'Value'));                       %%%
+% get min max settings
+maxV = str2double(get(handles.manualmax7,'String'));                %%%
+minV = str2double(get(handles.manualmin7,'String'));                %%%
+% construct vectors
+if minV > 0,
+    vector = logspace(log(minV)/log(10),log(maxV)/log(10),101);
+else
+    vector = [minV:(maxV-minV)/100:maxV];
+end
+% get paramvalues
+value = vector(v);
+% set parameter value
+set(handles.value7,'String',value);                                 %%%
+% update parameter information structure in handles with new values
+m = get(handles.modelselection,'Value');
+pindex = get(handles.manualparam7,'Value');                         %%%
+handles.parammodel(m).values(pindex) = value;
+% sim and plot
+handles = doSimAndPlot(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+
+
+% 
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% % Slider handling function
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% function slider_Callback(hObject, eventdata, handles)
+% % get slider settings
+% v1 = ceil(get(handles.manualslider1,'Value'));
+% v2 = ceil(get(handles.manualslider2,'Value'));
+% v3 = ceil(get(handles.manualslider3,'Value'));
+% v4 = ceil(get(handles.manualslider4,'Value'));
+% v5 = ceil(get(handles.manualslider5,'Value'));
+% v6 = ceil(get(handles.manualslider6,'Value'));
+% v7 = ceil(get(handles.manualslider7,'Value'));
+% % get min max settings
+% max1 = str2double(get(handles.manualmax1,'String'));
+% max2 = str2double(get(handles.manualmax2,'String'));
+% max3 = str2double(get(handles.manualmax3,'String'));
+% max4 = str2double(get(handles.manualmax4,'String'));
+% max5 = str2double(get(handles.manualmax5,'String'));
+% max6 = str2double(get(handles.manualmax6,'String'));
+% max7 = str2double(get(handles.manualmax7,'String'));
+% min1 = str2double(get(handles.manualmin1,'String'));
+% min2 = str2double(get(handles.manualmin2,'String'));
+% min3 = str2double(get(handles.manualmin3,'String'));
+% min4 = str2double(get(handles.manualmin4,'String'));
+% min5 = str2double(get(handles.manualmin5,'String'));
+% min6 = str2double(get(handles.manualmin6,'String'));
+% min7 = str2double(get(handles.manualmin7,'String'));
+% % construct vectors
+% if min1 > 0,
+%     vector1 = logspace(log(min1)/log(10),log(max1)/log(10),101);
+% else
+%     vector1 = [min1:(max1-min1)/100:max1];
+% end
+% if min2 > 0,
+%     vector2 = logspace(log(min2)/log(10),log(max2)/log(10),101);
+% else
+%     vector2 = [min2:(max2-min2)/100:max2];
+% end
+% if min3 > 0,
+%     vector3 = logspace(log(min3)/log(10),log(max3)/log(10),101);
+% else
+%     vector3 = [min3:(max3-min3)/100:max3];
+% end
+% if min4 > 0,
+%     vector4 = logspace(log(min4)/log(10),log(max4)/log(10),101);
+% else
+%     vector4 = [min4:(max4-min4)/100:max4];
+% end
+% if min5 > 0,
+%     vector5 = logspace(log(min5)/log(10),log(max5)/log(10),101);
+% else
+%     vector5 = [min5:(max5-min5)/100:max5];
+% end
+% if min6 > 0,
+%     vector6 = logspace(log(min6)/log(10),log(max6)/log(10),101);
+% else
+%     vector6 = [min6:(max6-min6)/100:max6];
+% end
+% if min7 > 0,
+%     vector7 = logspace(log(min7)/log(10),log(max7)/log(10),101);
+% else
+%     vector7 = [min7:(max7-min7)/100:max7];
+% end
+% % get paramvalues
+% values = [vector1(v1) vector2(v2) vector3(v3) vector4(v4) vector5(v5) vector6(v6) vector7(v7)];
+% % set parameter values
+% set(handles.value1,'String',values(1));
+% set(handles.value2,'String',values(2));
+% set(handles.value3,'String',values(3));
+% set(handles.value4,'String',values(4));
+% set(handles.value5,'String',values(5));
+% set(handles.value6,'String',values(6));
+% set(handles.value7,'String',values(7));
+% % update parameter information structure in handles with new values
+% m = get(handles.modelselection,'Value');
+% pindex = [];
+% pindex(end+1) = get(handles.manualparam1,'Value');
+% pindex(end+1) = get(handles.manualparam2,'Value');
+% pindex(end+1) = get(handles.manualparam3,'Value');
+% pindex(end+1) = get(handles.manualparam4,'Value');
+% pindex(end+1) = get(handles.manualparam5,'Value');
+% pindex(end+1) = get(handles.manualparam6,'Value');
+% pindex(end+1) = get(handles.manualparam7,'Value');
+% handles.parammodel(m).values(pindex) = values;
+% % sim and plot
+% handles = doSimAndPlot(handles);
+% % Update handles structure
+% guidata(hObject, handles);
+% return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Minmax handling function
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function minmax1_Callback(hObject, eventdata, handles)
+% get max min values
+max1 = str2double(get(handles.manualmax1,'String'));
+min1 = str2double(get(handles.manualmin1,'String'));
+% get slider setting
+v1 = ceil(get(handles.manualslider1,'Value'));
+% get current value
+value1 = str2double(get(handles.value1,'String'));
+% check and adjust bounds if needed
+if value1 < min1, value1 = min1; end
+if value1 > max1, value1 = max1; end
+% set slider value to correspond to value
+if min1 > 0,
+    vector1 = logspace(log(min1)/log(10),log(max1)/log(10),101);
+else
+    vector1 = [min1:(max1-min1)/100:max1];
+end
+[dummy,index] = min(abs(vector1-value1));
+set(handles.manualslider1,'Value',index);
+% update values field
+value1 = vector1(index);
+set(handles.value1,'String',value1);
+% update parameter information structure in handles with new value
+m = get(handles.modelselection,'Value');
+pindex = get(handles.manualparam1,'Value');
+handles.parammodel(m).max(pindex) = max1;
+handles.parammodel(m).min(pindex) = min1;
+handles.parammodel(m).values(pindex) = value1;
+% sim and plot
+handles = doSimAndPlot(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+function minmax2_Callback(hObject, eventdata, handles)
+% get max min values
+max2 = str2double(get(handles.manualmax2,'String'));
+min2 = str2double(get(handles.manualmin2,'String'));
+% get slider setting
+v2 = ceil(get(handles.manualslider2,'Value'));
+% get current value
+value2 = str2double(get(handles.value2,'String'));
+% check and adjust bounds if needed
+if value2 < min2, value2 = min2; end
+if value2 > max2, value2 = max2; end
+% set slider value to correspond to value
+if min2 > 0,
+    vector2 = logspace(log(min2)/log(10),log(max2)/log(10),101);
+else
+    vector2 = [min2:(max2-min2)/100:max2];
+end
+[dummy,index] = min(abs(vector2-value2));
+set(handles.manualslider2,'Value',index);
+% update values field
+value2 = vector2(index);
+set(handles.value2,'String',value2);
+% update parameter information structure in handles with new value
+m = get(handles.modelselection,'Value');
+pindex = get(handles.manualparam2,'Value');
+handles.parammodel(m).max(pindex) = max2;
+handles.parammodel(m).min(pindex) = min2;
+handles.parammodel(m).values(pindex) = value2;
+% sim and plot
+handles = doSimAndPlot(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+function minmax3_Callback(hObject, eventdata, handles)
+% get max min values
+max3 = str2double(get(handles.manualmax3,'String'));
+min3 = str2double(get(handles.manualmin3,'String'));
+% get slider setting
+v3 = ceil(get(handles.manualslider3,'Value'));
+% get current value
+value3 = str2double(get(handles.value3,'String'));
+% check and adjust bounds if needed
+if value3 < min3, value3 = min3; end
+if value3 > max3, value3 = max3; end
+% set slider value to correspond to value
+if min3 > 0,
+    vector3 = logspace(log(min3)/log(10),log(max3)/log(10),101);
+else
+    vector3 = [min3:(max3-min3)/100:max3];
+end
+[dummy,index] = min(abs(vector3-value3));
+set(handles.manualslider3,'Value',index);
+% update values field
+value3 = vector3(index);
+set(handles.value3,'String',value3);
+% update parameter information structure in handles with new value
+m = get(handles.modelselection,'Value');
+pindex = get(handles.manualparam3,'Value');
+handles.parammodel(m).max(pindex) = max3;
+handles.parammodel(m).min(pindex) = min3;
+handles.parammodel(m).values(pindex) = value3;
+% sim and plot
+handles = doSimAndPlot(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+function minmax4_Callback(hObject, eventdata, handles)
+% get max min values
+max4 = str2double(get(handles.manualmax4,'String'));
+min4 = str2double(get(handles.manualmin4,'String'));
+% get slider setting
+v4 = ceil(get(handles.manualslider4,'Value'));
+% get current value
+value4 = str2double(get(handles.value4,'String'));
+% check and adjust bounds if needed
+if value4 < min4, value4 = min4; end
+if value4 > max4, value4 = max4; end
+% set slider value to correspond to value
+if min4 > 0,
+    vector4 = logspace(log(min4)/log(10),log(max4)/log(10),101);
+else
+    vector4 = [min4:(max4-min4)/100:max4];
+end
+[dummy,index] = min(abs(vector4-value4));
+set(handles.manualslider4,'Value',index);
+% update values field
+value4 = vector4(index);
+set(handles.value4,'String',value4);
+% update parameter information structure in handles with new value
+m = get(handles.modelselection,'Value');
+pindex = get(handles.manualparam4,'Value');
+handles.parammodel(m).max(pindex) = max4;
+handles.parammodel(m).min(pindex) = min4;
+handles.parammodel(m).values(pindex) = value4;
+% sim and plot
+handles = doSimAndPlot(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+function minmax5_Callback(hObject, eventdata, handles)
+% get max min values
+max5 = str2double(get(handles.manualmax5,'String'));
+min5 = str2double(get(handles.manualmin5,'String'));
+% get slider setting
+v5 = ceil(get(handles.manualslider5,'Value'));
+% get current value
+value5 = str2double(get(handles.value5,'String'));
+% check and adjust bounds if needed
+if value5 < min5, value5 = min5; end
+if value5 > max5, value5 = max5; end
+% set slider value to correspond to value
+if min5 > 0,
+    vector5 = logspace(log(min5)/log(10),log(max5)/log(10),101);
+else
+    vector5 = [min5:(max5-min5)/100:max5];
+end
+[dummy,index] = min(abs(vector5-value5));
+set(handles.manualslider5,'Value',index);
+% update values field
+value5 = vector5(index);
+set(handles.value5,'String',value5);
+% update parameter information structure in handles with new value
+m = get(handles.modelselection,'Value');
+pindex = get(handles.manualparam5,'Value');
+handles.parammodel(m).max(pindex) = max5;
+handles.parammodel(m).min(pindex) = min5;
+handles.parammodel(m).values(pindex) = value5;
+% sim and plot
+handles = doSimAndPlot(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+function minmax6_Callback(hObject, eventdata, handles)
+% get max min values
+max6 = str2double(get(handles.manualmax6,'String'));
+min6 = str2double(get(handles.manualmin6,'String'));
+% get slider setting
+v6 = ceil(get(handles.manualslider6,'Value'));
+% get current value
+value6 = str2double(get(handles.value6,'String'));
+% check and adjust bounds if needed
+if value6 < min6, value6 = min6; end
+if value6 > max6, value6 = max6; end
+% set slider value to correspond to value
+if min6 > 0,
+    vector6 = logspace(log(min6)/log(10),log(max6)/log(10),101);
+else
+    vector6 = [min6:(max6-min6)/100:max6];
+end
+[dummy,index] = min(abs(vector6-value6));
+set(handles.manualslider6,'Value',index);
+% update values field
+value6 = vector6(index);
+set(handles.value6,'String',value6);
+% update parameter information structure in handles with new value
+m = get(handles.modelselection,'Value');
+pindex = get(handles.manualparam6,'Value');
+handles.parammodel(m).max(pindex) = max6;
+handles.parammodel(m).min(pindex) = min6;
+handles.parammodel(m).values(pindex) = value6;
+% sim and plot
+handles = doSimAndPlot(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+function minmax7_Callback(hObject, eventdata, handles)
+% get max min values
+max7 = str2double(get(handles.manualmax7,'String'));
+min7 = str2double(get(handles.manualmin7,'String'));
+% get slider setting
+v7 = ceil(get(handles.manualslider7,'Value'));
+% get current value
+value7 = str2double(get(handles.value7,'String'));
+% check and adjust bounds if needed
+if value7 < min7, value7 = min7; end
+if value7 > max7, value7 = max7; end
+% set slider value to correspond to value
+if min7 > 0,
+    vector7 = logspace(log(min7)/log(10),log(max7)/log(10),101);
+else
+    vector7 = [min7:(max7-min7)/100:max7];
+end
+[dummy,index] = min(abs(vector7-value7));
+set(handles.manualslider7,'Value',index);
+% update values field
+value7 = vector7(index);
+set(handles.value7,'String',value7);
+% update parameter information structure in handles with new value
+m = get(handles.modelselection,'Value');
+pindex = get(handles.manualparam7,'Value');
+handles.parammodel(m).max(pindex) = max7;
+handles.parammodel(m).min(pindex) = min7;
+handles.parammodel(m).values(pindex) = value7;
+% sim and plot
+handles = doSimAndPlot(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% MODEL PARAMETER HANDLING
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function manualparam1_Callback(hObject, eventdata, handles)
+m = get(handles.modelselection,'Value');
+pindex = get(handles.manualparam1,'Value');
+paramvalue = handles.parammodel(m).values(pindex);
+% set current parameter values
+set(handles.value1,'String',paramvalue);
+% set max and min values 
+max = handles.parammodel(m).max(pindex);
+min = handles.parammodel(m).min(pindex);
+set(handles.manualmax1,'String',max);
+set(handles.manualmin1,'String',min);
+% set slider min max and value
+set(handles.manualslider1,'Max',101);
+set(handles.manualslider1,'Min',1);
+% set slider value to correspond to value
+if min > 0,
+    vector = logspace(log(min)/log(10),log(max)/log(10),101);
+else
+    vector = [min:(max-min)/100:max];
+end
+[dummy,index] = minfunct(abs(vector-paramvalue));
+set(handles.manualslider1,'Value',index);
+% set slider steps
+set(handles.manualslider1,'SliderStep',[0.01 0.01]);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+function [a,b] = minfunct(X)
+[a,b] = min(X);
+return
+
+function manualparam2_Callback(hObject, eventdata, handles)
+m = get(handles.modelselection,'Value');
+pindex = get(handles.manualparam2,'Value');
+paramvalue = handles.parammodel(m).values(pindex);
+% set current parameter values
+set(handles.value2,'String',paramvalue);
+% set max and min values 
+max = handles.parammodel(m).max(pindex);
+min = handles.parammodel(m).min(pindex);
+set(handles.manualmax2,'String',max);
+set(handles.manualmin2,'String',min);
+% set slider min max and value
+set(handles.manualslider2,'Max',101);
+set(handles.manualslider2,'Min',1);
+% set slider value to correspond to value
+if min > 0,
+    vector = logspace(log(min)/log(10),log(max)/log(10),101);
+else
+    vector = [min:(max-min)/100:max];
+end
+[dummy,index] = minfunct(abs(vector-paramvalue));
+set(handles.manualslider2,'Value',index);
+% set slider steps
+set(handles.manualslider2,'SliderStep',[0.01 0.01]);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+function manualparam3_Callback(hObject, eventdata, handles)
+m = get(handles.modelselection,'Value');
+pindex = get(handles.manualparam3,'Value');
+paramvalue = handles.parammodel(m).values(pindex);
+% set current parameter values
+set(handles.value3,'String',paramvalue);
+% set max and min values 
+max = handles.parammodel(m).max(pindex);
+min = handles.parammodel(m).min(pindex);
+set(handles.manualmax3,'String',max);
+set(handles.manualmin3,'String',min);
+% set slider min max and value
+set(handles.manualslider3,'Max',101);
+set(handles.manualslider3,'Min',1);
+% set slider value to correspond to value
+if min > 0,
+    vector = logspace(log(min)/log(10),log(max)/log(10),101);
+else
+    vector = [min:(max-min)/100:max];
+end
+[dummy,index] = minfunct(abs(vector-paramvalue));
+set(handles.manualslider3,'Value',index);
+% set slider steps
+set(handles.manualslider3,'SliderStep',[0.01 0.01]);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+function manualparam4_Callback(hObject, eventdata, handles)
+m = get(handles.modelselection,'Value');
+pindex = get(handles.manualparam4,'Value');
+paramvalue = handles.parammodel(m).values(pindex);
+% set current parameter values
+set(handles.value4,'String',paramvalue);
+% set max and min values 
+max = handles.parammodel(m).max(pindex);
+min = handles.parammodel(m).min(pindex);
+set(handles.manualmax4,'String',max);
+set(handles.manualmin4,'String',min);
+% set slider min max and value
+set(handles.manualslider4,'Max',101);
+set(handles.manualslider4,'Min',1);
+% set slider value to correspond to value
+if min > 0,
+    vector = logspace(log(min)/log(10),log(max)/log(10),101);
+else
+    vector = [min:(max-min)/100:max];
+end
+[dummy,index] = minfunct(abs(vector-paramvalue));
+set(handles.manualslider4,'Value',index);
+% set slider steps
+set(handles.manualslider4,'SliderStep',[0.01 0.01]);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+function manualparam5_Callback(hObject, eventdata, handles)
+m = get(handles.modelselection,'Value');
+pindex = get(handles.manualparam5,'Value');
+paramvalue = handles.parammodel(m).values(pindex);
+% set current parameter values
+set(handles.value5,'String',paramvalue);
+% set max and min values 
+max = handles.parammodel(m).max(pindex);
+min = handles.parammodel(m).min(pindex);
+set(handles.manualmax5,'String',max);
+set(handles.manualmin5,'String',min);
+% set slider min max and value
+set(handles.manualslider5,'Max',101);
+set(handles.manualslider5,'Min',1);
+% set slider value to correspond to value
+if min > 0,
+    vector = logspace(log(min)/log(10),log(max)/log(10),101);
+else
+    vector = [min:(max-min)/100:max];
+end
+[dummy,index] = minfunct(abs(vector-paramvalue));
+set(handles.manualslider5,'Value',index);
+% set slider steps
+set(handles.manualslider5,'SliderStep',[0.01 0.01]);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+function manualparam6_Callback(hObject, eventdata, handles)
+m = get(handles.modelselection,'Value');
+pindex = get(handles.manualparam6,'Value');
+paramvalue = handles.parammodel(m).values(pindex);
+% set current parameter values
+set(handles.value6,'String',paramvalue);
+% set max and min values 
+max = handles.parammodel(m).max(pindex);
+min = handles.parammodel(m).min(pindex);
+set(handles.manualmax6,'String',max);
+set(handles.manualmin6,'String',min);
+% set slider min max and value
+set(handles.manualslider6,'Max',101);
+set(handles.manualslider6,'Min',1);
+% set slider value to correspond to value
+if min > 0,
+    vector = logspace(log(min)/log(10),log(max)/log(10),101);
+else
+    vector = [min:(max-min)/100:max];
+end
+[dummy,index] = minfunct(abs(vector-paramvalue));
+set(handles.manualslider6,'Value',index);
+% set slider steps
+set(handles.manualslider6,'SliderStep',[0.01 0.01]);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+function manualparam7_Callback(hObject, eventdata, handles)
+m = get(handles.modelselection,'Value');
+pindex = get(handles.manualparam7,'Value');
+paramvalue = handles.parammodel(m).values(pindex);
+% set current parameter values
+set(handles.value7,'String',paramvalue);
+% set max and min values 
+max = handles.parammodel(m).max(pindex);
+min = handles.parammodel(m).min(pindex);
+set(handles.manualmax7,'String',max);
+set(handles.manualmin7,'String',min);
+% set slider min max and value
+set(handles.manualslider7,'Max',101);
+set(handles.manualslider7,'Min',1);
+% set slider value to correspond to value
+if min > 0,
+    vector = logspace(log(min)/log(10),log(max)/log(10),101);
+else
+    vector = [min:(max-min)/100:max];
+end
+[dummy,index] = minfunct(abs(vector-paramvalue));
+set(handles.manualslider7,'Value',index);
+% set slider steps
+set(handles.manualslider7,'SliderStep',[0.01 0.01]);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INITIALIZE PLOTDATA (includes MEXfile data)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [plotdata] = initializePlotdata(projectstruct,modelindex,handles)
+% GET ALL MEASUREMENT INFORMATION
+infostruct = [];
+for k=1:length(projectstruct.models(modelindex)),
+    model = projectstruct.models{modelindex(k)};
+    experiments = projectstruct.experiments(handles.experimentindices);
+    displayFlag = 0;
+    expmeasinfo = getexpmeasinfoIQM(model,modelindex(k),experiments,handles.experimentindices,displayFlag);
+    infostruct(k).modelstruct = IQMstruct(projectstruct.models{modelindex(k)});
+    infostruct(k).modelindex = modelindex(k);
+    infostruct(k).expinfostruct = expmeasinfo;
+end
+% ADD SIMULATION DATA TO THE STRUCTURE
+plotdata = [];
+plotdata.project = projectstruct.name;
+plotdata.notes = projectstruct.notes;
+plotdata.model = [];
+% run through all models
+for m=1:length(projectstruct.models(modelindex)),
+    % model data
+    modelstruct = infostruct(m).modelstruct;
+    plotdata.model(m).name = modelstruct.name;      
+    plotdata.model(m).notes = modelstruct.notes;
+    allmeasuredcomponents = {};
+    for e=1:length(infostruct(m).expinfostruct),
+        % experiment data
+        plotdata.model(m).experiment(e).name = infostruct(m).expinfostruct(e).experimentname;
+        plotdata.model(m).experiment(e).mexmodel = infostruct(m).expinfostruct(e).model;
+        plotdata.model(m).experiment(e).mexfullpath = infostruct(m).expinfostruct(e).mexfullpath;
+        timevector = infostruct(m).expinfostruct(e).timevector;
+        timestart = timevector(1);
+        timeend = timevector(end);
+        timevectorsim = [timestart:(timeend-timestart)/1000:timeend];
+        plotdata.model(m).experiment(e).timevector = timevectorsim;
+        expstatenames = infostruct(m).expinfostruct(e).statenames;          
+        expvariablenames = infostruct(m).expinfostruct(e).variablenames; 
+        plotdata.model(m).experiment(e).componentnames = {expstatenames{:} expvariablenames{:}};  
+        % simulate to get the state and variable values
+        mexmodel = infostruct(m).expinfostruct(e).model;
+        ic = infostruct(m).expinfostruct(e).initialconditions;
+        plotdata.model(m).experiment(e).initialconditions = ic;
+        try
+            simdata = feval(mexmodel,timevectorsim,ic,[],handles.integratoroptions);
+        catch
+            simdata.statevalues = NaN(length(timevectorsim),length(ic));
+            simdata.variablevalues = NaN(length(timevectorsim),length(ic));
+%            disp(sprintf('Integrator problems for experiment %d.',e));
+        end
+        % collect all states that are measured
+        stateindices = infostruct(m).expinfostruct(e).stateindices;
+        variableindices = infostruct(m).expinfostruct(e).variableindices;
+        plotdata.model(m).experiment(e).stateindices = stateindices;
+        plotdata.model(m).experiment(e).variableindices = variableindices;
+        statevalues = simdata.statevalues(:,stateindices);
+        variablevalues = simdata.variablevalues(:,variableindices);
+        % add simulated state trajectories
+        plotdata.model(m).experiment(e).componentvalues = [statevalues variablevalues];
+        for meas=1:length(infostruct(m).expinfostruct(e).measurement),
+            % measurement data
+            plotdata.model(m).experiment(e).measurement(meas).name = infostruct(m).expinfostruct(e).measurement(meas).name;
+            timevectormeas = timevector(infostruct(m).expinfostruct(e).measurement(meas).timevectorindices);
+            plotdata.model(m).experiment(e).measurement(meas).timevector = timevectormeas;
+            % reorder the measurements
+            measstatenames = infostruct(m).expinfostruct(e).measurement(meas).statenames;
+            measvariablenames = infostruct(m).expinfostruct(e).measurement(meas).variablenames;
+            % states 
+            for k=1:length(expstatenames),
+                index = strmatchIQM(expstatenames{k},measstatenames,'exact');
+                if ~isempty(index),
+                    plotdata.model(m).experiment(e).measurement(meas).componentnames{k} = measstatenames{index};
+                    plotdata.model(m).experiment(e).measurement(meas).componentvalues(:,k) = infostruct(m).expinfostruct(e).measurement(meas).statereferences(:,index);
+                    plotdata.model(m).experiment(e).measurement(meas).maxvalues(:,k) = infostruct(m).expinfostruct(e).measurement(meas).statemaxvalues(:,index);
+                    plotdata.model(m).experiment(e).measurement(meas).minvalues(:,k) = infostruct(m).expinfostruct(e).measurement(meas).stateminvalues(:,index);
+                else
+                    plotdata.model(m).experiment(e).measurement(meas).componentnames{k} = 'not available';
+                    plotdata.model(m).experiment(e).measurement(meas).componnentvalues(:,k) = NaN(length(timevectormeas),1);
+                    plotdata.model(m).experiment(e).measurement(meas).maxvalues(:,k) = NaN(length(timevectormeas),1);
+                    plotdata.model(m).experiment(e).measurement(meas).minvalues(:,k) = NaN(length(timevectormeas),1);
+                end                    
+            end
+            offset = length(expstatenames);
+            % variables
+            for k=1:length(expvariablenames),
+                index = strmatchIQM(expvariablenames{k},measvariablenames,'exact');
+                if ~isempty(index),
+                    plotdata.model(m).experiment(e).measurement(meas).componentnames{offset+k} = measvariablenames{index};
+                    plotdata.model(m).experiment(e).measurement(meas).componentvalues(:,offset+k) = infostruct(m).expinfostruct(e).measurement(meas).variablereferences(:,index);
+                    plotdata.model(m).experiment(e).measurement(meas).maxvalues(:,offset+k) = infostruct(m).expinfostruct(e).measurement(meas).variablemaxvalues(:,index);
+                    plotdata.model(m).experiment(e).measurement(meas).minvalues(:,offset+k) = infostruct(m).expinfostruct(e).measurement(meas).variableminvalues(:,index);
+                else
+                    plotdata.model(m).experiment(e).measurement(meas).componentnames{offset+k} = 'not available';
+                    plotdata.model(m).experiment(e).measurement(meas).componentvalues(:,offset+k) = NaN(length(timevectormeas),1);
+                    plotdata.model(m).experiment(e).measurement(meas).maxvalues(:,offset+k) = NaN(length(timevectormeas),1);
+                    plotdata.model(m).experiment(e).measurement(meas).minvalues(:,offset+k) = NaN(length(timevectormeas),1);
+                end                    
+            end      
+            allmeasuredcomponents = {allmeasuredcomponents{:} plotdata.model(m).experiment(e).measurement(meas).componentnames{:}};
+        end
+    end
+    allmeasuredcomponents = unique(allmeasuredcomponents);
+    plotdata.model(m).allmeascomponents = allmeasuredcomponents;
+end     
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% TRIVIAL FUNCTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% --- Executes on button press in zoombutton.
+function legendbutton_Callback(hObject, eventdata, handles)
+% toogle the legends in the figure
+if handles.legendflag == 0,
+    handles.legendflag = 1;
+else
+    handles.legendflag = 0;
+end
+% plot
+doPlot(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+% --- Executes on button press in zoombutton.
+function errorbarbutton_Callback(hObject, eventdata, handles)
+% toogle the errorbars in the figure
+if handles.errorbars == 0,
+    handles.errorbars = 1;
+else
+    handles.errorbars = 0;
+end
+% plot
+doPlot(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+% --- Executes on button press in zoombutton.
+function zoombutton_Callback(hObject, eventdata, handles)
+% toogle the zoom in the figure
+zoom
+return
+
+% --- Executes on button press in gridbutton.
+function gridbutton_Callback(hObject, eventdata, handles)
+% toogle the grid in the figure
+grid
+if handles.grid == 1,
+    handles.grid = 0;
+else
+    handles.grid = 1;
+end
+% Update handles structure
+guidata(hObject, handles);
+return
+
+% --- Executes on selection change in modelselection.
+function modelselection_Callback(hObject, eventdata, handles)
+try
+    modelindex = get(handles.modelselection,'Value');
+    set(handles.experimentselection,'String',{handles.plotdata.model(modelindex).experiment.name});
+    doPlot(handles);
+catch
+    errordlg('This selection is not possible.','Error','on');               
+end
+% set all parameter selection boxes with parameter names (model dependent)
+initializeParameterLists(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+% --- Executes on selection change in resetall.
+function resetall_Callback(hObject, eventdata, handles)
+m = get(handles.modelselection,'Value');
+% reset all values for current model to starting values
+handles.parammodel(m).values = handles.parammodel(m).startvalues;
+handles.parammodel(m).max = handles.parammodel(m).startmax;
+handles.parammodel(m).min = handles.parammodel(m).startmin;
+% reinitialize parameter list
+initializeParameterLists(handles,'resetall');
+% simulate and plot it
+handles = doSimAndPlot(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+% --- Executes on selection change in resetcurrent.
+function resetcurrent_Callback(hObject, eventdata, handles)
+m = get(handles.modelselection,'Value');
+% reset all values for current model and current parameter selections to starting values
+% get current indices
+pindices = [];
+pindices(end+1) = get(handles.manualparam1,'Value');
+pindices(end+1) = get(handles.manualparam2,'Value');
+pindices(end+1) = get(handles.manualparam3,'Value');
+pindices(end+1) = get(handles.manualparam4,'Value');
+pindices(end+1) = get(handles.manualparam5,'Value');
+pindices(end+1) = get(handles.manualparam6,'Value');
+pindices(end+1) = get(handles.manualparam7,'Value');
+% reset values for current parameters
+handles.parammodel(m).values(pindices) = handles.parammodel(m).startvalues(pindices);
+handles.parammodel(m).max(pindices) = handles.parammodel(m).startmax(pindices);
+handles.parammodel(m).min(pindices) = handles.parammodel(m).startmin(pindices);
+% reinitialize parameter list
+initializeParameterLists(handles,'resetcurrent');
+% simulate and plot it
+handles = doSimAndPlot(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+% --- Executes on selection change in experimentselection.
+function experimentselection_Callback(hObject, eventdata, handles)
+try
+    doPlot(handles);
+catch
+    errordlg('This selection is not possible.','Error','on');               
+end
+% check if only one experiment selected ... then show the simulate button
+% otherwise hide it
+eall = get(handles.experimentselection,'Value');
+if length(eall) > 1,
+    set(handles.simexpbutton,'Enable','off');
+    set(handles.simexpbutton,'BackgroundColor',[0.8 0.8 0.8]);
+else
+    set(handles.simexpbutton,'Enable','on');
+    set(handles.simexpbutton,'BackgroundColor',[1 0.745 0.49]);
+end
+% Update handles structure
+guidata(hObject, handles);
+return
+
+% --- Executes on selection change in experimentselection.
+function componentselection_Callback(hObject, eventdata, handles)
+try
+    doPlot(handles);
+catch
+    errordlg('This selection is not possible.','Error','on');               
+end
+return
+
+% --- Executes on button press in plot.
+function plot_Callback(hObject, eventdata, handles)
+handles.dataPlotType = 'plot';
+% disable errorbarbutton
+set(handles.errorbarbutton,'Visible','on');
+% Update handles structure
+guidata(hObject, handles);
+doPlot(handles);
+return
+
+% --- Executes on button press in loglog.
+function semilogx_Callback(hObject, eventdata, handles)
+handles.dataPlotType = 'semilogx';
+% disable errorbarbutton
+set(handles.errorbarbutton,'Visible','off');
+handles.errorbars = 0;
+% Update handles structure
+guidata(hObject, handles);
+doPlot(handles);
+return
+
+% --- Executes on button press in semilogx.
+function semilogy_Callback(hObject, eventdata, handles)
+handles.dataPlotType = 'semilogy';
+% disable errorbarbutton
+set(handles.errorbarbutton,'Visible','off');
+handles.errorbars = 0;
+% Update handles structure
+guidata(hObject, handles);
+doPlot(handles);
+return
+
+% --- Executes on button press in loglog.
+function loglog_Callback(hObject, eventdata, handles)
+handles.dataPlotType = 'loglog';
+% disable errorbarbutton
+set(handles.errorbarbutton,'Visible','off');
+handles.errorbars = 0;
+% Update handles structure
+guidata(hObject, handles);
+doPlot(handles);
+return
+
+% --- Simulate current model with current experiment and display in IQMplot window
+function simulatebutton_Callback(hObject, eventdata, handles)
+m = get(handles.modelselection,'Value');
+e = get(handles.experimentselection,'Value');
+name = handles.plotdata.model(m).experiment(e).name;
+
+    mexmodel = handles.plotdata.model(m).experiment(e).mexmodel;
+    timevector = handles.plotdata.model(m).experiment(e).timevector;
+    ic = handles.plotdata.model(m).experiment(e).initialconditions;
+    % take away the things that are no parameters
+    noParamIndices = strmatchIQM('No Parameter',handles.parammodel(m).names,'exact');
+    paramIndices = setdiff([1:length(handles.parammodel(m).names)],noParamIndices);
+    paramnames = handles.parammodel(m).names(paramIndices);
+    paramvalues = handles.parammodel(m).values(paramIndices);
+
+simdata = IQMPsimulate(mexmodel,timevector,ic,paramnames,paramvalues,handles.integratoroptions);
+% remove '_' from name
+name = strrep(name,'_',' ');
+plotdatastruct = createdatastruct2IQMplotIQM(simdata,name);
+IQMplot(plotdatastruct);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+% --- Set axis bounds
+function bounds_Callback(hObject, eventdata, handles)
+try 
+    handles.boundsaxis = eval(get(handles.bounds,'String'));
+catch
+    handles.boundsaxis = NaN;
+    set(handles.bounds,'String','Nominal');
+end
+if length(handles.boundsaxis) ~= 4,
+    handles.boundsaxis = NaN;
+    set(handles.bounds,'String','Nominal');
+end    
+% Update handles structure
+guidata(hObject, handles);
+doPlot(handles);
+return
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMmodeltuningGUI/IQMmodeltuning.m b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMmodeltuningGUI/IQMmodeltuning.m
new file mode 100644
index 0000000000000000000000000000000000000000..e3f9448aa1fe5d9e4134f032a086e43800f1361b
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMmodeltuningGUI/IQMmodeltuning.m	
@@ -0,0 +1,133 @@
+function [modeltuned] = IQMmodeltuning(model,data,varargin)
+% IQMmodeltuning: Allows to compare and tune a model to one or more sets
+% of data. Here: No experiment description is required, the model is
+% assumed to already include the experimental settings.
+% If no data is available, a time vector can be provided. The model can
+% then be tuned. For comparison the simulation result of the nominal model
+% is also shown.
+%
+% USAGE:
+% ======
+% modeltuned = IQMmodeltuning(model,data)
+% modeltuned = IQMmodeltuning(model,data,options)
+% modeltuned = IQMmodeltuning(model,time)
+%
+% model: IQMmodel to tune
+% data:  Single IQMmeasurement object or cell-array with IQMmeasurement
+%        objects to which to fit the model
+% time:  timevector to use for model simulation
+% options: still unused
+%
+% DEFAULT VALUES:
+% ===============
+%
+% Output Arguments:
+% =================
+% modeltuned: The tuned model with changed parameters
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin == 2,
+    options = [];
+elseif nargin == 3,
+    options = varargin{1};
+else 
+    error('Incorrect number of input arguments.');
+end
+if ~isIQMmodel(model),
+    error('Function only defined for IQMmodels.');
+end
+if iscell(data),
+    for k=1:length(data),
+        if ~isIQMmeasurement(data{k}),
+            error('Error in the data input argument (IQMmeasurement required).');
+        end
+    end
+elseif isIQMmeasurement(data),
+    data = {data};
+elseif isnumeric(data),
+    time = data;
+    if length(time) == 1,
+        time = [0:time/1000:time];
+    end
+    data = {createDummyMeasurement(time,model)};
+else
+    error('Error in the data input argument (IQMmeasurement required).');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CREATE DUMMY PROJECT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+p = IQMprojectSB();                          % create empty project
+p = IQMupdatemodel(p,model);               % add model
+e = IQMexperiment(); es = struct(e); es.name = 'Empty Experiment'; e = IQMexperiment(es);
+p = IQMupdateexperiment(p,e); % add empty experiment
+for k=1:length(data),
+    p = IQMupdatemeasurement(p,1,data{k}); % add measurements
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Determine parameters changed by events
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Parameters that are changed by events are not allowed to be changed by the user during tuning
+ms = struct(model);
+pnames = {ms.parameters.name};
+% collect all assignment variables in all events that are parameters
+apnames = {};
+for k=1:length(ms.events),
+    for k2=1:length(ms.events(k).assignment),
+        vname = ms.events(k).assignment(k2).variable;
+        if ~isempty(strmatchIQM(vname,pnames,'exact')),
+            apnames{end+1} = vname;
+        end
+    end
+end
+apnames = unique(apnames);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CALL IQMmanualtuning
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ptuned = modeltuningIQM(p,1,apnames);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET TUNED MODEL
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+modeltuned = IQMgetmodel(ptuned,1);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% FINSIHED => RETURN
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Create a dummy measurement 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [dummymeas] = createDummyMeasurement(time,model)
+% Simulate the model over given time-vector
+simdata = IQMPsimulate(model,time);
+% create IQMmeasurement structure
+ms = struct(IQMmeasurement);
+ms.name = 'Nominal model';
+ms.notes = '';
+ms.time = time;
+for k=1:length(simdata.states),
+    ms.data(end+1).name = simdata.states{k};
+    ms.data(end).notes = '';
+    ms.data(end).values = simdata.statevalues(:,k);
+    x = NaN(size(simdata.statevalues(:,k)));
+    ms.data(end).maxvalues = x;
+    ms.data(end).minvalues = x;
+end
+for k=1:length(simdata.variables),
+    ms.data(end+1).name = simdata.variables{k};
+    ms.data(end).notes = '';
+    ms.data(end).values = simdata.variablevalues(:,k);
+    x = NaN(size(simdata.variablevalues(:,k)));
+    ms.data(end).maxvalues = x;
+    ms.data(end).minvalues = x;
+end
+dummymeas = IQMmeasurement(ms);
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMmodeltuningGUI/modeltuningIQM.fig b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMmodeltuningGUI/modeltuningIQM.fig
new file mode 100644
index 0000000000000000000000000000000000000000..b5660c8a3b154affb5fcd365a7e49358f02e472e
Binary files /dev/null and b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMmodeltuningGUI/modeltuningIQM.fig differ
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMmodeltuningGUI/modeltuningIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMmodeltuningGUI/modeltuningIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..12fb0e4fcadac61d42f0b92e4658a6e655b71321
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMmodeltuningGUI/modeltuningIQM.m	
@@ -0,0 +1,1424 @@
+function varargout = modeltuningIQM(varargin)
+% modeltuningIQM: Allows to compare and tune a model to measured data.
+% Each measured component is displayed in a single plot against the
+% measured data (possible multiple measurements).
+%
+% Function to a very large extent based on IQMmanualtuning. 
+%
+% NOTE: This function should not be called directly. It is called via the
+% IQMmodeltuning function.
+% 
+% USAGE:
+% ======
+% [project] = modeltuningIQM(project,modelindex,apnames,apvalues)
+%
+% project: IQMprojectSB to tune manually. 
+% modelindex: The index of the model in the project to use for tuning.
+% apnames: cell-array of model parameter names that are changed by events
+%   in the model (not allowed to be tuned and need to be reseted after each
+%   simulation)
+% apvalues: vector with the nominal values for the "apnames" parameters
+%
+% Output Arguments:
+% =================
+% The manually tuned project is given back.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INITIALIZATION CODE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Begin initialization code - DO NOT EDIT
+gui_Singleton = 1;
+gui_State = struct('gui_Name',       mfilename, ...
+                   'gui_Singleton',  gui_Singleton, ...
+                   'gui_OpeningFcn', @modeltuningIQM_OpeningFcn, ...
+                   'gui_OutputFcn',  @modeltuningIQM_OutputFcn, ...
+                   'gui_LayoutFcn',  [] , ...
+                   'gui_Callback',   []);
+if nargin && ischar(varargin{1})
+    gui_State.gui_Callback = str2func(varargin{1});
+end
+if nargout
+    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
+else
+    gui_mainfcn(gui_State, varargin{:});
+end
+% End initialization code - DO NOT EDIT
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INTERFACE FUNCTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% --- Executes just before modeltuningIQM is made visible.
+function modeltuningIQM_OpeningFcn(hObject, eventdata, handles, varargin)
+if nargin~=6,
+    error('Incorrect number of input arguments.');
+end
+project = varargin{1};
+if ~isIQMprojectSB(project), 
+    error('Input argument is not an IQMprojectSB.'); 
+end
+modelindex = varargin{2};
+event_param_names = varargin{3};
+% Integrator options (could be input argument later on)
+OPTIONS = [];
+% OPTIONS.abstol = 1e-10;
+% OPTIONS.reltol = 1e-10;
+% disp('!!!!!!!!!!!!!!!!!!!!!!')
+% disp('TOLERANCE SET TO 1e-10')
+% disp('!!!!!!!!!!!!!!!!!!!!!!')
+
+% assignments in handles structure
+handles.modelindex = modelindex;
+handles.projectstruct = struct(project);
+handles.estimation = [];       % not used in here
+handles.integratoroptions = OPTIONS;
+handles.event_param_names = event_param_names;
+handles.nrsliders = 7;  % not really used everywhere yet
+handles.saveORIGprojectstruct = handles.projectstruct; % save the unchanged project structure for output 
+handles.experimentindices = 1; % just a single experiment
+
+% initialize the plotdata
+handles.plotdata = initializePlotdata(handles.projectstruct,modelindex,handles);
+
+% set modelselection and choose first model (only one model in project)
+handles.modelselection = 1;
+
+% set experimentselection and choose first experiment (only one experiment in the project)
+handles.experimentselection = 1;
+
+% set component selection
+set(handles.componentselection,'String',handles.plotdata.model(1).allmeascomponents);
+set(handles.componentselection,'Value',1);
+
+% determine parameter data
+handles = getparamdata(handles);
+
+% set all parameter selection boxes with parameter names (model dependent)
+initializeParameterLists(handles);
+% select plottype
+handles.dataPlotType = 'plot';     
+% set errorbarflag to 1
+handles.errorbars = 1;
+% Initialize export figure handle and grid flag
+handles.exportFigureHandle = [];
+handles.grid = 0;
+% Doing a first plot
+doPlot(handles);
+% Choose default command line output for modeltuningIQM
+handles.output = hObject;
+% Update handles structure
+guidata(hObject, handles);
+uiwait;
+return
+
+% --- Outputs from this function are returned to the command line.
+function varargout = modeltuningIQM_OutputFcn(hObject, eventdata, handles) 
+% varargout  cell array for returning output args (see VARARGOUT);
+varargout{1} = handles.output;
+% delete temporary MEX models
+global compiledExpModelsIQMparamestGUI % if not empty then models are precompiled and should not be deleted
+if isempty(compiledExpModelsIQMparamestGUI),
+    clear mex
+    for m=1:length(handles.plotdata.model)
+        for e=1:length(handles.plotdata.model(m).experiment),
+            delete(handles.plotdata.model(m).experiment(e).mexfullpath);
+        end
+    end
+end
+% close the GUI
+delete(hObject);
+return
+
+% --- Closed by user
+function modeltuningIQM_CloseRequestFcn(hObject, eventdata, handles)
+exit_Callback(hObject, eventdata, handles)
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EXIT modeltuningIQM CALLBACK
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function exit_Callback(hObject, eventdata, handles)
+    % construct the output (its just an updated IQMprojectSB in which the 
+    % manually tuned parametervalues are entered)
+    % FOR THIS USE THE SAVED ORIG PROJECT!
+    for k=1:length(handles.modelindex),
+        m = handles.modelindex(k);
+        % get model to update
+        model = handles.saveORIGprojectstruct.models{m};
+        % set manually tuned parameters
+        % take away the things that are no parameters
+        noParamIndices = strmatchIQM('No Parameter',handles.parammodel(k).names,'exact');
+        paramIndices = setdiff([1:length(handles.parammodel(k).names)],noParamIndices);
+        paramnames = handles.parammodel(k).names(paramIndices);
+        paramvalues = handles.parammodel(k).values(paramIndices);
+        model = IQMparameters(model,paramnames,paramvalues);
+        % add model to project
+        handles.saveORIGprojectstruct.models{m} = model;
+    end
+    handles.output = IQMprojectSB(handles.saveORIGprojectstruct);
+    % Update handles structure
+    guidata(hObject, handles);
+    uiresume;
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% SIMULATION FUNCTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function handles=doSimAndPlot(handles)
+% get the parameter values to use for simulation
+m = handles.modelselection;
+%pv = handles.parammodel(m).values;
+% run through all experiments and perform them for the parameter settings
+for e = 1:length(handles.plotdata.model(m).experiment),
+    mexmodel = handles.plotdata.model(m).experiment(e).mexmodel;
+    timevector = handles.plotdata.model(m).experiment(e).timevector;
+    ic = handles.plotdata.model(m).experiment(e).initialconditions;
+    % take away the things that are no parameters
+    noParamIndices = strmatchIQM('No Parameter',handles.parammodel(m).names,'exact');
+    paramIndices = setdiff([1:length(handles.parammodel(m).names)],noParamIndices);
+    paramnames = handles.parammodel(m).names(paramIndices);
+    paramvalues = handles.parammodel(m).values(paramIndices);
+    % construct parameter vector for simulation
+    pv = makeparamvecIQM(mexmodel,paramnames,paramvalues);
+    try
+        simdata = feval(mexmodel,timevector,ic,pv,handles.integratoroptions);
+    catch
+        simdata = [];
+        break;
+    end
+    stateindices = handles.plotdata.model(m).experiment(e).stateindices;
+    statevalues = simdata.statevalues(:,stateindices);
+    variableindices = handles.plotdata.model(m).experiment(e).variableindices;
+    variablevalues = simdata.variablevalues(:,variableindices);
+    handles.plotdata.model(m).experiment(e).componentvalues = [statevalues variablevalues];
+end
+if ~isempty(simdata),
+    doPlot(handles);
+else
+    errordlg('Parameter setting leads to error.');
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PLOT FUNCTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% For each selected component a single plot will be shown
+function doPlot(handles)
+colorvector = {'b','g','r','c','m','y','k'};
+warning off;
+% get the data to plot
+plotdata = handles.plotdata;
+m = handles.modelselection;
+e = handles.experimentselection;
+callnames = get(handles.componentselection,'String');
+callselected = get(handles.componentselection,'Value');
+NTOTAL = length(callselected);
+NROW = ceil(sqrt(NTOTAL));
+NCOL = ceil(NTOTAL/NROW);
+for sp = 1:NTOTAL,
+    % component name ... for plotting
+    cname = callnames{callselected(sp)};
+    % generate subplot and get data
+    subplot(NROW,NCOL,sp,'Parent',handles.plotpanel);
+    edata = plotdata.model(m).experiment(e);
+    % general information
+    titletext = cname;
+    xlabeltext = 'Time';
+    % simulated data information
+    sim_timevector = edata.timevector;
+    sim_componentnames = cname;
+    index = strmatchIQM(cname,edata.componentnames,'exact');
+    sim_componentvalues = edata.componentvalues(:,index);
+    % plot simulated data
+    feval(handles.dataPlotType,sim_timevector,sim_componentvalues,'k','linewidth',2); hold on;
+    % plot measured data
+    for meas=1:length(edata.measurement),
+        meas_timevector = edata.measurement(meas).timevector;
+        meas_componentnames = edata.measurement(meas).componentnames;
+        meas_componentvalues = edata.measurement(meas).componentvalues;
+        meas_maxvalues = edata.measurement(meas).maxvalues;
+        meas_minvalues = edata.measurement(meas).minvalues;
+        index = strmatchIQM(cname,meas_componentnames,'exact');
+        if ~isempty(index),
+            % plot the measured values
+            meas_componentvalues = meas_componentvalues(:,index);
+            color = colorvector{mod(meas-1,length(colorvector))+1};
+            feval(handles.dataPlotType,meas_timevector,meas_componentvalues,[color '.'],'linewidth',2); hold on;        
+            % plot the errorbars (if desired)
+            meas_maxvalues = meas_maxvalues(:,index);
+            meas_minvalues = meas_minvalues(:,index);
+            if handles.errorbars == 1 && strcmp(handles.dataPlotType,'plot'),
+                % plot errorbars
+                for k1 = 1:length(meas_timevector),
+                    feval(handles.dataPlotType,[meas_timevector(k1),meas_timevector(k1)],[meas_minvalues(k1),meas_maxvalues(k1)],['.:',color]);
+                end
+            end
+        end
+    end
+    hold off;
+    hlhlx = legend(sim_componentnames);
+    set(hlhlx,'Interpreter','none');
+    hlhlx = title(titletext);
+    set(hlhlx,'Interpreter','none');
+    hlhlx = xlabel(xlabeltext);
+    set(hlhlx,'Interpreter','none');
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Determine parameter data and save in handles structure
+% Only parameters that appear in all expmmexmodels are considered.
+% Furthermore, they need to have the same values (so that they are not
+% modified due to experimental settings)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function handles = getparamdata(handles)
+% CODE VALID ONLY IF HANDLES.ESTIMATION = [] (THE CASE HERE)
+for m = 1:length(handles.plotdata.model),
+    % get parameter names that appear in all expmexmodels
+    for e = 1:length(handles.plotdata.model(m).experiment),
+        model = handles.plotdata.model(m).experiment(e).mexmodel;
+        if e == 1,
+            parameters = feval(model,'parameters');
+        else
+            parameters = intersect(parameters, feval(model,'parameters'));
+        end
+    end
+    % keep only those parameters that have the same value (not changed by
+    % experiment or changed equally)
+    indexdelete = [];
+    for e = 1:length(handles.plotdata.model(m).experiment),
+        model = handles.plotdata.model(m).experiment(e).mexmodel;
+        if e == 1,
+            % first run just get the parametervalues
+            parametervalues = IQMparameters(model,parameters);
+        else
+            % subsequent runs ... check if equal and get the indices of the
+            % non equal entries
+            pv = IQMparameters(model,parameters);
+            indexdelete = unique([indexdelete(:)', find(pv(:)'~=parametervalues(:)')]);
+        end
+    end
+    indexkeep = setdiff([1:length(parameters)],indexdelete);
+    parameters = parameters(indexkeep);
+    % FINALLY ALSO REMOVE THE PARAMETERS THAT ARE CHANGED BY EVENTS DURING
+    % THE SIMULATION (DEFINED IN: handles.event_param_names)
+    parameters = setdiff(parameters,handles.event_param_names);
+    parametervalues = IQMparameters(model,parameters);
+    % add param info to structure
+    handles.parammodel(m).names = parameters;
+    handles.parammodel(m).values = parametervalues;
+    handles.parammodel(m).startvalues = parametervalues;
+    max = 100*parametervalues;
+    max(find(max==0)) = 1;
+    handles.parammodel(m).max = max;
+    handles.parammodel(m).startmax = max;
+    handles.parammodel(m).min = 0.01*parametervalues;
+    handles.parammodel(m).startmin = 0.01*parametervalues;
+end
+% if fewer parameters than handles.nrsliders then add dummy ones
+if length(parametervalues) < handles.nrsliders,
+    for k=1:(handles.nrsliders-length(parametervalues)),
+        handles.parammodel.names{end+1} = 'No Parameter';
+        handles.parammodel.values(end+1) = NaN;
+        handles.parammodel.startvalues(end+1) = NaN;
+        handles.parammodel.max(end+1) = NaN;
+        handles.parammodel.startmax(end+1) = NaN;
+        handles.parammodel.min(end+1) = NaN;
+        handles.parammodel.startmin(end+1) = NaN;
+    end
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Initialize parameter lists
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [] = initializeParameterLists(handles,varargin)
+if nargin == 1,
+    i1 = 1;
+    i2 = 2;
+    i3 = 3;
+    i4 = 4;
+    i5 = 5;
+    i6 = 6;
+    i7 = 7;
+elseif nargin == 2,
+    if strcmp(varargin{1},'resetall'),
+        i1 = 1;
+        i2 = 2;
+        i3 = 3;
+        i4 = 4;
+        i5 = 5;
+        i6 = 6;
+        i7 = 7;
+    else
+        i1 = get(handles.manualparam1,'Value');
+        i2 = get(handles.manualparam2,'Value');
+        i3 = get(handles.manualparam3,'Value');
+        i4 = get(handles.manualparam4,'Value');
+        i5 = get(handles.manualparam5,'Value');
+        i6 = get(handles.manualparam6,'Value');
+        i7 = get(handles.manualparam7,'Value');
+    end
+end
+
+m = handles.modelselection;
+% get the models parameters and values
+parameters = handles.parammodel(m).names;
+parametervalues = handles.parammodel(m).values;
+parammax = handles.parammodel(m).max;
+parammin = handles.parammodel(m).min;
+% set the 7 parameter lists (adjust list of parameters)
+nrtakeaway = length(strmatchIQM('No Parameter',parameters,'exact'));
+if nrtakeaway > 0,
+    endindex = handles.nrsliders-nrtakeaway;
+    set(handles.manualparam1,'String',parameters(1:endindex));
+    set(handles.manualparam2,'String',parameters(1:endindex));
+    set(handles.manualparam3,'String',parameters(1:endindex));
+    set(handles.manualparam4,'String',parameters(1:endindex));
+    set(handles.manualparam5,'String',parameters(1:endindex));
+    set(handles.manualparam6,'String',parameters(1:endindex));
+    set(handles.manualparam7,'String',parameters(1:endindex));
+else
+    set(handles.manualparam1,'String',parameters);
+    set(handles.manualparam2,'String',parameters);
+    set(handles.manualparam3,'String',parameters);
+    set(handles.manualparam4,'String',parameters);
+    set(handles.manualparam5,'String',parameters);
+    set(handles.manualparam6,'String',parameters);
+    set(handles.manualparam7,'String',parameters);
+end    
+% set selected values
+set(handles.manualparam1,'Value',i1);
+set(handles.manualparam2,'Value',i2);
+set(handles.manualparam3,'Value',i3);
+set(handles.manualparam4,'Value',i4);
+set(handles.manualparam5,'Value',i5);
+set(handles.manualparam6,'Value',i6);
+set(handles.manualparam7,'Value',i7);
+% set current parameter values
+set(handles.value1,'String',parametervalues(i1));
+set(handles.value2,'String',parametervalues(i2));
+set(handles.value3,'String',parametervalues(i3));
+set(handles.value4,'String',parametervalues(i4));
+set(handles.value5,'String',parametervalues(i5));
+set(handles.value6,'String',parametervalues(i6));
+set(handles.value7,'String',parametervalues(i7));
+% set max and min values per default to *100 / *0.01
+set(handles.manualmax1,'String',parammax(i1));
+set(handles.manualmax2,'String',parammax(i2));
+set(handles.manualmax3,'String',parammax(i3));
+set(handles.manualmax4,'String',parammax(i4));
+set(handles.manualmax5,'String',parammax(i5));
+set(handles.manualmax6,'String',parammax(i6));
+set(handles.manualmax7,'String',parammax(i7));
+set(handles.manualmin1,'String',parammin(i1));
+set(handles.manualmin2,'String',parammin(i2));
+set(handles.manualmin3,'String',parammin(i3));
+set(handles.manualmin4,'String',parammin(i4));
+set(handles.manualmin5,'String',parammin(i5));
+set(handles.manualmin6,'String',parammin(i6));
+set(handles.manualmin7,'String',parammin(i7));
+% set slider min max and value
+set(handles.manualslider1,'Max',101);
+set(handles.manualslider2,'Max',101);
+set(handles.manualslider3,'Max',101);
+set(handles.manualslider4,'Max',101);
+set(handles.manualslider5,'Max',101);
+set(handles.manualslider6,'Max',101);
+set(handles.manualslider7,'Max',101);
+set(handles.manualslider1,'Min',1);
+set(handles.manualslider2,'Min',1);
+set(handles.manualslider3,'Min',1);
+set(handles.manualslider4,'Min',1);
+set(handles.manualslider5,'Min',1);
+set(handles.manualslider6,'Min',1);
+set(handles.manualslider7,'Min',1);
+% construct vectors
+if parammin(i1) > 0,
+    vector1 = logspace(log(parammin(i1))/log(10),log(parammax(i1))/log(10),101);
+else
+    vector1 = [parammin(i1):(parammax(i1)-parammin(i1))/100:parammax(i1)];
+end
+if parammin(i2) > 0,
+    vector2 = logspace(log(parammin(i2))/log(10),log(parammax(i2))/log(10),101);
+else
+    vector2 = [parammin(i2):(parammax(i2)-parammin(i2))/100:parammax(i2)];
+end
+if parammin(i3) > 0,
+    vector3 = logspace(log(parammin(i3))/log(10),log(parammax(i3))/log(10),101);
+else
+    vector3 = [parammin(i3):(parammax(i3)-parammin(i3))/100:parammax(i3)];
+end
+if parammin(i4) > 0,
+    vector4 = logspace(log(parammin(i4))/log(10),log(parammax(i4))/log(10),101);
+else
+    vector4 = [parammin(i4):(parammax(i4)-parammin(i4))/100:parammax(i4)];
+end
+if parammin(i5) > 0,
+    vector5 = logspace(log(parammin(i5))/log(10),log(parammax(i5))/log(10),101);
+else
+    vector5 = [parammin(i5):(parammax(i5)-parammin(i5))/100:parammax(i5)];
+end
+if parammin(i6) > 0,
+    vector6 = logspace(log(parammin(i6))/log(10),log(parammax(i6))/log(10),101);
+else
+    vector6 = [parammin(i6):(parammax(i6)-parammin(i6))/100:parammax(i6)];
+end
+if parammin(i7) > 0,
+    vector7 = logspace(log(parammin(i7))/log(10),log(parammax(i7))/log(10),101);
+else
+    vector7 = [parammin(i7):(parammax(i7)-parammin(i7))/100:parammax(i7)];
+end
+% set sliders
+[dummy,index] = min(abs(vector1-parametervalues(i1)));
+set(handles.manualslider1,'Value',index);
+[dummy,index] = min(abs(vector2-parametervalues(i2)));
+set(handles.manualslider2,'Value',index);
+[dummy,index] = min(abs(vector3-parametervalues(i3)));
+set(handles.manualslider3,'Value',index);
+[dummy,index] = min(abs(vector4-parametervalues(i4)));
+set(handles.manualslider4,'Value',index);
+[dummy,index] = min(abs(vector5-parametervalues(i5)));
+set(handles.manualslider5,'Value',index);
+[dummy,index] = min(abs(vector6-parametervalues(i6)));
+set(handles.manualslider6,'Value',index);
+[dummy,index] = min(abs(vector7-parametervalues(i7)));
+set(handles.manualslider7,'Value',index);
+% set slider steps
+set(handles.manualslider1,'SliderStep',[0.01 0.01]);
+set(handles.manualslider2,'SliderStep',[0.01 0.01]);
+set(handles.manualslider3,'SliderStep',[0.01 0.01]);
+set(handles.manualslider4,'SliderStep',[0.01 0.01]);
+set(handles.manualslider5,'SliderStep',[0.01 0.01]);
+set(handles.manualslider6,'SliderStep',[0.01 0.01]);
+set(handles.manualslider7,'SliderStep',[0.01 0.01]);
+% set Enable to off for the elements
+nrtakeaway = length(strmatchIQM('No Parameter',parameters,'exact'));
+if nrtakeaway >= 7,
+    set(handles.manualslider1,'Enable','off');
+    set(handles.manualmax1,'Enable','off');
+    set(handles.manualmin1,'Enable','off');
+    set(handles.manualparam1,'Enable','off');
+end
+if nrtakeaway >= 6,
+    set(handles.manualslider2,'Enable','off');
+    set(handles.manualmax2,'Enable','off');
+    set(handles.manualmin2,'Enable','off');
+    set(handles.manualparam2,'Enable','off');
+end
+if nrtakeaway >= 5,
+    set(handles.manualslider3,'Enable','off');
+    set(handles.manualmax3,'Enable','off');
+    set(handles.manualmin3,'Enable','off');
+    set(handles.manualparam3,'Enable','off');
+end
+if nrtakeaway >= 4,
+    set(handles.manualslider4,'Enable','off');
+    set(handles.manualmax4,'Enable','off');
+    set(handles.manualmin4,'Enable','off');
+    set(handles.manualparam4,'Enable','off');
+end
+if nrtakeaway >= 3,
+    set(handles.manualslider5,'Enable','off');
+    set(handles.manualmax5,'Enable','off');
+    set(handles.manualmin5,'Enable','off');
+    set(handles.manualparam5,'Enable','off');
+end
+if nrtakeaway >= 2,
+    set(handles.manualslider6,'Enable','off');
+    set(handles.manualmax6,'Enable','off');
+    set(handles.manualmin6,'Enable','off');
+    set(handles.manualparam6,'Enable','off');
+end
+if nrtakeaway >= 1,
+    set(handles.manualslider7,'Enable','off');
+    set(handles.manualmax7,'Enable','off');
+    set(handles.manualmin7,'Enable','off');
+    set(handles.manualparam7,'Enable','off');
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Slider1 handling function
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function slider1_Callback(hObject, eventdata, handles)
+% get slider settings
+v = ceil(get(handles.manualslider1,'Value'));                       %%%
+% get min max settings
+maxV = str2double(get(handles.manualmax1,'String'));                %%%
+minV = str2double(get(handles.manualmin1,'String'));                %%%
+% construct vectors
+if minV > 0,
+    vector = logspace(log(minV)/log(10),log(maxV)/log(10),101);
+else
+    vector = [minV:(maxV-minV)/100:maxV];
+end
+% get paramvalues
+value = vector(v);
+% set parameter value
+set(handles.value1,'String',value);                                 %%%
+% update parameter information structure in handles with new values
+m = handles.modelselection;
+pindex = get(handles.manualparam1,'Value');                         %%%
+handles.parammodel(m).values(pindex) = value;
+% sim and plot
+handles = doSimAndPlot(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Slider2 handling function
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function slider2_Callback(hObject, eventdata, handles)
+% get slider settings
+v = ceil(get(handles.manualslider2,'Value'));                       %%%
+% get min max settings
+maxV = str2double(get(handles.manualmax2,'String'));                %%%
+minV = str2double(get(handles.manualmin2,'String'));                %%%
+% construct vectors
+if minV > 0,
+    vector = logspace(log(minV)/log(10),log(maxV)/log(10),101);
+else
+    vector = [minV:(maxV-minV)/100:maxV];
+end
+% get paramvalues
+value = vector(v);
+% set parameter value
+set(handles.value2,'String',value);                                 %%%
+% update parameter information structure in handles with new values
+m = handles.modelselection;
+pindex = get(handles.manualparam2,'Value');                         %%%
+handles.parammodel(m).values(pindex) = value;
+% sim and plot
+handles = doSimAndPlot(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Slider3 handling function
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function slider3_Callback(hObject, eventdata, handles)
+% get slider settings
+v = ceil(get(handles.manualslider3,'Value'));                       %%%
+% get min max settings
+maxV = str2double(get(handles.manualmax3,'String'));                %%%
+minV = str2double(get(handles.manualmin3,'String'));                %%%
+% construct vectors
+if minV > 0,
+    vector = logspace(log(minV)/log(10),log(maxV)/log(10),101);
+else
+    vector = [minV:(maxV-minV)/100:maxV];
+end
+% get paramvalues
+value = vector(v);
+% set parameter value
+set(handles.value3,'String',value);                                 %%%
+% update parameter information structure in handles with new values
+m = handles.modelselection;
+pindex = get(handles.manualparam3,'Value');                         %%%
+handles.parammodel(m).values(pindex) = value;
+% sim and plot
+handles = doSimAndPlot(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Slider4 handling function
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function slider4_Callback(hObject, eventdata, handles)
+% get slider settings
+v = ceil(get(handles.manualslider4,'Value'));                       %%%
+% get min max settings
+maxV = str2double(get(handles.manualmax4,'String'));                %%%
+minV = str2double(get(handles.manualmin4,'String'));                %%%
+% construct vectors
+if minV > 0,
+    vector = logspace(log(minV)/log(10),log(maxV)/log(10),101);
+else
+    vector = [minV:(maxV-minV)/100:maxV];
+end
+% get paramvalues
+value = vector(v);
+% set parameter value
+set(handles.value4,'String',value);                                 %%%
+% update parameter information structure in handles with new values
+m = handles.modelselection;
+pindex = get(handles.manualparam4,'Value');                         %%%
+handles.parammodel(m).values(pindex) = value;
+% sim and plot
+handles = doSimAndPlot(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Slider5 handling function
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function slider5_Callback(hObject, eventdata, handles)
+% get slider settings
+v = ceil(get(handles.manualslider5,'Value'));                       %%%
+% get min max settings
+maxV = str2double(get(handles.manualmax5,'String'));                %%%
+minV = str2double(get(handles.manualmin5,'String'));                %%%
+% construct vectors
+if minV > 0,
+    vector = logspace(log(minV)/log(10),log(maxV)/log(10),101);
+else
+    vector = [minV:(maxV-minV)/100:maxV];
+end
+% get paramvalues
+value = vector(v);
+% set parameter value
+set(handles.value5,'String',value);                                 %%%
+% update parameter information structure in handles with new values
+m = handles.modelselection;
+pindex = get(handles.manualparam5,'Value');                         %%%
+handles.parammodel(m).values(pindex) = value;
+% sim and plot
+handles = doSimAndPlot(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Slider6 handling function
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function slider6_Callback(hObject, eventdata, handles)
+% get slider settings
+v = ceil(get(handles.manualslider6,'Value'));                       %%%
+% get min max settings
+maxV = str2double(get(handles.manualmax6,'String'));                %%%
+minV = str2double(get(handles.manualmin6,'String'));                %%%
+% construct vectors
+if minV > 0,
+    vector = logspace(log(minV)/log(10),log(maxV)/log(10),101);
+else
+    vector = [minV:(maxV-minV)/100:maxV];
+end
+% get paramvalues
+value = vector(v);
+% set parameter value
+set(handles.value6,'String',value);                                 %%%
+% update parameter information structure in handles with new values
+m = handles.modelselection;
+pindex = get(handles.manualparam6,'Value');                         %%%
+handles.parammodel(m).values(pindex) = value;
+% sim and plot
+handles = doSimAndPlot(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Slider7 handling function
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function slider7_Callback(hObject, eventdata, handles)
+% get slider settings
+v = ceil(get(handles.manualslider7,'Value'));                       %%%
+% get min max settings
+maxV = str2double(get(handles.manualmax7,'String'));                %%%
+minV = str2double(get(handles.manualmin7,'String'));                %%%
+% construct vectors
+if minV > 0,
+    vector = logspace(log(minV)/log(10),log(maxV)/log(10),101);
+else
+    vector = [minV:(maxV-minV)/100:maxV];
+end
+% get paramvalues
+value = vector(v);
+% set parameter value
+set(handles.value7,'String',value);                                 %%%
+% update parameter information structure in handles with new values
+m = handles.modelselection;
+pindex = get(handles.manualparam7,'Value');                         %%%
+handles.parammodel(m).values(pindex) = value;
+% sim and plot
+handles = doSimAndPlot(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Minmax handling function
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function minmax1_Callback(hObject, eventdata, handles)
+% get max min values
+max1 = str2double(get(handles.manualmax1,'String'));
+min1 = str2double(get(handles.manualmin1,'String'));
+% get slider setting
+v1 = ceil(get(handles.manualslider1,'Value'));
+% get current value
+value1 = str2double(get(handles.value1,'String'));
+% check and adjust bounds if needed
+if value1 < min1, value1 = min1; end
+if value1 > max1, value1 = max1; end
+% set slider value to correspond to value
+if min1 > 0,
+    vector1 = logspace(log(min1)/log(10),log(max1)/log(10),101);
+else
+    vector1 = [min1:(max1-min1)/100:max1];
+end
+[dummy,index] = min(abs(vector1-value1));
+set(handles.manualslider1,'Value',index);
+% update values field
+value1 = vector1(index);
+set(handles.value1,'String',value1);
+% update parameter information structure in handles with new value
+m = handles.modelselection;
+pindex = get(handles.manualparam1,'Value');
+handles.parammodel(m).max(pindex) = max1;
+handles.parammodel(m).min(pindex) = min1;
+handles.parammodel(m).values(pindex) = value1;
+% sim and plot
+handles = doSimAndPlot(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+function minmax2_Callback(hObject, eventdata, handles)
+% get max min values
+max2 = str2double(get(handles.manualmax2,'String'));
+min2 = str2double(get(handles.manualmin2,'String'));
+% get slider setting
+v2 = ceil(get(handles.manualslider2,'Value'));
+% get current value
+value2 = str2double(get(handles.value2,'String'));
+% check and adjust bounds if needed
+if value2 < min2, value2 = min2; end
+if value2 > max2, value2 = max2; end
+% set slider value to correspond to value
+if min2 > 0,
+    vector2 = logspace(log(min2)/log(10),log(max2)/log(10),101);
+else
+    vector2 = [min2:(max2-min2)/100:max2];
+end
+[dummy,index] = min(abs(vector2-value2));
+set(handles.manualslider2,'Value',index);
+% update values field
+value2 = vector2(index);
+set(handles.value2,'String',value2);
+% update parameter information structure in handles with new value
+m = handles.modelselection;
+pindex = get(handles.manualparam2,'Value');
+handles.parammodel(m).max(pindex) = max2;
+handles.parammodel(m).min(pindex) = min2;
+handles.parammodel(m).values(pindex) = value2;
+% sim and plot
+handles = doSimAndPlot(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+function minmax3_Callback(hObject, eventdata, handles)
+% get max min values
+max3 = str2double(get(handles.manualmax3,'String'));
+min3 = str2double(get(handles.manualmin3,'String'));
+% get slider setting
+v3 = ceil(get(handles.manualslider3,'Value'));
+% get current value
+value3 = str2double(get(handles.value3,'String'));
+% check and adjust bounds if needed
+if value3 < min3, value3 = min3; end
+if value3 > max3, value3 = max3; end
+% set slider value to correspond to value
+if min3 > 0,
+    vector3 = logspace(log(min3)/log(10),log(max3)/log(10),101);
+else
+    vector3 = [min3:(max3-min3)/100:max3];
+end
+[dummy,index] = min(abs(vector3-value3));
+set(handles.manualslider3,'Value',index);
+% update values field
+value3 = vector3(index);
+set(handles.value3,'String',value3);
+% update parameter information structure in handles with new value
+m = handles.modelselection;
+pindex = get(handles.manualparam3,'Value');
+handles.parammodel(m).max(pindex) = max3;
+handles.parammodel(m).min(pindex) = min3;
+handles.parammodel(m).values(pindex) = value3;
+% sim and plot
+handles = doSimAndPlot(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+function minmax4_Callback(hObject, eventdata, handles)
+% get max min values
+max4 = str2double(get(handles.manualmax4,'String'));
+min4 = str2double(get(handles.manualmin4,'String'));
+% get slider setting
+v4 = ceil(get(handles.manualslider4,'Value'));
+% get current value
+value4 = str2double(get(handles.value4,'String'));
+% check and adjust bounds if needed
+if value4 < min4, value4 = min4; end
+if value4 > max4, value4 = max4; end
+% set slider value to correspond to value
+if min4 > 0,
+    vector4 = logspace(log(min4)/log(10),log(max4)/log(10),101);
+else
+    vector4 = [min4:(max4-min4)/100:max4];
+end
+[dummy,index] = min(abs(vector4-value4));
+set(handles.manualslider4,'Value',index);
+% update values field
+value4 = vector4(index);
+set(handles.value4,'String',value4);
+% update parameter information structure in handles with new value
+m = handles.modelselection;
+pindex = get(handles.manualparam4,'Value');
+handles.parammodel(m).max(pindex) = max4;
+handles.parammodel(m).min(pindex) = min4;
+handles.parammodel(m).values(pindex) = value4;
+% sim and plot
+handles = doSimAndPlot(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+function minmax5_Callback(hObject, eventdata, handles)
+% get max min values
+max5 = str2double(get(handles.manualmax5,'String'));
+min5 = str2double(get(handles.manualmin5,'String'));
+% get slider setting
+v5 = ceil(get(handles.manualslider5,'Value'));
+% get current value
+value5 = str2double(get(handles.value5,'String'));
+% check and adjust bounds if needed
+if value5 < min5, value5 = min5; end
+if value5 > max5, value5 = max5; end
+% set slider value to correspond to value
+if min5 > 0,
+    vector5 = logspace(log(min5)/log(10),log(max5)/log(10),101);
+else
+    vector5 = [min5:(max5-min5)/100:max5];
+end
+[dummy,index] = min(abs(vector5-value5));
+set(handles.manualslider5,'Value',index);
+% update values field
+value5 = vector5(index);
+set(handles.value5,'String',value5);
+% update parameter information structure in handles with new value
+m = handles.modelselection;
+pindex = get(handles.manualparam5,'Value');
+handles.parammodel(m).max(pindex) = max5;
+handles.parammodel(m).min(pindex) = min5;
+handles.parammodel(m).values(pindex) = value5;
+% sim and plot
+handles = doSimAndPlot(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+function minmax6_Callback(hObject, eventdata, handles)
+% get max min values
+max6 = str2double(get(handles.manualmax6,'String'));
+min6 = str2double(get(handles.manualmin6,'String'));
+% get slider setting
+v6 = ceil(get(handles.manualslider6,'Value'));
+% get current value
+value6 = str2double(get(handles.value6,'String'));
+% check and adjust bounds if needed
+if value6 < min6, value6 = min6; end
+if value6 > max6, value6 = max6; end
+% set slider value to correspond to value
+if min6 > 0,
+    vector6 = logspace(log(min6)/log(10),log(max6)/log(10),101);
+else
+    vector6 = [min6:(max6-min6)/100:max6];
+end
+[dummy,index] = min(abs(vector6-value6));
+set(handles.manualslider6,'Value',index);
+% update values field
+value6 = vector6(index);
+set(handles.value6,'String',value6);
+% update parameter information structure in handles with new value
+m = handles.modelselection;
+pindex = get(handles.manualparam6,'Value');
+handles.parammodel(m).max(pindex) = max6;
+handles.parammodel(m).min(pindex) = min6;
+handles.parammodel(m).values(pindex) = value6;
+% sim and plot
+handles = doSimAndPlot(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+function minmax7_Callback(hObject, eventdata, handles)
+% get max min values
+max7 = str2double(get(handles.manualmax7,'String'));
+min7 = str2double(get(handles.manualmin7,'String'));
+% get slider setting
+v7 = ceil(get(handles.manualslider7,'Value'));
+% get current value
+value7 = str2double(get(handles.value7,'String'));
+% check and adjust bounds if needed
+if value7 < min7, value7 = min7; end
+if value7 > max7, value7 = max7; end
+% set slider value to correspond to value
+if min7 > 0,
+    vector7 = logspace(log(min7)/log(10),log(max7)/log(10),101);
+else
+    vector7 = [min7:(max7-min7)/100:max7];
+end
+[dummy,index] = min(abs(vector7-value7));
+set(handles.manualslider7,'Value',index);
+% update values field
+value7 = vector7(index);
+set(handles.value7,'String',value7);
+% update parameter information structure in handles with new value
+m = handles.modelselection;
+pindex = get(handles.manualparam7,'Value');
+handles.parammodel(m).max(pindex) = max7;
+handles.parammodel(m).min(pindex) = min7;
+handles.parammodel(m).values(pindex) = value7;
+% sim and plot
+handles = doSimAndPlot(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% MODEL PARAMETER HANDLING
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function manualparam1_Callback(hObject, eventdata, handles)
+m = handles.modelselection;
+pindex = get(handles.manualparam1,'Value');
+paramvalue = handles.parammodel(m).values(pindex);
+% set current parameter values
+set(handles.value1,'String',paramvalue);
+% set max and min values 
+max = handles.parammodel(m).max(pindex);
+min = handles.parammodel(m).min(pindex);
+set(handles.manualmax1,'String',max);
+set(handles.manualmin1,'String',min);
+% set slider min max and value
+set(handles.manualslider1,'Max',101);
+set(handles.manualslider1,'Min',1);
+% set slider value to correspond to value
+if min > 0,
+    vector = logspace(log(min)/log(10),log(max)/log(10),101);
+else
+    vector = [min:(max-min)/100:max];
+end
+[dummy,index] = minfunct(abs(vector-paramvalue));
+set(handles.manualslider1,'Value',index);
+% set slider steps
+set(handles.manualslider1,'SliderStep',[0.01 0.01]);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+function [a,b] = minfunct(X)
+[a,b] = min(X);
+return
+
+function manualparam2_Callback(hObject, eventdata, handles)
+m = handles.modelselection;
+pindex = get(handles.manualparam2,'Value');
+paramvalue = handles.parammodel(m).values(pindex);
+% set current parameter values
+set(handles.value2,'String',paramvalue);
+% set max and min values 
+max = handles.parammodel(m).max(pindex);
+min = handles.parammodel(m).min(pindex);
+set(handles.manualmax2,'String',max);
+set(handles.manualmin2,'String',min);
+% set slider min max and value
+set(handles.manualslider2,'Max',101);
+set(handles.manualslider2,'Min',1);
+% set slider value to correspond to value
+if min > 0,
+    vector = logspace(log(min)/log(10),log(max)/log(10),101);
+else
+    vector = [min:(max-min)/100:max];
+end
+[dummy,index] = minfunct(abs(vector-paramvalue));
+set(handles.manualslider2,'Value',index);
+% set slider steps
+set(handles.manualslider2,'SliderStep',[0.01 0.01]);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+function manualparam3_Callback(hObject, eventdata, handles)
+m = handles.modelselection;
+pindex = get(handles.manualparam3,'Value');
+paramvalue = handles.parammodel(m).values(pindex);
+% set current parameter values
+set(handles.value3,'String',paramvalue);
+% set max and min values 
+max = handles.parammodel(m).max(pindex);
+min = handles.parammodel(m).min(pindex);
+set(handles.manualmax3,'String',max);
+set(handles.manualmin3,'String',min);
+% set slider min max and value
+set(handles.manualslider3,'Max',101);
+set(handles.manualslider3,'Min',1);
+% set slider value to correspond to value
+if min > 0,
+    vector = logspace(log(min)/log(10),log(max)/log(10),101);
+else
+    vector = [min:(max-min)/100:max];
+end
+[dummy,index] = minfunct(abs(vector-paramvalue));
+set(handles.manualslider3,'Value',index);
+% set slider steps
+set(handles.manualslider3,'SliderStep',[0.01 0.01]);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+function manualparam4_Callback(hObject, eventdata, handles)
+m = handles.modelselection;
+pindex = get(handles.manualparam4,'Value');
+paramvalue = handles.parammodel(m).values(pindex);
+% set current parameter values
+set(handles.value4,'String',paramvalue);
+% set max and min values 
+max = handles.parammodel(m).max(pindex);
+min = handles.parammodel(m).min(pindex);
+set(handles.manualmax4,'String',max);
+set(handles.manualmin4,'String',min);
+% set slider min max and value
+set(handles.manualslider4,'Max',101);
+set(handles.manualslider4,'Min',1);
+% set slider value to correspond to value
+if min > 0,
+    vector = logspace(log(min)/log(10),log(max)/log(10),101);
+else
+    vector = [min:(max-min)/100:max];
+end
+[dummy,index] = minfunct(abs(vector-paramvalue));
+set(handles.manualslider4,'Value',index);
+% set slider steps
+set(handles.manualslider4,'SliderStep',[0.01 0.01]);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+function manualparam5_Callback(hObject, eventdata, handles)
+m = handles.modelselection;
+pindex = get(handles.manualparam5,'Value');
+paramvalue = handles.parammodel(m).values(pindex);
+% set current parameter values
+set(handles.value5,'String',paramvalue);
+% set max and min values 
+max = handles.parammodel(m).max(pindex);
+min = handles.parammodel(m).min(pindex);
+set(handles.manualmax5,'String',max);
+set(handles.manualmin5,'String',min);
+% set slider min max and value
+set(handles.manualslider5,'Max',101);
+set(handles.manualslider5,'Min',1);
+% set slider value to correspond to value
+if min > 0,
+    vector = logspace(log(min)/log(10),log(max)/log(10),101);
+else
+    vector = [min:(max-min)/100:max];
+end
+[dummy,index] = minfunct(abs(vector-paramvalue));
+set(handles.manualslider5,'Value',index);
+% set slider steps
+set(handles.manualslider5,'SliderStep',[0.01 0.01]);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+function manualparam6_Callback(hObject, eventdata, handles)
+m = handles.modelselection;
+pindex = get(handles.manualparam6,'Value');
+paramvalue = handles.parammodel(m).values(pindex);
+% set current parameter values
+set(handles.value6,'String',paramvalue);
+% set max and min values 
+max = handles.parammodel(m).max(pindex);
+min = handles.parammodel(m).min(pindex);
+set(handles.manualmax6,'String',max);
+set(handles.manualmin6,'String',min);
+% set slider min max and value
+set(handles.manualslider6,'Max',101);
+set(handles.manualslider6,'Min',1);
+% set slider value to correspond to value
+if min > 0,
+    vector = logspace(log(min)/log(10),log(max)/log(10),101);
+else
+    vector = [min:(max-min)/100:max];
+end
+[dummy,index] = minfunct(abs(vector-paramvalue));
+set(handles.manualslider6,'Value',index);
+% set slider steps
+set(handles.manualslider6,'SliderStep',[0.01 0.01]);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+function manualparam7_Callback(hObject, eventdata, handles)
+m = handles.modelselection;
+pindex = get(handles.manualparam7,'Value');
+paramvalue = handles.parammodel(m).values(pindex);
+% set current parameter values
+set(handles.value7,'String',paramvalue);
+% set max and min values 
+max = handles.parammodel(m).max(pindex);
+min = handles.parammodel(m).min(pindex);
+set(handles.manualmax7,'String',max);
+set(handles.manualmin7,'String',min);
+% set slider min max and value
+set(handles.manualslider7,'Max',101);
+set(handles.manualslider7,'Min',1);
+% set slider value to correspond to value
+if min > 0,
+    vector = logspace(log(min)/log(10),log(max)/log(10),101);
+else
+    vector = [min:(max-min)/100:max];
+end
+[dummy,index] = minfunct(abs(vector-paramvalue));
+set(handles.manualslider7,'Value',index);
+% set slider steps
+set(handles.manualslider7,'SliderStep',[0.01 0.01]);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INITIALIZE PLOTDATA (includes MEXfile data)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [plotdata] = initializePlotdata(projectstruct,modelindex,handles)
+% GET ALL MEASUREMENT INFORMATION
+infostruct = [];
+for k=1:length(projectstruct.models(modelindex)),
+    model = projectstruct.models{modelindex(k)};
+    experiments = projectstruct.experiments(handles.experimentindices);
+    displayFlag = 0;
+    expmeasinfo = getexpmeasinfoIQM(model,modelindex(k),experiments,handles.experimentindices,displayFlag);
+    infostruct(k).modelstruct = IQMstruct(projectstruct.models{modelindex(k)});
+    infostruct(k).modelindex = modelindex(k);
+    infostruct(k).expinfostruct = expmeasinfo;
+end
+% ADD SIMULATION DATA TO THE STRUCTURE
+plotdata = [];
+plotdata.project = projectstruct.name;
+plotdata.notes = projectstruct.notes;
+plotdata.model = [];
+% run through all models
+for m=1:length(projectstruct.models(modelindex)),
+    % model data
+    modelstruct = infostruct(m).modelstruct;
+    plotdata.model(m).name = modelstruct.name;      
+    plotdata.model(m).notes = modelstruct.notes;
+    allmeasuredcomponents = {};
+    for e=1:length(infostruct(m).expinfostruct),
+        % experiment data
+        plotdata.model(m).experiment(e).name = infostruct(m).expinfostruct(e).experimentname;
+        plotdata.model(m).experiment(e).mexmodel = infostruct(m).expinfostruct(e).model;
+        plotdata.model(m).experiment(e).mexfullpath = infostruct(m).expinfostruct(e).mexfullpath;
+        timevector = infostruct(m).expinfostruct(e).timevector;
+        timestart = timevector(1);
+        timeend = timevector(end);
+        timevectorsim = [timestart:(timeend-timestart)/1000:timeend];
+        plotdata.model(m).experiment(e).timevector = timevectorsim;
+        expstatenames = infostruct(m).expinfostruct(e).statenames;          
+        expvariablenames = infostruct(m).expinfostruct(e).variablenames; 
+        plotdata.model(m).experiment(e).componentnames = {expstatenames{:} expvariablenames{:}};  
+        % simulate to get the state and variable values
+        mexmodel = infostruct(m).expinfostruct(e).model;
+        ic = infostruct(m).expinfostruct(e).initialconditions;
+        plotdata.model(m).experiment(e).initialconditions = ic;
+        try
+            simdata = feval(mexmodel,timevectorsim,ic,[],handles.integratoroptions);
+        catch
+            simdata.statevalues = NaN(length(timevectorsim),length(ic));
+            simdata.variablevalues = NaN(length(timevectorsim),length(ic));
+        end
+        % collect all states that are measured
+        stateindices = infostruct(m).expinfostruct(e).stateindices;
+        variableindices = infostruct(m).expinfostruct(e).variableindices;
+        plotdata.model(m).experiment(e).stateindices = stateindices;
+        plotdata.model(m).experiment(e).variableindices = variableindices;
+        statevalues = simdata.statevalues(:,stateindices);
+        variablevalues = simdata.variablevalues(:,variableindices);
+        % add simulated state trajectories
+        plotdata.model(m).experiment(e).componentvalues = [statevalues variablevalues];
+        for meas=1:length(infostruct(m).expinfostruct(e).measurement),
+            % measurement data
+            plotdata.model(m).experiment(e).measurement(meas).name = infostruct(m).expinfostruct(e).measurement(meas).name;
+            timevectormeas = timevector(infostruct(m).expinfostruct(e).measurement(meas).timevectorindices);
+            plotdata.model(m).experiment(e).measurement(meas).timevector = timevectormeas;
+            % reorder the measurements
+            measstatenames = infostruct(m).expinfostruct(e).measurement(meas).statenames;
+            measvariablenames = infostruct(m).expinfostruct(e).measurement(meas).variablenames;
+            % states 
+            for k=1:length(expstatenames),
+                index = strmatchIQM(expstatenames{k},measstatenames,'exact');
+                if ~isempty(index),
+                    plotdata.model(m).experiment(e).measurement(meas).componentnames{k} = measstatenames{index};
+                    plotdata.model(m).experiment(e).measurement(meas).componentvalues(:,k) = infostruct(m).expinfostruct(e).measurement(meas).statereferences(:,index);
+                    plotdata.model(m).experiment(e).measurement(meas).maxvalues(:,k) = infostruct(m).expinfostruct(e).measurement(meas).statemaxvalues(:,index);
+                    plotdata.model(m).experiment(e).measurement(meas).minvalues(:,k) = infostruct(m).expinfostruct(e).measurement(meas).stateminvalues(:,index);
+                else
+                    plotdata.model(m).experiment(e).measurement(meas).componentnames{k} = 'not available';
+                    plotdata.model(m).experiment(e).measurement(meas).componnentvalues(:,k) = NaN(length(timevectormeas),1);
+                    plotdata.model(m).experiment(e).measurement(meas).maxvalues(:,k) = NaN(length(timevectormeas),1);
+                    plotdata.model(m).experiment(e).measurement(meas).minvalues(:,k) = NaN(length(timevectormeas),1);
+                end                    
+            end
+            offset = length(expstatenames);
+            % variables
+            for k=1:length(expvariablenames),
+                index = strmatchIQM(expvariablenames{k},measvariablenames,'exact');
+                if ~isempty(index),
+                    plotdata.model(m).experiment(e).measurement(meas).componentnames{offset+k} = measvariablenames{index};
+                    plotdata.model(m).experiment(e).measurement(meas).componentvalues(:,offset+k) = infostruct(m).expinfostruct(e).measurement(meas).variablereferences(:,index);
+                    plotdata.model(m).experiment(e).measurement(meas).maxvalues(:,offset+k) = infostruct(m).expinfostruct(e).measurement(meas).variablemaxvalues(:,index);
+                    plotdata.model(m).experiment(e).measurement(meas).minvalues(:,offset+k) = infostruct(m).expinfostruct(e).measurement(meas).variableminvalues(:,index);
+                else
+                    plotdata.model(m).experiment(e).measurement(meas).componentnames{offset+k} = 'not available';
+                    plotdata.model(m).experiment(e).measurement(meas).componentvalues(:,offset+k) = NaN(length(timevectormeas),1);
+                    plotdata.model(m).experiment(e).measurement(meas).maxvalues(:,offset+k) = NaN(length(timevectormeas),1);
+                    plotdata.model(m).experiment(e).measurement(meas).minvalues(:,offset+k) = NaN(length(timevectormeas),1);
+                end                    
+            end      
+            allmeasuredcomponents = {allmeasuredcomponents{:} plotdata.model(m).experiment(e).measurement(meas).componentnames{:}};
+        end
+    end
+    allmeasuredcomponents = unique(allmeasuredcomponents);
+    plotdata.model(m).allmeascomponents = allmeasuredcomponents;
+end     
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% TRIVIAL FUNCTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% --- Executes on button press in zoombutton.
+function errorbarbutton_Callback(hObject, eventdata, handles)
+% toogle the errorbars in the figure
+if handles.errorbars == 0,
+    handles.errorbars = 1;
+else
+    handles.errorbars = 0;
+end
+% plot
+doPlot(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+% --- Executes on button press in zoombutton.
+function zoombutton_Callback(hObject, eventdata, handles)
+% toogle the zoom in the figure
+zoom
+return
+
+% --- Executes on button press in gridbutton.
+function gridbutton_Callback(hObject, eventdata, handles)
+% toogle the grid in the figure
+grid
+if handles.grid == 1,
+    handles.grid = 0;
+else
+    handles.grid = 1;
+end
+% Update handles structure
+guidata(hObject, handles);
+return
+
+% --- Executes on selection change in resetall.
+function resetall_Callback(hObject, eventdata, handles)
+m = handles.modelselection;
+% reset all values for current model to starting values
+handles.parammodel(m).values = handles.parammodel(m).startvalues;
+handles.parammodel(m).max = handles.parammodel(m).startmax;
+handles.parammodel(m).min = handles.parammodel(m).startmin;
+% reinitialize parameter list
+initializeParameterLists(handles,'resetall');
+% simulate and plot it
+handles = doSimAndPlot(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+% --- Executes on selection change in resetcurrent.
+function resetcurrent_Callback(hObject, eventdata, handles)
+m = handles.modelselection;
+% reset all values for current model and current parameter selections to starting values
+% get current indices
+pindices = [];
+pindices(end+1) = get(handles.manualparam1,'Value');
+pindices(end+1) = get(handles.manualparam2,'Value');
+pindices(end+1) = get(handles.manualparam3,'Value');
+pindices(end+1) = get(handles.manualparam4,'Value');
+pindices(end+1) = get(handles.manualparam5,'Value');
+pindices(end+1) = get(handles.manualparam6,'Value');
+pindices(end+1) = get(handles.manualparam7,'Value');
+% reset values for current parameters
+handles.parammodel(m).values(pindices) = handles.parammodel(m).startvalues(pindices);
+handles.parammodel(m).max(pindices) = handles.parammodel(m).startmax(pindices);
+handles.parammodel(m).min(pindices) = handles.parammodel(m).startmin(pindices);
+% reinitialize parameter list
+initializeParameterLists(handles,'resetcurrent');
+% simulate and plot it
+handles = doSimAndPlot(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+% --- Executes on selection change in componentselection.
+function componentselection_Callback(hObject, eventdata, handles)
+try
+    doPlot(handles);
+catch
+    errordlg('This selection is not possible.','Error','on');               
+end
+return
+
+% --- Executes on button press in plot.
+function plot_Callback(hObject, eventdata, handles)
+handles.dataPlotType = 'plot';
+% disable errorbarbutton
+set(handles.errorbarbutton,'Visible','on');
+% Update handles structure
+guidata(hObject, handles);
+doPlot(handles);
+return
+
+% --- Executes on button press in loglog.
+function semilogx_Callback(hObject, eventdata, handles)
+handles.dataPlotType = 'semilogx';
+% disable errorbarbutton
+set(handles.errorbarbutton,'Visible','off');
+handles.errorbars = 0;
+% Update handles structure
+guidata(hObject, handles);
+doPlot(handles);
+return
+
+% --- Executes on button press in semilogx.
+function semilogy_Callback(hObject, eventdata, handles)
+handles.dataPlotType = 'semilogy';
+% disable errorbarbutton
+set(handles.errorbarbutton,'Visible','off');
+handles.errorbars = 0;
+% Update handles structure
+guidata(hObject, handles);
+doPlot(handles);
+return
+
+% --- Executes on button press in loglog.
+function loglog_Callback(hObject, eventdata, handles)
+handles.dataPlotType = 'loglog';
+% disable errorbarbutton
+set(handles.errorbarbutton,'Visible','off');
+handles.errorbars = 0;
+% Update handles structure
+guidata(hObject, handles);
+doPlot(handles);
+return
+
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMparamestGUI_dir/IQMparamestGUI.fig b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMparamestGUI_dir/IQMparamestGUI.fig
new file mode 100644
index 0000000000000000000000000000000000000000..f085fd43d759345713adc855754d81087af84c78
Binary files /dev/null and b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMparamestGUI_dir/IQMparamestGUI.fig differ
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMparamestGUI_dir/IQMparamestGUI.m b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMparamestGUI_dir/IQMparamestGUI.m
new file mode 100644
index 0000000000000000000000000000000000000000..074ffd43fa2dd057de1f05e78f1aa1eb2a24d2b5
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMparamestGUI_dir/IQMparamestGUI.m	
@@ -0,0 +1,2376 @@
+function varargout = IQMparamestGUI(varargin)
+% IQMparamestGUI: Graphical user-interface for running parameter estimation tasks.
+% More information you find in the "Help" menu of this GUI.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Begin initialization code - DO NOT EDIT
+gui_Singleton = 1;
+gui_State = struct('gui_Name',       mfilename, ...
+                   'gui_Singleton',  gui_Singleton, ...
+                   'gui_OpeningFcn', @IQMparamestGUI_OpeningFcn, ...
+                   'gui_OutputFcn',  @IQMparamestGUI_OutputFcn, ...
+                   'gui_LayoutFcn',  [] , ...
+                   'gui_Callback',   []);
+if nargin && ischar(varargin{1})
+    gui_State.gui_Callback = str2func(varargin{1});
+end
+if nargout
+    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
+else
+    gui_mainfcn(gui_State, varargin{:});
+end
+% End initialization code - DO NOT EDIT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% OPENING FUNCTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function IQMparamestGUI_OpeningFcn(hObject, eventdata, handles, varargin)
+
+% display wait bars in different functions
+global useIQMparamestGUIFlag
+useIQMparamestGUIFlag = 1;
+
+handles.output = hObject;
+
+% start with an empty IQMprojectSB
+handles.UserData.project = IQMprojectSB();
+handles.UserData.empty = 1;
+
+% clear everything related to a project (results in empty project)
+handles = clearProject(hObject, eventdata, handles);
+
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% OUTPUT FUNCTION (NOT USED but needs to be present)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function varargout = IQMparamestGUI_OutputFcn(hObject, eventdata, handles) 
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EXIT FUNCTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function Exit_Callback(hObject, eventdata, handles)
+if handles.UserData.empty == 0,
+    check = checkProjectOverwrite(handles);
+    if ~check,
+        return
+    end
+end
+% clear everything
+handles = clearProject(hObject, eventdata, handles);
+% reset waitbar display
+clear global useIQMparamestGUIFlag
+% close the GUI
+closereq
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PRINT MENU CALLBACKS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function PrintMenu_Callback(hObject, eventdata, handles)
+print -depsc2 -r300
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HELP MENU CALLBACKS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function DocumentationMenu_Callback(hObject, eventdata, handles)
+old = pwd;
+cd([fileparts(which('IQMparamestGUI')) '/documentation']);
+open('documentation.html');
+cd(old);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% ESTIMATION SETTINGS CALLBACK
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function handles = ApplyEstimationSettings_Callback(hObject, eventdata, handles)
+if handles.UserData.empty == 1,
+    return
+end
+% get the estimation settings
+estindex = get(handles.listofestimations,'Value');
+% get number of estimations available
+nrest = length(get(handles.listofestimations,'String'));
+if estindex > nrest,
+    estindex = 1;
+end
+ps = struct(handles.UserData.project);
+% check if estimation settings present in the project
+if isempty(ps.estimations),
+    return
+end
+estimation = ps.estimations{estindex};
+% Apply the estimation settings
+handles.UserData.INTEGRATOROPTIONS = estimation.integrator.options;
+handles = applyEstimationSettings(handles,estimation);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% LEFT BUTTON CALLBACKS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Plot measurements
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function PlotMeasurements_Callback(hObject, eventdata, handles)
+if handles.UserData.empty == 1,
+    errordlg('No project loaded.');
+    return
+end
+project = handles.UserData.project;
+e = get(handles.listofexperiments,'Value');
+if isempty(e),
+    errordlg('No measurements in project.');
+    return
+end
+try
+    IQMplotmeasurements(project,e);
+catch
+    errordlg(lasterr);
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Simulate single experiment
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function SimulateExperiment_Callback(hObject, eventdata, handles)
+if handles.UserData.empty == 1,
+    errordlg('No project loaded.');
+    return
+end
+clear mex % more robust like that!
+% get project structure
+ps = struct(handles.UserData.project);
+% check if models present
+if isempty(ps.models),
+    errordlg('No models present in project.');
+    return
+end
+% get index of selected model and the model
+m = get(handles.listofmodels,'Value');
+model = ps.models{m};
+% check selected experiment
+e = get(handles.listofexperiments,'Value');
+if length(e) ~= 1,
+    errordlg('You need to select a single experiment.');
+    return
+end
+% get experiment
+experiment = ps.experiments(e).experiment;
+% get simulation time
+time = str2num(get(handles.simEndTime,'String'));
+if isempty(time),
+    errordlg('Simulation end time (Te) needs to be a numeric value.');
+    return
+end
+if time <= 0,
+    errordlg('Simulation end time needs to be larger than zero.');
+    return
+end
+% do the simulation
+try
+    modexp = IQMmergemodexp(model,experiment);
+    IQMPsimulate(modexp,time,[],{},[],handles.UserData.INTEGRATOROPTIONS);
+catch
+    errordlg(lasterr);
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Compare measurements
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function CompareMeasurements_Callback(hObject, eventdata, handles)
+if handles.UserData.empty == 1,
+    errordlg('No project loaded.');
+    return
+end
+clear mex % more robust like that!
+% get project structure
+project = handles.UserData.project;
+ps = struct(project);
+% check if models present
+if isempty(ps.models),
+    errordlg('No models present in project.');
+    return
+end
+% get index of selected model and the model
+m = get(handles.listofmodels,'Value');
+% check if experiments present
+e = get(handles.listofexperiments,'Value');
+if isempty(e),
+    errordlg('No experiments in project.');
+    return
+end
+try
+    IQMcomparemeasurements(project,m,e,handles.UserData.INTEGRATOROPTIONS);
+catch
+    errordlg(lasterr);
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Manual tuning
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function ManualTuning_Callback(hObject, eventdata, handles)
+if handles.UserData.empty == 1,
+    errordlg('No project loaded.');
+    return
+end
+clear mex % more robust like that!
+% get estimation structure
+estimation = getEstimationStructure(handles);
+if isempty(estimation),
+    return
+end
+% Run manual tuning 
+try
+    handles.UserData.project = IQMmanualtuning(handles.UserData.project,estimation);
+catch
+    errordlg(lasterr);
+end
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Identifiability analysis
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function Identifiability_Callback(hObject, eventdata, handles)
+if handles.UserData.empty == 1,
+    errordlg('No project loaded.');
+    return
+end
+clear mex % more robust like that!
+% get project structure
+project = handles.UserData.project;
+ps = struct(project);
+% check if models present
+if isempty(ps.models),
+    errordlg('No models present in project.');
+    return
+end
+% get index of selected model and the model
+m = get(handles.listofmodels,'Value');
+% get selected experiments
+e = get(handles.listofexperiments,'Value');
+if isempty(e),
+    errordlg('You need to select at least one experiment.');
+    return
+end
+% get estimation structure
+estimation = getEstimationStructure(handles);
+if isempty(estimation),
+    return
+end
+% get the options
+OPTIONS = [];
+OPTIONS.modelindex = m;
+OPTIONS.experimentindices = e;
+OPTIONS.integratoroptions = handles.UserData.INTEGRATOROPTIONS;
+% Run identifiability analysis 
+try
+    IQMidentifiability(handles.UserData.project,estimation.parameters.names,OPTIONS);
+catch
+    errordlg(lasterr);
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% MIDDLE BUTTON CALLBACKS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INITIALIZING GLOBAL/LOCAL/IC FIELDS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function InitializeParamSettings_Callback(hObject, eventdata, handles)
+if handles.UserData.empty == 1,
+    errordlg('No project loaded.');
+    return
+end
+% get project structure
+project = handles.UserData.project;
+ps = struct(project);
+% check if models present
+if isempty(ps.models),
+    errordlg('No models present in project.');
+    return
+end
+% get index of selected model 
+m = get(handles.listofmodels,'Value');
+% get the factors for low and high bounds
+low = str2num(get(handles.lowbounds,'String'));
+high = str2num(get(handles.highbounds,'String'));
+% do checks
+if isempty(low),
+    errordlg('The lowbounds factor needs to be numeric and positive.');
+end
+if isempty(high),
+    errordlg('The highbounds factor needs to be numeric and positive.');
+end
+if low < 0 || high < 0 || low > high,
+    errordlg('The bounds factors need to be positive and ''low'' < ''high''.');
+end
+OPTIONS.lowbounds = low;
+OPTIONS.highbounds = high;
+try
+    output = getparamictextIQM(project,m,OPTIONS);
+catch
+    errordlg(lasterr);
+end
+% set the information in the gui
+set(handles.globalparaminfo,'String',output.parametersText);
+set(handles.localparaminfo,'String','');
+set(handles.icinfo,'String',output.initialConditionsText);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% WRITE OUT GLOBAL/LOCAL/IC DATA
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function WriteOutParamSettings_Callback(hObject, eventdata, handles)
+if handles.UserData.empty == 1,
+    errordlg('No project loaded.');
+    return
+end
+% get project structure
+project = handles.UserData.project;
+ps = struct(project);
+% check if models present
+if isempty(ps.models),
+    errordlg('No models present in project.');
+    return
+end
+% get index of selected model 
+m = get(handles.listofmodels,'Value');
+% get the factors for low and high bounds
+low = str2num(get(handles.lowbounds,'String'));
+high = str2num(get(handles.highbounds,'String'));
+% do checks
+if isempty(low),
+    errordlg('The lowbounds factor needs to be numeric and positive.');
+end
+if isempty(high),
+    errordlg('The highbounds factor needs to be numeric and positive.');
+end
+if low < 0 || high < 0 || low > high,
+    errordlg('The bounds factors need to be positive and ''low'' < ''high''.');
+end
+OPTIONS.lowbounds = low;
+OPTIONS.highbounds = high;
+try
+    output = getparamictextIQM(project,m,OPTIONS);
+catch
+    errordlg(lasterr);
+end
+% write out
+clc;
+disp('*****************************************************************');
+disp('* PARAMETER SETTINGS (COPY AND PASTE IN THE GUI AS YOU NEED IT) *');
+disp('*****************************************************************');
+disp(' Parameter name / lower bound / upper bound');
+disp(output.parametersText);
+disp(' ');
+disp('*****************************************************************');
+disp('* STATE IC SETTINGS (COPY AND PASTE IN THE GUI AS YOU NEED IT)  *');
+disp('*****************************************************************');
+disp(' State name / lower bound / upper bound');
+disp(output.initialConditionsText);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% RIGHT BUTTON CALLBACKS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% OPTIMIZER OPTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function OptimizerOptions_Callback(hObject, eventdata, handles)
+% get the number of the selected optimizer
+optindex = get(handles.optimizerlist,'Value');
+% get the options
+optimizeroptions = handles.UserData.optimizeroptions{optindex};
+% call the options gui
+handles.UserData.optimizeroptions{optindex} = editoptionsGUI({optimizeroptions},'Optimizer Options');
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% OPTIMIZER OPTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function IntegratorOptionsMenu_Callback(hObject, eventdata, handles)
+% get the integrator options
+options = handles.UserData.INTEGRATOROPTIONS;
+% make text out of it
+text = getdatatextstructIQM(options,'OPTIONS',sprintf('%% CVODE Integrator Settings\n'));
+text = editoptionsGUI({text},'Integrator Options');
+OPTIONS = [];
+eval(text);
+handles.UserData.INTEGRATOROPTIONS = OPTIONS;
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Run Estimation
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function RunEstimation_Callback(hObject, eventdata, handles)
+if handles.UserData.empty == 1,
+    errordlg('No project loaded.');
+    return
+end
+clear mex % more robust like that!
+% check if start or stop button
+text = get(handles.runestimation,'String');
+if strcmp(text,'Stop Estimation');
+    warning off;
+    global stopOptimization;
+    stopOptimization = 1;
+    warning on;
+    return
+end
+% get estimation structure
+estimation = getEstimationStructure(handles);
+if isempty(estimation),
+    return
+end
+% Run estimation
+try
+    handles = disableAllButtons(handles);
+    set(handles.runfitanalysis,'Enable','off');
+    set(handles.runestimation,'String','Stop Estimation');
+    set(handles.runestimation,'BackgroundColor',[1 0 0]);
+    output = IQMparameterestimation(handles.UserData.project,estimation,1);
+    % get optimized project
+    handles.UserData.project = output.projectopt;
+catch
+    errordlg(lasterr);
+    disp('Please check that the parameters you selected are really parameters in the model.');
+    disp('Take into consideration that sometimes parameters in the model are changed to variables');
+    disp('by experimental settings. Then these parameters are not allowed to be estimated.');
+end
+set(handles.runestimation,'String','Run Estimation');
+set(handles.runestimation,'BackgroundColor',[0.027 0.729 0.396]);
+handles = enableAllButtons(handles);
+set(handles.runfitanalysis,'Enable','on');
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Residual Analysis
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function ResidualAnalysis_Callback(hObject, eventdata, handles)
+if handles.UserData.empty == 1,
+    errordlg('No project loaded.');
+    return
+end
+clear mex % more robust like that!
+% get estimation structure
+estimation = getEstimationStructure(handles);
+if isempty(estimation),
+    return
+end
+% Run residual analysis
+try
+    IQManalyzeresiduals(handles.UserData.project,estimation);
+catch
+    errordlg(lasterr);
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Run Fit Analysis
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function RunFitAnalysis_Callback(hObject, eventdata, handles)
+if handles.UserData.empty == 1,
+    errordlg('No project loaded.');
+    return
+end
+clear mex % more robust like that!
+% check if start or stop button
+text = get(handles.runfitanalysis,'String');
+if strcmp(text,'Stop Fitanalysis');
+    warning off;
+    global stopOptimization;
+    stopOptimization = 1;
+    warning on;
+    return
+end
+% get estimation structure
+estimation = getEstimationStructure(handles);
+if isempty(estimation),
+    return
+end
+% get nrestimations
+nrestimations = str2num(get(handles.nrestimations,'String'));
+if isempty(nrestimations),
+    errordlg('#Estmations needs to be a numeric value.');
+    return
+end
+% get perttype
+perttype = str2num(get(handles.perttype,'String'));
+if isempty(perttype),
+    errordlg('Perttype needs to be a numeric value.');
+    return
+end
+% Run fitanalysis
+try
+    handles = disableAllButtons(handles);
+    set(handles.runestimation,'Enable','off');
+    set(handles.runfitanalysis,'String','Stop Fitanalysis');
+    set(handles.runfitanalysis,'BackgroundColor',[1 0 0]);
+    handles.UserData.estdata = IQMparameterfitanalysis(handles.UserData.project,estimation,nrestimations,perttype,1);
+catch
+    errordlg(lasterr);
+end
+set(handles.runfitanalysis,'String','Run Fitanalysis');
+set(handles.runfitanalysis,'BackgroundColor',[0.027 0.729 0.396]);
+handles = enableAllButtons(handles);
+set(handles.runestimation,'Enable','on');
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Box Plot
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function BoxPlot_Callback(hObject, eventdata, handles)
+estdata = handles.UserData.estdata;
+if isempty(estdata),
+    errordlg('You need to first run the fit analysis.');
+    return
+end
+if estdata.nrestimations < 10,
+    errordlg('At least 10 estimation runs are required.');
+    return
+end
+IQMfaboxplot(estdata);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Correlation
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function Correlation_Callback(hObject, eventdata, handles)
+estdata = handles.UserData.estdata;
+if isempty(estdata),
+    errordlg('You need to first run the fit analysis.');
+    return
+end
+if estdata.nrestimations < 10,
+    errordlg('At least 10 estimation runs are required.');
+    return
+end
+IQMfacorr(estdata);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Pairwise Correlation
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function PairwiseCorrelation_Callback(hObject, eventdata, handles)
+estdata = handles.UserData.estdata;
+if isempty(estdata),
+    errordlg('You need to first run the fit analysis.');
+    return
+end
+if estdata.nrestimations < 10,
+    errordlg('At least 10 estimation runs are required.');
+    return
+end
+IQMfadetcorr(estdata);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Histogram
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function Histogram_Callback(hObject, eventdata, handles)
+estdata = handles.UserData.estdata;
+if isempty(estdata),
+    errordlg('You need to first run the fit analysis.');
+    return
+end
+if estdata.nrestimations < 10,
+    errordlg('At least 10 estimation runs are required.');
+    return
+end
+IQMfahist(estdata);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Clustering
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function Clustering_Callback(hObject, eventdata, handles)
+estdata = handles.UserData.estdata;
+if isempty(estdata),
+    errordlg('You need to first run the fit analysis.');
+    return
+end
+if estdata.nrestimations < 10,
+    errordlg('At least 10 estimation runs are required.');
+    return
+end
+IQMfaclustering(estdata);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Significant Correlation
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function SignificantCorrelation_Callback(hObject, eventdata, handles)
+estdata = handles.UserData.estdata;
+if isempty(estdata),
+    errordlg('You need to first run the fit analysis.');
+    return
+end
+if estdata.nrestimations < 10,
+    errordlg('At least 10 estimation runs are required.');
+    return
+end
+IQMfasigncorr(estdata);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Save Estimation Settings
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function handles = SaveEstimationSettings_Callback(hObject, eventdata, handles)
+if handles.UserData.empty == 1,
+    errordlg('No project loaded.');
+    return
+end
+% get the text
+text = get(handles.estimationsettingnotes,'String');
+% check if empty
+if isempty(strtrim(text)),
+    errordlg('Please enter at least a name for the estimation data.');
+    return
+end
+% get name and notes
+name = text(1,:);
+notes = text(2:end,:);
+name = strtrim(sprintf('%s',char([double(name)])'));
+notes = strtrim(sprintf('%s',char([double(notes) 10*ones(size(notes,1),1)])'));
+% get estimation structure
+estimation = getEstimationStructure(handles);
+if isempty(estimation),
+    return
+end
+% add name and notes
+estimation.name = name;
+estimation.notes = notes;
+% add estimation structure to the project
+ps = struct(handles.UserData.project);
+ps.estimations{end+1} = estimation;
+handles.UserData.project = IQMprojectSB(ps);
+% Update project information
+handles.UserData.donotchangeexperimentsFlag = 1;
+handles = UpdateProjectInformation(hObject, eventdata, handles);
+handles.UserData.donotchangeexperimentsFlag = 0;
+% set right value in estimation thing field
+nrest = length(get(handles.listofestimations,'String'));
+set(handles.listofestimations,'Value',nrest);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Update Estimation Settings
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function UpdateEstimationSettings_Callback(hObject, eventdata, handles)
+if handles.UserData.empty == 1,
+    errordlg('No project loaded.');
+    return
+end
+% get current estimation index
+estnames = get(handles.listofestimations,'String');
+if ~isempty(estnames),
+    estindex = get(handles.listofestimations,'Value');
+else 
+    estindex = 1;
+end
+% get the text
+text = get(handles.estimationsettingnotes,'String');
+% check if empty
+if isempty(strtrim(text)),
+    errordlg('Please enter at least a name for the estimation data.');
+    return
+end
+% get name and notes
+name = text(1,:);
+notes = text(2:end,:);
+name = strtrim(sprintf('%s',char([double(name)])'));
+notes = strtrim(sprintf('%s',char([double(notes) 10*ones(size(notes,1),1)])'));
+% get estimation structure
+estimation = getEstimationStructure(handles);
+if isempty(estimation),
+    return
+end
+% add name and notes
+estimation.name = name;
+estimation.notes = notes;
+% add estimation structure to the project
+ps = struct(handles.UserData.project);
+ps.estimations{estindex} = estimation;
+handles.UserData.project = IQMprojectSB(ps);
+% Update project information
+handles.UserData.donotchangeexperimentsFlag = 1;
+handles = UpdateProjectInformation(hObject, eventdata, handles);
+handles.UserData.donotchangeexperimentsFlag = 0;
+% set right value in estimation thing field
+set(handles.listofestimations,'Value',estindex);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Reset Project
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function ResetProject_Callback(hObject, eventdata, handles)
+if handles.UserData.empty == 1,
+    errordlg('No project loaded.');
+    return
+end
+% add estimations to the original project
+psO = struct(handles.UserData.projectOrig);
+ps = struct(handles.UserData.project);
+psO.estimations = ps.estimations;
+% save the old handles (for removing the old MEX models)
+handlesold = handles;
+handles.UserData.projectOrig = IQMprojectSB(psO);
+% reset it
+handles.UserData.project = handles.UserData.projectOrig;
+% set estimation index to 1
+set(handles.listofestimations,'Value',1);
+% update GUI
+handles = UpdateProjectInformation(hObject, eventdata, handles);
+% apply estimation settings
+handles.donotchangeParameters = 1;
+handles = ApplyEstimationSettings_Callback(hObject, eventdata, handles);
+handles.donotchangeParameters = 0;
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLING FILE MENU FUNCTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% LOAD PROJECT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function LoadProjectMenu_Callback(hObject, eventdata, handles)
+warning off;
+if handles.UserData.empty == 0,
+    check = checkProjectOverwrite(handles);
+    if ~check,
+        return
+    end
+end
+% clear the old project
+handles = clearProject(hObject, eventdata, handles);
+% get project file
+[filename, pathname] = uigetfile({'*.iqmp', 'IQMprojectSB file (*.iqmp)'},'Pick a project file to load');
+if filename == 0,
+    return
+end
+% load project
+try
+    project = IQMprojectSB([pathname filename]);
+    % add project to handles
+    handles.UserData.project = project;
+    % check and remove incorrect estimation settings
+    handles = checkEstimations(handles);    
+    % set original project
+    handles.UserData.projectOrig = project;
+    handles.UserData.empty = 0;
+catch
+    errordlg(lasterr);
+    return
+end
+% set default experiment weights
+handles.UserData.allExperimentWeights = ones(1,length(IQMgetexperiment(project)));
+% update GUI
+handles = UpdateProjectInformation(hObject, eventdata, handles);
+% set estimation index to 1
+set(handles.listofestimations,'Value',1);
+% apply estimation settings
+handles = ApplyEstimationSettings_Callback(hObject, eventdata, handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% IMPORT PROJECT MENU 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function ImportProjectMenu_Callback(hObject, eventdata, handles)
+warning off;
+if handles.UserData.empty == 0,
+    check = checkProjectOverwrite(handles);
+    if ~check,
+        return
+    end
+end
+% clear the old project
+handles = clearProject(hObject, eventdata, handles);
+% get project folder name
+dirname = uigetdir('Pick an IQMprojectSB folder');
+if dirname == 0,
+    return
+end
+% load project
+try
+    project = IQMprojectSB(dirname);
+    % add project to handles
+    handles.UserData.project = project;
+    % check and remove incorrect estimation settings
+    handles = checkEstimations(handles);    
+    % set original project
+    handles.UserData.projectOrig = project;
+    handles.UserData.empty = 0;
+catch
+    disp(lasterr);
+    errordlg('An error occured. Please check output on console.');
+    return
+end
+% set default experiment weights
+handles.UserData.allExperimentWeights = ones(1,length(IQMgetexperiment(project)));
+% update GUI
+handles = UpdateProjectInformation(hObject, eventdata, handles);
+% set estimation index to 1
+set(handles.listofestimations,'Value',1);
+% apply estimation settings
+handles = ApplyEstimationSettings_Callback(hObject, eventdata, handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function handles = checkEstimations(handles)
+% we want to check all estimation settings ... estimations with
+% modelindices that do not correspond to a model are deleted. 
+% models. 
+ps = struct(handles.UserData.project);
+nrmodels = length(ps.models);
+nrexperiments = length(ps.experiments);
+keepindices = [];
+for k=1:length(ps.estimations),
+    try
+        mi = ps.estimations{k}.modelindex;
+    catch
+        mi = 1;
+        ps.estimations{k}.modelindex = mi;
+    end
+    if ~(mi < 0 || mi > nrmodels),
+        keepindices(end+1) = k;
+    end
+end
+ps.estimations = ps.estimations(keepindices);
+% We also check experiment indices and if not fitting then we
+% delete them also
+keepindices = [];
+for k=1:length(ps.estimations),
+    try
+        ei = ps.estimations{k}.experiments.indices;
+        if length(ps.estimations{k}.experiments.weight) ~= length(ei),
+            ps.estimations{k}.experiments.weight = ones(1,length(ei));
+        end
+    catch
+        ei = [1:nrexperiments];
+        ps.estimations{k}.experiments.indices = ei;
+        ps.estimations{k}.experiments.weight = ones(1,length(ei));
+    end
+    if isempty([find(ei<0) find(ei>nrexperiments)]),
+        keepindices(end+1) = k;
+    end
+end
+ps.estimations = ps.estimations(keepindices);
+handles.UserData.project = IQMprojectSB(ps);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function handles = removeEstimations(handles,modelindex,experimentindex)
+ps = struct(handles.UserData.project);
+if ~isempty(modelindex),
+    keepindices = [];
+    % cycle trough the estimations and check in which estimations the
+    % modelindex appears => these are deleted.
+    for est=1:length(ps.estimations),
+        if ps.estimations{est}.modelindex < modelindex,
+            keepindices(end+1) = est;
+        elseif ps.estimations{est}.modelindex > modelindex,
+            keepindices(end+1) = est;
+            % also reduce the modelindices here by one (since one model
+            % deleted from the project)
+            ps.estimations{est}.modelindex = ps.estimations{est}.modelindex - 1;
+        else
+            % do nothing
+        end
+    end
+    % remove the estimations
+    ps.estimations = ps.estimations(keepindices);
+elseif ~isempty(experimentindex),
+    % cycle trough all estimations and check the experiment indices
+    % remove the given one, reduce the larger ones by one, check if
+    % experiments.indices is empty ... then remove the whole estimation
+    % setting
+    keepindices = [];
+    for est=1:length(ps.estimations),
+        ei = ps.estimations{est}.experiments.indices;
+        % find experimentindex in ei
+        ind = find(ei==experimentindex);
+        % remove entry from the vector
+        ei(ind) = [];
+        % remove the corresponding weights
+        ps.estimations{est}.experiments.weight(ind) = [];
+        % find elements in ei larger than experimentindex
+        larger = ei > experimentindex;
+        % decrease these elements by one
+        ei = ei - larger;
+        % check if ei is empty 
+        if ~isempty(ei),
+            keepindices(end+1) = est;
+        end
+        % update the structure
+        ps.estimations{est}.experiments.indices = ei;
+    end
+    % remove the estimations for which no experiments left in settings
+    ps.estimations = ps.estimations(keepindices);
+end
+% update the model and return
+handles.UserData.project = IQMprojectSB(ps);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% SAVE PROJECT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function SaveProjectMenu_Callback(hObject, eventdata, handles)
+if handles.UserData.empty == 1,
+    errordlg('No project loaded.');
+    return
+end
+[filename, pathname] = uiputfile({'*.iqmp', 'IQMprojectSB file (*.iqmp)'}, 'Select a project file to write');
+if filename == 0,
+    return
+end
+% remove extension
+[dummy,projectfilename] = fileparts(filename);
+% save the project
+old = pwd;
+cd(pathname);
+IQMsaveproject(handles.UserData.project,projectfilename);
+cd(old);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EXPORT PROJECT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function ExportProjectMenu_Callback(hObject, eventdata, handles)
+if handles.UserData.empty == 1,
+    errordlg('No project loaded.');
+    return
+end
+foldername = uigetdir('Select a folder to export the IQMprojectSB folder to');
+if foldername == 0,
+    return
+end
+projectname = inputdlg('Please enter a name for the project','Project name',1);
+if isempty(projectname),
+    return
+end
+projectname = projectname{1};
+% check if folder exists
+old = pwd;
+cd(foldername);
+if exist(projectname) == 7,
+    answer = questdlg(sprintf('The project folder exists.\nDo you want to overwrite it?'), 'Question', 'YES', 'NO','NO');
+    if strcmp(answer,'NO'),
+        return;
+    end
+end
+IQMexportproject(handles.UserData.project,projectname);
+cd(old);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% SHOW AND EDIT PROJECT NOTES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function ShowEditProjectNotesMenu_Callback(hObject, eventdata, handles)
+if handles.UserData.empty == 1,
+    errordlg('No project loaded.');
+    return
+end
+% get the project notes
+ps = struct(handles.UserData.project);
+notes = {ps.notes};
+name = ps.name;
+ps.notes = notepadGUI(notes,sprintf('Notes for IQMprojectSB: %s',name));
+% update project
+handles.UserData.project = IQMprojectSB(ps);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CLEAR PROJECT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function ClearProjectMenu_Callback(hObject, eventdata, handles)
+if handles.UserData.empty == 1,
+    errordlg('No project loaded.');
+    return
+end
+check = checkProjectOverwrite(handles);
+if ~check,
+    return
+end
+handles = clearProject(hObject, eventdata, handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLING MODEL MENU FUNCTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Add Model
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function AddModelMenu_Callback(hObject, eventdata, handles)
+if handles.UserData.empty == 1,
+    errordlg('No project loaded.');
+    return
+end
+ps = struct(handles.UserData.project);
+% get model file
+[filename, pathname] = uigetfile({'*.txt;*.txtbc;*.xml', 'Model Files (*.txt,*.txtbc,*.xml)'},'Pick a model file to import');
+if filename == 0,
+    return
+end
+% load model
+try
+    model = IQMmodel([pathname filename]);
+catch
+    errordlg(lasterr);
+    return
+end
+% append the model to the project
+ps.models{end+1} = model;
+% update project
+handles.UserData.project = IQMprojectSB(ps);
+% update GUI
+handles = UpdateProjectInformation(hObject, eventdata, handles);
+% set model index to the added one
+set(handles.listofmodels,'Value',length(ps.models));
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Edit Model
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function EditModelMenu_Callback(hObject, eventdata, handles)
+if handles.UserData.empty == 1,
+    errordlg('No project loaded.');
+    return
+end
+ps = struct(handles.UserData.project);
+% check if models do exist (at least one must be present)
+if length(ps.models) < 1,
+    errordlg('No model to edit.');
+    return
+end
+% get the model
+m = get(handles.listofmodels,'Value');
+model = ps.models{m};
+modelold = model;
+% edit the model
+answer = questdlg('Select the format to edit the model in.', 'Question', 'TEXT Format', 'TEXTBC Format', 'TEXT Format');
+switch answer,
+    case 'TEXT Format',
+        model = IQMedit(model);
+    case 'TEXTBC Format',
+        model = IQMeditBC(model);
+    case '',
+        return
+end
+% add the model to project again
+ps.models{m} = model;
+% update project
+handles.UserData.project = IQMprojectSB(ps);
+% update GUI
+handles = UpdateProjectInformation(hObject, eventdata, handles);
+% set model index to the edited one
+set(handles.listofmodels,'Value',m);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Update Model
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function UpdateModelMenu_Callback(hObject, eventdata, handles)
+if handles.UserData.empty == 1,
+    errordlg('No project loaded.');
+    return
+end
+ps = struct(handles.UserData.project);
+% check if models do exist (at least one must be present)
+if length(ps.models) < 1,
+    errordlg('No model to update.');
+    return
+end
+% get model file
+[filename, pathname] = uigetfile({'*.txt;*.txtbc;*.xml', 'Model Files (*.txt,*.txtbc,*.xml)'},'Pick a modelfile to import');
+if filename == 0,
+    return
+end
+% load model
+try
+    model = IQMmodel([pathname filename]);
+catch
+    errordlg(lasterr);
+    return
+end
+% add the model to project again
+m = get(handles.listofmodels,'Value');
+modelold = ps.models{m};
+ps.models{m} = model;
+% update project
+handles.UserData.project = IQMprojectSB(ps);
+% update GUI
+handles = UpdateProjectInformation(hObject, eventdata, handles);
+% set model index to the edited one
+set(handles.listofmodels,'Value',m);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Delete Model
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function DeleteModelMenu_Callback(hObject, eventdata, handles)
+if handles.UserData.empty == 1,
+    errordlg('No project loaded.');
+    return
+end
+ps = struct(handles.UserData.project);
+% check if models do exist (at least one must be present)
+if length(ps.models) <= 1,
+    errordlg('At least one model needs to be present in the project.');
+    return
+end
+% check if deletion desired
+output = checkYESNO('Delete the selected model?');
+if output == 0,
+    return
+end
+% get modelindex 
+mi = get(handles.listofmodels,'Value');
+% delete the model from the project
+keepindices = setdiff([1:length(ps.models)],mi);
+ps.models = ps.models(keepindices);
+% update project
+handles.UserData.project = IQMprojectSB(ps);
+% Finally also check the estimation settings and remove the estimations
+% that contain this model
+handles = removeEstimations(handles,mi,[]);
+% update GUI
+handles = UpdateProjectInformation(hObject, eventdata, handles);
+% set model index
+set(handles.listofmodels,'Value',1);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Export Model
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function ExportModelMenu_Callback(hObject, eventdata, handles)
+if handles.UserData.empty == 1,
+    errordlg('No project loaded.');
+    return
+end
+ps = struct(handles.UserData.project);
+% check if models do exist (at least one must be present)
+if length(ps.models) < 1,
+    errordlg('No model in project that could be exported.');
+    return
+end
+% get the model
+model = ps.models{get(handles.listofmodels,'Value')};
+% get the type of export
+output = checkMODELTYPE('Select the format for the model export:');
+if output == 0,
+    return
+end
+switch output,
+    case '*.txt',
+        % get file name
+        [filename, pathname] = uiputfile({'*.txt','IQMmodel TEXT description (*.txt)'},'Select a filename for the model');
+        if filename == 0,
+            return
+        end
+        % do the export
+        old = pwd;
+        cd(pathname);
+        [dummy,filename] = fileparts(filename);
+        IQMcreateTEXTfile(model,filename);
+        cd(old);
+    case '*.txtbc',
+        % get file name
+        [filename, pathname] = uiputfile({'*.txtbc','IQMmodel TEXTBC description (*.txtbc)'}, 'Select a filename for the model');
+        if filename == 0,
+            return
+        end
+        % do the export
+        old = pwd;
+        cd(pathname);
+        [dummy,filename] = fileparts(filename);
+        IQMcreateTEXTBCfile(model,filename);
+        cd(old);
+    case '*.xml',
+        IQMexportSBML(model);
+end
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% View Model 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function ViewModelMenu_Callback(hObject, eventdata, handles)
+if handles.UserData.empty == 1,
+    errordlg('No project loaded.');
+    return
+end
+ps = struct(handles.UserData.project);
+% get the model
+m = get(handles.listofmodels,'Value');
+model = ps.models{m};
+% view the model
+answer = questdlg('Select the format to view the model in.', 'Question', 'TEXT Format', 'TEXTBC Format', 'TEXT Format');
+switch answer,
+    case 'TEXT Format',
+        IQMedit(model);
+    case 'TEXTBC Format',
+        IQMeditBC(model);
+    case '',
+        return
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% View Model with Experiment
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function ViewModelExperiment_Callback(hObject, eventdata, handles)
+if handles.UserData.empty == 1,
+    errordlg('No project loaded.');
+    return
+end
+ps = struct(handles.UserData.project);
+% get the model
+m = get(handles.listofmodels,'Value');
+model = ps.models{m};
+% get the experiment
+e = get(handles.listofexperiments,'Value');
+if length(e) > 1,
+    errordlg('Please select a single experiment.');
+    return
+end
+experiment = ps.experiments(e).experiment;
+% combine model with experiment
+modexp = IQMmergemodexp(model,experiment);
+% view the model
+answer = questdlg('Select the format to view the model with experiment changes in.', 'Question', 'TEXT Format', 'TEXTBC Format', 'TEXT Format');
+switch answer,
+    case 'TEXT Format',
+        IQMedit(modexp);
+    case 'TEXTBC Format',
+        IQMeditBC(modexp);
+    case '',
+        return
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Export Model with Experiment
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function ExportModelExperiment_Callback(hObject, eventdata, handles)
+if handles.UserData.empty == 1,
+    errordlg('No project loaded.');
+    return
+end
+ps = struct(handles.UserData.project);
+% get the model
+model = ps.models{get(handles.listofmodels,'Value')};
+% get the experiment
+e = get(handles.listofexperiments,'Value');
+if length(e) > 1,
+    errordlg('Please select a single experiment.');
+    return
+end
+experiment = ps.experiments(e).experiment;
+% combine model with experiment
+modexp = IQMmergemodexp(model,experiment);
+% get the type of export
+output = checkMODELTYPE('Select the format for the model (with experiment changes) export:');
+if output == 0,
+    return
+end
+switch output,
+    case '*.txt',
+        % get file name
+        [filename, pathname] = uiputfile({'*.txt','IQMmodel TEXT description (*.txt)'},'Select a filename for the model');
+        if filename == 0,
+            return
+        end
+        % do the export
+        old = pwd;
+        cd(pathname);
+        [dummy,filename] = fileparts(filename);
+        IQMcreateTEXTfile(modexp,filename);
+        cd(old);
+    case '*.txtbc',
+        % get file name
+        [filename, pathname] = uiputfile({'*.txtbc','IQMmodel TEXTBC description (*.txtbc)'}, 'Select a filename for the model');
+        if filename == 0,
+            return
+        end
+        % do the export
+        old = pwd;
+        cd(pathname);
+        [dummy,filename] = fileparts(filename);
+        IQMcreateTEXTBCfile(modexp,filename);
+        cd(old);
+    case '*.xml',
+        IQMexportSBML(modexp);
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLING EXPERIMENT MENU FUNCTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Edit Experiment
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function EditExperimentMenu_Callback(hObject, eventdata, handles)
+if handles.UserData.empty == 1,
+    errordlg('No project loaded.');
+    return
+end
+ps = struct(handles.UserData.project);
+% check if experiments do exist (at least one must be present)
+if length(ps.experiments) < 1,
+    errordlg('No experiment to edit.');
+    return
+end
+% check if only one experiment selected
+e = get(handles.listofexperiments,'Value');
+if length(e) > 1,
+    errordlg('Please select a single experiment for update.');
+    return
+end
+% get the experiment
+experiment = ps.experiments(e).experiment;
+% convert to text
+expTextStructure = convertExpToTextIQM(experiment);
+exptext = setPartsToCompleteTextExpIQM(expTextStructure);
+% edit the exptext using notepadGUI
+[exptext,flag] = notepadGUI({exptext},'Edit Experiment Description');
+if flag==0,
+    return
+end
+% convert exptext to IQMexperiment
+[IQMstructure,errorMsg] = convertTextToExpIQM(exptext);
+if ~isempty(errorMsg),
+    errordlg(errorMsg);
+    return
+end
+experiment = IQMexperiment(IQMstructure);
+% add the model to project again
+experimentold = ps.experiments(e).experiment;
+ps.experiments(e).experiment = experiment;
+% update project
+handles.UserData.project = IQMprojectSB(ps);
+% update GUI
+handles = UpdateProjectInformation(hObject, eventdata, handles);
+% set experiment index to the edited one
+set(handles.listofexperiments,'Value',e);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% View Experiment
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function ViewExperimentMenu_Callback(hObject, eventdata, handles)
+if handles.UserData.empty == 1,
+    errordlg('No project loaded.');
+    return
+end
+ps = struct(handles.UserData.project);
+% check if only one experiment selected
+e = get(handles.listofexperiments,'Value');
+if length(e) > 1,
+    errordlg('Please select a single experiment for viewing.');
+    return
+end
+% get the experiment
+experiment = ps.experiments(e).experiment;
+% convert to text
+expTextStructure = convertExpToTextIQM(experiment);
+exptext = setPartsToCompleteTextExpIQM(expTextStructure);
+% edit the exptext using notepadGUI
+notepadGUI({exptext},'View Experiment Description',0);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Update Experiment
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function UpdateExperimentMenu_Callback(hObject, eventdata, handles)
+if handles.UserData.empty == 1,
+    errordlg('No project loaded.');
+    return
+end
+ps = struct(handles.UserData.project);
+% check if experiments do exist (at least one must be present)
+if length(ps.experiments) < 1,
+    errordlg('No experiment to update.');
+    return
+end
+% check if only one experiment selected
+e = get(handles.listofexperiments,'Value');
+if length(e) > 1,
+    errordlg('Please select a single experiment for update.');
+    return
+end
+% get experiment file
+[filename, pathname] = uigetfile({'*.exp', 'IQMexperiment description (*.exp))'},'Pick an experiment file to import');
+if filename == 0,
+    return
+end
+% load experiment
+try
+    experiment = IQMexperiment([pathname filename]);
+catch
+    errordlg(lasterr);
+    return
+end
+% add the experiment to project again
+experimentold = ps.experiments(e).experiment;
+ps.experiments(e).experiment = experiment;
+% update project
+handles.UserData.project = IQMprojectSB(ps);
+% update GUI
+handles = UpdateProjectInformation(hObject, eventdata, handles);
+% set model index to the edited one
+set(handles.listofexperiments,'Value',e);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Delete Experiment
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function DeleteExperimentMenu_Callback(hObject, eventdata, handles)
+if handles.UserData.empty == 1,
+    errordlg('No project loaded.');
+    return
+end
+ps = struct(handles.UserData.project);
+% check if experiments do exist (at least one must be present)
+if length(ps.experiments) <= 1,
+    errordlg('At least one experiment needs to be present in the project.');
+    return
+end
+% check if only one experiment selected
+e = get(handles.listofexperiments,'Value');
+if length(e) > 1,
+    errordlg('Please select a single experiment for deletion.');
+    return
+end
+% check if deletion desired
+output = checkYESNO('Delete the selected experiment?');
+if output == 0,
+    return
+end
+% delete the experiment from the project
+keepindices = setdiff([1:length(ps.experiments)],e);
+ps.experiments = ps.experiments(keepindices);
+% remove the saved experiment weight
+handles.UserData.allExperimentWeights(e) = [];
+% update project
+handles.UserData.project = IQMprojectSB(ps);
+% Finally also check the estimation settings and remove and change the
+% experiment indices from the estimations
+handles = removeEstimations(handles,[],e);
+% update GUI
+handles = UpdateProjectInformation(hObject, eventdata, handles);
+% set experiment index
+set(handles.listofexperiments,'Value',1);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Export Experiment
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function ExportExperimentMenu_Callback(hObject, eventdata, handles)
+if handles.UserData.empty == 1,
+    errordlg('No project loaded.');
+    return
+end
+ps = struct(handles.UserData.project);
+% check if experiments do exist (at least one must be present)
+if length(ps.experiments) < 1,
+    errordlg('No experiment in project that could be exported.');
+    return
+end
+% get experiment index
+e = get(handles.listofexperiments,'Value');
+% check that only one experiment
+if length(e) ~= 1,
+    errordlg('Please select only on experiment.');
+    return
+end
+% get the experiment
+experiment = ps.experiments(e).experiment;
+% get file name
+[filename, pathname] = uiputfile({'*.exp', 'IQMexperiment description (*.exp))'}, 'Select a filename for the experiment');
+if filename == 0,
+    return
+end
+% do the export
+old = pwd;
+cd(pathname);
+[dummy,filename] = fileparts(filename);
+IQMcreateEXPfile(experiment,filename);
+cd(old);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLING ESTIMATION MENU FUNCTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% VIEW ESTIMATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function ViewEstimationSettings_Callback(hObject, eventdata, handles)
+if handles.UserData.empty == 1,
+    errordlg('No project loaded.');
+    return
+end
+% get estimation index 
+est = get(handles.listofestimations,'Value');
+% get the estimation
+ps = struct(handles.UserData.project);
+estimation = ps.estimations{est};
+% convert estimation to text
+text = sprintf('%% Estimation Settings\n\nestimation = [];');
+text = getdatatextstructIQM(estimation,'estimation',text);
+notepadGUI({text},'View Estimation Settings (MATLAB structure)',0);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Delete Estimation
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function DeleteEstimationMenu_Callback(hObject, eventdata, handles)
+if handles.UserData.empty == 1,
+    errordlg('No project loaded.');
+    return
+end
+ps = struct(handles.UserData.project);
+% check if estimations do exist 
+if isempty(ps.estimations),
+    errordlg('No estimation present in project.');
+    return
+end
+% check if deletion desired
+output = checkYESNO('Delete the selected estimation setting?');
+if output == 0,
+    return
+end
+% get estimation index 
+est = get(handles.listofestimations,'Value');
+% delete the estimation from the project
+keepindices = setdiff([1:length(ps.estimations)],est);
+ps.estimations = ps.estimations(keepindices);
+% update project
+handles.UserData.project = IQMprojectSB(ps);
+% update GUI
+handles = UpdateProjectInformation(hObject, eventdata, handles);
+% set estimation index
+set(handles.listofestimations,'Value',1);
+% apply estimation settings
+handles = ApplyEstimationSettings_Callback(hObject, eventdata, handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Delete All Estimations
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function DeleteAllEstimationsMenu_Callback(hObject, eventdata, handles)
+if handles.UserData.empty == 1,
+    errordlg('No project loaded.');
+    return
+end
+ps = struct(handles.UserData.project);
+% check if estimations do exist 
+if isempty(ps.estimations),
+    errordlg('No estimation present in project.');
+    return
+end
+% check if deletion desired
+output = checkYESNO('Delete ALL estimation setting?');
+if output == 0,
+    return
+end
+% remove all of them
+ps.estimations = {};
+% update project
+handles.UserData.project = IQMprojectSB(ps);
+% update GUI
+handles = UpdateProjectInformation(hObject, eventdata, handles);
+% set estimation index
+set(handles.listofestimations,'Value',1);
+% apply estimation settings
+handles = ApplyEstimationSettings_Callback(hObject, eventdata, handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EXPORT ESTIMATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function ExportEstimationMenu_Callback(hObject, eventdata, handles)
+if handles.UserData.empty == 1,
+    errordlg('No project loaded.');
+    return
+end
+[filename, pathname] = uiputfile({'*.est', 'Estimation structure description (*.est))'}, 'Select estimation file to write');
+if filename == 0,
+    return
+end
+% remove extension
+[dummy,filename] = fileparts(filename);
+% get estimation index 
+est = get(handles.listofestimations,'Value');
+% save the estimation
+old = pwd;
+cd(pathname);
+IQMexportestimation(handles.UserData.project,est,filename)
+cd(old);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLING OTHER MENU FUNCTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Create Run Estimation Script
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function CreateRunEstimationScript_Callback(hObject, eventdata, handles)
+if handles.UserData.empty == 1,
+    errordlg('No project loaded.');
+    return
+end
+ps = struct(handles.UserData.project);
+% check if model is present in project
+if isempty(ps.models),
+    errordlg('No models present in project.');
+    return
+end
+% check if experiments are present in project
+if isempty(ps.experiments),
+    errordlg('No experiments present in project.');
+    return
+end
+% select filename (.m)
+[filename, pathname] = uiputfile({'*.m', 'MATLAB m-file script (*.m)'}, 'Select file to write the script to');
+if filename == 0,
+    return
+end
+% remove extension
+[dummy,filename] = fileparts(filename);
+% get model index 
+m = get(handles.listofmodels,'Value');
+% construct the OPTIONS structure
+lowbounds = str2num(get(handles.lowbounds,'String')); 
+highbounds = str2num(get(handles.highbounds,'String'));
+if isempty(lowbounds),
+    lowbounds = 0.1;
+end
+if isempty(highbounds),
+    highbounds = 10;
+end
+OPTIONS = [];
+OPTIONS.lowbounds = lowbounds;
+OPTIONS.highbounds = highbounds;
+% create the file
+old = pwd;
+cd(pathname);
+IQMcreaterunestimationscript(handles.UserData.project,m,filename,OPTIONS)
+cd(old);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% AUXILIARY FUNCTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [output] = checkMODELTYPE(question)
+answer = questdlg(question, 'Question', 'TEXT (*.txt)', 'TEXTBC (*.txtbc)','SBML L2V1 (*.xml)','TEXT (*.txt)');
+switch answer,
+    case '',
+        output = 0;
+    case 'TEXT (*.txt)',
+        output = '*.txt';
+    case 'TEXTBC (*.txtbc)',
+        output = '*.txtbc';
+    case 'SBML L2V1 (*.xml)',
+        output = '*.xml';
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [output] = checkYESNO(question)
+output = 1;
+answer = questdlg(question, 'Question', 'YES', 'NO','NO');
+if strcmp(answer,'NO'),
+    output = 0;
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [output] = checkProjectOverwrite(handles)
+output = checkYESNO('Discard current project?');
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function handles = UpdateExperimentWeights(hObject, eventdata, handles)
+if handles.UserData.empty == 1,
+    return
+end
+% get number of experiments in project
+experiments = IQMgetexperiment(handles.UserData.project);
+nrexperiments = length(experiments);
+% check previous settings of the weights
+allWeights = handles.UserData.allExperimentWeights;
+if isempty(allWeights),
+    % set all to one if not defined otherwise
+    allWeights = ones(1,length(experiments));
+end
+if length(allWeights) < nrexperiments,
+    allWeights = [allWeights ones(1,nrexperiments-length(allWeights))];
+end
+if length(allWeights) > nrexperiments,
+    allWeights = allWeights(1:nrexperiments);
+end
+% get weights for the selected experiments
+indices = get(handles.listofexperiments,'Value');
+weights = allWeights(indices);
+% set weights in display
+text = sprintf('%g, ',weights);
+text = text(1:end-2);
+% add them to GUI
+set(handles.experimentweights,'String',text);
+% save allWeights if changed
+handles.UserData.allExperimentWeights = allWeights;
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function SetExperimentWeights(hObject, eventdata, handles)
+% get number of experiments in project
+experiments = IQMgetexperiment(handles.UserData.project);
+nrexperiments = length(experiments);
+% get and check all weights
+allWeights = handles.UserData.allExperimentWeights;
+if isempty(allWeights),
+    % set all to one if not defined otherwise
+    allWeights = ones(1,length(experiments));
+end
+if length(allWeights) < nrexperiments,
+    warndlg(sprintf('Number of experiments exceeds number of weigths.\nThe weights are postpadded by ones.'));
+    allWeights = [allWeights ones(1,nrexperiments-allWeights)];
+end
+if length(allWeights) > nrexperiments,
+    warndlg(sprintf('Number of weights exceeds number of experiments.\nThe weights in excess are discarded.'));
+    allWeights = allWeights(1:nrexperiments);
+end
+% get indices and nr of currently selected experiments
+selectedindices = get(handles.listofexperiments,'Value');
+nrselectedexperiments = length(selectedindices);
+% now get the current weight settings and do some checks (need to fit to
+% currently nr of currently selected experiments
+try
+    setValues = eval(['[' get(handles.experimentweights,'String'), ']']);
+catch
+    warndlg('Incorrect weight setting.');
+end
+if length(setValues) > nrselectedexperiments,
+    warndlg(sprintf('Number of weights exceeds number of selected experiments.\nPlease correct that.'));
+    return
+end
+if length(setValues) < nrselectedexperiments,
+    warndlg(sprintf('Number of selected experiments exceeds number of weights.\nPlease correct that.'));
+    return
+end
+% Update all weights with the entered values
+allWeights(selectedindices) = setValues;
+handles.UserData.allExperimentWeights = allWeights;
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function handles = UpdateProjectInformation(hObject, eventdata, handles)
+if handles.UserData.empty == 1,
+    return
+end
+project = handles.UserData.project;
+ps = struct(project);
+% get model names
+models = ps.models;
+modelnames = {};
+for k=1:length(models),
+    ms = struct(models{k});
+    modelnames{end+1} = ms.name;
+end
+% get experiment names
+experimentnames = {};
+for k=1:length(ps.experiments),
+    es = struct(ps.experiments(k).experiment);
+    experimentnames{end+1} = es.name;
+end
+% get estimation names
+estimationnames = {};
+estimationnotes = {};
+for k=1:length(ps.estimations),
+    est = ps.estimations{k};
+    try
+        estimationnames{k} = sprintf('%d: %s',k,est.name);
+    catch
+        estimationnames{k} = sprintf('Estimation #%d',k);
+    end
+    try
+        estimationnotes{k} = est.notes;
+    catch
+        estimationnotes{k} = sprintf('No notes');
+    end
+end
+% set the info
+if handles.UserData.donotchangeexperimentsFlag ~= 1,
+    set(handles.listofmodels,'String',modelnames);
+    set(handles.listofexperiments,'String',experimentnames);
+    % select all experiments by default
+    set(handles.listofexperiments,'Value',[1:length(experimentnames)]);
+end
+% handle list of estimations
+if isempty(estimationnames),
+    InitializeParamSettings_Callback(hObject, eventdata, handles);
+    % make a default estimation setting
+    set(handles.estimationsettingnotes,'String',sprintf('default\nDefault estimation setting.'));
+    handles = SaveEstimationSettings_Callback(hObject, eventdata, handles);
+else 
+    set(handles.listofestimations,'String',estimationnames);
+    if get(handles.listofestimations,'Value') > length(estimationnames),
+        set(handles.listofestimations,'Value',1);
+    end
+end
+% update experiment weights
+handles = UpdateExperimentWeights(hObject, eventdata, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function estimation = getEstimationStructure(handles)
+estimation = [];
+% check if model and experiments in project
+project = handles.UserData.project;
+ps = struct(project);
+% check if models present
+if isempty(ps.models),
+    errordlg('No models present in project.');
+    return
+end
+% check if experiments in project
+if isempty(ps.experiments),
+    errordlg('No experiments present in project.');
+    return
+end
+% get estimation structure content
+% model, experiment, measurement related
+estimation.modelindex = get(handles.listofmodels,'Value');
+estimation.experiments.indices = get(handles.listofexperiments,'Value');
+estimation.experiments.measurementindices = {};
+estimation.experiments.weight = handles.UserData.allExperimentWeights(estimation.experiments.indices);
+estimation.experiments.measuremenweight = {};
+% parameter and initial condition related
+result = getParamInfo(handles);
+if isempty(result),
+    estimation = [];
+    return
+end
+estimation.parameters.names = result.paramnames;
+estimation.parameters.lowbounds = result.paramlow;
+estimation.parameters.highbounds = result.paramhigh;
+estimation.parameterslocal.names = result.paramlocalnames;
+estimation.parameterslocal.lowbounds = result.paramlocallow;
+estimation.parameterslocal.highbounds = result.paramlocalhigh;
+estimation.initialconditions.names = result.icnames;
+estimation.initialconditions.lowbounds = result.iclow;
+estimation.initialconditions.highbounds = result.ichigh;
+% options related
+estimation.optimization.method = handles.UserData.optimizernames{get(handles.optimizerlist,'Value')};
+OPTIONS = [];
+eval(handles.UserData.optimizeroptions{get(handles.optimizerlist,'Value')});
+estimation.optimization.options = OPTIONS;
+% integrator options
+estimation.integrator.options = handles.UserData.INTEGRATOROPTIONS;
+% flags
+estimation.initialconditionsFlag = get(handles.initialConditionsFlag,'Value')-1;
+estimation.displayFlag = get(handles.displayFlag,'Value')-1;
+estimation.scalingFlag = get(handles.scalingFlag,'Value')-1;
+estimation.timescalingFlag = get(handles.timeScalingFlag,'Value')-1;
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [result] = getParamInfo(handles)
+result = [];
+% get the three texts
+help = get(handles.globalparaminfo,'String');
+globalparaminfo = sprintf('%s',char([double(help) 10*ones(size(help,1),1)])');
+help = get(handles.localparaminfo,'String');
+localparaminfo = sprintf('%s',char([double(help) 10*ones(size(help,1),1)])');
+help = get(handles.icinfo,'String');
+icinfo = sprintf('%s',char([double(help) 10*ones(size(help,1),1)])');
+paramglobaltext = ['{' globalparaminfo '};'];
+paramlocaltext = ['{' localparaminfo '};'];
+ictext = ['{' icinfo '};'];
+% evaluate the texts
+try
+    paramglobal = eval(paramglobaltext);    
+catch
+    errordlg('Please check the definition of the global parameter settings.');
+    return
+end
+try
+    paramlocal = eval(paramlocaltext);
+catch
+    errordlg('Please check the definition of the local parameter settings.');
+    return
+end
+try
+    ic = eval(ictext);
+catch
+    errordlg('Please check the definition of the initial condition settings.');
+    return
+end
+% assign output variables
+if ~isempty(paramglobal),
+    try
+        result.paramnames = paramglobal(:,1);
+        result.paramlow = cell2mat(paramglobal(:,2));
+        result.paramhigh = cell2mat(paramglobal(:,3));
+    catch
+        errordlg('Please check the definition of the global parameter settings.');
+        result = [];
+        return
+    end
+else
+    errordlg('You need to define at least one global parameter to consider.');
+    result = [];
+    return
+end
+if ~isempty(paramlocal),
+    try
+        result.paramlocalnames = paramlocal(:,1);
+        result.paramlocallow = cell2mat(paramlocal(:,2));
+        result.paramlocalhigh = cell2mat(paramlocal(:,3));
+    catch
+        errordlg('Please check the definition of the local parameter settings.');
+        result = [];
+        return
+    end
+else
+    result.paramlocalnames = {};
+    result.paramlocallow = [];
+    result.paramlocalhigh = [];
+end
+if ~isempty(ic),
+    try
+        result.icnames = ic(:,1);
+        result.iclow = cell2mat(ic(:,2));
+        result.ichigh = cell2mat(ic(:,3));
+    catch
+        errordlg('Please check the definition of the initial condition settings.');
+        result = [];
+        return
+    end
+else
+    result.icnames = {};
+    result.iclow = [];
+    result.ichigh = [];
+end
+% check low < high
+if sum(result.paramlow > result.paramhigh) ~= 0,
+    errordlg('At least on high bound < low bound in global parameters.');
+    result = [];
+    return
+end
+if sum(result.paramlocallow > result.paramlocalhigh) ~= 0,
+    errordlg('At least on high bound < low bound in local parameters.');
+    result = [];
+    return
+end
+if sum(result.iclow > result.ichigh) ~= 0,
+    errordlg('At least on high bound < low bound in initial conditions.');
+    result = [];
+    return
+end
+% check that params really model parameters
+project = handles.UserData.project;
+ps = struct(project);
+m = get(handles.listofmodels,'Value');
+model = ps.models{m};
+try
+    dummy = IQMparameters(model,result.paramnames);
+    dummy = IQMparameters(model,result.paramlocalnames);
+    % check that ics really model states
+    dummy = IQMinitialconditions(model,result.icnames);
+catch
+    errordlg(lasterr);
+    result = [];
+    return
+end
+% check that no double definition of local and global params
+intersection = intersect(result.paramnames,result.paramlocalnames);
+text = '';
+for k=1:length(intersection),
+    text = sprintf('%s%s,',text,intersection{k});
+end
+text = text(1:end-1);
+if ~isempty(intersection),
+	errordlg(sprintf('The following parameters are defined both as local and global:\n%s',text));
+    result = [];
+    return
+end
+% check elements appearing more than once
+if length(unique(result.paramnames)) ~= length(result.paramnames),
+    errordlg('Some global parameters appear more than once.');
+    result = [];
+    return
+end
+if length(unique(result.paramlocalnames)) ~= length(result.paramlocalnames),
+    errordlg('Some local parameters appear more than once.');
+    result = [];
+    return
+end
+if length(unique(result.icnames)) ~= length(result.icnames),
+    errordlg('Some initial conditions appear more than once.');
+    result = [];
+    return
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function handles = initializeEstimationOptions(handles)
+handles = setOptimizers(handles);
+handles = prepareOptimizerOptions(handles);
+% set flags
+% initial conditions flag
+String = {'0: use nominal model/experiment settings', '1: use averages from first time-point in measurements'};
+set(handles.initialConditionsFlag,'String',String);
+set(handles.initialConditionsFlag,'Value',2);
+% Scaling flag
+String = {'0: no scaling', '1: max values', '2: mean values', '3: (max-min) error bound sacaling'};
+set(handles.scalingFlag,'String',String);
+set(handles.scalingFlag,'Value',2);
+% Timescaling flag
+String = {'0: no timescaling', '1: strong timescaling', '2: less timescaling', '3: even less', '4: etc. ...', '5','6','7','8'};
+set(handles.timeScalingFlag,'String',String);
+set(handles.timeScalingFlag,'Value',1);
+% Display flag
+String = {'0: no messages', '1: final message', '2: iteration and final'};
+set(handles.displayFlag,'String',String);
+set(handles.displayFlag,'Value',3);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function handles = setOptimizers(handles)
+% find the available optimizers in the IQM Tools Lite (non academic)
+optimizersPath = [fileparts(which('installIQMlite')) '/tools/optimization'];
+old = pwd;
+cd(optimizersPath);
+all = dir('*.m');
+cd(old);
+optimizerfunctions = {all.name};
+% swap first with simplexIQM
+indexsimplex = strmatchIQM('simplexIQM',optimizerfunctions);
+help = optimizerfunctions{1};
+optimizerfunctions{1} = 'simplexIQM.m';
+optimizerfunctions{indexsimplex} = help;
+% remove .m from the names
+for k=1:length(optimizerfunctions),
+    optimizerfunctions{k} = strrep(optimizerfunctions{k},'.m','');
+end
+optimizernames = {};
+optimizerdescription = {};
+% get description if existing
+for k=1:length(optimizerfunctions),
+    try
+        help = feval(optimizerfunctions{k});
+        isok = 1;
+    catch
+        isok = 0;
+    end
+    if isok,
+        try 
+            optimizernames{end+1} = optimizerfunctions{k};
+            optimizerdescription{end+1} = sprintf('%s: %s',optimizerfunctions{k},help.description);
+        catch
+            optimizernames{end+1} = optimizerfunctions{k};
+            optimizerdescription{end+1} = optimizerfunctions{k};
+        end
+    end
+end
+% set them into the pulldownmenu
+set(handles.optimizerlist,'String',optimizerdescription);
+% save the names of the optimizers to use them afterwards
+handles.UserData.optimizernames = optimizernames;
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function handles = prepareOptimizerOptions(handles)
+% get optimizernames
+optimizernames = handles.UserData.optimizernames;
+% build optimizer-specific options text
+optimizeroptions = {};
+for k=1:length(optimizernames),
+    text = '';
+    % get optimizer decriptions and default options
+    optinfo = feval(optimizernames{k});
+    % add name of optimizer
+    try 
+        text = sprintf('%s%% Optimizer: %s\n',text,optinfo.name); 
+    catch
+        text = sprintf('%s%% Optimizer: %s\n',text,optimizernames{k});         
+    end
+    % add description
+    try text = sprintf('%s%% %s\n\n',text,optinfo.description); catch, end
+    % add default settings
+    try
+        optnames = optinfo.defaultOptions.names;
+        optvalues = optinfo.defaultOptions.values;
+        optdescription = optinfo.defaultOptions.description;
+        for k2=1:length(optnames),
+            text = sprintf('%s%% %s:\nOPTIONS.%s = %s;\n',text,optdescription{k2},optnames{k2},optvalues{k2});
+        end
+    catch
+    end
+    % save the stuff
+    optimizeroptions{k} = text;
+end
+handles.UserData.optimizeroptions = optimizeroptions;
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function handles = disableAllButtons(handles)
+% disable all but the run estimation and run fit analysis button
+set(handles.plotmeasurements,'Enable','off');
+set(handles.simulatesingleexperiment,'Enable','off');
+set(handles.comparemeasurement,'Enable','off');
+set(handles.manualtuning,'Enable','off');
+set(handles.identifiabilityanalysis,'Enable','off');
+set(handles.optimizerOptions,'Enable','off');
+set(handles.InitializeParamSettings,'Enable','off');
+set(handles.writeout,'Enable','off');
+set(handles.residualanalysis,'Enable','off');
+set(handles.boxplot,'Enable','off');
+set(handles.clustering,'Enable','off');
+set(handles.correlation,'Enable','off');
+set(handles.histogram,'Enable','off');
+set(handles.pairwisecorrelation,'Enable','off');
+set(handles.significantcorrelation,'Enable','off');
+set(handles.updateestimationsettings,'Enable','off');
+set(handles.saveestimationsettings,'Enable','off');
+set(handles.resetproject,'Enable','off');
+set(handles.FileMenu,'Enable','off');
+set(handles.ModelMenu,'Enable','off');
+set(handles.ExperimentMenu,'Enable','off');
+set(handles.EstimationMenu,'Enable','off');
+set(handles.OtherMenu,'Enable','off');
+set(handles.HelpMenu,'Enable','off');
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function handles = enableAllButtons(handles)
+% disable all but the run estimation and run fit analysis button
+set(handles.plotmeasurements,'Enable','on');
+set(handles.simulatesingleexperiment,'Enable','on');
+set(handles.comparemeasurement,'Enable','on');
+set(handles.manualtuning,'Enable','on');
+set(handles.identifiabilityanalysis,'Enable','on');
+set(handles.optimizerOptions,'Enable','on');
+set(handles.InitializeParamSettings,'Enable','on');
+set(handles.writeout,'Enable','on');
+set(handles.residualanalysis,'Enable','on');
+set(handles.boxplot,'Enable','on');
+set(handles.clustering,'Enable','on');
+set(handles.correlation,'Enable','on');
+set(handles.histogram,'Enable','on');
+set(handles.pairwisecorrelation,'Enable','on');
+set(handles.significantcorrelation,'Enable','on');
+set(handles.updateestimationsettings,'Enable','on');
+set(handles.saveestimationsettings,'Enable','on');
+set(handles.resetproject,'Enable','on');
+set(handles.FileMenu,'Enable','on');
+set(handles.ModelMenu,'Enable','on');
+set(handles.ExperimentMenu,'Enable','on');
+set(handles.EstimationMenu,'Enable','on');
+set(handles.OtherMenu,'Enable','on');
+set(handles.HelpMenu,'Enable','on');
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function handles = applyEstimationSettings(handles,estimation)
+% name and notes
+try name = estimation.name; catch, name = 'untitled estimation'; end
+try notes = estimation.notes; catch, notes = 'no estimation notes'; end
+allnotestext = sprintf('%s\n%s',name,notes);
+set(handles.estimationsettingnotes,'String',allnotestext);
+% model index
+set(handles.listofmodels,'Value',estimation.modelindex);
+% experiment indices
+set(handles.listofexperiments,'Value',estimation.experiments.indices);
+% experiment weights
+text = sprintf('%g,',estimation.experiments.weight);
+set(handles.experimentweights,'String',text(1:end-1));
+if handles.donotchangeParameters == 0,
+    % global/local parameters + ics
+    pgn = estimation.parameters.names;
+    pglb = estimation.parameters.lowbounds;
+    pgub = estimation.parameters.highbounds;
+    pln = estimation.parameterslocal.names;
+    pllb = estimation.parameterslocal.lowbounds;
+    plub = estimation.parameterslocal.highbounds;
+    icn = estimation.initialconditions.names;
+    iclb = estimation.initialconditions.lowbounds;
+    icub = estimation.initialconditions.highbounds;
+    [ictext,paramtext,paramlocaltext] = helpparamictextIQM(pgn,pglb,pgub,pln,pllb,plub,icn,iclb,icub);
+    set(handles.globalparaminfo,'String',paramtext);
+    set(handles.localparaminfo,'String',paramlocaltext);
+    set(handles.icinfo,'String',ictext);
+end
+% optimization method
+optindex = strmatchIQM(estimation.optimization.method,handles.UserData.optimizernames,'exact');
+set(handles.optimizerlist,'Value',optindex);
+% optimization options
+optoptionstext = getoptimizeroptionstext(estimation.optimization.options,estimation.optimization.method);
+handles.UserData.optimizeroptions{optindex} = optoptionstext;
+% flags
+set(handles.initialConditionsFlag,'Value',estimation.initialconditionsFlag+1);
+set(handles.displayFlag,'Value',estimation.displayFlag+1);
+set(handles.scalingFlag,'Value',estimation.scalingFlag+1);
+set(handles.timeScalingFlag,'Value',estimation.timescalingFlag+1);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function text = getoptimizeroptionstext(options,method)
+text = '';
+% get optimizer decriptions and default options
+optinfo = feval(method);
+% add name of optimizer
+try
+    text0 = sprintf('%s%% Optimizer: %s\n',text,optinfo.name);
+catch
+    text0 = sprintf('%s%% Optimizer: %s\n',text,method);
+end
+% add description
+try text0 = sprintf('%s%% %s\n\nOPTIONS = [];',text0,optinfo.description); catch, end
+% parse the options structure and add to options text
+text = getdatatextstructIQM(options,'OPTIONS',text0);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function text = getdatatextstruct(root,roottext)
+% converting given root level of a structure into text
+text = '';
+fn = fieldnames(root);
+for k=1:length(fn),
+    fv = getfield(root,fn{k});
+    if isnumeric(fv),
+        help = num2str(fv);
+        if length(fv) == 1,
+            text = sprintf('%s%s.%s = %s;\n',text,roottext,fn{k},help);
+        else
+            text = sprintf('%s%s.%s = [%s];\n',text,roottext,fn{k},help);
+        end
+    end
+    if ischar(fv),
+        text = sprintf('%s%s.%s = ''%s'';\n',text,roottext,fn{k},fv);
+    end
+    if iscell(fv),
+        help = '';
+        for k2 = 1:length(fv),
+            if ischar(fv{k2}),
+                help2 = ['''' fv{k2} ''''];
+            elseif isnumeric(fv{k2}),
+                help2 = num2str(fv{k2});
+            else
+                help2 = '';
+            end
+            help = sprintf('%s%s,',help,help2);
+        end
+        text = sprintf('%s%s.%s = {%s};\n',text,roottext,fn{k},help(1:end-1));
+    end
+end
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function handles = clearProject(hObject, eventdata, handles)
+% remove other things
+handles.UserData = [];
+handles.UserData.projectOrig = IQMprojectSB();  % empty project
+handles.UserData.project = IQMprojectSB();      % empty project
+handles.UserData.allExperimentWeights = [];
+handles.UserData.estdata = [];
+handles.UserData.donotchangeexperimentsFlag = 0;
+handles.UserData.empty = 1;
+handles.donotchangeParameters = 0;
+% intergrator options
+handles.UserData.INTEGRATOROPTIONS = [];
+handles.UserData.INTEGRATOROPTIONS.abstol = 1e-6;
+handles.UserData.INTEGRATOROPTIONS.reltol = 1e-6;
+handles.UserData.INTEGRATOROPTIONS.minstep = 0;
+handles.UserData.INTEGRATOROPTIONS.maxstep = inf;
+handles.UserData.INTEGRATOROPTIONS.maxnumsteps = 1000;
+% clear GUI
+set(handles.experimentweights,'String',' ');
+set(handles.globalparaminfo,'String','');
+set(handles.localparaminfo,'String','');
+set(handles.icinfo,'String','');
+set(handles.estimationsettingnotes,'String','');
+% initialize right hand options for estimation
+handles = initializeEstimationOptions(handles);
+set(handles.listofestimations,'String',' '); % intentionally a space
+set(handles.listofmodels,'String',' '); % intentionally a space
+set(handles.listofexperiments,'String',' '); % intentionally a space
+set(handles.listofestimations,'Value',1); 
+set(handles.listofmodels,'Value',1); 
+set(handles.listofexperiments,'Value',1); 
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMparamestGUI_dir/auxiliary/editoptionsGUI.fig b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMparamestGUI_dir/auxiliary/editoptionsGUI.fig
new file mode 100644
index 0000000000000000000000000000000000000000..bf633a437b2f35c1124cd9d1e3a16cf46eb9fb3f
Binary files /dev/null and b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMparamestGUI_dir/auxiliary/editoptionsGUI.fig differ
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMparamestGUI_dir/auxiliary/editoptionsGUI.m b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMparamestGUI_dir/auxiliary/editoptionsGUI.m
new file mode 100644
index 0000000000000000000000000000000000000000..f28d5262b9cb97e475fccc333870217f5382a88c
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMparamestGUI_dir/auxiliary/editoptionsGUI.m	
@@ -0,0 +1,102 @@
+function varargout = editoptionsGUI(varargin)
+% Just takes some options text and allows to modify it.
+
+% Begin initialization code - DO NOT EDIT
+gui_Singleton = 1;
+gui_State = struct('gui_Name',       mfilename, ...
+                   'gui_Singleton',  gui_Singleton, ...
+                   'gui_OpeningFcn', @editoptionsGUI_OpeningFcn, ...
+                   'gui_OutputFcn',  @editoptionsGUI_OutputFcn, ...
+                   'gui_LayoutFcn',  [] , ...
+                   'gui_Callback',   []);
+if nargin && ischar(varargin{1})
+    gui_State.gui_Callback = str2func(varargin{1});
+end
+
+if nargout
+    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
+else
+    gui_mainfcn(gui_State, varargin{:});
+end
+% End initialization code - DO NOT EDIT
+
+% --- Executes just before editoptionsGUI is made visible.
+function editoptionsGUI_OpeningFcn(hObject, eventdata, handles, varargin)
+handles.output = hObject;
+% get the input argument and display it
+help = varargin{1};
+handles.UserData.optionstext = help{1};
+header = varargin{2};
+set(handles.optionstextEdit,'String',handles.UserData.optionstext);
+set(handles.header,'String',header);
+% Update handles structure
+guidata(hObject, handles);
+% wait for action
+uiwait(handles.figure1)
+return
+
+% --- Outputs from this function are returned to the command line.
+function varargout = editoptionsGUI_OutputFcn(hObject, eventdata, handles) 
+varargout{1} = handles.output;
+% close the GUI
+delete(hObject);
+return
+
+% --- Executes on button press in okbutton.
+function okbutton_Callback(hObject, eventdata, handles)
+% get the text
+text = get(handles.optionstextEdit,'String');
+% convert it to a normal string
+text = sprintf('%s',char([double(text) 10*ones(size(text,1),1)])');
+% evaluate it to see if it leads to an error
+OPTIONS = [];
+try 
+    texttest = strrep(text,sprintf('\n'),sprintf(';\n'));
+    eval(texttest); 
+catch
+    errordlg('Syntax error in the options definition.');
+    return
+end
+% otherwise update options text
+handles.output = text;
+% Update handles structure
+guidata(hObject, handles);
+% Resume
+uiresume(handles.figure1);
+return
+
+% --- Executes on button press in cancelbutton.
+function cancelbutton_Callback(hObject, eventdata, handles)
+handles.output = handles.UserData.optionstext;
+% Update handles structure
+guidata(hObject, handles);
+% Resume
+uiresume(handles.figure1);
+return
+
+
+
+
+
+function optionstextEdit_Callback(hObject, eventdata, handles)
+% hObject    handle to optionstextEdit (see GCBO)
+% eventdata  reserved - to be defined in a future version of MATLAB
+% handles    structure with handles and user data (see GUIDATA)
+
+% Hints: get(hObject,'String') returns contents of optionstextEdit as text
+%        str2double(get(hObject,'String')) returns contents of optionstextEdit as a double
+
+
+% --- Executes during object creation, after setting all properties.
+function optionstextEdit_CreateFcn(hObject, eventdata, handles)
+% hObject    handle to optionstextEdit (see GCBO)
+% eventdata  reserved - to be defined in a future version of MATLAB
+% handles    empty - handles not created until after all CreateFcns called
+
+% Hint: edit controls usually have a white background on Windows.
+%       See ISPC and COMPUTER.
+if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
+    set(hObject,'BackgroundColor','white');
+end
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMparamestGUI_dir/auxiliary/getparamictextIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMparamestGUI_dir/auxiliary/getparamictextIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..496bbd593b96f5fe0612bdafa7d01c9bcc112eeb
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMparamestGUI_dir/auxiliary/getparamictextIQM.m	
@@ -0,0 +1,168 @@
+function [varargout] = getparamictextIQM(varargin)
+% getparamictextIQM: This function aids in constructing the text that is 
+% needed to define the global and local parameters and the initial
+% conditions for parameter estimation purposes. It works both on project
+% and models.
+%
+% USAGE:
+% ======
+% getparamictextIQM(model)
+% getparamictextIQM(project)
+% getparamictextIQM(project,modelindex)
+% getparamictextIQM(model,OPTIONS)
+% getparamictextIQM(project,OPTIONS)
+% getparamictextIQM(project,modelindex,OPTIONS)
+% [output] = getparamictextIQM(model)
+% [output] = getparamictextIQM(project)
+% [output] = getparamictextIQM(project,modelindex)
+% [output] = getparamictextIQM(model,OPTIONS)
+% [output] = getparamictextIQM(project,OPTIONS)
+% [output] = getparamictextIQM(project,modelindex,OPTIONS)
+% 
+% model: IQMmodel
+% project: IQMprojectSB
+% modelindex: The index of the model in an IQMprojectSB to use
+% OPTIONS: a structure with additional informations
+%   OPTIONS.lowerbounds: scalar factor, determining the lower bound for a
+%       parameter by: factor*"original parameter value".
+%   OPTIONS.highbounds: scalar factor, determining the upper bound for a
+%       parameter by: factor*"original parameter value".
+%
+% DEFAULT VALUES:
+% ===============
+% modelindex: 1
+% OPTIONS.lowbounds: 0.1
+% OPTIONS.highbounds: 10
+%
+% Output Arguments:
+% =================
+% If no output argument is specified, the determined text it written out in
+% the matlab command window. Otherwise, the information is returned in a
+% structure:
+%
+% output.completeText: The complete text.
+% output.parametersText: Only the parameters with bounds
+% output.initialConditionsText: Only the initial conditions with bounds
+%
+% Note that automatically no distinction between parameters can be made
+% that are to be estimated locally or globally. Therefore, all parameters
+% appear in the complete text in the global parameter section. Just copy
+% and paste when you need it!
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin < 1 || nargin > 3,
+    error('Incorrect number of input arguments.');
+end
+modelindex = 1;
+OPTIONS = [];
+if nargin == 2,
+    if isstruct(varargin{2}),
+        OPTIONS = varargin{2};
+    else
+        modelindex = varargin{2};
+    end
+end
+if nargin == 3,
+    modelindex = varargin{2};
+    OPTIONS = varargin{3};
+end
+if isIQMmodel(varargin{1}),
+    model = varargin{1};
+elseif isIQMprojectSB(varargin{1}),
+    project = varargin{1};
+    model = IQMgetmodel(project,modelindex);
+else
+    error('Incorrect input arguments.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE NON-NUMERIC INITIAL CONDITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% just by replacing them
+% + warning ... as user feedback
+if ~hasonlynumericICsIQM(model),
+    model = IQMconvertNonNum2NumIC(model);
+    disp('Warning: The model contains non-numeric initial conditions. For this analysis these are replaced');
+    disp('by numeric initial conditions, determined from the non-numeric ones.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET LOWER AND UPPER BOUND FACTORS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+lowbounds = 0.1;
+highbounds = 10;
+try lowbounds = OPTIONS.lowbounds; catch, end
+try highbounds = OPTIONS.highbounds; catch, end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET STATENAMES, ICs, PARAMNAMES, VALUES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[sn,dummy,ic] = IQMstates(model);
+[pn,pv] = IQMparameters(model);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CONSTRUCT IC and PARAM TEXTs
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+pgn = pn;
+pln = {};
+icn = sn;
+pglb = pv*lowbounds;
+pgub = pv*highbounds;
+pllb = [];
+plub = [];
+iclb = ic*lowbounds;
+icub = ic*highbounds;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE ZERO VALUE NOMINAL VALUES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+pgub(find(pv==0)) = 100;
+icub(find(ic==0)) = 100;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET TEXT PARTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[ictext,paramtext,paramlocaltext,maxlength] = helpparamictextIQM(pgn,pglb,pgub,pln,pllb,plub,icn,iclb,icub);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CONSTRUCT COMPLETE TEXT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+add = maxlength-length('Name');
+addText = char(32*ones(1,add));
+add2 = maxlength-length('Lower bounds');
+addText2 = char(32*ones(1,add2));
+completeText = '';
+completeText = sprintf('%s%%%% SELECT PARAMETERS/STATES TO ESTIMATE AND CORRESPONDING BOUNDS\n',completeText);
+completeText = sprintf('%s%% Global parameters\n',completeText);
+completeText = sprintf('%s%% Names%s  Lower bounds%s  Upper bounds\n',completeText,addText,addText2);
+completeText = sprintf('%sparamdata = {\n',completeText);
+completeText = sprintf('%s%s',completeText,paramtext);
+completeText = sprintf('%s};\n\n',completeText);
+
+completeText = sprintf('%s%% Local (experiment dependend) parameters\n',completeText);
+completeText = sprintf('%s%% Names%s  Lower bounds%s  Upper bounds\n',completeText,addText,addText2);
+completeText = sprintf('%sparamdatalocal = {\n',completeText);
+completeText = sprintf('%s};\n\n',completeText);
+
+completeText = sprintf('%s%% Initial conditions (always experiment dependend)\n',completeText);
+completeText = sprintf('%s%% Names%s  Lower bounds%s  Upper bounds\n',completeText,addText,addText2);
+completeText = sprintf('%sicdata = {\n',completeText);
+completeText = sprintf('%s%s',completeText,ictext);
+completeText = sprintf('%s};\n\n',completeText);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE THE OUTPUT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargout == 0,
+    disp(completeText);
+else
+    output = [];
+    output.completeText = completeText;
+	output.parametersText = paramtext;
+	output.initialConditionsText = ictext;
+    varargout{1} = output;
+end
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMparamestGUI_dir/auxiliary/helpparamictextIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMparamestGUI_dir/auxiliary/helpparamictextIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..191bccc8779f8dff0db1a00a7606fa0c9353264e
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMparamestGUI_dir/auxiliary/helpparamictextIQM.m	
@@ -0,0 +1,81 @@
+function [ictext,paramtext,paramlocaltext,maxlength] = helpparamictextIQM(pgn,pglb,pgub,pln,pllb,plub,icn,iclb,icub)
+% helpparamictextIQM: help function to construct the text that is
+% necessary to define parameters and initialconditions and associated high
+% and low bounds
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% and lowbounds for the estimation
+ictext = '';
+paramtext = '';
+paramlocaltext = '';
+% get the formatting nice
+maxlength = 0;
+maxlength2 = 0;
+for k=1:length(icn),
+    l = length(icn{k});
+    if l>maxlength,
+        maxlength = l;
+    end
+    l = length(sprintf('%g',iclb(k)));
+    if l>maxlength2,
+        maxlength2 = l;
+    end    
+end
+for k=1:length(pgn),
+    l = length(pgn{k});
+    if l>maxlength,
+        maxlength = l;
+    end
+    l = length(sprintf('%g',pglb(k)));
+    if l>maxlength2,
+        maxlength2 = l;
+    end    
+end
+for k=1:length(pln),
+    l = length(pln{k});
+    if l>maxlength,
+        maxlength = l;
+    end
+    l = length(sprintf('%g',pllb(k)));
+    if l>maxlength2,
+        maxlength2 = l;
+    end    
+end
+maxlength2 = max(maxlength2,length('Lower bounds'));
+% states
+ictext = '';
+for k=1:length(icn),
+    l = length(icn{k});
+    add = maxlength - l;
+    addText = char(32*ones(1,add));
+    l = length(sprintf('%g',iclb(k)));
+    add2 = maxlength2 - l;
+    addText2 = char(32*ones(1,add2));
+    text = sprintf('''%s''%s  %g%s  %g',icn{k},addText,iclb(k),addText2,icub(k));
+    ictext = sprintf('%s%s\n',ictext,text);
+end
+% parameters global
+paramtext = '';
+for k=1:length(pgn),
+    l = length(pgn{k});
+    add = maxlength - l;
+    addText = char(32*ones(1,add));
+    l = length(sprintf('%g',pglb(k)));
+    add2 = maxlength2 - l;
+    addText2 = char(32*ones(1,add2));    
+    text = sprintf('''%s''%s  %g%s  %g',pgn{k},addText,pglb(k),addText2,pgub(k));
+    paramtext = sprintf('%s%s\n',paramtext,text);
+end
+% parameters local
+paramlocaltext = '';
+for k=1:length(pln),
+    l = length(pln{k});
+    add = maxlength - l;
+    addText = char(32*ones(1,add));
+    l = length(sprintf('%g',pllb(k)));
+    add2 = maxlength2 - l;
+    addText2 = char(32*ones(1,add2));    
+    text = sprintf('''%s''%s  %g%s  %g',pln{k},addText,pllb(k),addText2,plub(k));
+    paramlocaltext = sprintf('%s%s\n',paramlocaltext,text);
+end
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMparamestGUI_dir/auxiliary/notepadGUI.fig b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMparamestGUI_dir/auxiliary/notepadGUI.fig
new file mode 100644
index 0000000000000000000000000000000000000000..e09f639386eb1e6413ec7129e892758d52a9e88d
Binary files /dev/null and b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMparamestGUI_dir/auxiliary/notepadGUI.fig differ
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMparamestGUI_dir/auxiliary/notepadGUI.m b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMparamestGUI_dir/auxiliary/notepadGUI.m
new file mode 100644
index 0000000000000000000000000000000000000000..4cd6846e58f145545146d6734fbd97b857fb3408
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMparamestGUI_dir/auxiliary/notepadGUI.m	
@@ -0,0 +1,91 @@
+function varargout = notepadGUI(varargin)
+% Just takes some text and allows to modify it. Takes two input 
+% arguments. The first is the text to display and modify, the second
+% is the headline
+
+% Begin initialization code - DO NOT EDIT
+gui_Singleton = 1;
+gui_State = struct('gui_Name',       mfilename, ...
+                   'gui_Singleton',  gui_Singleton, ...
+                   'gui_OpeningFcn', @notepadGUI_OpeningFcn, ...
+                   'gui_OutputFcn',  @notepadGUI_OutputFcn, ...
+                   'gui_LayoutFcn',  [] , ...
+                   'gui_Callback',   []);
+if nargin && ischar(varargin{1})
+    gui_State.gui_Callback = str2func(varargin{1});
+end
+
+if nargout
+    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
+else
+    gui_mainfcn(gui_State, varargin{:});
+end
+% End initialization code - DO NOT EDIT
+
+% --- Executes just before notepadGUI is made visible.
+function notepadGUI_OpeningFcn(hObject, eventdata, handles, varargin)
+notestext = 'No Text';
+header = 'No Header';
+edit = 1;
+if nargin >= 4,
+    notestext = varargin{1};
+    notestext = notestext{1};
+end
+if nargin >= 5,
+    header = varargin{2};
+end
+if nargin >= 6,
+    edit = varargin{3};
+end
+if nargin > 7,
+    error('Incorrect number of input arguments.');
+end
+handles.output = notestext;
+% assign inputs
+handles.UserData.notestext = notestext;
+set(handles.notestextEdit,'String',handles.UserData.notestext);
+set(handles.header,'String',header);
+% check if edit or view
+if edit == 0,
+    set(handles.savechanges,'Visible','off');
+end
+% Update handles structure
+guidata(hObject, handles);
+% wait for action
+uiwait(handles.figure1)
+return
+
+% --- Outputs from this function are returned to the command line.
+function varargout = notepadGUI_OutputFcn(hObject, eventdata, handles) 
+varargout{1} = handles.output;
+varargout{2} = handles.output2;
+% close the GUI
+delete(hObject);
+return
+
+% --- Executes on button press in savechanges.
+function savechanges_Callback(hObject, eventdata, handles)
+% get the text
+text = get(handles.notestextEdit,'String');
+% convert it to a normal string
+text = sprintf('%s',char([double(text) 10*ones(size(text,1),1)])');
+% otherwise update optionstext
+handles.output = text;
+handles.output2 = 1;
+% Update handles structure
+guidata(hObject, handles);
+% Resume
+uiresume(handles.figure1);
+return
+
+% --- Executes on button press in exit.
+function exit_Callback(hObject, eventdata, handles)
+handles.output = handles.UserData.notestext;
+handles.output2 = 0;
+% Update handles structure
+guidata(hObject, handles);
+% Resume
+uiresume(handles.figure1);
+return
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMparamestGUI_dir/documentation/documentation.html b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMparamestGUI_dir/documentation/documentation.html
new file mode 100644
index 0000000000000000000000000000000000000000..f94b5250f123a4c5a6970ac28646bdaf918cd491
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMparamestGUI_dir/documentation/documentation.html	
@@ -0,0 +1,88 @@
+<style>
+/* MAIN POSITION */
+body {
+  background-color: #ffffff;
+  margin: 5px;
+  FONT-FAMILY: Verdana, Arial, Helvetica, sans-serif; 
+  FONT-SIZE: 12px; 
+  color: #2e3640;
+  text-align : justify;
+  line-height: 150%;
+}
+
+h1 {  
+	COLOR: #ffffff;   
+	FONT-SIZE: 20px;   
+	FONT-WEIGHT: normal;   
+	BACKGROUND: #d4db7b; 
+	padding: 2px 2px 7px 5px;  /* t r b l */
+	margin: 0px 0px 10px 0px;
+	display: block;
+	text-align: left;
+}
+
+p {
+	margin-bottom : 5px;	
+}
+
+a { 
+	COLOR: #929d00; 
+}
+
+table {
+	padding: 0px 0px 0px 0px;
+	margin: 0px 0px 0px 0px;
+	background: #ffffff;
+}
+
+td { 
+	padding: 5px 5px 5px 5px;
+	background: #f3f5f7;
+	margin: 0px 0px 0px 0px;
+	color: #2e3640;
+	font-size: 12px;
+    line-height: 150%;  
+}
+
+td.announcement {
+	border-style: solid;
+	border-color: #b7c034;
+	border-width: 2px;
+}
+
+li {
+	margin: 0px 0px 4px 0px;
+}
+
+ul {
+	padding-top: 5px;
+	padding-bottom: 5px;
+}
+</style>
+<h1>Documentation IQMparamestGUI</h1>
+<img src="pics/dart.png" width="200" align="right">
+<b>The IQMparamestGUI is a graphical user-interface aiming at giving users,
+which are unfamiliar with the MATLAB command line interface, the possibility of using 
+the IQM Tools Pro for parameter estimation tasks.</b>
+<p>
+Its use is hopefully (almost) self-explaining. Essentially, the main steps are the following:
+<ol>
+    <li><em>Load</em> (or <em>Import</em>) a project using the <em>File</em> menu.
+    <li>Choose the parameters/initial conditions you want to estimate. You need to specify their names and
+        lower and upper bounds.
+        <ul>
+            <li>Global parameters are model parameters that are the same across all experiments.
+            <li>Local parameters are experiment dependent.
+            <li>Initial conditions are always estimated experiment dependent.
+        </ul>
+        The <em>Initialize</em> and <em>Write out</em> buttons help with this task. Try them out and you will see
+        what they do. Copy and paste and change as you need it.
+    <li>Select desired estimation settings.
+    <li>Run the parameter estimation.
+    <li>Following the parameter estimation you can perform a fit analysis. A good idea is to select the 
+        <em>simplexIQM</em> or <em>SSmIQM</em> (if availabe) optimization methods for that, using smaller settings
+        for the maximum number of iterations.
+    <li>Export or save the project using again the <em>File</em> menu.
+</ol>
+At all times other tasks can be run from the buttons to the left. Just try them out.
+<p>
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMparamestGUI_dir/documentation/pics/dart.png b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMparamestGUI_dir/documentation/pics/dart.png
new file mode 100644
index 0000000000000000000000000000000000000000..daef88864b4d8c5964184dfd47247c730328c00a
Binary files /dev/null and b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMparamestGUI_dir/documentation/pics/dart.png differ
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMparamestGUI_dir/documentation/pics/green.jpg b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMparamestGUI_dir/documentation/pics/green.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..eb891f1918b30473121c6375042a1a310f0afece
Binary files /dev/null and b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMparamestGUI_dir/documentation/pics/green.jpg differ
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMparametercorrelation.m b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMparametercorrelation.m
new file mode 100644
index 0000000000000000000000000000000000000000..4e8ad83b74012b908ab779e62d4937c4679ecce0
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/IQMparametercorrelation.m	
@@ -0,0 +1,297 @@
+function [varargout] = IQMparametercorrelation(senssimdata,sensparameters,measuredcomponents)
+% IQMparametercorrelation: Function for determining parameter correlations 
+%   based on parametric sensitivities. The result can be used to check 
+%   a priori identifiability of parameters for given experimental settings.
+%   Several experiments can be combined. Measured states AND measured
+%   variables can be considered.
+%
+%   The method is based on:
+%   Jacquez, J.A. and Greif, P. (1985) Numerical parameter identifiability
+%   and estimability: Integrating identifiability, estimability, and
+%   optimal sampling design, Mathematical Biosciences, 77, pp. 201-227
+%
+% This function determines correlations between parameters. The inputs to
+% this function are parameter sensitivity trajectories returned from the
+% IQMsensitivity function, reflecting the sensitivity of the states and variables
+% to parameter changes during user-defined experiments. From this
+% information a parameter correlation matrix is determined. Off-diagonal
+% elements in this matrix that are close to +1 or -1 indicate problems in
+% identifying the corresponding parameters independently. Elements that are
+% close to zero indicate that there is no important correlation between the
+% corresponding elements and thus these parameters should be identifiable
+% independently without problem (for the defined experiments).
+%
+% A priori identifiability: The identifiability is a local property. For
+% different sets of parameter values different correlation matrices can be
+% obtained. Since unknown parameters are, by definition, unknown this might
+% lead to problems interpreting the results. However, one possible approach
+% is to run the identifiability analysis for different sets of parameter
+% values, randomly chosen in certain intervals around a best initial
+% guess.
+%
+% USAGE:
+% ======
+% output = IQMparametercorrelation(senssimdata,sensparameters,measuredcomponents)
+%
+% senssimdata: cell-array with output arguments from the sensitivity analysis function
+%       IQMsensitivity. The simulation should reflect (wrt, e.g., sampling
+%       time, stimuli) the experiments that are planned to obtain
+%       measurement data for the parameter estimation. 
+% sensparameters: cell-array with parameter names for which to determine
+%       the correlations
+% measuredcomponents: structure defining the measured states and variables:
+%       measuredcomponents.states
+%       measuredcomponents.variables
+%       It is possible to specify just one set of measured components. But
+%       it is also possible to specify one set per senssimdata.
+%
+% Output Arguments:
+% =================
+% When called without an output argument the parameter correlation matrix
+% is graphically represented. For easier graphical interpretation the
+% absolute values of the matrix elements are taken. White color indicates a
+% perfect correlation and black color indicates no correlation between
+% parameters. If an output argument is given, the results are returned as a
+% MATLAB structure as follows:
+%      output.parameters: cell-array with parameter names
+%      output.correlationMatrix: parameter correlation matrix
+%      output.G: stacked sensitivity matrix
+%      output.pValues: a matrix of p-values for testing
+%           the hypothesis of no correlation.  Each p-value is the probability
+%           of getting a correlation as large as the observed value by random
+%           chance, when the true correlation is zero.  If pValues(i,j) is small, say
+%           less than 0.05, then the correlation correlationMatrix(i,j) is significant.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE INPUT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin ~= 3,
+    error('Incorrect number of input arguments.');
+end
+if isstruct(senssimdata),
+    senssimdata = {senssimdata};
+end
+if ischar(sensparameters),
+    sensparameters = {sensparameters};
+end
+if length(measuredcomponents) == 1 && length(senssimdata) ~= 1,
+    newmeascomp = [];
+    for k=1:length(senssimdata),
+        newmeascomp(k) = measuredcomponents;
+    end
+    measuredcomponents = newmeascomp;
+elseif length(measuredcomponents) ~= length(senssimdata),
+    error('Number of sensitivity datasets and measured component set does not match.');
+end
+% check if ok
+if ~isfield(measuredcomponents,'states'),
+    error('Measured states not defined (if none, set to empty).');
+end
+if ~isfield(measuredcomponents,'variables'),
+    error('Measured variables not defined (if none, set to empty).');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK THAT ALL SENSPARAMETERS AND MEASURED ELEMENTS EXIST IN THE SENSSIMDATA
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Additionally the sensitivity data corresponding to the selected parameters is extracted
+% and information about the indices of the state and variable
+% elements is gathered since it might be different due to different
+% experiments.
+datainfo = [];
+datainfo.sensparamindices = [];
+datainfo.measuredstateindices = [];
+datainfo.measuredvariableindices = [];
+datainfo.timevector = [];
+datainfo.sensestatetrajectories = [];
+datainfo.sensevariabletrajectories = [];
+for k = 1:length(senssimdata),
+    senssimdatak = senssimdata{k};
+    senssimparam = senssimdatak.sensparameters;
+    senssimstates = senssimdatak.states;
+    senssimvariables = senssimdatak.variables;
+    % check sensparameters
+    for k2=1:length(sensparameters),
+        index = strmatchIQM(sensparameters{k2},senssimparam,'exact');
+        if isempty(index),
+            error('Parameter ''%s'' does not exist in the simulated sensitivity data.',sensparameters{k2});
+        else
+            datainfo(k).sensparamindices(k2) = index;
+        end
+    end
+    % check measured states
+    for k2=1:length(measuredcomponents(k).states),
+        index = strmatchIQM(measuredcomponents(k).states{k2},senssimstates,'exact');
+        if isempty(index),
+            error('State ''%s'' does not exist in the simulated sensitivity data.',measuredcomponents(k).states{k2});
+        else
+            datainfo(k).measuredstateindices(k2) = index;
+        end
+    end
+    % check measured variables
+    for k2=1:length(measuredcomponents(k).variables),
+        index = strmatchIQM(measuredcomponents(k).variables{k2},senssimvariables,'exact');
+        if isempty(index),
+            error('Variables ''%s'' does not exist in the simulated sensitivity data.',measuredcomponents(k).variables{k2});
+        else
+            datainfo(k).measuredvariableindices(k2) = index;
+        end
+    end
+    % get time vector for data 
+    datainfo(k).timevector = senssimdatak.time;
+    % get the sensitivities for the chosen parameters
+    datainfo(k).sensestatetrajectories = senssimdatak.paramtrajectories.states(datainfo(k).sensparamindices);
+    datainfo(k).sensevariabletrajectories = senssimdatak.paramtrajectories.variables(datainfo(k).sensparamindices);   
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DETERMINE CORRELATIONS BY STACKING
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DETERMINE THE STACKED SENSITIVITY MATRIX
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+G = [];
+for kdata = 1:length(datainfo),
+    for ktime = 1:length(datainfo(kdata).timevector),
+        Systates = []; % measured states in columns, sensparameters in rows
+        Syvariables = []; % measured variables in columns, sensparameters in rows
+        for kparam = 1:length(datainfo(kdata).sensestatetrajectories),
+            if ~isempty(datainfo(kdata).measuredstateindices),
+                Systates(:,end+1) = datainfo(kdata).sensestatetrajectories{kparam}(ktime,datainfo(kdata).measuredstateindices)';
+            end
+        end
+        for kparam = 1:length(datainfo(kdata).sensevariabletrajectories),
+            if ~isempty(datainfo(kdata).measuredvariableindices),
+                Syvariables(:,end+1) = datainfo(kdata).sensevariabletrajectories{kparam}(ktime,datainfo(kdata).measuredvariableindices)';
+            end
+        end
+        G = [G; Systates; Syvariables];
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DETERMINE THE PARAMETER CORRELATION MATRIX
+% Take out parameters with zero variance!
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[n,m] = size(G);
+C = cov(G);
+zerovarianceindices = find(diag(C)==0);
+G(:,zerovarianceindices) = [];  % take out the parameters
+allsensparameters = sensparameters;
+sensparameters = sensparameters(setdiff([1:length(sensparameters)],zerovarianceindices));
+[correlationMatrix,P,LB,UB] = corrcoef(G);
+
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% % DETERMINE CORRELATIONS BY AVERAGING
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% % DETERMINE THE STACKED SENSITIVITY MATRIX FOR EACH EXPERIMENT
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% G = {};
+% for kdata = 1:length(datainfo),
+%     G{kdata} = [];
+%     for ktime = 1:length(datainfo(kdata).timevector),
+%         Systates = []; % measured states in columns, sensparameters in rows
+%         Syvariables = []; % measured variables in columns, sensparameters in rows
+%         for kparam = 1:length(datainfo(kdata).sensestatetrajectories),
+%             if ~isempty(datainfo(kdata).measuredstateindices),
+%                 Systates(:,end+1) = datainfo(kdata).sensestatetrajectories{kparam}(ktime,datainfo(kdata).measuredstateindices)';
+%             end
+%         end
+%         for kparam = 1:length(datainfo(kdata).sensevariabletrajectories),
+%             if ~isempty(datainfo(kdata).measuredvariableindices),
+%                 Syvariables(:,end+1) = datainfo(kdata).sensevariabletrajectories{kparam}(ktime,datainfo(kdata).measuredvariableindices)';
+%             end
+%         end
+%         G{kdata} = [G{kdata}; Systates; Syvariables];
+%     end
+% end
+% 
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% % DETERMINE THE PARAMETER CORRELATION MATRIX
+% % Take out parameters with zero variance!
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% cM = {};
+% zVI_All = [];
+% zVI = {};
+% 
+% for k=1:length(G),
+%     Gk = G{k};
+%     C = cov(Gk);
+%     zerovarianceindices = find(diag(C)==0);
+%     zVI{k} = zerovarianceindices
+%     % get common zero variances
+%     if k==1,
+%         zVI_All = zerovarianceindices;
+%     else
+%         zVI_All = intersect(zVI_All,zerovarianceindices);
+%     end
+%     % remove the zero variance parameters from Gk
+%     Gk(:,zerovarianceindices) = [];  % take out the parameters
+%     [cM{k},P,LB,UB] = corrcoef(Gk);
+% end
+% 
+% helpCM = zeros(size(G{1},2));
+% correlationMatrix = zeros(size(G{1},2));
+% for k=1:length(cM),
+%     x = setdiff([1:size(G{k},2)],zVI{k});
+%     helpCM(x,x) = cM{k};
+%     correlationMatrix = correlationMatrix+helpCM;
+% end
+% correlationMatrix = correlationMatrix/length(G);
+% correlationMatrix(:,zVI_All) = [];
+% correlationMatrix(zVI_All,:) = [];
+% allsensparameters = sensparameters;
+% sensparameters = sensparameters(setdiff([1:length(sensparameters)],zVI_All));
+% zerovarianceindices = zVI_All;
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DISPLAY NOTE IF PARAMTERS HAVE BEEN TAKEN OUT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(zerovarianceindices),
+    text = '';
+    for k=1:length(zerovarianceindices),
+        text = sprintf('%sParameter ''%s'' shows 0 variance. Taken out of consideration.\n',text,allsensparameters{zerovarianceindices(k)});
+    end
+    disp(text);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle the output
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargout > 1,
+    error('Incorrect number of output arguments.');
+elseif nargout == 1,
+    output = [];
+    output.parameters = sensparameters;
+    output.correlationMatrix = correlationMatrix;
+    output.pValues = P;
+    output.corrcoefLB = LB;
+    output.corrcoefUB = UB;
+    output.G = G;
+    varargout{1} = output;
+else
+    % Plot the correlation matrix (absolute values)
+    % Prepare plot matrix
+    plotMatrix = [correlationMatrix zeros(size(correlationMatrix,1),1); -ones(1,size(correlationMatrix,2)+1)];
+    plotMatrix = abs(plotMatrix);
+    % Plot the result
+    figH = figure; clf;
+    axesH = gca(figH);
+    pcolor(plotMatrix);
+    axis square;
+    colorbar('EastOutside','YTick',[-1,-0.8,-0.6,-0.4,-0.2,0,0.2,0.4,0.6,0.8,1]);
+    set(axesH,'XTick',[1.5:size(correlationMatrix,1)+0.5]);
+    set(axesH,'XTickLabel',sensparameters);
+    try
+        set(gca,'XTickLabelRotation',90);
+    catch
+    end
+    set(axesH,'YTick',[1.5:size(correlationMatrix,1)+0.5]);
+    set(axesH,'YTickLabel',sensparameters);
+    colormap('Bone');
+    title('Parameter Correlation Matrix (absolute values)');
+end
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/auxiliary/plotIQMP_dir/plotIQMP.fig b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/auxiliary/plotIQMP_dir/plotIQMP.fig
new file mode 100644
index 0000000000000000000000000000000000000000..4425b9bfb3f0c1803f3be87766ab7be8b9e20a71
Binary files /dev/null and b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/auxiliary/plotIQMP_dir/plotIQMP.fig differ
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/auxiliary/plotIQMP_dir/plotIQMP.m b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/auxiliary/plotIQMP_dir/plotIQMP.m
new file mode 100644
index 0000000000000000000000000000000000000000..c0fff52a40d8fa8612eb55bf86be4118d356eb35
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/auxiliary/plotIQMP_dir/plotIQMP.m	
@@ -0,0 +1,270 @@
+function varargout = plotIQMP(varargin)
+% plotIQMP - allows to compare simulated experiments data to measurements
+%
+% USAGE:
+% ======
+% [] = plotIQMP(plotdata)
+%
+% plotdata: This datastructure is the output argument of the function 
+% IQMcomparemeasurements. 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INITIALIZATION CODE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Begin initialization code - DO NOT EDIT
+gui_Singleton = 1;
+gui_State = struct('gui_Name',       mfilename, ...
+                   'gui_Singleton',  gui_Singleton, ...
+                   'gui_OpeningFcn', @plotIQMP_OpeningFcn, ...
+                   'gui_OutputFcn',  @plotIQMP_OutputFcn, ...
+                   'gui_LayoutFcn',  [] , ...
+                   'gui_Callback',   []);
+if nargin && ischar(varargin{1})
+    gui_State.gui_Callback = str2func(varargin{1});
+end
+if nargout
+    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
+else
+    gui_mainfcn(gui_State, varargin{:});
+end
+% End initialization code - DO NOT EDIT
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INTERFACE FUNCTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% --- Executes just before plotIQMP is made visible.
+function plotIQMP_OpeningFcn(hObject, eventdata, handles, varargin)
+
+if nargin ~= 4,
+    error('Incorrect number of input arguments.');
+end
+handles.plotdata = varargin{1};
+% set modelselection and choose first model
+set(handles.modelselection,'String',{handles.plotdata.model.name});
+set(handles.modelselection,'Value',1);
+% set experimentselection for first model and first experiment
+set(handles.experimentselection,'String',{handles.plotdata.model(1).experiment.name});
+set(handles.experimentselection,'Value',1);
+% select plottype 
+handles.dataPlotType = 'plot';     
+% set errorbarflag to 1
+handles.errorbars = 1;
+% Initialize export figure handle and grid flag
+handles.exportFigureHandle = [];
+handles.grid = 0;
+% Doing a first plot
+doPlot(handles);
+% Choose default command line output for plotIQMP
+handles.output = hObject;
+% Update handles structure
+guidata(hObject, handles);
+return
+
+% --- Outputs from this function are returned to the command line.
+function varargout = plotIQMP_OutputFcn(hObject, eventdata, handles) 
+%varargout{1} = handles.output;
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PLOT FUNCTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function doPlot(handles)
+colorvector = {'b','g','r','c','m','y','k'};
+%markervector = {'o','x','+','*','s','d','v','^','<','>','p','h'};
+warning off;
+% get the data to plot
+plotdata = handles.plotdata;
+m = get(handles.modelselection,'Value');
+e = get(handles.experimentselection,'Value');
+edata = plotdata.model(m).experiment(e);
+% general information
+titletext = regexprep(edata.name,'_',' ');
+xlabeltext = 'Time';
+% simulated data information
+sim_timevector = edata.timevector;
+sim_componentnames = edata.componentnames;
+sim_componentvalues = edata.componentvalues;
+if isempty(sim_componentvalues),
+    error('Please check if the names of the measured data appear in the model.');
+end
+% plot simulated data
+for k=1:size(sim_componentvalues,2),
+    feval(handles.dataPlotType,sim_timevector,sim_componentvalues(:,k),'linewidth',2,'color',colorvector{mod(k-1,7)+1}); hold on;
+end
+% measured data information 
+for meas=1:length(edata.measurement),
+    meas_timevector = edata.measurement(meas).timevector;
+    meas_componentnames = edata.measurement(meas).componentnames;
+    meas_componentvalues = edata.measurement(meas).componentvalues;   
+    meas_maxvalues = edata.measurement(meas).maxvalues;   
+    meas_minvalues = edata.measurement(meas).minvalues;   
+%     marker = markervector{mod(meas-1,length(markervector))+1};
+%     feval(handles.dataPlotType,meas_timevector,meas_componentvalues,['--' marker]); hold on;
+    for k=1:size(sim_componentvalues,2),
+        feval(handles.dataPlotType,meas_timevector,meas_componentvalues(:,k),['*:'],'linewidth',2,'color',colorvector{mod(k-1,7)+1}); hold on;
+    end
+    if handles.errorbars == 1 && strcmp(handles.dataPlotType,'plot'),
+        % plot error bounds
+        for k=1:length(meas_componentnames),
+            color = colorvector{mod(k-1,7)+1};
+%             for k1 = 1:size(meas_timevector,1),
+            for k1 = 1:length(meas_timevector),
+                feval(handles.dataPlotType,[meas_timevector(k1),meas_timevector(k1)],[meas_minvalues(k1,k),meas_maxvalues(k1,k)],['.:',color]);
+            end
+        end
+    end
+end
+hold off;
+hlhlx = legend(sim_componentnames);
+set(hlhlx,'Interpreter','none');
+
+hlhlx = title(titletext);
+set(hlhlx,'Interpreter','none');
+hlhlx = xlabel(xlabeltext);
+set(hlhlx,'Interpreter','none');
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EXPORT FIGURE FUNCTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Export the figure
+function export_Callback(hObject, eventdata, handles)
+warning off;
+if isempty(handles.exportFigureHandle),
+    figH = figure;
+    handles.exportFigureHandle = figH;
+    % Update handles structure
+    guidata(hObject, handles);
+else
+    figH = handles.exportFigureHandle;
+    figure(figH);
+end
+nrow = str2num(get(handles.nrow,'String'));
+ncol = str2num(get(handles.ncol,'String'));
+nnumber = str2num(get(handles.nnumber,'String'));
+subplot(nrow,ncol,nnumber);
+doPlot(handles);
+if handles.grid == 1,
+    grid;
+end
+% set axes
+XLim = get(handles.plotarea,'Xlim');
+YLim = get(handles.plotarea,'Ylim');
+axis([XLim, YLim]);
+return
+
+% Request new figure for export
+function newexportfigure_Callback(hObject, eventdata, handles)
+handles.exportFigureHandle = [];
+% Update handles structure
+guidata(hObject, handles);
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% TRIVIAL FUNCTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% --- Executes on button press in zoombutton.
+function errorbarbutton_Callback(hObject, eventdata, handles)
+% toogle the errorbars in the figure
+if handles.errorbars == 0,
+    handles.errorbars = 1;
+else
+    handles.errorbars = 0;
+end
+% plot
+doPlot(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+% --- Executes on button press in zoombutton.
+function zoombutton_Callback(hObject, eventdata, handles)
+% toogle the zoom in the figure
+zoom
+return
+
+% --- Executes on button press in gridbutton.
+function gridbutton_Callback(hObject, eventdata, handles)
+% toogle the grid in the figure
+grid
+if handles.grid == 1,
+    handles.grid = 0;
+else
+    handles.grid = 1;
+end
+% Update handles structure
+guidata(hObject, handles);
+return
+
+% --- Executes on selection change in modelselection.
+function modelselection_Callback(hObject, eventdata, handles)
+try
+    modelindex = get(handles.modelselection,'Value');
+    set(handles.experimentselection,'String',{handles.plotdata.model(modelindex).experiment.name});
+    doPlot(handles);
+catch
+    errordlg('This selection is not possible.','Error','on');               
+end
+return
+
+% --- Executes on selection change in experimentselection.
+function experimentselection_Callback(hObject, eventdata, handles)
+try
+    doPlot(handles);
+catch
+    errordlg('This selection is not possible.','Error','on');               
+end
+return
+
+% --- From R2014B the radiobutton groups are handled differently ...
+function plotAxesSelection_SelectionChangeFcn(hObject, eventdata, handles)
+handles.dataPlotType = eventdata.NewValue.String;
+% Update handles structure
+guidata(hObject, handles);
+doPlot(handles);
+return
+
+% --- Executes on button press in plot.
+function plot_Callback(hObject, eventdata, handles)
+handles.dataPlotType = 'plot';
+% disable errorbarbutton
+set(handles.errorbarbutton,'Visible','on');
+% Update handles structure
+guidata(hObject, handles);
+doPlot(handles);
+return
+
+% --- Executes on button press in loglog.
+function semilogx_Callback(hObject, eventdata, handles)
+handles.dataPlotType = 'semilogx';
+% disable errorbarbutton
+set(handles.errorbarbutton,'Visible','off');
+handles.errorbars = 0;
+% Update handles structure
+guidata(hObject, handles);
+doPlot(handles);
+return
+
+% --- Executes on button press in semilogx.
+function semilogy_Callback(hObject, eventdata, handles)
+handles.dataPlotType = 'semilogy';
+% disable errorbarbutton
+set(handles.errorbarbutton,'Visible','off');
+handles.errorbars = 0;
+% Update handles structure
+guidata(hObject, handles);
+doPlot(handles);
+return
+
+% --- Executes on button press in loglog.
+function loglog_Callback(hObject, eventdata, handles)
+handles.dataPlotType = 'loglog';
+% disable errorbarbutton
+set(handles.errorbarbutton,'Visible','off');
+handles.errorbars = 0;
+% Update handles structure
+guidata(hObject, handles);
+doPlot(handles);
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/IQMparameterestimation.m b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/IQMparameterestimation.m
new file mode 100644
index 0000000000000000000000000000000000000000..d4c4e71585394710896f2424bdd546fc18cc5044
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/IQMparameterestimation.m	
@@ -0,0 +1,470 @@
+function [output] = IQMparameterestimation(project,estimation,varargin)
+% IQMparameterestimation: This function performs parameter estimation for
+% a given IQM project.
+% 
+% USAGE:
+% ======
+% [output] = IQMparameterestimation(project,estimation)        
+% [output] = IQMparameterestimation(project,estimation,noStopButtonFlag)        
+%
+% project: IQMprojectSB for which to do the estimation
+% noStopButtonFlag: 0: stop button, 1: no stop button
+% estimation: Structure that defines what to do.
+%     estimation.modelindex: index of the model in the project for which to
+%                            do the estimation
+%
+%     estimation.experiments.indices: vector with indices of the
+%                            experiments in the project for which to do the
+%                            estimation 
+%     estimation.experiments.measurementindices: cell-array with vector
+%                            entries, definining the indices of the
+%                            measurements to take into account for each
+%                            selected experiment
+%     estimation.experiments.weight: vector with weights of the
+%                            experiments in the project for which to do the
+%                            estimation 
+%     estimation.experiments.measurementweight: cell-array with vector
+%                            entries, definining the weight of the
+%                            measurements to take into account for each
+%                            selected experiment
+%
+%     Note that the measurementweights, if defined, override the weights
+%     on the experiments! Experiment weights are assigned equally to all 
+%     measurements within the corresponding experiment.
+% 
+%     The parameters to be estimated and their upper and lower bounds can
+%     be specified in a cell-matrix in which the first column contains the
+%     names of the parameters, the second column the lower bounds and the
+%     third column the upper bounds. This cell-matrix needs to be
+%     assigned to the following field:
+%                                       estimation.parameters
+%
+%     Alternatively, parameters and lower and upper bounds can be specified
+%     as follows:
+%
+%     estimation.parameters.names: cell-array with names of parameters to
+%                            be optimized
+%     estimation.parameters.lowbounds: lower bounds for the parameters. If
+%                            scalar, then this scalar is multiplied to the
+%                            initial guesses to obtain the lower bounds.
+%                            Otherwise, a vector can be specified with the
+%                            same length as the number of parameters to be
+%                            optimized.   
+%     estimation.parameters.highbounds: upper bounds for the parameters. If
+%                            scalar, then this scalar is multiplied to the
+%                            initial guesses to obtain the upper bounds.
+%                            Otherwise, a vector can be specified with the
+%                            same length as the number of parameters to be
+%                            optimized.
+%
+%     The local parameters to be estimated and their upper and lower bounds can
+%     be specified in a cell-matrix in which the first column contains the
+%     names of the parameters, the second column the lower bounds and the
+%     third column the upper bounds. This cell-matrix needs to be
+%     assigned to the following field:
+%                                       estimation.parameterslocal
+%
+%     Alternatively, local parameters and lower and upper bounds can be specified
+%     as follows:
+%
+%     estimation.parameterslocal.names: cell-array with names of parameters to
+%                            be optimized locally (independently for each
+%                            experiment).  Initial guesses are obtained from
+%                            the nominal model/nominal experiment.
+%     estimation.parameterslocal.lowbounds: same as for the parameters
+%                            above, just for the parameters to be estimated
+%                            locally. 
+%     estimation.parameterslocal.highbounds: same as for the parameters
+%                            above, just for the parameters to be estimated
+%                            locally. 
+%
+%     The states for which to estimate the initial conditions and their
+%     upper and lower bounds can be specified in a cell-matrix in which the
+%     first column contains the names of the states, the second column
+%     the lower bounds and the third column the upper bounds. This
+%     cell-matrix needs to be assigned to the following field:
+%
+%                                       estimation.initialconditions
+%
+%     NOTE THAT: initial conditions are always estimated independently for
+%     each experiment!
+%
+%     Alternatively, states and lower and upper bounds can be specified
+%     as follows:
+% 
+%     estimation.initialconditions.names: names of the states for which to
+%                            optimize the initial conditions. Optimization
+%                            is done for one experiment at a time. No
+%                            starting guesses can be specified. These are
+%                            taken from the model and the experiment
+%                            description + measurements.
+%     estimation.initialconditions.lowbounds: scalar or vector. Same
+%                            procedure as for parameter lowbounds.
+%     estimation.initialconditions.higbounds: scalar or vector. Same
+%                            procedure as for parameter highbounds.
+%
+%     estimation.optimization.method: name of an optimization function. This
+%                            function has to be present in the MATLAB path
+%                            and the input/output interface has to be the
+%                            same as in the IQM Tools Lite optimization methods.  
+%     estimation.optimization.options: options for the optimization method
+%                            (third input argument to the optimization
+%                            method). It is assumed that these options are
+%                            defined in a structure (see simplexIQM.m as
+%                            example). 
+%
+%     estimation.integrator.options: options for the integration using MEX
+%                           simulation files. These are defined as a
+%                           structure. The available fields, etc. are
+%                           documented in the help text of the IQMPsimulate
+%                           function.
+% 
+%     estimation.initialconditionsFlag: 0=nominal from model or experiment
+%                            description, 1=average from first timepoint in
+%                            measurements  
+%     estimation.displayFlag: show output or not (0=none, 1=final,
+%                            2=1+iterations, 3=2+othermessages
+%     estimation.scalingFlag: 0=no scaling, 1=scaling by max(abs())
+%                            values in measurements, 2=scaling by mean
+%                            values of measurements, 3=scaling by min/max
+%                            bounds:
+%                            [x_measured(ti)-x(ti)]^2/[xmax(ti)-xmin(ti)]^2
+%                            This last scaling alternative is only
+%                            possible, if all max and min values for all
+%                            the measurements are defined in the
+%                            measurement data.
+%     estimation.timescalingFlag: timescaling is useful in cases of
+%                            nonequidistant sampling, where some ranges are
+%                            tightly sampled and others aren't. In the case
+%                            of equidistant sampling this flag has no
+%                            effect. Otherwise the effect is maximal if it
+%                            is set to 1, with decreasing effect as it
+%                            increases.
+%
+%     estimation.costfunction: string with the name of the costfunction
+%                            called by the costfunction interface.
+%     estimation.logscalingResidualsFlag: Flag to indicate if the residuals
+%                            should be scaled logarithmically or not. 0
+%                            means no logscaling, 1 means logscaling.
+%
+%
+% DEFAULT VALUES:
+% ===============
+% noStopButtonFlag: 0 
+%
+% estimation.modelindex: 1 (first model in project)
+% estimation.experiments.indices: [] (use all experiments available)
+% estimation.experiments.measurementindices: {} (use all measurements available)
+% estimation.experiments.weight: {} (all weights 1)
+% estimation.experiments.measuremenweight: {} (all weights 1}
+% estimation.parameters.names: {} (estimate all parameters in the model)
+% estimation.parameters.lowbounds: 1e-3 (1e-3*initialguess)
+% estimation.parameters.highbounds: 1e3 (1e3*initialguess)
+% estimation.parameterslocal.names: {} (don't do any local estimation)
+% estimation.parameterslocal.lowbounds: 1e-3 (1e-3*initialguess)
+% estimation.parameterslocal.highbounds: 1e3 (1e3*initialguess)
+% estimation.initialconditions.names: {} (don't estimate initial conditions)
+% estimation.initialconditions.lowbounds: 1e-3 (1e-3*nominalvalues)
+% estimation.initialconditions.highbounds: 1e3 (1e3*nominalvalues)
+% estimation.optimization.method: 'simplexIQM'
+% estimation.optimization.options: [] (default options for optimization method)
+% estimation.integrator.options: [] (default options for integration)
+% estimation.initialconditionsFlag: 1 (average from first timepoint in measurements (if measured) otherwise from model or experiment description)
+% estimation.displayFlag: 2 (show iterations and final message)
+% estimation.scalingFlag: 2 (scaling by mean values)
+% estimation.timescalingFlag: 0 (no scaling)
+% estimation.costfunction: 'defaultcostparameterestimationIQM'
+% estimation.logscalingResidualsFlag: 0 (no logscaling)
+%
+% Output Arguments:
+% =================
+% The output is given as a structure:
+%      parameters: cell-array with names of optimized parameters
+%            Popt: vector with values of optimized parameters
+% parameterslocal: cell-array with names of locally optimized parameters
+%                  (for each experiment indenpendently)
+%       PLOCALopt: vector with values of locally optimized parameters
+%         icnames: cell-array with names of states for which the initial conditions have been optimized
+%           ICopt: vector with values of optimized initial conditions
+%         FVALopt: optimal cost function value
+%      projectopt: IQMprojectSB with updated optimized model and initial conditions in the experiment descriptions
+%      estimation: The estimation input argument
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GLOBAL VARIABLES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+global workestimation parameters stopOptimization costfunction fh fh2
+global displayFlag initialconditionsFlag scalingFlag optimizerboundsFlag
+global timescalingFlag logscalingResidualsFlag
+global PICmin PICmax parameterslocal integratoroptions
+
+global compiledExpModelsIQMparamestGUI
+
+stopOptimization = 0;
+
+noStopButton = 0;
+if nargin >= 3,
+    noStopButton = varargin{1};
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% BASIC CHECK OF THE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isIQMprojectSB(project),
+    error('Input argument ''project'' is not an IQMprojectSB.');
+end
+if ~isstruct(estimation) && ~isempty(estimation),
+    error('Input argument ''estimation'' is not a structure.');
+end
+projectstruct = IQMstruct(project);
+
+% get integrator options
+try
+    integratoroptions = estimation.integrator.options; 
+catch
+    integratoroptions = [];
+    integratoroptions.maxnumsteps = 1000;
+    estimation.integrator.options = integratoroptions;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE PARAM DATA MATRIX
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if iscell(estimation.parameters),
+    if ~isempty(estimation.parameters),
+        paramnames = estimation.parameters(:,1); 
+        paramlowbounds = cell2mat(estimation.parameters(:,2)); 
+        paramhighbounds = cell2mat(estimation.parameters(:,3)); 
+    else
+        paramnames = {}; 
+        paramlowbounds = []; 
+        paramhighbounds = []; 
+    end
+    estimation.parameters = [];
+    estimation.parameters.names = paramnames;
+    estimation.parameters.lowbounds = paramlowbounds;
+    estimation.parameters.highbounds = paramhighbounds; 
+end
+if iscell(estimation.parameterslocal),
+    if ~isempty(estimation.parameterslocal),
+        paramnameslocal = estimation.parameterslocal(:,1);
+        paramlowboundslocal = cell2mat(estimation.parameterslocal(:,2));
+        paramhighboundslocal = cell2mat(estimation.parameterslocal(:,3));
+    else
+        paramnameslocal = {};
+        paramlowboundslocal = [];
+        paramhighboundslocal = [];
+    end
+    estimation.parameterslocal = [];
+    estimation.parameterslocal.names = paramnameslocal;
+    estimation.parameterslocal.lowbounds = paramlowboundslocal;
+    estimation.parameterslocal.highbounds = paramhighboundslocal;
+end
+if iscell(estimation.initialconditions),
+    if ~isempty(estimation.initialconditions),
+        icnames = estimation.initialconditions(:,1);
+        iclowbounds = cell2mat(estimation.initialconditions(:,2));
+        ichighbounds = cell2mat(estimation.initialconditions(:,3));
+    else
+        icnames = {};
+        iclowbounds = [];
+        ichighbounds = [];
+    end
+    estimation.initialconditions = [];
+    estimation.initialconditions.names = icnames;
+    estimation.initialconditions.lowbounds = iclowbounds;
+    estimation.initialconditions.highbounds = ichighbounds;
+end
+
+if isempty(estimation.parameters.names),
+    error(sprintf('At least one global parameter needs to be estimated!\nJust choose one and set very tight bounds for it.'));
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK INFO AND GET DATA FROM PROJECT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[model,experiments,parameters,parameterslocal,initialconditions,optimization,costfunction,estimation,experimentmeasurementweights] = checkandprocessinput(project,projectstruct,estimation);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE NON-NUMERIC INITIAL CONDITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% just by replacing them
+% + warning ... as user feedback
+if ~hasonlynumericICsIQM(model),
+    model = IQMconvertNonNum2NumIC(model);
+    disp('Warning: The model contains non-numeric initial conditions. For this analysis these are replaced');
+    disp('by numeric initial conditions, determined from the non-numeric ones.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS EXPERIMENT AND MEASUREMENT INFORMATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+workestimation = getexpmeasinfoIQM(model,estimation.modelindex,experiments,estimation.experiments.indices,displayFlag,scalingFlag,timescalingFlag,initialconditionsFlag,experimentmeasurementweights);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% ADD PARAMETER INDICES AND NOMINAL VALUES TO WORKESTIMATION STRUCTURE
+% Could be different indices for different experiments ... so its done here
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+workestimation = addparameterindices(workestimation,parameters,parameterslocal);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EXPAND THE INFO FOR THE LOCAL PARAMETERS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[parameterslocal,workestimation] = getparameterslocaldata(workestimation,parameterslocal);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% ADD INDICES OF THE STATES FOR WHICH TO OPTIMIZE THE INITIAL CONDITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+workestimation = addstateicoptimindices(workestimation,initialconditions);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET INITIAL CONDITIONS VECTOR AND LOW AND HIGH BOUNDS
+% ADD IC INDICES TO WORKESTIMATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[initialconditions,workestimation] = geticdata(workestimation,initialconditions);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% NOW WE CAN CHECK BOUNDS FOR LOCAL PARAM AND INITIAL CONDS
+% IF outside then warn and correct to be inside
+% SKIP the warning for now!
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+tol = 0.00001;
+indexhi = find(parameters.initialguesses(:)>=parameters.highbounds(:));
+parameters.initialguesses(indexhi) = parameters.highbounds(indexhi)*(1-tol);
+indexlo = find(parameters.initialguesses(:)<=parameters.lowbounds(:));
+parameters.initialguesses(indexlo) = parameters.lowbounds(indexlo)*(1+tol);
+
+indexhi = find(parameterslocal.pliv(:)>=parameterslocal.plhigherbounds(:));
+parameterslocal.pliv(indexhi) = parameterslocal.plhigherbounds(indexhi)*(1-tol);
+indexlo = find(parameterslocal.pliv(:)<=parameterslocal.pllowerbounds(:));
+parameterslocal.pliv(indexlo) = parameterslocal.pllowerbounds(indexlo)*(1+tol);
+
+indexhi = find(initialconditions.ic0(:)>=initialconditions.icupperbounds(:));
+initialconditions.ic0(indexhi) = initialconditions.icupperbounds(indexhi)*(1-tol);
+indexlo = find(initialconditions.ic0(:)<=initialconditions.iclowerbounds(:));
+initialconditions.ic0(indexlo) = initialconditions.iclowerbounds(indexlo)*(1+tol);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Take care of optimization methods that require (can handle) upper and lower bounds
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+optimizerboundsFlag = 0;
+try
+    info = feval(optimization.method);
+    if info.constrained == 1,
+        % chosen optimization method handles constraints 
+        % => disable IQMparameterestimation bounds handling
+        optimizerboundsFlag = 1;
+    end
+catch
+    % if an external (from IQM Tools Lite) optimization method has been called
+    % then catch the error and handle bounds outside the optimizer.
+    optimizerboundsFlag = 0;
+end
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Transform parameters and initial conditions to be optimized 
+% for taking into account upper and lower bounds
+% This allows to use -Inf and +Inf as optimization bounds
+% only done in the case that the chosen optimizer is not able
+% to handle bounds.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if optimizerboundsFlag == 1,
+    X0 = [parameters.initialguesses(:); parameterslocal.pliv(:); initialconditions.ic0(:)];
+else
+    PICmin = [parameters.lowbounds(:); parameterslocal.pllowerbounds(:); initialconditions.iclowerbounds(:)];
+    PICmax = [parameters.highbounds(:); parameterslocal.plhigherbounds(:); initialconditions.icupperbounds(:)];
+    PIC0 = [parameters.initialguesses(:); parameterslocal.pliv(:); initialconditions.ic0(:)];
+    X0 = log((PIC0(:)-PICmin(:))./(PICmax(:)-PIC0(:)));
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% RUN THE ESTIMATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+createstopbutton();
+if noStopButton,
+    close(fh)
+end
+
+OPTIONS = setoptimizerOptions(optimization,length(X0)); % disable lowbounds,highbounds,silent & outputfunction
+if optimizerboundsFlag == 1,
+    % Add optimizer bounds if the optimization methods requires it.
+    OPTIONS.lowbounds = [parameters.lowbounds(:); parameterslocal.pllowerbounds(:); initialconditions.iclowerbounds(:)];
+    OPTIONS.highbounds = [parameters.highbounds(:); parameterslocal.plhigherbounds(:); initialconditions.icupperbounds(:)];
+    %%[OPTIONS.lowbounds(:), X0(:), OPTIONS.highbounds(:)]    
+end
+warning off
+[Xopt,FVALopt] = feval(optimization.method,@costFunctionInterface,X0,OPTIONS);
+warning on
+
+% For some strange reason does the call to javaaddpath clear all global
+% variables. This call is performed in the case that JavaEvA optimization
+% methods are used. The involved functions take care of keeping the global
+% variables but it is necessary to declare them again as global here in
+% this function. Stupid stupid stupid :)
+% so check if optimizerboundsFlag is still defined global in this function
+try 
+    optimizerboundsFlag;
+catch
+    % No, it isn't ... so lets make all the globals global again!
+    global workestimation parameters stopOptimization costfunction fh fh2
+    global displayFlag initialconditionsFlag scalingFlag optimizerboundsFlag
+    global timescalingFlag
+    global PICmin PICmax parameterslocal compiledExpModelsIQMparamestGUI
+end
+
+% close the stop estimation button
+try close(fh); catch, end
+try close(fh2); catch, end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% BACKTRANSFORM OPTIMIZED PARAMETERS/ICS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if optimizerboundsFlag == 1,
+    Popt = Xopt(1:length(parameters.names));
+    PLOCALopt = Xopt(length(parameters.names)+1:length(parameters.names)+length(parameterslocal.names)*length(workestimation));
+    ICopt = Xopt(length(parameters.names)+length(parameterslocal.names)*length(workestimation)+1:end);
+else
+    PICopt = (PICmin(:)+PICmax(:).*exp(Xopt(:)))./(1+exp(Xopt(:)));
+    Popt = PICopt(1:length(parameters.names));
+    PLOCALopt = PICopt(length(parameters.names)+1:length(parameters.names)+length(parameterslocal.names)*length(workestimation));
+    ICopt = PICopt(length(parameters.names)+length(parameterslocal.names)*length(workestimation)+1:end);
+end
+% Set ICopts to 0 if between -10*eps and +10*eps
+for k=1:length(ICopt), if ICopt(k) < 10*eps && ICopt(k) > -10*eps, ICopt(k) = 0; end; end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% REPORT RESULTS IF WANTED
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[paramreporttext] = boundsconstructreport(parameters,Popt);
+[paramreporttextlocal] = boundsconstructreportlocal(parameterslocal,PLOCALopt);
+[icreporttext] = reportICoptimization(workestimation,initialconditions,estimation,ICopt);
+if displayFlag >= 1,
+    disp(' ');
+    disp(paramreporttext);
+    disp(paramreporttextlocal);
+    disp(icreporttext);
+    disp(sprintf('Optimal cost: %g',FVALopt));
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% OUTPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+output = constructoutput(projectstruct,estimation,parameters,parameterslocal,initialconditions,experiments,workestimation,Popt,PLOCALopt,ICopt,FVALopt);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CLEAN UP AND RETURN
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if displayFlag == 3,
+    disp('Finished ...');
+end
+if isempty(compiledExpModelsIQMparamestGUI),
+    deleteTempMEXmodels(workestimation);
+end
+% clear all global variables
+clear global workestimation parameters stopOptimization costfunction fh
+clear global displayFlag initialconditionsFlag scalingFlag optimizerboundsFlag
+clear global timescalingFlag 
+clear global PICmin PICmax parameterslocal integratoroptions
+return
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/auxiliary/addparameterindices.m b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/auxiliary/addparameterindices.m
new file mode 100644
index 0000000000000000000000000000000000000000..c5f42a9fb0e75a928374af1bb98123bde18552c4
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/auxiliary/addparameterindices.m	
@@ -0,0 +1,15 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% ADD PARAMETER INDICES AND NOMINAL VALUES TO WORKESTIMATION STRUCTURE
+% Could be different indices for different experiments ... so its done here
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [workestimation] = addparameterindices(workestimation,parameters,parameterslocal)
+for k=1:length(workestimation),
+    [allparameters,nominalparamvalues] = IQMparameters(workestimation(k).IQMmodel);
+    paramindices = getnamevectorindices(allparameters,parameters.names);
+    paramindiceslocal = getnamevectorindices(allparameters,parameterslocal.names);
+    workestimation(k).paramindices = paramindices;
+    workestimation(k).paramindiceslocal = paramindiceslocal;
+    workestimation(k).paramnominal = nominalparamvalues;
+end
+return
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/auxiliary/addstateicoptimindices.m b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/auxiliary/addstateicoptimindices.m
new file mode 100644
index 0000000000000000000000000000000000000000..9e7a814c471c7beb639dc9e18847beb30c7511fa
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/auxiliary/addstateicoptimindices.m	
@@ -0,0 +1,8 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% ADD INDICES OF THE STATES FOR WHICH TO OPTIMIZE THE INITIAL CONDITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [workestimation] = addstateicoptimindices(workestimation,initialconditions)
+for k=1:length(workestimation),
+    stateindicesicoptim = getnamevectorindices(IQMstates(workestimation(k).model),initialconditions.names);
+    workestimation(k).stateindicesicoptim = stateindicesicoptim;
+end
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/auxiliary/boundsconstructreport.m b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/auxiliary/boundsconstructreport.m
new file mode 100644
index 0000000000000000000000000000000000000000..1ded415ef53b409c1f2ec4086555ac1920419709
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/auxiliary/boundsconstructreport.m	
@@ -0,0 +1,18 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PARAMETER BOUNDS REPORT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [text] = boundsconstructreport(parameters,Popt)
+text = sprintf('Estimated parameters\n====================\n');
+for k=1:length(parameters.names),
+    % check if lower or higher bound tested
+    tol = 0.00001;
+    if str2num(sprintf('%g',Popt(k))) <= parameters.lowbounds(k)*(1+tol),
+        boundtext = sprintf('%% At lower bound');
+    elseif str2num(sprintf('%g',Popt(k))) >= parameters.highbounds(k)*(1-tol),
+        boundtext = sprintf('%% At upper bound');
+    else
+        boundtext = '';
+    end
+    text = sprintf('%s%s = %g   %s\n',text,parameters.names{k},Popt(k),boundtext);
+end
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/auxiliary/boundsconstructreportlocal.m b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/auxiliary/boundsconstructreportlocal.m
new file mode 100644
index 0000000000000000000000000000000000000000..4497b12c93b2874834b4210cc1b949bc89964411
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/auxiliary/boundsconstructreportlocal.m	
@@ -0,0 +1,22 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% LOCAL PARAMETER BOUNDS REPORT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [text] = boundsconstructreportlocal(parameterslocal,PLOCALopt)
+if isempty(PLOCALopt), 
+    text = '';
+    return
+end
+text = sprintf('Estimated local parameters\n==========================\n');
+for k=1:length(PLOCALopt),
+    % check if lower or higher bound tested
+    tol = 0.00001;
+    if str2num(sprintf('%g',PLOCALopt(k))) <= parameterslocal.pllowerbounds(k)*(1+tol),
+        boundtext = sprintf('%% At lower bound');
+    elseif str2num(sprintf('%g',PLOCALopt(k))) >= parameterslocal.plhigherbounds(k)*(1-tol),
+        boundtext = sprintf('%% At upper bound');
+    else
+        boundtext = '';
+    end
+    text = sprintf('%s%s = %g   %s\n',text,parameterslocal.names{mod(k-1,length(parameterslocal.names))+1},PLOCALopt(k),boundtext);
+end
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/auxiliary/checkandprocessinput.m b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/auxiliary/checkandprocessinput.m
new file mode 100644
index 0000000000000000000000000000000000000000..84b29222a5bcc383ab34fc4979fcd20bf2f4e99e
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/auxiliary/checkandprocessinput.m	
@@ -0,0 +1,351 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DETAILED CHECK AND PROCESSING OF INPUT ARGUMENTS 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [model,experiments,parameters,parameterslocal,initialconditions,optimization,costfunction,estimation,experimentmeasurementweights] = checkandprocessinput(project,projectstruct,estimation)
+global displayFlag initialconditionsFlag scalingFlag 
+global timescalingFlag optimizeinitialconditionsFlag logscalingResidualsFlag
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECKING THE FIELDS OF ESTIMATION AND HANDLING DEFAULT VALUES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+modelindex = 1; % default: model 1
+experimentindices = []; % default: all experiments
+experimentmeasurementindices = {}; % default: all measurements for all experiments
+experimentweights = []; % default: 1
+experimentmeasurementweights = {}; % default: 1
+parameternames = {}; % default: all parameters in the model 
+parameterlowbounds = 1e-3; % default: 1e-3*parameterinitialguesses
+parameterhighbounds = 1e3; % default: 1e3*parameterinitialguesses
+parameternameslocal = {}; % default: no parameters to be estimated locally
+parameterlowboundslocal = 1e-3; % default: 1e-3*parameterinitialguesseslocal
+parameterhighboundslocal = 1e3; % default: 1e3*parameterinitialguesseslocal
+icnames = {}; % default: all unmeasured and unset states in the model
+iclowbounds = 1e-3; % default: 1e-3*nomvalue
+ichighbounds = 1e3; % default: 1e3*nomvalue
+optimizationmethod = 'simplexIQM'; % default: simplexIQM
+optimizationoptions = []; % default: no additional options for the optimization method
+initialconditionsFlag = 1; % 0=nominal from model or experiment description, 1=average from first timepoint in measurements
+displayFlag = 2; % default: final message + iteration
+scalingFlag = 2; % 0=noscaling, 1=scaling by max(abs()) values in measurements, 2=scaling by mean values of measurements,3=scaling by difference between max and min values
+timescalingFlag = 0; % 0=no scaling, 1=log scaling
+optimizeinitialconditionsFlag = 0; % 0=no, 1=optimize initial conditions for states for which no measurements 
+                                   % and no experiment settings are available. estimated for each measurement 
+                                   % in each experiment
+costfunction = 'defaultcostparameterestimationIQM';
+logscalingResidualsFlag = 0;
+try modelindex = estimation.modelindex; catch, end
+try experimentweights = estimation.experiments.weight; catch, end
+try experimentmeasurementweights = estimation.experiments.measurementweight; catch, end
+try experimentindices = estimation.experiments.indices; catch, end
+try experimentmeasurementindices = estimation.experiments.measurementindices; catch, end
+try parameternames = estimation.parameters.names; catch, end
+try parameterlowbounds = estimation.parameters.lowbounds; catch, end
+try parameterhighbounds = estimation.parameters.highbounds; catch, end
+try parameternameslocal = estimation.parameterslocal.names; catch, end
+try parameterlowboundslocal = estimation.parameterslocal.lowbounds; catch, end
+try parameterhighboundslocal = estimation.parameterslocal.highbounds; catch, end
+try icnames = estimation.initialconditions.names; catch, end
+try iclowbounds = estimation.initialconditions.lowbounds; catch, end
+try ichighbounds = estimation.initialconditions.highbounds; catch, end
+try optimizationmethod = estimation.optimization.method; catch, end
+try optimizationoptions = estimation.optimization.options; catch, end
+try displayFlag = estimation.displayFlag; catch, end
+try initialconditionsFlag = estimation.initialconditionsFlag; catch, end
+try scalingFlag = estimation.scalingFlag; catch, end
+try timescalingFlag = estimation.timescalingFlag; catch, end
+try costfunction = estimation.costfunction; catch, end
+try logscalingResidualsFlag = estimation.logscalingResidualsFlag; catch, end
+if displayFlag == 3,
+    disp('Checking and processing input arguments ...');
+end
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK FLAGS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if scalingFlag < 0 || scalingFlag > 3,
+    error('''estimation.scalingFlag'': Not set correctly.');
+end
+if timescalingFlag < 0,
+    error('''estimation.timescalingFlag'': Not set correctly.');
+end
+if initialconditionsFlag < 0 || initialconditionsFlag > 1,
+    error('''estimation.initialconditionsFlag'': Not set correctly.');
+end
+if displayFlag < 0 || displayFlag > 3,
+    error('''estimation.displayFlag'': Not set correctly.');
+end
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK AND PROCESS INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK AND MODEL
+if length(modelindex) > 1,
+    % more than one model is specified
+    error('''estimation.modelindex'': Only one model at a time can be specified.');
+else
+    % get the model
+    model = IQMgetmodel(project,modelindex);
+end
+estimation.modelindex = modelindex;
+% CHECK AND GET EXPERIMENTS AND MEASUREMENTS
+if ~isempty(find(experimentindices<1)) || ~isempty(find(experimentindices>length(projectstruct.experiments))),
+    % experiment indices out of bounds
+    error('''estimation.experiments.indices'': Out of bounds.');
+end
+if isempty(experimentindices),
+    % if experimentindices is empty then use all experiments (default setting)
+    experimentindices = 1:length(projectstruct.experiments);
+end
+
+
+% CHECK EXPERIMENT AND MEASUREMENT WEIGHTS
+% check that every experiment has weights
+if ~isempty(experimentweights),
+    if length(experimentweights) ~= length(experimentindices),
+        % numbers of experiments and experimentweight do not fit
+        error('''estimation.experiments.weight'': Number of elements does not fit with number of elements in ''estimation.experiments.indices''.');
+    end
+end
+if ~isempty(experimentmeasurementweights),
+    if length(experimentmeasurementweights) ~= length(experimentindices),
+        % numbers of experiments and experimentweight do not fit
+        error('''estimation.experiments.measurementweight'': Number of elements does not fit with number of elements in ''estimation.experiments.experimentindices''.');
+    end
+    if ~isempty(experimentmeasurementindices),
+        for k=1:length(experimentindices),
+            if length(experimentmeasurementindices{k})~= length(experimentmeasurementweights{k}),
+                error(['''estimation.experiments.measurementweight{',num2str(k),'}'': Number of elements does not fit with number of elements in ''estimation.experiments.measurementindices{',num2str(k),'}''.']);
+            end
+        end
+    else
+        for k=1:length(experimentindices),
+            experimentindex = experimentindices(k);
+            if length(experimentmeasurementweights{k}) ~= length(projectstruct.experiments(experimentindex).measurements),
+                error(['''estimation.experiments.measurementweight{',num2str(k),'}'': Number of elements does not fit with number of elements in ''estimation.experiments.measurementindices{',num2str(k),'}''.']);
+            end
+            % check if elements are vectors
+            if ~isnumeric(experimentmeasurementweights{k}),
+                error('''estimation.experiments.measurementweight'': The elements in here should be scalars or vectors, but no cell-arrays.');
+            end
+        end
+    end
+else
+    % experimentmeasurementweights is empty ...
+    % assign 1 if weights are not specified and experiment weight to all
+    % measurements of the experiment
+    if isempty(experimentweights),
+        experimentweights=ones(1,length(experimentindices));
+    end
+    for k=1:length(experimentindices),
+        experimentindex = experimentindices(k);
+        experimentmeasurementweights{end+1}=experimentweights(k)*ones(1,length(projectstruct.experiments(experimentindex).measurements));
+    end
+end
+% check length of experiment weights and indices
+if length(experimentmeasurementweights) ~= length(experimentindices),
+    % numbers of experiments and experimentweight do not fit
+    error('''estimation.experiments.measurementweight'': Numbers of elements do not fit with numbers of elements in ''estimation.experiments.measurementindices''.');
+end
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK WHICH EXPERIMENTS DO NOT HAVE MEASUREMENT DATA ASSIGNED TO
+% THESE ARE SKIPPED FROM THE CONSIDERATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+experimentindices_checked = [];
+experimentmeasurementweights_checked = {};
+ind=1;
+for e=1:length(experimentindices),
+    index = experimentindices(e);
+    if isempty(projectstruct.experiments(index).measurements),
+        disp(sprintf('Experiment %d has no measurements assigned to ... not considered here.\n',index));
+    else
+        % delete experiment from consideration
+        experimentindices_checked = [experimentindices_checked index];
+        experimentmeasurementweights_checked{ind} = experimentmeasurementweights{e};
+        ind=ind+1;
+    end
+end
+experimentindices = experimentindices_checked;
+experimentmeasurementweights = experimentmeasurementweights_checked;
+if isempty(experimentindices),
+    error('No measurements present in the project. No estimation possible.');
+end
+% go on
+if isempty(experimentmeasurementindices),
+    % if experimentmeasurementindices then all measurements for all
+    % experiments given in experimentindices
+    for k=1:length(experimentindices),
+        experimentindex = experimentindices(k);
+        experimentmeasurementindices{end+1} = 1:length(projectstruct.experiments(experimentindex).measurements);
+    end
+end
+if length(experimentindices) ~= length(experimentmeasurementindices),
+    % numbers of experiments and experimentmeasurements do not fit
+    error('''estimation.experiments.measurementindices'': Numbers of elements do not fit with numbers of elements in ''estimation.experiments.indices''.');
+end
+for k=1:length(experimentindices),
+    experimentindex = experimentindices(k);
+    if isempty(experimentmeasurementindices{k}),
+        % if is empty then use all experiments for current experiment
+        experimentmeasurementindices{k} = 1:length(projectstruct.experiments(experimentindex).measurements);
+    elseif ~isempty(find(experimentmeasurementindices{k}<1)) || ~isempty(find(experimentmeasurementindices{k}>length(projectstruct.experiments(experimentindex).measurements))),
+        % experimentmeasurementindices are out of bounds
+        error('''estimation.experiments.measurementindices{%d}'': Out of bounds.',k);
+    end
+end
+for k=1:length(experimentindices),
+    % get experiments and measurements
+    experimentindex = experimentindices(k);
+    experiments(k).experiment = IQMgetexperiment(project,experimentindex);
+    measurements = IQMgetmeasurement(project,experimentindex,experimentmeasurementindices{k});
+    if ~iscell(measurements),
+        % convert also single measurements to a cell-array for easier handling
+        measurements = {measurements};
+    end
+    experiments(k).measurements = measurements;
+end
+% CHECK AND GET PARAMETERNAMES AND PARAMETERINITIALVALUES
+[modelparameters,modelparametervalues] = IQMparameters(model);
+if isempty(parameternames),
+    % if no parameternames defined then use all in the model
+    parameters.names = modelparameters;
+else
+    parameters.names = parameternames;
+end
+% just call IQMparameters with the parameters.names .... this checks
+% if all given parameters exist in the model and additionally gets 
+% possible start values if none provided.
+try
+    [selectedparametervalues] = IQMparameters(model,parameters.names);
+catch
+    error('Error in parameters to be estimated: %s', lasterr);
+end
+% take them from the model
+parameters.initialguesses = selectedparametervalues;
+% CHECK AND GET LOWBOUNDS AND HIGHBOUNDS FOR PARAMETERS 
+if length(parameterlowbounds) == 1,
+    if length(parameters.names) == 1,
+        parameters.lowbounds = parameterlowbounds;
+    else
+        parameters.lowbounds = parameters.initialguesses*parameterlowbounds;
+    end
+else
+    if length(parameterlowbounds) ~= length(parameters.names),
+        error('''estimation.parameters.lowbounds'': Incorrect number of elements.');
+    end
+    parameters.lowbounds = parameterlowbounds;
+end
+if length(parameterhighbounds) == 1,
+    if length(parameters.names) == 1,
+        parameters.highbounds = parameterhighbounds;
+    else
+        parameters.highbounds = parameters.initialguesses*parameterhighbounds;
+    end
+else
+    if length(parameterhighbounds) ~= length(parameters.names),
+        error('''estimation.parameters.highbounds'': Incorrect number of elements.');
+    end
+    parameters.highbounds = parameterhighbounds;
+end
+% CHECK AND GET LOCAL PARAMETERNAMES AND PARAMETERINITIALVALUES 
+parameterslocal.names = parameternameslocal;
+try
+    dummy = IQMparameters(model,parameterslocal.names);  % just an error check (IQMparameters function returns 
+                                                        % error if parameter not defined in model)
+catch
+    error('Error in local parameters to be estimated: %s',lasterr);
+end
+% CHECK AND GET LOWBOUNDS AND HIGHBOUNDS FOR PARAMETERS 
+if length(parameterlowboundslocal) == 1,
+    parameterslocal.lowbounds = parameterlowboundslocal;
+else
+    if length(parameterlowboundslocal) ~= length(parameterslocal.names),
+        error('''estimation.parameterslocal.lowbounds'': Incorrect number of elements.');
+    end
+    parameterslocal.lowbounds = parameterlowboundslocal;
+end
+if length(parameterhighboundslocal) == 1,
+    parameterslocal.highbounds = parameterhighboundslocal;
+else
+    if length(parameterhighboundslocal) ~= length(parameterslocal.names),
+        error('''estimation.parameterslocal.highbounds'': Incorrect number of elements.');
+    end
+    parameterslocal.highbounds = parameterhighboundslocal;
+end
+% CHECK AND GET ICNAMES (if given the latter)
+try
+    icmodel = IQMinitialconditions(model,icnames);  % just an error check (IQMstates function returns 
+                                                   % error if state not defined in model)
+catch
+    error('Error in initial conditions to be estimated: %s',lasterr);
+end
+initialconditions.names = icnames;
+% set iclowbounds and ichighbounds to empty if no icnames given!
+if isempty(icnames),
+    iclowbounds = [];
+    ichighbounds = [];
+end
+% CHECK AND GET LOWBOUNDS and HIGHBOUNDS
+if length(iclowbounds) == 1,
+    if length(icnames) == 1,
+        initialconditions.lowbounds = iclowbounds;
+    else
+        initialconditions.lowbounds = iclowbounds*icmodel(:);
+    end
+else
+    if length(iclowbounds) ~= length(initialconditions.names),
+        error('''estimation.initialconditions.lowbounds'': Incorrect number of elements.');
+    end
+    initialconditions.lowbounds = iclowbounds(:);
+end
+if length(ichighbounds) == 1,
+    if length(icnames) == 1,
+        initialconditions.highbounds = ichighbounds;
+    else
+        initialconditions.highbounds = ichighbounds*icmodel(:);
+    end    
+else
+    if length(ichighbounds) ~= length(initialconditions.names),
+        error('''estimation.initialconditions.highbounds'': Incorrect number of elements.');
+    end
+    initialconditions.highbounds = ichighbounds(:);
+end
+% SET OPTIMIZE INITIALCONDITIONS FLAG
+if length(icnames) ~= 0,
+    optimizeinitialconditionsFlag = 1;
+else 
+    optimizeinitialconditionsFlag = 0;
+end
+% CHECK AND GET OPTIMIZATION METHOD AND OPTIONS
+if isempty(optimizationmethod),
+    optimizationmethod = 'simplexIQM';
+end
+if isfield(optimizationoptions,'lowbounds'),
+    warning('''estimation.optimization.options.lowbounds'': This setting is ignored. Please use ''estimation.parameters.lowbounds''.');
+end
+if isfield(optimizationoptions,'highbounds'),
+    warning('''estimation.optimization.options.highbounds'': This setting is ignored. Please use ''estimation.parameters.highbounds''.');
+end
+if ~exist(optimizationmethod),
+    error('''estimation.optimization.method'': Method does not exist.');
+else
+    optimization.method = optimizationmethod;
+    optimization.options = optimizationoptions;
+end
+% CHECK COSTFUNCTION
+if exist(costfunction) ~= 2 && exist(costfunction)~=3,
+    error('''estimation.costfunction'': Function does not exist.');
+end    
+% Finally check if global and local parameters intersect with a non empty set
+check = intersect(parameters.names,parameterslocal.names);
+if ~isempty(check),
+    text = sprintf('The following global and local parameters to be estimated do intersect:\n');
+    for k=1:length(check),
+        text = sprintf('%s%s\n',text,check{k});
+    end
+    error(text);
+end
+% Finally Finally update the estimation structure (if necessary)
+estimation.experiments.indices = experimentindices;
+return
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/auxiliary/checkstopbutton.m b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/auxiliary/checkstopbutton.m
new file mode 100644
index 0000000000000000000000000000000000000000..b85cfbc89d8cdbdaf9fad2e34cac407e0eeb89fa
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/auxiliary/checkstopbutton.m	
@@ -0,0 +1,14 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK STOP BUTTON
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [] = checkstopbutton()
+% Showing a button that allows stopping the estimation
+global stopOptimization fh fh2
+if gcf == fh,
+    stopOptimization = 1;
+    close(fh);
+    close(fh2);
+    disp('User Interrupt requested ... please wait!');
+end
+drawnow;
+return
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/auxiliary/constructoutput.m b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/auxiliary/constructoutput.m
new file mode 100644
index 0000000000000000000000000000000000000000..0ed2822eaa0d3cd461328f18d942c6dcc25260b1
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/auxiliary/constructoutput.m	
@@ -0,0 +1,76 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Construct the output argument of the parameter estimation
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [output] = constructoutput(projectstruct,estimation,parameters,parameterslocal,initialconditions,experiments,workestimation,Popt,PLOCALopt,ICopt,FVALopt)
+% construct optimized project 
+% 1) add optimized parameters to the model
+% 2) add optimized local parameters and initial conditions to the experiment descriptions
+projectoptstruct = projectstruct;
+projectoptstruct.models{estimation.modelindex} = IQMparameters(projectoptstruct.models{estimation.modelindex},parameters.names,Popt);
+icnames = initialconditions.names;
+plnames = parameterslocal.names;
+for k=1:length(experiments),
+    experiment = experiments(k).experiment;
+    experimentstruct = struct(experiment);
+    allpresenticnames = {experimentstruct.paramicsettings.name}; % gets icnames and parameternames mixed! but thats ok ...
+    % optimized initialconditions
+    for k2=1:length(icnames),
+        % check if initial condition already defined in the experiment
+        index = strmatchIQM(icnames{k2},allpresenticnames,'exact');
+        if ~isempty(index),
+            % overwrite
+            experimentstruct.paramicsettings(index).name = icnames{k2};
+            experimentstruct.paramicsettings(index).formula = sprintf('%g',ICopt(workestimation(k).indicesinICvector(k2)));
+            experimentstruct.paramicsettings(index).notes = 'optimized value';
+            experimentstruct.paramicsettings(index).icflag = 1;
+        else
+            % append
+            experimentstruct.paramicsettings(end+1).name = icnames{k2};
+            experimentstruct.paramicsettings(end).formula = sprintf('%g',ICopt(workestimation(k).indicesinICvector(k2)));
+            experimentstruct.paramicsettings(end).notes = 'optimized value';
+            experimentstruct.paramicsettings(end).icflag = 1;
+        end
+    end
+    % optimized local parameters
+    for k2=1:length(plnames),
+        % check if local parameter already defined in the experiment
+        index = strmatchIQM(plnames{k2},allpresenticnames,'exact');
+        if ~isempty(index),
+            % overwrite
+            experimentstruct.paramicsettings(index).name = plnames{k2};
+            experimentstruct.paramicsettings(index).formula = sprintf('%g',PLOCALopt(workestimation(k).indicesinLOCALPARAMvector(k2)));
+            experimentstruct.paramicsettings(index).notes = 'optimized value';
+            experimentstruct.paramicsettings(index).icflag = 0;
+        else
+            % append
+            experimentstruct.paramicsettings(end+1).name = plnames{k2};
+            experimentstruct.paramicsettings(end).formula = sprintf('%g',PLOCALopt(workestimation(k).indicesinLOCALPARAMvector(k2)));
+            experimentstruct.paramicsettings(end).notes = 'optimized value';
+            experimentstruct.paramicsettings(end).icflag = 0;
+        end
+    end    
+    % get index of experiment in the project
+    indexexp = estimation.experiments.indices(k);
+    projectoptstruct.experiments(indexexp).experiment = IQMexperiment(experimentstruct);
+end
+projectopt = IQMprojectSB(projectoptstruct);
+% output is a structure
+output = [];
+output.parameters = parameters.names;
+output.Popt = Popt;
+output.parameterslocal = parameterslocal.names;
+if ~isempty(parameterslocal.names),
+    output.PLOCALopt = reshape(PLOCALopt',length(parameterslocal.names),length(PLOCALopt)/length(parameterslocal.names))';
+else 
+    output.PLOCALopt = [];
+end
+output.icnames = initialconditions.names;
+if ~isempty(initialconditions.names),
+    output.ICopt = reshape(ICopt',length(initialconditions.names),length(ICopt)/length(initialconditions.names))';
+else 
+    output.ICopt = [];
+end
+output.FVALopt = FVALopt;
+output.projectopt = projectopt;
+output.estimation = estimation;
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/auxiliary/costFunctionInterface.m b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/auxiliary/costFunctionInterface.m
new file mode 100644
index 0000000000000000000000000000000000000000..cc322c3a4bb02762edcf39ef543bd020e400b912
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/auxiliary/costFunctionInterface.m	
@@ -0,0 +1,95 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% COST FUNCTION INTERFACE (CALLED BY THE OPTIMIZATION METHOD)
+% X is transformed to be able to handle min and max parameter bounds:
+% X = log((p-pmin)/(pmax-p)) where p=parameter value, pmin: lower bound, pmax: upper bound
+% In this function here a backtransformation needs to be done
+%
+% two additional output values were added 4/4/8
+% constr: allows the specification of constraints (here disabled by setting
+%         constr=0.
+% resid:  a vector of residuals for all experiments and measurements
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [cost,constr,resid] = costFunctionInterface(X)
+% need some global variables
+global workestimation parameters scalingFlag costfunction optimizerboundsFlag 
+global PICmin PICmax parameterslocal integratoroptions 
+%%%% handle residuals (determine dimension of residuals vector)
+resid = [];
+lengthresid = 0;
+for k=1:length(workestimation),
+    for k2=1:length(workestimation(k).measurement),
+        lengthresid = lengthresid + length(workestimation(k).measurement(k2).statereferences(:));
+        lengthresid = lengthresid + length(workestimation(k).measurement(k2).variablereferences(:));
+    end
+end
+%%%% setting default constraint output argument
+constr = 0; % just disable constraints
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK STOP BUTTON
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+checkstopbutton();
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% BACKTRANSFORM PARAMETERS IF NECESSARY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if optimizerboundsFlag == 1,
+    parametervalues = X(1:length(parameters.names));
+    parametervalueslocal = X(length(parameters.names)+1:length(parameters.names)+length(parameterslocal.names)*length(workestimation));
+    icvalues = X(length(parameters.names)+length(parameterslocal.names)*length(workestimation)+1:end);
+else
+    PICvalues = (PICmin(:)+PICmax(:).*exp(X(:)))./(1+exp(X(:)));
+    parametervalues = PICvalues(1:length(parameters.names));
+    parametervalueslocal = PICvalues(length(parameters.names)+1:length(parameters.names)+length(parameterslocal.names)*length(workestimation));
+    icvalues = PICvalues(length(parameters.names)+length(parameterslocal.names)*length(workestimation)+1:end);
+end
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% SIMULATE ALL EXPERIMENTS FOR GIVEN ICS AND PARAMETERS
+% GET THE COST FOR EACH EXPERIMENT AND SUM UP
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+cost = 0;
+for k=1:length(workestimation),
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % CONSTRUCT FULL PARAM AND IC VECTORS FOR SIMULATION
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % construct a full parameter value vector (include values being optimized)
+    pv = workestimation(k).paramnominal;
+    % add first the globally optimized parameters    
+    paramindices = workestimation(k).paramindices;
+    pv(paramindices) = parametervalues;
+    % then add the locally optimized parameters
+    indicesinLOCALPARAMvector = workestimation(k).indicesinLOCALPARAMvector;
+    paramindiceslocal = workestimation(k).paramindiceslocal;
+    pv(paramindiceslocal) = parametervalueslocal(indicesinLOCALPARAMvector);
+    % construct a full initial conditions vector (include values being optimized)
+    ic = workestimation(k).initialconditions;
+    stateindicesicoptim = workestimation(k).stateindicesicoptim;
+    indicesinICvector = workestimation(k).indicesinICvector;
+    ic(stateindicesicoptim) = icvalues(indicesinICvector);
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % DO THE SIMULATION OF THE EXPERIMENT
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    try
+        simstructure = feval(workestimation(k).model,workestimation(k).timevector,ic,pv,integratoroptions);
+    catch
+        cost = inf;
+        resid = 1e20*ones(1,lengthresid);
+        return
+    end
+    % check if the simulation result contains NaN values - then cost = inf
+    % and return
+    if sum(sum(isnan([simstructure.statevalues simstructure.variablevalues]))), 
+        cost = inf;
+        resid = 1e20*ones(1,lengthresid);
+        return
+    end
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % RUN THE COST FUNCTION AND GET THE COST FOR THIS EXPERIMENT
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % determine the cost for all the measurements in each experiment
+    [costExperiment residexp] = feval(costfunction,simstructure,workestimation(k),scalingFlag);
+resid = [resid residexp];    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % SUM UP TOTAL COST
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    cost = cost + costExperiment; 
+end
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/auxiliary/createstopbutton.m b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/auxiliary/createstopbutton.m
new file mode 100644
index 0000000000000000000000000000000000000000..ec546566d5a73ee7b9b550e1bda4c19ad8383d1a
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/auxiliary/createstopbutton.m	
@@ -0,0 +1,13 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CREATE STOP BUTTON
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [] = createstopbutton()
+global fh fh2
+fh = figure(999);
+set(fh,'Position',[800 600 120 90],'MenuBar','none','NumberTitle','off','Name','Click to stop estimation','Toolbar','none','Color',[1 1 0])
+uicontrol('Style', 'pushbutton', 'String', 'Stop Estimation','Position', [10 10 100 70], 'BackgroundColor',[1 0 0],'FontWeight','bold');
+fh2 = figure(998);
+set(fh2,'Position',[-10 -10 10 10],'MenuBar','none','NumberTitle','off','Name','','Toolbar','none','Color',[1 1 1])
+% set(fh2,'Visible','off')
+drawnow;
+return
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/auxiliary/deleteTempMEXmodels.m b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/auxiliary/deleteTempMEXmodels.m
new file mode 100644
index 0000000000000000000000000000000000000000..7823b862ab2600a05b2c5cd011b053909d9a0749
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/auxiliary/deleteTempMEXmodels.m	
@@ -0,0 +1,13 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DELETE THE TEMPORARY MEX MODELS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [] = deleteTempMEXmodels(workestimation)
+global displayFlag
+if displayFlag == 3,
+    disp('Deleting the temporary MEX model(s) ...');
+end
+clear mex
+for k=1:length(workestimation),
+    delete(workestimation(k).mexfullpath);
+end
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/auxiliary/geticdata.m b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/auxiliary/geticdata.m
new file mode 100644
index 0000000000000000000000000000000000000000..a76e48c665fc68833094694600f4af4b486a5895
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/auxiliary/geticdata.m	
@@ -0,0 +1,31 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Construct initial guess vector from workestimation.initialconditions  
+% for each experiment. Further, construct lowbound and highbounds vector.
+% Add indices in the vectors for each experiment to the workestimation structure
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [initialconditions,workestimation] = geticdata(workestimation,initialconditions)
+global optimizeinitialconditionsFlag
+ic0 = [];
+iclowerbounds = [];
+icupperbounds = [];
+if optimizeinitialconditionsFlag == 1,
+    for e=1:length(workestimation),
+        ic0e = workestimation(e).initialconditions(workestimation(e).stateindicesicoptim);
+        ic0 = [ic0(:); ic0e(:)];
+        indicesinICvector = length(ic0)+[1-length(ic0e):0];
+        workestimation(e).indicesinICvector = indicesinICvector;
+        iclowerbounds = [iclowerbounds(:); initialconditions.lowbounds]; 
+        icupperbounds = [icupperbounds(:); initialconditions.highbounds]; 
+    end
+    % determine lower/upper bounds
+    iclowerbounds(find(iclowerbounds==0)) = -eps;
+    icupperbounds(find(icupperbounds==0)) = 1e10;
+else
+    for e=1:length(workestimation),
+        workestimation(e).indicesinICvector = [];
+    end
+end
+initialconditions.ic0 = ic0;
+initialconditions.iclowerbounds = iclowerbounds;
+initialconditions.icupperbounds = icupperbounds;
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/auxiliary/getnamevectorindices.m b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/auxiliary/getnamevectorindices.m
new file mode 100644
index 0000000000000000000000000000000000000000..557007bc9cfbd0bbc697d8cfe8acbe1cb35fffab
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/auxiliary/getnamevectorindices.m	
@@ -0,0 +1,13 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% OBTAIN INDICES FOR GIVEN LISTS OF ALLNAMES AND NAMES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [indices] = getnamevectorindices(allnames,names)
+indices = [];
+% cycle through names and add new values to output
+for k = 1:length(names),
+    index = strmatchIQM(names{k},allnames,'exact');
+    if ~isempty(index),
+        indices(end+1) = index;
+    end
+end
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/auxiliary/getparameterslocaldata.m b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/auxiliary/getparameterslocaldata.m
new file mode 100644
index 0000000000000000000000000000000000000000..0ebe872291f0baae5f4f15ba7b9b96ec9ddb24f4
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/auxiliary/getparameterslocaldata.m	
@@ -0,0 +1,40 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EXPAND THE INFO FOR THE LOCAL PARAMETERS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [parameterslocal,workestimation] = getparameterslocaldata(workestimation,parameterslocal)
+pliv = [];
+pllowerbounds = [];
+plhigherbounds = [];
+for k=1:length(workestimation),
+    % determine initial guesses for each experiment
+    plivk = workestimation(k).paramnominal(workestimation(k).paramindiceslocal);
+    pliv = [pliv(:); plivk(:)];
+    % determine lower and upper bounds for local parameters in each experiment
+    if length(parameterslocal.lowbounds) == 1,
+        if length(parameterslocal.names) == 1,
+            lowerbounds = parameterslocal.lowbounds;
+        else
+            lowerbounds = parameterslocal.lowbounds*pliv;
+        end
+    else
+        lowerbounds = parameterslocal.lowbounds;
+    end
+    if length(parameterslocal.highbounds) == 1,
+        if length(parameterslocal.names) == 1,
+            higherbounds = parameterslocal.highbounds;
+        else
+            higherbounds = parameterslocal.highbounds*pliv;
+        end
+    else
+        higherbounds = parameterslocal.highbounds;
+    end    
+    % finally expand the information
+    pllowerbounds = [pllowerbounds(:); lowerbounds(:)];
+    plhigherbounds = [plhigherbounds(:); higherbounds(:)];
+    indicesinLOCALPARAMvector = length(pliv)+[1-length(plivk):0];
+    workestimation(k).indicesinLOCALPARAMvector = indicesinLOCALPARAMvector;
+end    
+parameterslocal.pliv = pliv;
+parameterslocal.pllowerbounds = pllowerbounds;
+parameterslocal.plhigherbounds = plhigherbounds;
+return
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/auxiliary/reportICoptimization.m b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/auxiliary/reportICoptimization.m
new file mode 100644
index 0000000000000000000000000000000000000000..5c20ca6da2cd3105c0c07f79a12a00da13e46257
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/auxiliary/reportICoptimization.m	
@@ -0,0 +1,20 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Report IC optimization results
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [text] = reportICoptimization(workestimation,initialconditions,estimation,ICopt)
+global optimizeinitialconditionsFlag
+if optimizeinitialconditionsFlag ~= 1,
+    text = '';
+    return;
+end
+text = sprintf('Estimated initial conditions\n============================\n');
+for k=1:length(workestimation),
+    for k2=1:length(initialconditions.names),
+        icname = initialconditions.names{k2};
+        icvalue = ICopt(workestimation(k).indicesinICvector(k2));
+        numberexp = estimation.experiments.indices(k);
+        text = sprintf('%s%s=%g (Experiment %d)\n',text,icname,icvalue,numberexp);
+    end
+end
+return
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/auxiliary/setoptimizerOptions.m b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/auxiliary/setoptimizerOptions.m
new file mode 100644
index 0000000000000000000000000000000000000000..b2fcf428de299056ec0dd8c81e2bbe81a4bb8dc2
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/auxiliary/setoptimizerOptions.m	
@@ -0,0 +1,15 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE OPTIMIZER OPTIONS (disable lowbounds,highbounds,silent & outputfunction)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [OPTIONS] = setoptimizerOptions(optimization,numberoptparam)
+global displayFlag
+OPTIONS = optimization.options;
+OPTIONS.lowbounds = -Inf*ones(numberoptparam,1);  % bounds handled by transformation
+OPTIONS.highbounds = Inf*ones(numberoptparam,1);  % bounds handled by transformation
+if displayFlag >= 2,
+    OPTIONS.silent = 0;         % show iteration information if displayFlag set to 2 or 3 (override user settings)
+else
+    OPTIONS.silent = 1;         % show iteration information if displayFlag set to 2 or 3 (override user settings)
+end
+OPTIONS.outputfunction = '';    % overwrite eventual outputfunction with '' (eventually one could add an output function specific for parameter estimation)
+return
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/defaultcostparameterestimationIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/defaultcostparameterestimationIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..3671f51f171bf1bb6121001d7a6080f64994df5a
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterestimation/defaultcostparameterestimationIQM.m	
@@ -0,0 +1,115 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DEFAULT COST FUNCTION 
+%    - data have been simulated in the interface function.
+%    - this function simply compares the simulation to the measurements
+%      that have been done for the current experiment
+%    - sum of squared error
+%    - weighting: none, mean, max, diff. min/max
+%    - timeweighting: none, sampling interval difference dependent weighting
+%    - weighting of different measurements in different experiments
+% one additional output value was added 4/4/8
+% resid:  a vector of residuals for all measurements
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [cost,resid] = defaultcostparameterestimationIQM(simstructure,workestimationk,scalingFlag)
+global logscalingResidualsFlag
+
+cost = 0;
+resid = [];
+% get the simulated states and variables data
+statedata = simstructure.statevalues;
+variabledata = simstructure.variablevalues;
+% Cycle through all the measurements in the current experiment
+% and sum up the cost
+for k2=1:length(workestimationk.measurement),
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % GET SIM AND MEAS DATA AND SCALING DATA
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    timevectorindicesmeas = workestimationk.measurement(k2).timevectorindices; % get the indices of the timevector at which measurements have been done
+    % check if states have been measured in this measurement
+    if isempty(workestimationk.measurement(k2).stateindices),
+        % no states => empty
+        statesimulatedmeas = [];
+        statereferencesmeas = [];
+        statescaling = [];
+    else
+        % get the simulated and corresponding measured data
+        statesimulatedmeas = statedata(timevectorindicesmeas,workestimationk.measurement(k2).stateindices);
+        statereferencesmeas = workestimationk.measurement(k2).statereferences;
+        statescaling = workestimationk.measurement(k2).statescaling;
+%         if (prod(double(isnan(statescaling))) == 1), 
+%             error(sprintf('Please check your scaling settings.\nIt might be that you chose min/max scaling (3) but did not provide\nany min/max information for at least one measurement.')); 
+%         end
+    end
+    % check if variables have been measured in this measurement
+    if isempty(workestimationk.measurement(k2).variableindices),
+        % no states => empty
+        variablesimulatedmeas = [];
+        variablereferencesmeas = [];
+        variablescaling = [];
+    else
+        % get the simulated and corresponding measured data
+        variablesimulatedmeas = variabledata(timevectorindicesmeas,workestimationk.measurement(k2).variableindices);
+        variablereferencesmeas = workestimationk.measurement(k2).variablereferences;
+        variablescaling = workestimationk.measurement(k2).variablescaling;
+%         if (prod(double(isnan(variablescaling))) == 1), 
+%             error(sprintf('Please check your scaling settings.\nIt might be that you chose min/max scaling (3) but did not provide\nany min/max information for at least one measurement.')); 
+%         end
+    end
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % GET RESIDUALS
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    stateresidualsmeas = statesimulatedmeas-statereferencesmeas;
+    variableresidualsmeas = variablesimulatedmeas-variablereferencesmeas;
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % GET TIMESCALING
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    timescalingvector = workestimationk.measurement(k2).timescaling;
+    timescalingstates = timescalingvector(:,ones(size(statesimulatedmeas,2),1));
+    timescalingvariables = timescalingvector(:,ones(size(variablesimulatedmeas,2),1));
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % APPLY SCALING AND TIMESCALING TO RESIDUALS
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    if isempty(stateresidualsmeas),
+        scaledstateresiduals = [];
+    else
+        scaledstateresiduals = (stateresidualsmeas./statescaling).*timescalingstates;
+    end
+    if isempty(variableresidualsmeas),
+        scaledvariableresiduals = [];
+    else
+        scaledvariableresiduals = (variableresidualsmeas./variablescaling).*timescalingvariables;
+    end
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % HANDLE NaN elements (neglect them)
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    scaledstateresiduals(find(isnan(scaledstateresiduals))) = 0;
+    scaledvariableresiduals(find(isnan(scaledvariableresiduals))) = 0;
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % DO SOME ADDITIONAL SCALING AND WEIGHTING
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    factor1 = sqrt(1/length(timescalingvector)/(size(scaledstateresiduals,2) + size(scaledvariableresiduals,2)));
+    factor2 = sqrt(workestimationk.measurement(k2).weight);
+    scaledstateresiduals = scaledstateresiduals*factor1*factor2;
+    scaledvariableresiduals = scaledvariableresiduals*factor1*factor2;
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % LOGSCALE RESIDUALS IF DESIRED
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    if logscalingResidualsFlag,
+        scaledstateresiduals = log(abs(scaledstateresiduals)+1);
+        scaledvariableresiduals = log(abs(scaledvariableresiduals)+1);
+    end
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % SAVE THE RESIDUALS
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    resid = [resid reshape(scaledstateresiduals,1,[]) reshape(scaledvariableresiduals,1,[])];
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % GET THE COST FOR CURRENT MEASUREMENT
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    costmeas = sum(sum(scaledstateresiduals.^2)) + sum(sum(scaledvariableresiduals.^2));
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % SUM UP THE COST PER MEASUREMENT
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    cost = cost + costmeas;
+end
+return
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterfitanalysis/IQMfaboxplot.m b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterfitanalysis/IQMfaboxplot.m
new file mode 100644
index 0000000000000000000000000000000000000000..deb6d560a215cded3e80c197742261d794ab4625
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterfitanalysis/IQMfaboxplot.m	
@@ -0,0 +1,124 @@
+function [] = IQMfaboxplot(estdata,varargin)
+% IQMfaboxplot: Plots a box-and-whisker diagram for the estimation data,
+% visualizing the spread in the results. Separate plots are shown for
+% global and local parameters and initial conditions. Determine also mean
+% and standard deviation for all parameters and display them next to the
+% names.
+%
+% To normalize the data, the parameters are scaled such that the median of
+% each single parameter is 1. 
+%
+% USAGE:
+% ======
+% IQMfaboxplot(estdata)        
+% IQMfaboxplot(estdata, OPTIONS)        
+%
+% estdata: The estimation data returned by the function IQMparameterfitanalysis
+% OPTIONS: Structure containing options for the function
+%       OPTIONS.boxWidth: Width of the boxes to be drawn
+%       OPTIONS.verticalFlag: Flag determining if the boxes are oriented
+%                             vertically (=1) or horizontally (=0)
+%
+% DEFAULT VALUES:
+% ===============
+% OPTIONS.boxWidth:       0.5
+% OPTIONS.verticalFlag:   0 (plot horizontally)
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin == 1,
+    OPTIONS = [];
+elseif nargin == 2,
+    OPTIONS = varargin{1};
+else
+    error('Incorrect number of input arguments.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET THE DATA
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+Popt = estdata.Popt;
+PLOCALopt = estdata.PLOCALopt;
+ICopt = estdata.ICopt;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DETERMINE MEAN AND STD
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% scale each single parameter by its median
+if ~isempty(Popt),
+    meanPopt = mean(Popt);
+    stdPopt = std(Popt);
+end
+if ~isempty(PLOCALopt),
+    meanPLOCALopt = mean(PLOCALopt);
+    stdPLOCALopt = std(PLOCALopt);
+end
+if ~isempty(ICopt),
+    meanICopt = mean(ICopt);
+    stdICopt = std(ICopt);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% SCALE THE DATA SEPARATELY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% scale each single parameter by its median
+if ~isempty(Popt),
+    S = diag(1./median(Popt));
+    Poptscaled = Popt*S;
+end
+if ~isempty(PLOCALopt),
+    S = diag(1./median(PLOCALopt));
+    PLOCALoptscaled = PLOCALopt*S;
+end
+if ~isempty(ICopt),
+    S = diag(1./median(ICopt));
+    ICoptscaled = ICopt*S;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DETERMINE THE NAMES (add mean + std)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+globalnames = {};
+for k0 = 1:length(estdata.parameters),
+    globalnames{end+1} = sprintf('(%0.3g %s %0.3g)  %s',meanPopt(k0),char(177),stdPopt(k0),estdata.parameters{k0});
+end
+localnames = {};
+for k0 = 1:length(estdata.parameterslocal),
+    dataindex = [k0:length(estdata.parameterslocal):size(estdata.PLOCALopt,2)];
+    for k=1:length(dataindex),
+        localnames{end+1} = sprintf('(%0.3g %s %0.3g)  %s %d',meanPLOCALopt(dataindex(k)),char(177),stdPLOCALopt(dataindex(k)),estdata.parameterslocal{k0},k);
+    end
+end
+icnames = {};
+for k0 = 1:length(estdata.icnames),
+    dataindex = [k0:length(estdata.icnames):size(estdata.ICopt,2)];
+    for k=1:length(dataindex),
+        icnames{end+1} = sprintf('(%0.3g %s %0.3g)  %s %d',meanICopt(dataindex(k)),char(177),stdICopt(dataindex(k)),estdata.icnames{k0},k);
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DO THE PLOT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(Popt)
+    % add the names the options
+    OPTIONS.samplenames = globalnames;
+    figure;
+    boxplotIQM(Poptscaled,OPTIONS);
+    title('Fitted and scaled GLOBAL parameters');
+end
+if ~isempty(PLOCALopt)
+    OPTIONS.samplenames = localnames;
+    figure;    
+    boxplotIQM(PLOCALoptscaled,OPTIONS);
+    title('Fitted and scaled LOCAL parameters');
+end
+if ~isempty(ICopt)
+    OPTIONS.samplenames = icnames;
+    figure;
+    boxplotIQM(ICoptscaled,OPTIONS);
+    title('Fitted and scaled initial conditions');
+end
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterfitanalysis/IQMfaclustering.m b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterfitanalysis/IQMfaclustering.m
new file mode 100644
index 0000000000000000000000000000000000000000..f5ad7c54838d645db0b5baa3d3fd82ba25e69f68
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterfitanalysis/IQMfaclustering.m	
@@ -0,0 +1,65 @@
+function [] = IQMfaclustering(estdata,varargin)
+% IQMfaclustering: This function performs hierarchical clustering based on
+% Euclidean distance of the estimated parameter sets. If the estimates are
+% grouped around a single minimum a single cluster tree should be seen.
+% However, if the parameter sets lie around different local minima the tree
+% will show several large branches.
+%
+% To normalize the data, the parameters are scaled such that the median of
+% each single parameter is 1.
+%
+% USAGE:
+% ======
+% IQMfaclustering(estdata)        
+% IQMfaclustering(estdata,fontsize)        
+%
+% estdata:  The estimation data returned by the function IQMparameterfitanalysis
+% fontsize: Fontsize for the dendrogram (default: 10)
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fontsize = 10;
+if nargin == 2,
+    fontsize = varargin{1};
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET THE DATA
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+Popt = estdata.Popt;
+PLOCALopt = estdata.PLOCALopt;
+ICopt = estdata.ICopt;
+ALL = [Popt, PLOCALopt, ICopt];
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% SCALE THE DATA
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% scale each single parameter by its median
+S = diag(1./median(ALL));
+iInf=find(S==Inf);
+S(iInf)=1;
+ALLscaled = ALL*S;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CALCULATE THE EUCLIDEAN DISTANCES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+D = pdistIQM(ALLscaled);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DO THE CLUSTERING 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+topology = clusteringIQM(D);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DO THE PLOT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+figure; clf;
+plot_dendrogram(topology,[],fontsize);
+title('Dendrogram of clustered parameter estimates');
+xlabel('Distance');
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterfitanalysis/IQMfacorr.m b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterfitanalysis/IQMfacorr.m
new file mode 100644
index 0000000000000000000000000000000000000000..3eb80c0d70e827a7a47221119f689af8a512fd91
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterfitanalysis/IQMfacorr.m	
@@ -0,0 +1,66 @@
+function [] = IQMfacorr(estdata, varargin)
+% IQMfacorr: This function determines the correlation matrix for the
+% parameter sets determined with the IQMparameterfitanalysis function.
+% The closer the magnitude of the values is to one, the more correlated the
+% parameters. 
+%
+% Results are generated only for the global parameters.
+%
+% USAGE:
+% ======
+% IQMfacorr(estdata)
+%
+% estdata:  The estimation data returned by the function IQMparameterfitanalysis
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Get the parameter information
+parameters = estdata.parameters;
+G = estdata.Popt;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DETERMINE THE PARAMETER CORRELATION MATRIX
+% Take out parameters with zero variance!
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[n,m] = size(G);
+C = cov(G);
+zerovarianceindices = find(diag(C)==0);
+G(:,zerovarianceindices) = [];  % take out these parameters
+allparameters = parameters;
+parameters = parameters(setdiff([1:length(parameters)],zerovarianceindices));
+[correlationMatrix,P,LB,UB] = corrcoef(G);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DISPLAY NOTE IF PARAMTERS HAVE BEEN TAKEN OUT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(zerovarianceindices),
+    text = '';
+    for k=1:length(zerovarianceindices),
+        text = sprintf('%sParameter ''%s'' shows 0 variance. Taken out of consideration.\n',text,allparameters{zerovarianceindices(k)});
+    end
+    disp(text);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle the output
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Plot the correlation matrix (absolute values)
+% Prepare plot matrix
+plotMatrix = [correlationMatrix zeros(size(correlationMatrix,1),1); 0*ones(1,size(correlationMatrix,2)+1)];
+plotMatrix = abs(plotMatrix);
+% Plot the result
+figH = figure; clf;
+axesH = gca(figH);
+pcolor(plotMatrix);
+axis square;
+colorbar('EastOutside','YTick',[-1,-0.8,-0.6,-0.4,-0.2,0,0.2,0.4,0.6,0.8,1]);
+set(axesH,'XTick',[1.5:size(correlationMatrix,1)+0.5]);
+set(axesH,'XTickLabel',parameters);
+try
+    set(gca,'XTickLabelRotation',45);
+catch
+end
+set(axesH,'YTick',[1.5:size(correlationMatrix,1)+0.5]);
+set(axesH,'YTickLabel',parameters);
+colormap('Bone');
+title('Parameter Correlation Matrix (absolute values)');
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterfitanalysis/IQMfadetcorr/IQMfadetcorr.fig b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterfitanalysis/IQMfadetcorr/IQMfadetcorr.fig
new file mode 100644
index 0000000000000000000000000000000000000000..0ff0e568012b01dc6bdaf8ccf2af222424826d69
Binary files /dev/null and b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterfitanalysis/IQMfadetcorr/IQMfadetcorr.fig differ
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterfitanalysis/IQMfadetcorr/IQMfadetcorr.m b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterfitanalysis/IQMfadetcorr/IQMfadetcorr.m
new file mode 100644
index 0000000000000000000000000000000000000000..d8357304f622a7f0e8bd91ea9d6c879b4adec43e
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterfitanalysis/IQMfadetcorr/IQMfadetcorr.m	
@@ -0,0 +1,212 @@
+function varargout = IQMfadetcorr(varargin)
+% IQMfadetcorr: Plots detailed pairwise correlations between parameters.
+% Parameters to display on the X and Y axis should be selected. 
+%
+% USAGE:
+% ======
+% [project] = IQMfadetcorr(estdata)
+%
+% estdata:  The estimation data returned by the function IQMparameterfitanalysis
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INITIALIZATION CODE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Begin initialization code - DO NOT EDIT
+
+gui_Singleton = 1;
+gui_State = struct('gui_Name',       mfilename, ...
+                   'gui_Singleton',  gui_Singleton, ...
+                   'gui_OpeningFcn', @IQMfadetcorr_OpeningFcn, ...
+                   'gui_OutputFcn',  @IQMfadetcorr_OutputFcn, ...
+                   'gui_LayoutFcn',  [] , ...
+                   'gui_Callback',   []);
+if nargin && ischar(varargin{1})
+    gui_State.gui_Callback = str2func(varargin{1});
+end
+if nargout
+    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
+else
+    gui_mainfcn(gui_State, varargin{:});
+end
+% End initialization code - DO NOT EDIT
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INTERFACE FUNCTIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% --- Executes just before IQMfadetcorr is made visible.
+function IQMfadetcorr_OpeningFcn(hObject, eventdata, handles, varargin)
+
+if nargin ~= 4,
+    error('Incorrect number of input arguments.');
+else
+    estdata = varargin{1};
+end
+handles.estdata = estdata;
+set(handles.parametersx,'String',handles.estdata.parameters);
+set(handles.parametersx,'Value',1);
+set(handles.parametersy,'String',handles.estdata.parameters);
+set(handles.parametersy,'Value',1);
+% select plottype 
+handles.dataPlotType = 'plot';     
+% text flag
+handles.textFlag = 0;
+% Doing a first plot
+handles = doPlot(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+% --- Outputs from this function are returned to the command line.
+function varargout = IQMfadetcorr_OutputFcn(hObject, eventdata, handles) 
+varargout{1} = [];
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PLOT FUNCTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function handles = doPlot(handles)
+% get the data to plot
+try
+    estdata = handles.estdata;
+catch
+    return
+end
+% get x and y parameters
+xparamindices = get(handles.parametersx,'Value');
+yparamindices = get(handles.parametersy,'Value');
+xparamnames = estdata.parameters(xparamindices);
+yparamnames = estdata.parameters(yparamindices);
+NROW = length(yparamindices);
+NCOL = length(xparamindices);
+for sp = 1:NROW*NCOL,
+    nx = mod(sp-1,NCOL)+1;
+    ny = ceil(sp/NCOL);
+    subplot(NROW,NCOL,sp,'Parent',handles.plotpanel);
+    ylabeltext = xparamnames{nx};
+    xlabeltext = yparamnames{ny};
+    if ~strcmp(ylabeltext,xlabeltext),
+        xvalues = estdata.Popt(:,xparamindices(nx));
+        yvalues = estdata.Popt(:,yparamindices(ny));
+        feval(handles.dataPlotType,xvalues,yvalues,'o');
+    else
+        set(gca,'Color',[0 0 0]);
+    end
+    set(gca,'XTick',[]);
+    set(gca,'YTick',[]);    
+end
+% get plotpanel handle and initialize text elements
+ppH = handles.plotpanel;
+if handles.textFlag == 0,
+    XtextH = {};
+    YtextH = {};
+    
+    for k = 1:length(estdata.parameters),
+        XtextH{k} = uicontrol(ppH,'Style','text','String','','Position',[-100,-100,2,2]);
+    end
+    for k = 1:length(estdata.parameters),
+        YtextH{k} = uicontrol(ppH,'Style','text','String','','Position',[-100,-100,2,2]);
+    end
+    handles.XtextH = XtextH;    
+    handles.YtextH = YtextH;
+else
+    % reset the position of the text
+    for k = 1:length(estdata.parameters),
+        set(handles.XtextH{k},'Position',[-100,-100,2,2]);
+    end
+    for k = 1:length(estdata.parameters),
+        set(handles.YtextH{k},'Position',[-100,-100,2,2]);
+    end
+end
+
+% get size of plot panel in pixels
+fadetcorr = get(handles.IQMfadetcorr,'Position');
+pp = get(ppH,'Position');
+screen = get(0,'ScreenSize');
+ppWidth = fadetcorr(3)*pp(3)*screen(3);
+ppHeight = fadetcorr(4)*pp(4)*screen(4);
+% get all x and y values where to place text
+positions = [];
+figH = get(handles.plotpanel,'Children');
+for k = 1:length(figH),
+    positions = [positions; get(figH(k),'Position')];
+end
+x = unique(positions(:,1));
+width = positions(:,3);
+y = unique(positions(:,2));
+height = positions(:,4);
+x(x<0) = [];
+y(y<0) = [];
+width(width>1) = [];
+height(height>1) = [];
+width = width(1);
+height = height(1);
+if handles.textFlag ~= 0,
+    % set the text
+    for k = 1:length(x),
+        set(handles.XtextH{k},'Position',[x(k)*ppWidth,y(1)*ppHeight-20,length(xparamnames{k})*8,10],'String',xparamnames{k});
+    end       
+    for k = 1:length(y),
+        set(handles.YtextH{k},'Position',[x(1)*ppWidth-120,y(k)*ppHeight+height/2*ppHeight-10,length(yparamnames{k})*8,10],'String',yparamnames{end-k+1});
+    end
+else
+    % add text elements the first time
+    handles.textFlag = 1;
+end
+return
+
+function parametersx_Callback(hObject, eventdata, handles)
+handles = doPlot(handles);
+return
+
+function parametersy_Callback(hObject, eventdata, handles)
+handles = doPlot(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
+
+% --- Executes on button press in zoombutton.
+function zoombutton_Callback(hObject, eventdata, handles)
+% toogle the zoom in the figure
+zoom
+return
+
+% --- Executes on button press in plot.
+function plot_Callback(hObject, eventdata, handles)
+handles.dataPlotType = 'plot';
+% Update handles structure
+guidata(hObject, handles);
+handles = doPlot(handles);
+return
+
+% --- Executes on button press in loglog.
+function semilogx_Callback(hObject, eventdata, handles)
+handles.dataPlotType = 'semilogx';
+% Update handles structure
+guidata(hObject, handles);
+handles = doPlot(handles);
+return
+
+% --- Executes on button press in semilogx.
+function semilogy_Callback(hObject, eventdata, handles)
+handles.dataPlotType = 'semilogy';
+% Update handles structure
+guidata(hObject, handles);
+handles = doPlot(handles);
+return
+
+% --- Executes on button press in loglog.
+function loglog_Callback(hObject, eventdata, handles)
+handles.dataPlotType = 'loglog';
+% Update handles structure
+guidata(hObject, handles);
+handles = doPlot(handles);
+return
+
+function resize_Callback(hObject, eventdata, handles)
+handles = doPlot(handles);
+% Update handles structure
+guidata(hObject, handles);
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterfitanalysis/IQMfahist.m b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterfitanalysis/IQMfahist.m
new file mode 100644
index 0000000000000000000000000000000000000000..68c9b20ca6ad575422b5757024f9171ace0f56d3
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterfitanalysis/IQMfahist.m	
@@ -0,0 +1,114 @@
+function [] = IQMfahist(estdata,varargin)
+% IQMfahist: This function plots histograms for the parameter values that 
+% have been estimated using the IQMparameterfitanalysis function. This
+% gives a first impression over how well the parameters can be determined.
+%
+% The bins are equally distributed over the parameter range given by the
+% upper and lower bounds.
+%
+% Results are displayed separately for global parameters, local parameters,
+% and initial conditions. For each estimated local parameter and initial
+% condition a new figure is displayed, since usually there will be several
+% experiments.
+%
+% USAGE:
+% ======
+% IQMfahist(estdata)        
+% IQMfahist(estdata,nrbins)        
+%
+% estdata:  The estimation data returned by the function IQMparameterfitanalysis
+% nrbins:   Number of bins to sort the values into
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+nrbins = 15;
+if nargin == 2,
+    nrbins = varargin{1};
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE GLOBAL PARAMETERS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+Popt = estdata.Popt;
+Pnames = estdata.parameters;
+if ~isempty(Popt),
+    figure; clf;
+    nrPlots = size(Popt,2);
+    nrCols = ceil(sqrt(nrPlots));
+    nrRows = ceil(nrPlots/nrCols);
+    for k=1:size(Popt,2),
+        subplot(nrRows,nrCols,k);
+        % create the bin center vector
+        dn = estdata.parameterslowbounds(k);
+        up = estdata.parametershighbounds(k);
+        delta=(up-dn)/nrbins; 
+        centervector = [dn+delta/2:delta:up-delta/2];
+        hist(Popt(:,k),centervector);
+        [N,X] = hist(Popt(:,k),centervector);
+        hlhlx = title(Pnames{k});
+        set(hlhlx,'Interpreter','none');
+        axis([dn up 0 max(N)*1.05]);
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE LOCAL PARAMETERS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+PLOCALopt = estdata.PLOCALopt;
+PLOCALnames = estdata.parameterslocal;
+if ~isempty(PLOCALopt),
+    for k0 = 1:length(PLOCALnames),
+        figure; clf;       
+        dataindex = [k0:length(PLOCALnames):size(PLOCALopt,2)];
+        nrPlots = length(dataindex);
+        nrCols = ceil(sqrt(nrPlots));
+        nrRows = ceil(nrPlots/nrCols);
+        for k=1:length(dataindex),
+            subplot(nrRows,nrCols,k);
+            % create the bin center vector
+            dn = estdata.parameterslocallowbounds(dataindex(k));
+            up = estdata.parameterslocalhighbounds(dataindex(k));
+            delta=(up-dn)/nrbins; 
+            centervector = [dn+delta/2:delta:up-delta/2];
+            hist(PLOCALopt(:,dataindex(k)),centervector);
+            [N,X] = hist(PLOCALopt(:,dataindex(k)),centervector);
+            hlhlx = title(sprintf('%s - Experiment %d',PLOCALnames{k0},k));
+            set(hlhlx,'Interpreter','none');
+            delta = (X(2)-X(1))/2;
+            axis([dn up 0 max(N)*1.05]);
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE INITIAL CONDITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ICopt = estdata.ICopt;
+icnames = estdata.icnames;
+if ~isempty(ICopt),
+    for k0 = 1:length(icnames),
+        figure; clf;       
+        dataindex = [k0:length(icnames):size(ICopt,2)];
+        nrPlots = length(dataindex);
+        nrCols = ceil(sqrt(nrPlots));
+        nrRows = ceil(nrPlots/nrCols);
+        for k=1:length(dataindex),
+            subplot(nrRows,nrCols,k);
+            % create the bin center vector
+            dn = estdata.iclowbounds(dataindex(k));
+            up = estdata.ichighbounds(dataindex(k));
+            delta=(up-dn)/nrbins; 
+            centervector = [dn+delta/2:delta:up-delta/2];
+            hist(ICopt(:,dataindex(k)),centervector);
+            [N,X] = hist(ICopt(:,dataindex(k)),centervector);
+            hlhlx = title(sprintf('%s - Experiment %d',icnames{k0},k));
+            set(hlhlx,'Interpreter','none');
+            delta = (X(2)-X(1))/2;
+            axis([dn up 0 max(N)*1.05]);
+        end
+    end
+end
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterfitanalysis/IQMfasigncorr.m b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterfitanalysis/IQMfasigncorr.m
new file mode 100644
index 0000000000000000000000000000000000000000..bc6a39f8a0d2e7f3c25b47f8353e4d581f85e2fa
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterfitanalysis/IQMfasigncorr.m	
@@ -0,0 +1,84 @@
+function [] = IQMfasigncorr(estdata, varargin)
+% IQMfasigncorr: A matrix of p-values for testing
+% the hypothesis of no significant correlation is computed based on the 
+% results generated by IQMparameterfitanalysis and displayed.
+% Each p-value is the probability of getting a correlation 
+% as large as the observed value by random chance, when 
+% the true correlation is zero.  If P(i,j) is small then the
+% correlation between these two parameters is significant. 
+%
+% Results are generated only for the global parameters.
+%
+% USAGE:
+% ======
+% IQMfasigncorr(estdata)
+% IQMfasigncorr(estdata,alpha)
+%
+% estdata:  The estimation data returned by the function IQMparameterfitanalysis
+% alpha:    A number between 0 and 1 to specify a confidence
+%                   level of 100*(1-alpha)%.  
+%
+%           Default: alpha=0.05
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+alpha = 0.05;
+if nargin == 2,
+    alpha = varargin{1};
+    if alpha > 1 || alpha < 0,
+        error('Wrong value for alpha');
+    end
+end
+
+% Get the parameter information
+parameters = estdata.parameters;
+G = estdata.Popt;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DETERMINE THE PARAMETER CORRELATION MATRIX
+% Take out parameters with zero variance!
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[n,m] = size(G);
+C = cov(G);
+zerovarianceindices = find(diag(C)==0);
+G(:,zerovarianceindices) = [];  % take out these parameters
+allparameters = parameters;
+parameters = parameters(setdiff([1:length(parameters)],zerovarianceindices));
+[correlationMatrix,P,LB,UB] = corrcoef(G,'alpha',alpha);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DISPLAY NOTE IF PARAMTERS HAVE BEEN TAKEN OUT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(zerovarianceindices),
+    text = '';
+    for k=1:length(zerovarianceindices),
+        text = sprintf('%sParameter ''%s'' shows 0 variance. Taken out of consideration.\n',text,allparameters{zerovarianceindices(k)});
+    end
+    disp(text);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle the output
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Plot the P matrix 
+% Prepare plot matrix
+plotMatrix = abs([P zeros(size(P,1),1); 0*ones(1,size(P,2)+1)]);
+% Plot the result
+figH = figure; clf;
+axesH = gca(figH);
+pcolor(plotMatrix);
+axis square;
+colorbar('EastOutside','YTick',[-1,-0.8,-0.6,-0.4,-0.2,0,0.2,0.4,0.6,0.8,1]);
+set(axesH,'XTick',[1.5:size(correlationMatrix,1)+0.5]);
+set(axesH,'XTickLabel',parameters);
+try
+    set(gca,'XTickLabelRotation',45);
+catch
+end
+set(axesH,'YTick',[1.5:size(correlationMatrix,1)+0.5]);
+set(axesH,'YTickLabel',parameters);
+colormap('Bone');
+title(sprintf('Significant Correlations (p-values with alpha=%g)',alpha));
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterfitanalysis/IQMparameterfitanalysis.m b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterfitanalysis/IQMparameterfitanalysis.m
new file mode 100644
index 0000000000000000000000000000000000000000..f62bcf454e4c970d0d04df9715504d1778eb6737
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterfitanalysis/IQMparameterfitanalysis.m	
@@ -0,0 +1,401 @@
+function [estdata] = IQMparameterfitanalysis(project,estimation,varargin)
+% IQMparameterfitanalysis: Parameter estimation for the given project is
+% repeated several times from randomly perturbed starting conditions. The
+% estimated parameters values are stored and can subsequently can be used
+% to obtain insight into correlations between parameters, local minima, etc.
+%
+% This function only generates the data, which then is analyzed by
+% specialized functions (IQMfaboxplot, IQMfaclustering, IQMfahist).
+% 
+% USAGE:
+% ======
+% [estdata] = IQMparameterfitanalysis(project,estimation)        
+% [estdata] = IQMparameterfitanalysis(project,estimation,nrestimations,perttype)               
+% [estdata] = IQMparameterfitanalysis(project,estimation,nrestimations,perttype,noStopButtonFlag)        
+%
+% project:        IQMprojectSB for which to do the estimation
+% estimation: Structure that defines what to do. Same structure as used for
+%   IQMparameterestimation, thereforw not documented here again.
+% nrestimations:  number of estimations that are to be done from
+%                            varying initial conditions
+% perttype:       =0: perturbed parameters/initial conditions
+%                 chosen randomly distributed uniformly between
+%                 the low and high bounds. 
+%                 >0: perturbed parameters obtained from an
+%                 exponential distribution around the nominal
+%                 values: ppert=p0*10^(randn(1)*perttype)
+% noStopButtonFlag: 0: stop button, 1: no stop button
+%
+% DEFAULT VALUES:
+% ===============
+% estimation:            same as in IQMparameterestimation
+% nrestimations:         50
+% perttype:              0.5 (exponential distribution around nominal parameter values/initial conditions
+% noStopButtonFlag: 0 
+%
+% Output Arguments:
+% =================
+% The output 'estdata' is given as a structure:
+%   nrestimations: number of estimations performed
+%        perttype: the chosen perturbation type
+%      parameters: cell-array with names of optimized parameters
+%            Popt: vector with values of optimized parameters
+% parameterslocal: cell-array with names of locally optimized parameters
+%                  (for each experiment indenpendently)
+%       PLOCALopt: vector with values of locally optimized parameters
+%         icnames: cell-array with names of states for which the initial conditions have been optimized
+%           ICopt: vector with values of optimized initial conditions
+%         FVALopt: optimal cost function value
+%       FVALstart: the cost at the starting conditions
+%     timeelapsed: the time needed for all the estimations
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GLOBAL VARIABLES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+global workestimation parameters stopOptimization costfunction fh
+global displayFlag initialconditionsFlag scalingFlag 
+global timescalingFlag 
+global PICmin PICmax parameterslocal optimizerboundsFlag integratoroptions
+
+global compiledExpModelsIQMparamestGUI
+
+stopOptimization = 0;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% BASIC CHECK OF THE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isIQMprojectSB(project),
+    error('Input argument ''project'' is not an IQMprojectSB.');
+end
+if ~isstruct(estimation) && ~isempty(estimation),
+    error('Input argument ''estimation'' is not an structure.');
+end
+projectstruct = IQMstruct(project);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE PARAM DATA MATRIX
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if iscell(estimation.parameters),
+    if ~isempty(estimation.parameters),
+        paramnames = estimation.parameters(:,1); 
+        paramlowbounds = cell2mat(estimation.parameters(:,2)); 
+        paramhighbounds = cell2mat(estimation.parameters(:,3)); 
+    else
+        paramnames = {}; 
+        paramlowbounds = []; 
+        paramhighbounds = []; 
+    end
+    estimation.parameters = [];
+    estimation.parameters.names = paramnames;
+    estimation.parameters.lowbounds = paramlowbounds;
+    estimation.parameters.highbounds = paramhighbounds; 
+end
+if iscell(estimation.parameterslocal),
+    if ~isempty(estimation.parameterslocal),
+        paramnameslocal = estimation.parameterslocal(:,1);
+        paramlowboundslocal = cell2mat(estimation.parameterslocal(:,2));
+        paramhighboundslocal = cell2mat(estimation.parameterslocal(:,3));
+    else
+        paramnameslocal = {};
+        paramlowboundslocal = [];
+        paramhighboundslocal = [];
+    end
+    estimation.parameterslocal = [];
+    estimation.parameterslocal.names = paramnameslocal;
+    estimation.parameterslocal.lowbounds = paramlowboundslocal;
+    estimation.parameterslocal.highbounds = paramhighboundslocal;
+end
+if iscell(estimation.initialconditions),
+    if ~isempty(estimation.initialconditions),
+        icnames = estimation.initialconditions(:,1);
+        iclowbounds = cell2mat(estimation.initialconditions(:,2));
+        ichighbounds = cell2mat(estimation.initialconditions(:,3));
+    else
+        icnames = {};
+        iclowbounds = [];
+        ichighbounds = [];
+    end
+    estimation.initialconditions = [];
+    estimation.initialconditions.names = icnames;
+    estimation.initialconditions.lowbounds = iclowbounds;
+    estimation.initialconditions.highbounds = ichighbounds;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK INFO AND GET DATA FROM PROJECT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[model,experiments,parameters,parameterslocal,initialconditions,optimization,costfunction,estimation,experimentmeasurementweights] = checkandprocessinput(project,projectstruct,estimation);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE NON-NUMERIC INITIAL CONDITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% just by replacing them
+% + warning ... as user feedback
+if ~hasonlynumericICsIQM(model),
+    model = IQMconvertNonNum2NumIC(model);
+    disp('Warning: The model contains non-numeric initial conditions. For this analysis these are replaced');
+    disp('by numeric initial conditions, determined from the non-numeric ones.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CHECK VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+displayFlag = 0;
+nrestimations = 50;
+perttype = 0.5;
+noStopButton = 0;
+integratoroptions = [];
+integratoroptions.maxnumsteps = 1000;
+if nargin >= 3,
+    nrestimations = varargin{1};
+end
+if nargin >= 4,
+    perttype = varargin{2};
+end
+if nargin >= 5,
+    noStopButton = varargin{3};
+end
+if nargin<2 || nargin>5,
+    error('Incorrect number of input arguments.');
+end
+
+% get integrator options
+try
+    integratoroptions = estimation.integrator.options; 
+catch
+    integratoroptions = [];
+    integratoroptions.maxnumsteps = 1000;
+    estimation.integrator.options = integratoroptions;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PROCESS EXPERIMENT AND MEASUREMENT INFORMATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+workestimation = getexpmeasinfoIQM(model,estimation.modelindex,experiments,estimation.experiments.indices,displayFlag,scalingFlag,timescalingFlag,initialconditionsFlag,experimentmeasurementweights);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% ADD PARAMETER INDICES AND NOMINAL VALUES TO WORKESTIMATION STRUCTURE
+% Could be different indices for different experiments ... so its done here
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+workestimation = addparameterindices(workestimation,parameters,parameterslocal);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EXPAND THE INFO FOR THE LOCAL PARAMETERS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[parameterslocal,workestimation] = getparameterslocaldata(workestimation,parameterslocal);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% ADD INDICES OF THE STATES FOR WHICH TO OPTIMIZE THE INITIAL CONDITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+workestimation = addstateicoptimindices(workestimation,initialconditions);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET INITIAL CONDITIONS VECTOR AND LOW AND HIGH BOUNDS
+% ADD IC INDICES TO WORKESTIMATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[initialconditions,workestimation] = geticdata(workestimation,initialconditions);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% NOW WE CAN CHECK BOUNDS FOR LOCAL PARAM AND INITIAL CONDS
+% IF outside then warn and correct to be inside
+% SKIP the warning for now!
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+tol = 0.00001;
+indexhi = find(parameters.initialguesses(:)>=parameters.highbounds(:));
+parameters.initialguesses(indexhi) = parameters.highbounds(indexhi)*(1-tol);
+indexlo = find(parameters.initialguesses(:)<=parameters.lowbounds(:));
+parameters.initialguesses(indexlo) = parameters.lowbounds(indexlo)*(1+tol);
+
+indexhi = find(parameterslocal.pliv(:)>=parameterslocal.plhigherbounds(:));
+parameterslocal.pliv(indexhi) = parameterslocal.plhigherbounds(indexhi)*(1-tol);
+indexlo = find(parameterslocal.pliv(:)<=parameterslocal.pllowerbounds(:));
+parameterslocal.pliv(indexlo) = parameterslocal.pllowerbounds(indexlo)*(1+tol);
+
+indexhi = find(initialconditions.ic0(:)>=initialconditions.icupperbounds(:));
+initialconditions.ic0(indexhi) = initialconditions.icupperbounds(indexhi)*(1-tol);
+indexlo = find(initialconditions.ic0(:)<=initialconditions.iclowerbounds(:));
+initialconditions.ic0(indexlo) = initialconditions.iclowerbounds(indexlo)*(1+tol);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Take care of optimization methods that require upper and lower bounds
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+optimizerboundsFlag = 0;
+info = feval(optimization.method);
+if info.constrained == 1,
+    % chosen optimization method handles constraints 
+    % => disable IQMparameterestimation bounds handling
+    optimizerboundsFlag = 1;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Prepare estimation data structure
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+estdata = [];
+estdata.nrestimations = nrestimations;
+estdata.cutoffthreshold = inf;
+estdata.perttype = perttype;
+estdata.parameters = parameters.names(:)';
+estdata.parametershighbounds = parameters.highbounds(:)';
+estdata.parameterslowbounds = parameters.lowbounds(:)';
+estdata.Popt = [];
+estdata.parameterslocal = parameterslocal.names(:)';
+estdata.parameterslocalhighbounds = parameterslocal.plhigherbounds(:)';
+estdata.parameterslocallowbounds = parameterslocal.pllowerbounds(:)';
+estdata.PLOCALopt = [];
+estdata.icnames = initialconditions.names(:)';
+estdata.ichighbounds = initialconditions.icupperbounds(:)';
+estdata.iclowbounds = initialconditions.iclowerbounds(:)';
+estdata.ICopt = [];
+estdata.FVALopt = [];
+estdata.FVALstart = [];
+estdata.timeelapsed = [];
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% START THE ESTIMATION LOOP
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+timestartall = clock;
+timesinglerun = [];
+timeelapsed = 0;
+createstopbutton();
+if noStopButton,
+    set(fh,'Visible','off');
+end
+
+for loop=1:nrestimations,
+    timestart = clock;
+    disp(sprintf('Parameter estimation #%d',loop));
+    % get nominal values, max and min bounds
+    paramnominal = [parameters.initialguesses(:); parameterslocal.pliv(:); initialconditions.ic0(:)];
+    parammax = [parameters.highbounds(:); parameterslocal.plhigherbounds(:); initialconditions.icupperbounds(:)];
+    parammin = [parameters.lowbounds(:); parameterslocal.pllowerbounds(:); initialconditions.iclowerbounds(:)];
+    
+    % perturb the parameters
+    if perttype == 0,
+        % uniform distribution between min and max values
+        parampert = rand(length(paramnominal),1).*(parammax-parammin)+parammin;
+    else
+        % exponential distribution
+        parampert = paramnominal.*10.^(randn(length(paramnominal),1)*perttype);
+    end
+    
+    % fix perturbed values to bounds
+    indexup = find(parampert>=parammax);
+    indexdn = find(parampert<=parammin);
+    tol = 0.00001;
+    parampert(indexup) = parammax(indexup)*(1-tol);
+    parampert(indexdn) = parammin(indexdn)*(1+tol);
+    
+    % Transform parameters and initial conditions to be optimized for taking into account upper and lower bounds
+    if optimizerboundsFlag == 1,
+        X0 = parampert;
+    else
+        PICmin = parammin;
+        PICmax = parammax;
+        PIC0 = parampert;
+        X0 = log((PIC0(:)-PICmin(:))./(PICmax(:)-PIC0(:)));
+    end
+
+    % SET OPTIMIZER OPTIONS
+    OPTIONS = setoptimizerOptions(optimization,length(X0)); % disable lowbounds,highbounds,silent & outputfunction
+    if optimizerboundsFlag == 1,
+        % Add optimizer bounds if the optimization methods requires it.
+        OPTIONS.lowbounds = [parameters.lowbounds(:); parameterslocal.pllowerbounds(:); initialconditions.iclowerbounds(:)];
+        OPTIONS.highbounds = [parameters.highbounds(:); parameterslocal.plhigherbounds(:); initialconditions.icupperbounds(:)];
+    end
+
+    % RUN THE ESTIMATION
+    warning off
+    [Xopt,FVALopt] = feval(optimization.method,@costFunctionInterface,X0,OPTIONS);
+    warning on
+    
+    % For some strange reason does the call to javaaddpath clear all global
+    % variables. This call is performed in the case that JavaEvA optimization
+    % methods are used. The involved functions take care of keeping the global
+    % variables but it is necessary to declare them again as global here in
+    % this function. Stupid stupid stupid :)
+
+    % so check if optimizerboundsFlag is still defined global in this function
+    try
+        optimizerboundsFlag;
+    catch
+        % No, it isn't ... so lets make all the globals global again!
+        global workestimation parameters stopOptimization costfunction fh
+        global displayFlag initialconditionsFlag scalingFlag optimizerboundsFlag
+        global timescalingFlag
+        global PICmin PICmax parameterslocal compiledExpModelsIQMparamestGUI
+    end
+
+    % BACKTRANSFORM OPTIMIZED PARAMETERS/ICS
+    if optimizerboundsFlag == 1,
+        Popt = Xopt(1:length(parameters.names));
+        PLOCALopt = Xopt(length(parameters.names)+1:length(parameters.names)+length(parameterslocal.names)*length(workestimation));
+        ICopt = Xopt(length(parameters.names)+length(parameterslocal.names)*length(workestimation)+1:end);
+    else
+        PICopt = (PICmin(:)+PICmax(:).*exp(Xopt(:)))./(1+exp(Xopt(:)));
+        Popt = PICopt(1:length(parameters.names));
+        PLOCALopt = PICopt(length(parameters.names)+1:length(parameters.names)+length(parameterslocal.names)*length(workestimation));
+        ICopt = PICopt(length(parameters.names)+length(parameterslocal.names)*length(workestimation)+1:end);
+    end
+    % Set ICopts to 0 if between -10*eps and +10*eps
+    for k=1:length(ICopt), if ICopt(k) < 10*eps && ICopt(k) > -10*eps, ICopt(k) = 0; end; end
+
+    % If estimation stopped then quit the loop
+    if stopOptimization,
+        break;
+    end
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % COLLECT ESTIMATION DATA
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    estdata.Popt = [estdata.Popt; Popt(:)'];
+    estdata.PLOCALopt = [estdata.PLOCALopt; PLOCALopt(:)'];
+    estdata.ICopt = [estdata.ICopt; ICopt(:)'];
+    estdata.FVALopt = [estdata.FVALopt; FVALopt];
+    estdata.FVALstart = [estdata.FVALstart; costFunctionInterface(X0)];
+
+    % display some status information
+    timenow = clock;
+    timesinglerun = [timesinglerun, etime(timenow,timestart)];
+    timeelapsed = etime(timenow,timestartall);
+    timeleft = mean(timesinglerun)*nrestimations-timeelapsed;
+    disp(sprintf('Start/optimal cost: %g / %g - Time left for estimation: %d min',estdata.FVALstart(end),FVALopt,round(timeleft/60)));
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % END THE ESTIMATION LOOP
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+end
+estdata.timeelapsed = timeelapsed/60;
+estdata.nrestimations = size(estdata.Popt,1);
+% close the stopbutton window
+try close(fh); catch, end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CUT OFF THE DATA (CUT OFF CAN BE DONE AFTERWARDS ALSO
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+estdata = cutoffdataIQM(estdata);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CLEAN UP AND RETURN
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if displayFlag == 3,
+    disp('Finished ...');
+end
+global compiledExpModelsIQMparamestGUI % if not empty then models are precompiled and should not be deleted
+if isempty(compiledExpModelsIQMparamestGUI),
+    deleteTempMEXmodels(workestimation);
+end
+% clear all global variables
+clear global workestimation parameters stopOptimization costfunction fh
+clear global displayFlag initialconditionsFlag scalingFlag optimizerboundsFlag
+clear global timescalingFlag 
+clear global PICmin PICmax parameterslocal 
+return
+
+
+
+
+
+
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterfitanalysis/auxiliary/cutoffdataIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterfitanalysis/auxiliary/cutoffdataIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..4bbafee5b4944d685f66dd356a52c1b8bf8c7ba4
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/02-SystemsModeling/parameterfitanalysis/auxiliary/cutoffdataIQM.m	
@@ -0,0 +1,42 @@
+function [estdata] = cutoffdataIQM(estdata)
+% cutoffdataIQM: Function used to select a cut-off threshold for the
+% estimation data collected during the fit analysis.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+if estdata.nrestimations > 0,
+    indices_out = [];
+    fhselect = figure(1);
+    cutoffthreshold = inf;
+    while 1,
+        figure(1); clf;
+        subplot(2,1,1);
+        semilogy(estdata.FVALopt,'-ok'); hold on;
+        semilogy(estdata.FVALstart,'-or');
+        legend('optimized cost','cost at start conditions');
+        title(sprintf('%d estimations from randomized starting conditions',estdata.nrestimations));
+        subplot(2,1,2);
+        selectedFVALopt = estdata.FVALopt;
+        selectedFVALopt(indices_out) = NaN;
+        plot(selectedFVALopt,'-ok'); hold on;
+        legend('optimized cost');
+        title(sprintf('Selected estimations for further analysis (press enter to continue)',estdata.nrestimations));
+        xlabel('Estimation number');
+        axis([1 estdata.nrestimations min(estdata.FVALopt) max(estdata.FVALopt)]);
+        input = ginput(1);
+        if isempty(input),
+            break;
+        end
+        cutoffthreshold = input(2)
+        indices_out = find(estdata.FVALopt > cutoffthreshold);
+    end
+    close(fhselect);
+    % apply the selection to the data
+    estdata.Popt(indices_out,:) = [];
+    estdata.PLOCALopt(indices_out,:) = [];
+    estdata.ICopt(indices_out,:) = [];
+    estdata.FVALopt(indices_out) = [];
+    estdata.FVALstart(indices_out) = [];
+    estdata.cutoffthreshold = cutoffthreshold;
+    estdata.nrestimations = size(estdata.Popt,1);
+end
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/01-GeneralDataFormat/IQMaddNLMEinfo2data.m b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/01-GeneralDataFormat/IQMaddNLMEinfo2data.m
new file mode 100644
index 0000000000000000000000000000000000000000..c82ed919110cc7578f30579a7f19e2abc1bff5a7
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/01-GeneralDataFormat/IQMaddNLMEinfo2data.m	
@@ -0,0 +1,402 @@
+function [dataOut] = IQMaddNLMEinfo2data(data,DOSENAMES,OBSNAMES,FLAG_EXPAND_REPEATED_DOSES)
+% This function adds some analysis and NLME tool relevant information into
+% the provided dataset. It requires that the provided dataset is in the
+% general clinical data format, used in IQM Tools. Several additional
+% assumptions are detailed below.
+%
+% Repeated doses, defined by entries in columns INTERVAL and NRDOSES are
+% NOT expanded by default. Expansion can be done by setting input argument 
+% FLAG_EXPAND_REPEATED_DOSES = 1 (default: 0). Note that NRDOSES codes for
+% ADDITIONAL doses, in the same way (identical) as the ADDL column in
+% NONMEM and MONOLIX. This means that NRDOSES=1 codes for 2 doses, spaced
+% by INTERVAL.
+%
+% The following columns are added (if already present they are overwritten):
+%
+%   ID:         Numeric unique subject ID 
+%   TIMEPOS:    Individual shifter TIME with 0 at first event in each
+%               subject. Needed for good old NONMEM
+%   TAD:        Time since last dose (pre-first-dose values same as TIME)
+%               This columns does not make a difference between different
+%               dose names. It contains the time since last dose,
+%               independently of the DOSENAME.
+%   DV:         Observation value (0 for dose records)
+%   MDV:        Missing data value columns (0 if observation value is
+%               defined and not IGNORE set, 1 for dose records and for
+%               unknown observation values, 1 for all records that do have
+%               IGNORE not empty) 
+%   EVID:       Event ID. 0 for observations, 1 for dosing records.
+%   CENS:       Censoring column - only populated with 0. Handled later.
+%   AMT:        Dose given at dosing instant (0 for observation records).
+%               Placebo subjects need AMT=0 at times of placebo
+%               administration
+%   ADM:        Administration column:
+%                   0 for observation records
+%
+%               If only a single entry is defined for DOSENAMES, then the
+%               following mapping is used:
+%
+%                   ROUTE                 ADM INDEX
+%                   iv                        2
+%                   subcut                    1 
+%                   oral                      1
+%                   intramuscular             1
+%                   intraarticular            1
+%                   inhaled                   1
+%                   rectal                    1
+%                   topical                   3
+%
+%               If more than one entries are defined in DOSENAMES, then 
+%               each combination of DOSENAMES and ROUTE obtains a unique
+%               ADM value, starting from 1.
+% 
+%               The results of this mapping are shown in a table. The user
+%               then can afterwards still make changes.
+%
+%   TINF:       Infusion time. (0 for observation records, 0 for "Bolus" or
+%               "first order absorption" dose records, Infusion time in
+%               TIMEUNIT unit if infusion dose record). Calculated from
+%               DURATION.
+%   RATE:       TIME column changed to start from 0 at first event
+%               Needed for good old NONMEM, Calculated from AMT and TINF.
+%
+% In the case that DOSENAMES contains more than one entry, then additional
+% TAD columns are added:
+%   TAD_"name"  "name" is the dose NAME with replaced non variable
+%               characters. If a certain dose name does not appear in a
+%               subject, the TAD_"name" values are all set to NaN. Values
+%               prior to the first specified dose are negative.
+%
+% In order to identify doses and observations, the user needs to provide
+% the function with an argument that identifies the NAME of the event that
+% specifies the DOSE events of interest. One or more DOSENAMES are allowed.
+%
+% Observation names to consider can be provided. If not, all non DOSE
+% events will be assumed to be observations. If Observation names are
+% provided, then all non observation and non dose events will be removed
+% from the data.
+%
+% [SYNTAX]
+% [dataOut] = IQMaddNLMEinfo2data(data,DOSENAMES)
+% [dataOut] = IQMaddNLMEinfo2data(data,DOSENAMES,OBSNAMES)
+% [dataOut] = IQMaddNLMEinfo2data(data,DOSENAMES,OBSNAMES,FLAG_EXPAND_REPEATED_DOSES)
+%
+% [INPUT]
+% data:             General clinical dataset format as used by IQM Tools
+% DOSENAMES:        String defining the NAME of the dose event to consider
+%                   a dose event. Or cell-array with strings of names in
+%                   the case that multiple different dose events are
+%                   present in the dataset.
+% OBSNAMES:         Optional - string or cell-array of strings. Defining
+%                   the names of all events to consider observations. If
+%                   provided all undefined events will be removed. If not
+%                   provided then all non-dose events considered
+%                   observations.   
+% FLAG_EXPAND_REPEATED_DOSES: Repeated doses, defined by entries in columns
+%                   INTERVAL and NRDOSES are NOT expanded by default.
+%                   Expansion can be done by setting input argument
+%                   FLAG_EXPAND_REPEATED_DOSES = 1 (default: 0). 
+%                   NOTE THAT NRDOSES has the same meaning as ADDL in
+%                   NONMEM and MONOLIX ... so it is the number of
+%                   ADDITIONAL doses. 
+%
+% [OUTPUT]
+% dataOut:          Dataset with added NLME information.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check input arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ischar(data),
+    data = IQMloadCSVdataset(data);
+end
+
+if ~istable(data),
+    error('Input argument is not a MATLAB table.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check if required columns present in dataset
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+data = IQMcheckGeneralDataFormatHeader(data);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle optional arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin<2,
+    error('Incorrect number of input arguments.');
+end
+
+if nargin < 3,
+	OBSNAMES = {};
+end
+
+if nargin<4,
+    FLAG_EXPAND_REPEATED_DOSES = 0;
+end
+
+% Handle cell thing
+if ischar(DOSENAMES),
+    DOSENAMES = {DOSENAMES};
+end
+if ischar(OBSNAMES),
+    OBSNAMES = {OBSNAMES};
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check if DOSENAMES and OBSNAMES present in dataset
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+NAMEs = unique(data.NAME);
+for k=1:length(DOSENAMES),
+    if isempty(strmatchIQM(DOSENAMES{k},NAMEs,'exact')),
+        error('Name of dose event "%s" not available in dataset.',DOSENAMES{k});
+    end
+end
+for k=1:length(OBSNAMES),
+    if isempty(strmatchIQM(OBSNAMES{k},NAMEs,'exact')),
+        error('Name of observation event "%s" not available in dataset.',OBSNAMES{k});
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Keep only defined dose and observation events
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(OBSNAMES),
+    dataOut = IQMselectDataEvents(data,[DOSENAMES OBSNAMES]);
+else
+    dataOut = data;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check if VALUE has NaN ... not allowed since DV needs to be calculated 
+% Might be due to VALUETXT defined ... requiring generation of VALUE
+% codes.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+dataTemp = dataOut(isnan(dataOut.VALUE),:);
+if ~isempty(dataTemp),
+    warning('Some entries in column VALUE are NaN or NA. This might be due to VALUETXT definition. Please consider first use of IQMgenerateVALUEfromVALUE_TEXT.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check VALUE and VALUETXT and maybe deliver an error
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+message = checkGeneralVALUE_VALUEtextIQM(dataOut);
+if ~isempty(message),
+    warning(message);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Initialize new columns in dataOut
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+dataOut.ID          = NaN(height(dataOut),1);
+dataOut.TIMEPOS     = NaN(height(dataOut),1);
+dataOut.TAD         = NaN(height(dataOut),1);
+dataOut.DV          = NaN(height(dataOut),1);
+dataOut.MDV         = NaN(height(dataOut),1);
+dataOut.EVID        = NaN(height(dataOut),1);
+dataOut.CENS        = zeros(height(dataOut),1);
+dataOut.AMT         = NaN(height(dataOut),1);
+dataOut.ADM         = zeros(height(dataOut),1);
+dataOut.TINF        = NaN(height(dataOut),1);
+dataOut.RATE        = NaN(height(dataOut),1);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle NRDOSES and INTERVAL - by expansion only
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if FLAG_EXPAND_REPEATED_DOSES,
+    dataOut             = expandGeneralNR_DOSES_intervalIQM(dataOut,DOSENAMES);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EVID
+% 0 for observation, 1 for dose
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+dataOut.EVID        = zeros(height(dataOut),1);
+for k=1:length(DOSENAMES),
+    ixD                 = strmatchIQM(DOSENAMES{k},dataOut.NAME,'exact');
+    dataOut.EVID(ixD)   = 1;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% MDV
+% 0 for observation without IGNORE
+% 1 for dose and all IGNORED records
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+dataOut.MDV         = dataOut.EVID;
+if ~isnumeric(dataOut.IGNORE),
+    ix_empty        = strmatchIQM('',dataOut.IGNORE,'exact');
+    ix_dot          = strmatchIQM('.',dataOut.IGNORE,'exact');
+    ix_NaN          = strmatchIQM('NaN',dataOut.IGNORE,'exact');
+    ix_do_not_ignore = [ix_empty ix_dot ix_NaN];
+    ix_IGNORE       = setdiff([1:height(dataOut)],ix_do_not_ignore);    
+    dataOut.MDV(ix_IGNORE) = 1;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% AMT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+dataOut.AMT = zeros(height(dataOut),1);
+dataOut.AMT(dataOut.EVID==1) = dataOut.VALUE(dataOut.EVID==1);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% TINF
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+dataOut.TINF = zeros(height(dataOut),1);
+dataOut.TINF(dataOut.EVID==1) = dataOut.DURATION(dataOut.EVID==1);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% RATE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+dataOut.RATE = dataOut.AMT./dataOut.TINF;
+dataOut.RATE(dataOut.EVID==0) = 0;
+dataOut.RATE(isnan(dataOut.RATE)) = 0;
+dataOut.RATE(isinf(dataOut.RATE)) = 0;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle subject individual things
+% - Create ID column (Make the IDs short ... just 1...N)
+% - Create TIMEPOS column
+% - TAD
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+allSUBJ     = unique(dataOut.USUBJID);
+dataTemp    = table();
+for kID=1:length(allSUBJ),
+    
+    % Add ID
+    datak           = dataOut(strcmp(dataOut.USUBJID,allSUBJ{kID}),:);
+    datak.ID        = kID*ones(height(datak),1);
+    
+    % Add TIMEPOS
+    datak.TIMEPOS   = datak.TIME-datak.TIME(1);
+    
+    % Add TAD
+    TIME            = datak.TIME;
+    TAD             = TIME;
+    ixDOSE          = find(datak.EVID==1);
+    for k2=1:length(ixDOSE),
+        DOSETIME    = TIME(ixDOSE(k2));
+        % Get index until which to apply change (before next dose or length
+        % of vector if last dose
+        if k2==length(ixDOSE),
+            END = length(TAD);
+        else
+            END = ixDOSE(k2+1)-1;
+        end
+        % Substract dose time from relevant range
+        TAD(ixDOSE(k2):END) = TAD(ixDOSE(k2):END) - DOSETIME;
+    end
+    datak.TAD = TAD;
+    
+    % Collect data
+    dataTemp = [dataTemp; datak];
+end
+dataOut = dataTemp;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DV - based on VALUE
+% If in original dataset only VALUETXT definitions present for an event
+% then this needs to be handled before.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+dataOut.DV = zeros(height(dataOut),1);
+dataOut.DV(dataOut.EVID==0) = dataOut.VALUE(dataOut.EVID==0);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Create ADM column
+%   ADM:        Administration column:
+%                   0 for observation records
+%
+%               If only a single entry is defined for DOSENAMES, then the
+%               following mapping is used:
+%
+%                   ROUTE                 ADM INDEX
+%                   iv                        2
+%                   subcut                    1 
+%                   oral                      1
+%                   intramuscular             1
+%                   intraarticular            1
+%                   inhaled                   1
+%                   rectal                    1
+%                   topical                   3
+%
+%               If more than one entries are defined in DOSENAMES, then 
+%               each combination of DOSENAMES and ROUTE obtains a unique
+%               ADM value, starting from 1.
+% 
+%               The results of this mapping are shown in a table. The user
+%               then can afterwards still make changes.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+if length(DOSENAMES)==1,
+    routes  = {'iv','subcut','oral','intramuscular','intrarticular','inhaled','rectal','topical'};
+    indices = [  2      1        1         1                1            1        1        3    ];
+    dataOut.ADM = zeros(height(dataOut),1);
+    ROUTE = lower(dataOut.ROUTE);
+    for k=1:length(routes),
+        ix = strmatchIQM(routes{k},ROUTE,'exact');
+        dataOut.ADM(ix) = indices(k);
+    end
+else
+    % Get information about dose and route
+    dataOut.ADM = zeros(height(dataOut),1);    
+    x = unique(dataOut(dataOut.EVID==1,{'NAME','ROUTE'}));
+    for k=1:height(x),
+        ix = find(strcmp(dataOut.NAME,x.NAME{k}) & strcmp(dataOut.ROUTE,x.ROUTE{k}));
+        dataOut.ADM(ix) = k;
+    end
+end
+
+% Show table linking ADM to NAME and ROUTE
+dataDOSE = dataOut(dataOut.EVID==1,{'ADM','NAME','ROUTE'});
+disp('The doses and routes are matched with ADM numbers as follows:');
+disp(unique(dataDOSE));
+    
+% Check that each DOSE has a ROUTE defined
+if ~isempty(strmatchIQM('',dataOut.ROUTE(dataOut.EVID==1),'exact')),
+    error('There are dose records present in the dataset without ROUTE definition. Please check!');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Handle TAD in case of several elements in DOSENAMES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if length(DOSENAMES) > 1,
+    allSUBJ     = unique(dataOut.USUBJID);
+    dataTemp    = table();
+    for kID=1:length(allSUBJ),
+        
+        % Get subject data
+        datak           = dataOut(strcmp(dataOut.USUBJID,allSUBJ{kID}),:);
+        
+        % Add TAD_"name"
+        for kDose=1:length(DOSENAMES),
+            ixDOSE          = find(strcmp(datak.NAME,DOSENAMES{kDose}));
+            if isempty(ixDOSE),
+                % If dose not present then set this TAD to NaN
+                TAD = NaN(height(datak),1);
+            else
+                TIME            = datak.TIMEPOS - datak.TIMEPOS(ixDOSE(1));
+                TAD             = TIME;
+                
+                for k2=1:length(ixDOSE),
+                    DOSETIME    = TIME(ixDOSE(k2));
+                    % Get index until which to apply change (before next dose or length
+                    % of vector if last dose
+                    if k2==length(ixDOSE),
+                        END = length(TAD);
+                    else
+                        END = ixDOSE(k2+1)-1;
+                    end
+                    % Substract dose time from relevant range
+                    TAD(ixDOSE(k2):END) = TAD(ixDOSE(k2):END) - DOSETIME;
+                end
+            end
+            TAD_name = sprintf('TAD_%s',makeVariableNameIQM(DOSENAMES{kDose}));
+            datak.(TAD_name) = TAD;
+        end
+        
+        % Collect data
+        dataTemp = [dataTemp; datak];
+    end
+    dataOut = dataTemp;
+end
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/01-GeneralDataFormat/IQMcheckGeneralDataFormat.m b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/01-GeneralDataFormat/IQMcheckGeneralDataFormat.m
new file mode 100644
index 0000000000000000000000000000000000000000..bf040aee8685286fa4caba4f8a2e4d49f37d55da
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/01-GeneralDataFormat/IQMcheckGeneralDataFormat.m	
@@ -0,0 +1,471 @@
+function [data] = IQMcheckGeneralDataFormat(data,silent)
+% The IQM Tools' workflow functions assume a general dataset format that is
+% independent of modeling activities and tools. This function here will
+% check the availability of the required columns. Additionally, it will do
+% some sanity checks of the dataset and report potential issues in the
+% Command Window as text. 
+%
+% Additionally, some check will be done on the type of columns and
+% conversions might be done. In this case the user is warned and an upated
+% dataset is provided as output.
+%
+% [SYNTAX]
+% []     = IQMcheckGeneralDataFormat(data)
+% [data] = IQMcheckGeneralDataFormat(data)
+%
+% [INPUT]
+% data:         MATLAB dataset in the general dataset format to be checked
+%               or path to dataset
+%
+% [OUTPUT]
+% If at least one of the required columns is not present an error will be
+% shown. Warnings might be shown for other detected things. No claim on
+% completeness of checks is done!
+%
+% The dataset is also returned - with potential modifications of the header names.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Specification of general dataset format:
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% COLUMN NAME                               TYPE 		DESCRIPTION
+% -------------------------------------------------------------------------
+% IXGDF                                     numeric     Column containing numeric indices for each record (1,2,3,4,5, ...) 
+%                                                       to allow for matching records in case of postprocessing the general dataset format
+% IGNORE                                    string		Reason/comment related to exclusion of the sample/observation from the analysis
+% USUBJID                                   string  	Unique subject identifier
+% COMPOUND                                  string		Name of the investigational compound 
+% STUDY                                     string		Study number
+% STUDYDES                                  string		Study description
+% PART                                      string		Part of study as defined per protocol (1 if only one part)
+% EXTENS                	                numeric 	Extension of the core study (0 if not extension, 1 if extension)   
+% CENTER                                    numeric		Center number
+% SUBJECT                                   string      Subject identifier (within a center - typically not unique across whole dataset)
+% INDNAME                                   string		Indication name   
+% TRTNAME               	                string		Name of actual treatment given
+% TRTNAMER                                  string 		Name of treatment to which individual was randomized
+% VISIT                                     numeric		Visit number
+% VISNAME                                   string		Visit name
+% BASE                                      numeric		Flag indicating assessments at baseline 
+%                                                       (=0 for non-baseline, =1 for first baseline, =2 for second baseline, etc.)
+% SCREEN                                    numeric 	Flag indicating assessments at screening
+%                                                       (=0 for non-screening, =1 for first screening, =2 for second screening, etc.)
+% DATEDAY                                   string		Start date of event ('01-JUL-2015')
+% DATETIME                                  string		Start time of event ('09:34')   
+% DURATION                                  numeric		Duration of event in same time units as TIMEUNIT
+% NT                                        numeric 	Planned time of event. Based on protocol, in the time unit defined in TIMEUNIT column
+% TIME                                      numeric 	Actual time of event relative to first administration, in the time unit defined in TIMEUNIT column
+% TIMEUNIT                                  string 		Unit of all numerical time definitions in the dataset ('hours','days','weeks','minutes')
+% TYPENAME                                  string		Unique type of event
+% NAME                                      string 		Unique name for the event 
+% VALUE                                     numeric  	Value of the event, defined by NAME. E.g., the given dose, the observed PK concentration, 
+%                                                       or the value of other readouts. The values need to be in the units, defined in the UNIT column.
+%                                                       Specific cases:
+%                                                           - For concomitant medications the dose will be given
+% 										                    - Severity levels for adverse events
+%                                                           - For BLOQ records: any value can be entered that is lower than the actual LLOQ. 
+%                                                             It is not acceptable to set this value to “NaN” or “NA” since then no discrimination 
+%                                                             can be made between “missing” and “<LLOQ”. For PK records on untransformed data “0” 
+%                                                             is suggested. On log transformed data 0 should not be used but log(LLOQ/2) would be acceptable.
+%                                                       Should not be populated if VALUETXT is populated
+% VALUETXT                                  string		Text version of value (if available and useful)
+%                                                       Character value as given in the CRF.
+%                                                       Should not be populated if VALUE is populated
+% UNIT              	                    string		Unit of the value reported in the VALUE column. For same event the same unit has to be used across the dataset.
+% ULOQ          		                    numeric		Upper limit of quantification of event defined by NAME     
+% LLOQ               	                    numeric		Lower limit of quantification of event defined by NAME     
+% ROUTE              	                    string		Route of administration (iv, subcut, intramuscular, intraarticular, oral, inhaled, topical, rectal)
+% INTERVAL                                  numeric		Interval of dosing, if single row should define multiple dosings
+% NRDOSES                                   numeric 	Number of ADDITIONAL doses given within the specified interval, 
+%                                                       NRDOSES=N codes for a total of N+1 doses with an interval as defined in the 
+%                                                       column "INTERVAL" starting at the time defined in the dose record.
+% COMMENT                                   string 		Additional information for the observation/event
+%                                                       For example:
+%                                                           - For PK: concatenation of DMPK flag to exclude or not the PK from the 
+%                                                                     DMPK analysis and comment for each sample (e.g., if the sample is 
+%                                                                     flagged as 'Excluded' than this word should be a prefix to the comment)
+%                                                           - For adverse events concatenation of the seriousness and if the AE is drug related or not
+%                                                           - For an imputation, it should mention 'Imputed'.
+%
+% The general data format might also contain the following columns, which
+% are numeric equivalents to some string columns. If not provided, then
+% these can be generated automatically by using the command
+% IQMconvertGeneral2TaskDataset.
+%
+% IND:              Numeric indication flag (unique for each entry in INDNAME)
+% STUDYN:           Numeric study flag (unique for each entry in STUDY)
+% TRT:              Numeric actual treatment flag (unique for each entry in TRTNAME)
+% TRTR:             Numeric randomized treatment flag (unique for each entry in TRTNAMER)
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle variable input arguments
+if nargin==1,
+    silent = 0;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check input arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ischar(data),
+    data = IQMloadCSVdataset(data);
+end
+if ~istable(data),
+    error('Input argument is not a MATLAB table.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Define accepted column names 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+colNames_used  = {'IXGDF',  'IGNORE','USUBJID','COMPOUND','STUDY', 'STUDYDES',         'PART',   'EXTENS',   'CENTER', 'SUBJECT','INDNAME',        'TRTNAME',        'TRTNAMER',           'VISIT',  'VISNAME',   'BASE',   'SCREEN', 'DATEDAY',  'DATETIME',  'DURATION', 'NT',          'TIME',   'TIMEUNIT', 'TYPENAME', 'NAME',  'VALUE',  'VALUETXT',  'UNIT',  'ULOQ',   'LLOQ',   'ROUTE', 'INTERVAL','NRDOSES', 'COMMENT'};
+col_TYPE       = {'numeric','string','string', 'string',  'string','string',           'string', 'numeric',  'numeric','string', 'string',         'string',         'string',             'numeric','string',    'numeric','numeric','string',   'string',    'numeric',  'numeric',     'numeric','string',   'string',   'string','numeric','string',    'string','numeric','numeric','string','numeric', 'numeric', 'string'};
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check column names against required ones
+% All need to be present - even if for analysis not all might be needed
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+VarNames = data.Properties.VariableNames;
+errorText = '';
+for k=1:length(colNames_used),
+    ix = strmatchIQM(colNames_used{k},VarNames,'exact');
+    if isempty(ix), 
+        errorText = sprintf('%sThe dataset does not contain the column ''%s''.\n',errorText,colNames_used{k});  %#ok<*SPERR>
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Show error if needed
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(errorText),
+    error(errorText);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Checking and handling if possible
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% If IGNORE is numeric, convert to cell with empty
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isnumeric(data.IGNORE),
+    data.IGNORE = cell(height(data),1);
+    data.IGNORE(1:end) = {''};
+    disp('IGNORE set to empty strings. Output argument of IQMcheckGeneralDataFormat contains updated dataset.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% If USUBJID is numeric, convert to cell with strings
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isnumeric(data.USUBJID),
+    USUBJID = cell(height(data),1);
+    for k=1:height(data),
+        USUBJID{k} = num2str(data.USUBJID(k));
+    end
+    data.USUBJID = USUBJID;
+    disp('USUBJID converted from numeric to string. Output argument of IQMcheckGeneralDataFormat contains updated dataset.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% If SUBJECT is numeric, convert to cell with strings
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isnumeric(data.SUBJECT),
+    SUBJECT = cell(height(data),1);
+    for k=1:height(data),
+        SUBJECT{k} = num2str(data.SUBJECT(k));
+    end
+    data.SUBJECT = SUBJECT;
+    disp('SUBJECT converted from numeric to string. Output argument of IQMcheckGeneralDataFormat contains updated dataset.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% If PART is numeric, convert to cell with strings
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isnumeric(data.PART),
+    PART = cell(height(data),1);
+    for k=1:height(data),
+        PART{k} = num2str(data.PART(k));
+    end
+    data.PART = PART;
+    disp('PART converted from numeric to string. Output argument of IQMcheckGeneralDataFormat contains updated dataset.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% If STUDY is numeric, convert to cell with strings
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isnumeric(data.STUDY),
+    STUDY = cell(height(data),1);
+    for k=1:height(data),
+        STUDY{k} = num2str(data.STUDY(k));
+    end
+    data.STUDY = STUDY;
+    disp('STUDY converted from numeric to string. Output argument of IQMcheckGeneralDataFormat contains updated dataset.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% If VALUETXT is numeric, convert to cell with empty
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isnumeric(data.VALUETXT),
+    data.VALUETXT = cell(height(data),1);
+    data.VALUETXT(1:end) = {''};
+    disp('VALUETXT set to empty strings. Output argument of IQMcheckGeneralDataFormat contains updated dataset.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% If COMMENT is numeric, convert to cell with empty
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isnumeric(data.COMMENT),
+    data.COMMENT = cell(height(data),1);
+    data.COMMENT(1:end) = {''};
+    disp('COMMENT set to empty strings. Output argument of IQMcheckGeneralDataFormat contains updated dataset.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Set NaN in DURATION to 0
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+data.DURATION(isnan(data.DURATION)) = 0;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Checking 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check all numeric types
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+errorText = '';
+for k=1:length(col_TYPE),
+    if strcmp(col_TYPE{k},'numeric'),
+        if ~isnumeric(data.(colNames_used{k})),
+            errorText = sprintf('%sColumn ''%s'' is not numeric - please check.\n',errorText,colNames_used{k});
+        end
+    else
+        if ~iscell(data.(colNames_used{k})),
+            errorText = sprintf('%sColumn ''%s'' is not a cell-array with strings - please check.\n',errorText,colNames_used{k});
+        end
+    end
+end
+if ~isempty(errorText),
+    disp(errorText);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check uniqueness of TIME per USUBJID/NAME
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+allID = unique(data.USUBJID);
+for k=1:length(allID),
+    datak = data(strcmp(data.USUBJID,allID{k}),:);
+    allNAME = unique(datak.NAME);
+    for k2=1:length(allNAME),
+        datakk2 = datak(strcmp(datak.NAME,allNAME{k2}),:);
+        % Get TIME
+        TIME = datakk2.TIME;
+        % Check it
+        if ~(length(TIME) == length(unique(TIME))),
+            fprintf('Subject %s has records of NAME "%s" at same TIME points.\n',allID{k},allNAME{k2});
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check monotonous non decreasing TIME and NT per USUBJID
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+allID = unique(data.USUBJID);
+for k=1:length(allID),
+    datak = data(strcmp(data.USUBJID,allID{k}),:);
+    if sum(diff(datak.TIME) < 0),
+        fprintf('TIME not monotonously increasing for USUBJID "%s".\n',allID{k});
+    end
+    if sum(diff(datak.NT) < 0),
+        fprintf('NT not monotonously increasing for USUBJID "%s".\n',allID{k});
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check uniqueness of TIMEUNIT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+timeunits = unique(data.TIMEUNIT);
+if length(timeunits) > 1,
+    fprintf('Different time units are present in the TIMEUNIT column.\n');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check time units definitions
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+allowed_units = {'hours','days','weeks','minutes'};
+if isempty(strmatchIQM(lower(data.TIMEUNIT{1}),allowed_units,'exact')),
+    fprintf('Unknown time unit "%s" used in column TIMEUNIT (allowed: "hours", "days, "weeks", "minutes")\n.',data.TIMEUNIT{1});
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check uniqueness of UNIT for each NAME
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+allNAME = unique(data.NAME);
+for k=1:length(allNAME),
+    datak = data(strcmp(data.NAME,allNAME{k}),:);
+    % Check UNIT
+    unit = unique(datak.UNIT);
+    if length(unit) ~= 1,
+        fprintf('Different entries in UNIT column for NAME "%s".\n',allNAME{k});
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check NaN in TIME
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if sum(isnan(data.TIME)) > 0,
+    fprintf('Undefined (NaN or empty) values are present in the TIME column.\n');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check NaN in NT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if sum(isnan(data.NT)) > 0,
+    fprintf('Undefined (NaN or empty) values are present in the NT column.\n');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check NaN in EXTENS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if sum(isnan(data.EXTENS)) > 0,
+    fprintf('Undefined (NaN or empty) values are present in the EXTENS column.\n');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check NaN in CENTER
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if sum(isnan(data.CENTER)) > 0,
+    fprintf('Undefined (NaN or empty) values are present in the CENTER column.\n');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check NaN in VISIT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if sum(isnan(data.VISIT)) > 0,
+    fprintf('Undefined (NaN or empty) values are present in the VISIT column - please use a numeric identifier for unscheduled visits.\n');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check NaN in BASE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if sum(isnan(data.BASE)) > 0,
+    fprintf('Undefined (NaN or empty) values are present in the BASE column.\n');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check NaN in SCREEN
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if sum(isnan(data.SCREEN)) > 0,
+    fprintf('Undefined (NaN or empty) values are present in the SCREEN column.\n');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% TRTNAME, TRTNAMER, INDNAME, PART, EXTENS, CENTER, SUBJECT same for each USUBJID
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+allID = unique(data.USUBJID);
+for k=1:length(allID),
+    datak = data(strcmp(data.USUBJID,allID{k}),:);
+    % Check TRTNAME
+    if length(unique(datak.TRTNAME)) ~= 1,
+        fprintf('Different entries for TRTNAME in subject "%s" are present.\n',allID{k});
+    end
+    % Check TRTNAMER
+    if length(unique(datak.TRTNAMER)) ~= 1,
+        fprintf('Different entries for TRTNAMER in subject "%s" are present.\n',allID{k});
+    end
+    % Check INDNAME
+    if length(unique(datak.INDNAME)) ~= 1,
+        fprintf('Different entries for INDNAME in subject "%s" are present.\n',allID{k});
+    end
+    % Check PART
+    if length(unique(datak.PART)) ~= 1,
+        fprintf('Different entries for PART in subject "%s" are present.\n',allID{k});
+    end
+    % Check EXTENS
+    if length(unique(datak.EXTENS)) ~= 1,
+        fprintf('Different entries for EXTENS in subject "%s" are present.\n',allID{k});
+    end
+    % Check CENTER
+    if length(unique(datak.CENTER)) ~= 1,
+        fprintf('Different entries for CENTER in subject "%s" are present.\n',allID{k});
+    end
+    % Check SUBJECT
+    if length(unique(datak.SUBJECT)) ~= 1,
+        fprintf('Different entries for SUBJECT in subject "%s" are present.\n',allID{k});
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check STUDYDES, COMPOUND and STUDY aligned
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+allSTUDY = unique(data.STUDY);
+for k=1:length(allSTUDY),
+    datak = data(strcmp(data.STUDY,allSTUDY{k}),:);
+    % Check STUDYDES
+    if length(unique(datak.STUDYDES)) ~= 1,
+        fprintf('Different entries for STUDYDES in study "%s" are present.\n',allSTUDY{k});
+    end
+    % Check COMPOUND
+    if length(unique(datak.COMPOUND)) ~= 1,
+        fprintf('Different entries for COMPOUND in study "%s" are present.\n',allSTUDY{k});
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check contents of route of administration for dosing events
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ROUTE = data.ROUTE;
+ROUTE(strmatchIQM('',ROUTE,'exact')) = [];
+for k=1:length(ROUTE),
+    if ~isempty(ROUTE{k}),
+        if isempty(strmatchIQM(lower(ROUTE{k}),{'iv', 'subcut', 'intramuscular', 'intraarticular', 'oral', 'inhaled', 'topical', 'rectal'},'exact')),
+            fprintf('ROUTE entry "%s" not recognized - currently used route definitions: iv, subcut, intramuscular, intraarticular, oral, inhaled, topical, rectal.\n',ROUTE{k});
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Checking specifically VALUE and VALUETXT
+% - Both VALUE and VALUETXT can be defined - but in this case the pairs
+%   have always to match for a specific event NAME
+% - It is allowed to have only VALUE or VALUETXT defined - but it has to be
+%   consistent for a specific event name.
+% - At least one of them needs to be defined.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+checkGeneralVALUE_VALUEtextIQM(data);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check IND, STUDYN, TRT, TRTR against the string
+% versions
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+check_1 = {'INDNAME','STUDY','TRTNAME','TRTNAMER'};
+check_2 = {'IND','STUDYN','TRT','TRTR'};
+for k=1:length(check_1),
+    try
+        x = unique(data(:,{check_1{k},check_2{k}}));
+        if length(unique(x.(check_1{k}))) ~= length(unique(x.(check_2{k}))),
+            fprintf('Match between "%s" and "%s" is not unique.\n',check_1{k},check_2{k})
+        end
+    catch
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Checking NRDOSES and warning if used so that user can check if it was
+% done correctly.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Check if NRDOSES somewhere different from NaN
+NRDOSES = data.NRDOSES(~isnan(data.NRDOSES));
+if ~isempty(NRDOSES),
+    fprintf('\nThe NRDOSES column has been defined in the dataset. Please consider expansion of these dose records to individual dose records when\n');
+    fprintf('generating the task dataset. The function IQMconvertGeneral2TaskDataset allows the definition of a flag to do this expansion automatically.\n');
+    fprintf('The expansion is beneficial since the VPC functions in IQM tools require definition of single dose records. Parameter estimation in NONMEM\n');
+    fprintf('and Monolix will not be affected by your choice. Also note that NRDOSES is equivalent to the ADDL column in NONMEM and MONOLIX and should\n');
+    fprintf('be defined accordingly (NRDOSES=N codes for 1 dose and N additional doses => N+1 total doses).\n');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Final message
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~silent,
+    fprintf('\nIQMcheckGeneralDataFormat: If no output (except this here) is produced then all checks are passed.\nOtherwise, please consider all outputs and handle accordingly.\n\n');
+end
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/01-GeneralDataFormat/IQMcheckGeneralDataFormatHeader.m b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/01-GeneralDataFormat/IQMcheckGeneralDataFormatHeader.m
new file mode 100644
index 0000000000000000000000000000000000000000..52cc7a572639cc3e9657a1bd9b4067ae4dafa6fb
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/01-GeneralDataFormat/IQMcheckGeneralDataFormatHeader.m	
@@ -0,0 +1,121 @@
+function [data] = IQMcheckGeneralDataFormatHeader(data)
+% The IQM Tools' workflow functions assume a general dataset format that is
+% independent of modeling activities and tools. This function here will
+% check the availability of the required columns. For a more thorough
+% check, please consider the function "IQMcheckGeneralDataFormat".
+%
+% [SYNTAX]
+% []     = IQMcheckGeneralDataFormatHeader(data)
+% [data] = IQMcheckGeneralDataFormatHeader(data)
+%
+% [INPUT]
+% data:         MATLAB dataset in the general dataset format to be checked
+%               or path to dataset
+%
+% [OUTPUT]
+% If at least one of the required columns is not present an error will be
+% shown. 
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Specification of general dataset format:
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% COLUMN NAME                               TYPE 		DESCRIPTION
+% -------------------------------------------------------------------------
+% IXGDF                                     numeric     Column containing numeric indices for each record (1,2,3,4,5, ...) 
+%                                                       to allow for matching records in case of postprocessing the general dataset format
+% IGNORE                                    string		Reason/comment related to exclusion of the sample/observation from the analysis
+% USUBJID                                   string  	Unique subject identifier
+% COMPOUND                                  string		Name of the investigational compound 
+% STUDY                                     string		Study number
+% STUDYDES                                  string		Study description
+% PART                                      string		Part of study as defined per protocol (1 if only one part)
+% EXTENS                	                numeric 	Extension of the core study (0 if not extension, 1 if extension)   
+% CENTER                                    numeric		Center number
+% SUBJECT                                   string      Subject identifier (within a center - typically not unique across whole dataset)
+% INDNAME                                   string		Indication name   
+% TRTNAME               	                string		Name of actual treatment given
+% TRTNAMER                                  string 		Name of treatment to which individual was randomized
+% VISIT                                     numeric		Visit number
+% VISNAME                                   string		Visit name
+% BASE                                      numeric		Flag indicating assessments at baseline 
+%                                                       (=0 for non-baseline, =1 for first baseline, =2 for second baseline, etc.)
+% SCREEN                                    numeric 	Flag indicating assessments at screening
+%                                                       (=0 for non-screening, =1 for first screening, =2 for second screening, etc.)
+% DATEDAY                                   string		Start date of event ('01-JUL-2015')
+% DATETIME                                  string		Start time of event ('09:34')   
+% DURATION                                  numeric		Duration of event in same time units as TIMEUNIT
+% NT                                        numeric 	Planned time of event. Based on protocol, in the time unit defined in TIMEUNIT column
+% TIME                                      numeric 	Actual time of event relative to first administration, in the time unit defined in TIMEUNIT column
+% TIMEUNIT                                  string 		Unit of all numerical time definitions in the dataset ('hours','days','weeks','minutes')
+% TYPENAME                                  string		Unique type of event
+% NAME                                      string 		Unique name for the event 
+% VALUE                                     numeric  	Value of the event, defined by NAME. E.g., the given dose, the observed PK concentration, 
+%                                                       or the value of other readouts. The values need to be in the units, defined in the UNIT column.
+%                                                       Specific cases:
+%                                                           - For concomitant medications the dose will be given
+% 										                    - Severity levels for adverse events
+%                                                           - For BLOQ records: any value can be entered that is lower than the actual LLOQ. 
+%                                                             It is not acceptable to set this value to “NaN” or “NA” since then no discrimination 
+%                                                             can be made between “missing” and “<LLOQ”. For PK records on untransformed data “0” 
+%                                                             is suggested. On log transformed data 0 should not be used but log(LLOQ/2) would be acceptable.
+%                                                       Should not be populated if VALUETXT is populated
+% VALUETXT                                  string		Text version of value (if available and useful)
+%                                                       Character value as given in the CRF.
+%                                                       Should not be populated if VALUE is populated
+% UNIT              	                    string		Unit of the value reported in the VALUE column. For same event the same unit has to be used across the dataset.
+% ULOQ          		                    numeric		Upper limit of quantification of event defined by NAME     
+% LLOQ               	                    numeric		Lower limit of quantification of event defined by NAME     
+% ROUTE              	                    string		Route of administration (iv, subcut, intramuscular, intraarticular, oral, inhaled, topical, rectal)
+% INTERVAL                                  numeric		Interval of dosing, if single row should define multiple dosings
+% NRDOSES                                   numeric 	Number of ADDITIONAL doses given within the specified interval, 
+%                                                       NRDOSES=N codes for a total of N+1 doses with an interval as defined in the 
+%                                                       column "INTERVAL" starting at the time defined in the dose record.
+% COMMENT                                   string 		Additional information for the observation/event
+%                                                       For example:
+%                                                           - For PK: concatenation of DMPK flag to exclude or not the PK from the 
+%                                                                     DMPK analysis and comment for each sample (e.g., if the sample is 
+%                                                                     flagged as 'Excluded' than this word should be a prefix to the comment)
+%                                                           - For adverse events concatenation of the seriousness and if the AE is drug related or not
+%                                                           - For an imputation, it should mention 'Imputed'.
+%
+% The general data format might also contain the following columns, which
+% are numeric equivalents to some string columns. If not provided, then
+% these can be generated automatically by using the command
+% IQMconvertGeneral2TaskDataset.
+%
+% IND:              Numeric indication flag (unique for each entry in INDNAME)
+% STUDYN:           Numeric study flag (unique for each entry in STUDY)
+% TRT:              Numeric actual treatment flag (unique for each entry in TRTNAME)
+% TRTR:             Numeric randomized treatment flag (unique for each entry in TRTNAMER)
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Check input arguments
+if ischar(data),
+    data = IQMloadCSVdataset(data);
+end
+if ~istable(data),
+    error('Input argument is not a MATLAB table.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Define accepted column names 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+colNames_used  = {'IXGDF', 'IGNORE','USUBJID','COMPOUND','STUDY', 'STUDYDES',         'PART',   'EXTENS',   'CENTER', 'SUBJECT','INDNAME',        'TRTNAME',        'TRTNAMER',           'VISIT',  'VISNAME',   'BASE',   'SCREEN', 'DATEDAY',  'DATETIME',  'DURATION', 'NT',          'TIME',   'TIMEUNIT', 'TYPENAME', 'NAME',  'VALUE',  'VALUETXT',  'UNIT',  'ULOQ',   'LLOQ',   'ROUTE', 'INTERVAL','NRDOSES', 'COMMENT'};
+
+% Check column names against required ones
+% All need to be present - even if for analysis not all might be needed
+VarNames = data.Properties.VariableNames;
+errorText = '';
+for k=1:length(colNames_used),
+    ix = strmatchIQM(colNames_used{k},VarNames,'exact');
+    if isempty(ix), 
+        errorText = sprintf('%sThe dataset does not contain the column ''%s''.\n',errorText,colNames_used{k});  %#ok<*SPERR>
+    end
+end
+
+% Show error if needed
+if ~isempty(errorText),
+    error(errorText);
+end
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/01-GeneralDataFormat/IQMcreateGeneralDataset.m b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/01-GeneralDataFormat/IQMcreateGeneralDataset.m
new file mode 100644
index 0000000000000000000000000000000000000000..3becfc9c879ccd46364d2cfd5ab35facedba57c5
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/01-GeneralDataFormat/IQMcreateGeneralDataset.m	
@@ -0,0 +1 @@
+function [dataGeneral] = IQMcreateGeneralDataset(varargin)
% The IQM Tools' workflow functions assume a general dataset format that is
% independent of modeling activities and tools. This function here allows
% to generate an empty dataset with this structure. Additionally, in this 
% help text here the format of this dataset is defined.
%
% [SYNTAX]
% [data] = IQMcreateGeneralDataset()
% [data] = IQMcreateGeneralDataset(NROWS)
%
% [INPUT]
% NRROWS:	Number of rows in the generated (empty) dataset (default: 1)
%
% [OUTPUT]
% Empty dataset in the general dataset format
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Specification of general dataset format:
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% COLUMN NAME                               TYPE 		DESCRIPTION
% -------------------------------------------------------------------------
% IXGDF                                     numeric     Column containing numeric indices for each record (1,2,3,4,5, ...) 
%                                                       to allow for matching records in case of postprocessing the general dataset format
% IGNORE                                    string		Reason/comment related to exclusion of the sample/observation from the analysis
% USUBJID                                   string  	Unique subject identifier
% COMPOUND                                  string		Name of the investigational compound 
% STUDY                                     string		Study number
% STUDYDES                                  string		Study description
% PART                                      string		Part of study as defined per protocol (1 if only one part)
% EXTENS                	                numeric 	Extension of the core study (0 if not extension, 1 if extension)   
% CENTER                                    numeric		Center number
% SUBJECT                                   string      Subject identifier (within a center - typically not unique across whole dataset)
% INDNAME                                   string		Indication name   
% TRTNAME               	                string		Name of actual treatment given
% TRTNAMER                                  string 		Name of treatment to which individual was randomized
% VISIT                                     numeric		Visit number
% VISNAME                                   string		Visit name
% BASE                                      numeric		Flag indicating assessments at baseline 
%                                                       (=0 for non-baseline, =1 for first baseline, =2 for second baseline, etc.)
% SCREEN                                    numeric 	Flag indicating assessments at screening
%                                                       (=0 for non-screening, =1 for first screening, =2 for second screening, etc.)
% DATEDAY                                   string		Start date of event ('01-JUL-2015')
% DATETIME                                  string		Start time of event ('09:34')   
% DURATION                                  numeric		Duration of event in same time units as TIMEUNIT
% NT                                        numeric 	Planned time of event. Based on protocol, in the time unit defined in TIMEUNIT column
% TIME                                      numeric 	Actual time of event relative to first administration, in the time unit defined in TIMEUNIT column
% TIMEUNIT                                  string 		Unit of all numerical time definitions in the dataset ('hours','days','weeks','minutes')
% TYPENAME                                  string		Unique type of event
% NAME                                      string 		Unique name for the event 
% VALUE                                     numeric  	Value of the event, defined by NAME. E.g., the given dose, the observed PK concentration, 
%                                                       or the value of other readouts. The values need to be in the units, defined in the UNIT column.
%                                                       Specific cases:
%                                                           - For concomitant medications the dose will be given
% 										                    - Severity levels for adverse events
%                                                           - For BLOQ records: any value can be entered that is lower than the actual LLOQ. 
%                                                             It is not acceptable to set this value to “NaN” or “NA” since then no discrimination 
%                                                             can be made between “missing” and “<LLOQ”. For PK records on untransformed data “0” 
%                                                             is suggested. On log transformed data 0 should not be used but log(LLOQ/2) would be acceptable.
%                                                       Should not be populated if VALUETXT is populated
% VALUETXT                                  string		Text version of value (if available and useful)
%                                                       Character value as given in the CRF.
%                                                       Should not be populated if VALUE is populated
% UNIT              	                    string		Unit of the value reported in the VALUE column. For same event the same unit has to be used across the dataset.
% ULOQ          		                    numeric		Upper limit of quantification of event defined by NAME     
% LLOQ               	                    numeric		Lower limit of quantification of event defined by NAME     
% ROUTE              	                    string		Route of administration (iv, subcut, intramuscular, intraarticular, oral, inhaled, topical, rectal)
% INTERVAL                                  numeric		Interval of dosing, if single row should define multiple dosings
% NRDOSES                                   numeric 	Number of ADDITIONAL doses given within the specified interval, 
%                                                       NRDOSES=N codes for a total of N+1 doses with an interval as defined in the 
%                                                       column "INTERVAL" starting at the time defined in the dose record.
% COMMENT                                   string 		Additional information for the observation/event
%                                                       For example:
%                                                           - For PK: concatenation of DMPK flag to exclude or not the PK from the 
%                                                                     DMPK analysis and comment for each sample (e.g., if the sample is 
%                                                                     flagged as 'Excluded' than this word should be a prefix to the comment)
%                                                           - For adverse events concatenation of the seriousness and if the AE is drug related or not
%                                                           - For an imputation, it should mention 'Imputed'.
%
% The general data format might also contain the following columns, which
% are numeric equivalents to some string columns. If not provided, then
% these can be generated automatically by using the command
% IQMconvertGeneral2TaskDataset.
%
% IND:              Numeric indication flag (unique for each entry in INDNAME)
% STUDYN:           Numeric study flag (unique for each entry in STUDY)
% TRT:              Numeric actual treatment flag (unique for each entry in TRTNAME)
% TRTR:             Numeric randomized treatment flag (unique for each entry in TRTNAMER)

% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>

NROWS = 1;
if nargin==1,
    NROWS = varargin{1};
end

% Create standard dataset structure
dataGeneral                        = table();
% Indices
dataGeneral.IXGDF                  = [1:NROWS]';
% General
dataGeneral.IGNORE                 = cell(NROWS,1); dataGeneral.IGNORE(1:end) = {''};
% Unique subject identifier
dataGeneral.USUBJID                = cell(NROWS,1); dataGeneral.USUBJID(1:end) = {''};
% Study information
dataGeneral.COMPOUND               = cell(NROWS,1); dataGeneral.COMPOUND(1:end) = {''};
dataGeneral.STUDY                  = cell(NROWS,1); dataGeneral.STUDY(1:end) = {''};
dataGeneral.STUDYDES               = cell(NROWS,1); dataGeneral.STUDYDES(1:end) = {''};
dataGeneral.PART                   = cell(NROWS,1); dataGeneral.PART(1:end) = {''};
dataGeneral.EXTENS                 = zeros(NROWS,1);
dataGeneral.CENTER                 = NaN(NROWS,1);
dataGeneral.SUBJECT                = cell(NROWS,1); dataGeneral.SUBJECT(1:end) = {''};
dataGeneral.INDNAME                = cell(NROWS,1); dataGeneral.INDNAME(1:end) = {''};
% Treatment group information
dataGeneral.TRTNAME                = cell(NROWS,1); dataGeneral.TRTNAME(1:end) = {''};
dataGeneral.TRTNAMER               = cell(NROWS,1); dataGeneral.TRTNAMER(1:end) = {''};
% Visit information
dataGeneral.VISIT                  = NaN(NROWS,1);
dataGeneral.VISNAME                = cell(NROWS,1); dataGeneral.VISNAME(1:end) = {''};
dataGeneral.BASE                   = zeros(NROWS,1);
dataGeneral.SCREEN                 = zeros(NROWS,1);
% Event time information
dataGeneral.DATEDAY                = cell(NROWS,1); dataGeneral.DATEDAY(1:end) = {''};
dataGeneral.DATETIME               = cell(NROWS,1); dataGeneral.DATETIME(1:end) = {''};
dataGeneral.DURATION               = zeros(NROWS,1);
dataGeneral.NT                     = NaN(NROWS,1);
dataGeneral.TIME                   = NaN(NROWS,1);
dataGeneral.TIMEUNIT              = cell(NROWS,1); dataGeneral.TIMEUNIT(1:end) = {''};
% Event value information
dataGeneral.TYPENAME              = cell(NROWS,1); dataGeneral.TYPENAME(1:end) = {''};
dataGeneral.NAME                   = cell(NROWS,1); dataGeneral.NAME(1:end) = {''};
dataGeneral.VALUE                  = NaN(NROWS,1);
dataGeneral.VALUETXT             = cell(NROWS,1); dataGeneral.VALUETXT(1:end) = {''};
dataGeneral.UNIT                   = cell(NROWS,1); dataGeneral.UNIT(1:end) = {''};
dataGeneral.ULOQ                   = NaN(NROWS,1);
dataGeneral.LLOQ                   = NaN(NROWS,1);
dataGeneral.ROUTE                  = cell(NROWS,1); dataGeneral.ROUTE(1:end) = {''};
dataGeneral.INTERVAL               = NaN(NROWS,1);
dataGeneral.NRDOSES               = NaN(NROWS,1);
% Comment
dataGeneral.COMMENT                = cell(NROWS,1); dataGeneral.COMMENT(1:end) = {''};
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/01-GeneralDataFormat/IQMdataAddTimeDependentCovariate.m b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/01-GeneralDataFormat/IQMdataAddTimeDependentCovariate.m
new file mode 100644
index 0000000000000000000000000000000000000000..ef5728e9b2c69f23bb146dad58d3596250c5264d
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/01-GeneralDataFormat/IQMdataAddTimeDependentCovariate.m	
@@ -0,0 +1,85 @@
+function [dataOut] = IQMdataAddTimeDependentCovariate(data,covariateInfo,FLAG)
+% This function adds user defined time dependent continuous and
+% categorical covariates to a dataset in the general data format.
+% 
+% Carry forward of last measured value will be used to define the values of
+% the time dependent covariate columns. Before the first definition of a
+% value NaN will be used (undefined).
+%
+% [SYNTAX]
+% [dataOut] = IQMdataAddTimeDependentCovariate(data,covariateInfo)
+% [dataOut] = IQMdataAddTimeDependentCovariate(data,covariateInfo,FLAG)
+%
+% [INPUT]
+% data:             MATLAB table in the general dataset format to get the
+%                   VALUE and VALUETXT things handled.
+% covariateInfo:    MATLAB cell-array, defining which readouts in the
+%                   general dataset should be added as time Dependent
+%                   covariates. The format for this argument is as
+%                   follows (documented by example):
+% 
+%                   covariateInfo = {
+%                        % NAME              USENAME     
+%                         'Weight'            'WT'       
+%                         'Biomarker X'       'X'        
+%                         'Efficacy marker'   'EFF'      
+%                   };
+%
+%                   The first column defines the name of the readout in
+%                   the original general dataset format. The second column
+%                   defines the name of the covariate column to be created.
+% FLAG:             =1: first non-NaN value will be used for leading NaN
+%                   values.
+%                   =0: leading NaN values will be kept (default).
+%                      
+% [OUTPUT]
+% dataOut:          Updated dataset with covariate columns added.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle variable input arguments
+if nargin<3,
+    FLAG = 0;
+end
+
+% Check data
+data = IQMcheckGeneralDataFormatHeader(data);
+
+% Check if covariateInfo is empty
+if isempty(covariateInfo),
+    dataOut = data;
+    return
+end
+
+% Check if covariateInfo names in dataset
+for k=1:size(covariateInfo,1),
+    ix = strmatchIQM(covariateInfo{k,1},unique(data.NAME),'exact');
+    if isempty(ix),
+        error('"%s" not present in dataset in column NAME.',covariateInfo{1,k});
+    end
+end
+
+% Initialize covariate columns
+dataOut = data;
+for k=1:size(covariateInfo,1),
+    dataOut.(covariateInfo{k,2}) = NaN(height(dataOut),1);
+end
+
+% Cycle through each individual and do it
+allID = unique(dataOut.USUBJID);
+dataTemp = table();
+for k=1:length(allID),
+    datak = dataOut(strcmp(dataOut.USUBJID,allID{k}),:);
+    for k2=1:size(covariateInfo,1),
+        ix = strmatchIQM(covariateInfo{k2,1},datak.NAME,'exact');
+        VALUE = datak.VALUE;
+        VALUE(setdiff(1:length(VALUE),ix)) = NaN;
+        % Carry forward vector
+        CFvector = createCarryForwardValuesIQM(VALUE,FLAG);
+        datak.(covariateInfo{k2,2}) = CFvector;
+    end
+    dataTemp = [dataTemp; datak];
+end
+dataOut = dataTemp;
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/01-GeneralDataFormat/IQMdataAddTimeIndependentCovariate.m b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/01-GeneralDataFormat/IQMdataAddTimeIndependentCovariate.m
new file mode 100644
index 0000000000000000000000000000000000000000..9c5bb3183cf55ea7a57702328d89083aa5ea9ca7
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/01-GeneralDataFormat/IQMdataAddTimeIndependentCovariate.m	
@@ -0,0 +1,79 @@
+function [dataOut] = IQMdataAddTimeIndependentCovariate(data,covariateInfo)
+% This function adds user defined time independent continuous and
+% categorical covariates to a dataset in the general data format.
+% 
+% The values for the covariates will be determined as follows:
+% - Use mean of BASEline assessments by default.
+% - If BASE not defined then use mean of SCREEN assessments.
+% - BASE and SCREEN not defined then use mean of pre-first-dose assessments.
+% - If still undefined then covariate is undefined (NaN)
+%
+% [SYNTAX]
+% [dataOut] = IQMdataAddTimeIndependentCovariate(data,covariateInfo)
+%
+% [INPUT]
+% data:             MATLAB table in the general dataset format to get the
+%                   VALUE and VALUETXT things handled.
+% covariateInfo:    MATLAB cell-array, defining which readouts in the
+%                   general dataset should be added as time independent
+%                   covariates. The format for this argument is as
+%                   follows (documented by example):
+% 
+%                       covariateInfo = {
+%                           % NAME              USENAME      
+%                            'Gender'            'SEX'       
+%                            'Age'               'AGE0'      
+%                            'Bodyweight'        'WT0'       
+%                            'Height'            'HT0'       
+%                            'BMI'               'BMI0'      
+%                       };
+%
+%                   The first columns defines the name of the readout in
+%                   the original general dataset format. The second column
+%                   defines the name of the covariate column to be created.
+%                      
+% [OUTPUT]
+% dataOut:          Updated dataset with covariate columns added.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Check data
+data = IQMcheckGeneralDataFormatHeader(data);
+
+% Check if covariateInfo is empty
+if isempty(covariateInfo),
+    dataOut = data;
+    return
+end
+
+% Determine baseline values
+baselineCOV = IQMdataGetBaselineValues(data,covariateInfo(:,1));
+
+% Initialize covariate columns
+dataOut = data;
+for k=1:size(covariateInfo,1),
+    dataOut.(covariateInfo{k,2}) = NaN(height(dataOut),1);
+end
+
+% Add covariates
+for k=1:height(baselineCOV),
+    ixID = find(strcmp(dataOut.USUBJID,baselineCOV.USUBJID{k}));
+    for k2=1:size(covariateInfo,1),
+        dataOut.(covariateInfo{k2,2})(ixID) = baselineCOV.(regexprep(covariateInfo{k2,1},'\W',''))(k);
+    end
+end
+
+% Report a table of mappings 
+dataX = IQMselectDataEvents(dataOut(:,{'NAME' 'VALUE' 'VALUETXT'}) ,covariateInfo(:,1));
+dataX(strmatchIQM('',dataX.VALUETXT,'exact'),:) = [];
+dataX = unique(dataX);
+dataX.COVARIATE_NAME = cell(height(dataX),1);
+for k=1:size(dataX,1),
+    dataX.COVARIATE_NAME(k) = covariateInfo(strmatchIQM(dataX.NAME{k},covariateInfo(:,1),'exact'),2);
+end
+disp('Generated mapping of event names, covariate values, covariate names, VALUE and VALUETXT.');
+dataX.VALUE(isnan(dataX.VALUE)) = -99999.99999;
+dataX = unique(dataX);
+dataX.VALUE(dataX.VALUE==-99999.99999) = NaN;
+disp(dataX)
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/01-GeneralDataFormat/IQMgenerateVALUEfromVALUE_TEXT.m b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/01-GeneralDataFormat/IQMgenerateVALUEfromVALUE_TEXT.m
new file mode 100644
index 0000000000000000000000000000000000000000..5870666553cdae644795adc287bd9dc40cd57fc0
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/01-GeneralDataFormat/IQMgenerateVALUEfromVALUE_TEXT.m	
@@ -0,0 +1,102 @@
+function [dataOut,changed_NAMEs] = IQMgenerateVALUEfromVALUE_TEXT(data)
+% If values of events are only defined by VALUETXT then in order to be
+% useful for modeling and augmentation of the general dataset format
+% corresponding VALUEs need to be defined and added to the dataset.
+%
+% This function will do that. Already existing VALUE/VALUETXT
+% combinations will not be changed.
+% 
+% At the end a table is shown with all VALUETXT/VALUE combinations for
+% each NAME.
+%
+% [SYNTAX]
+% [dataOut]               = IQMgenerateVALUEfromVALUE_TEXT(data)
+% [dataOut,changed_NAMEs] = IQMgenerateVALUEfromVALUE_TEXT(data)
+%
+% [INPUT]
+% data:         MATLAB table in the general dataset format to get the
+%               VALUE and VALUETXT things handled.
+%
+% [OUTPUT]
+% dataOut:          Updated dataset. Additionally in the command window the
+%                   matches between VALUEs and VALUE_TEXTs will be displayed
+%                   for each NAME 
+% changed_NAMEs:    Cell-array with the NAME entries that only had
+%                   VALUETXT defined.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check dataset to be in the general format
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+data = IQMcheckGeneralDataFormatHeader(data);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check if VALUETXT might be numeric and all NaN .. then it is empty.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isnumeric(data.VALUETXT),
+    data.VALUETXT = cell(height(data),1);
+    data.VALUETXT(1:end) = {''};
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check checkGeneralVALUE_VALUEtextIQM
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% message = checkGeneralVALUE_VALUEtextIQM(data);
+% if ~isempty(message),
+%     error(message);
+% end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Find all records with VALUETXT defined and VALUE undefined
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ix_VALUE_undefined      = find(isnan(data.VALUE));
+ix_VALUE_TEXT_defined   = setdiff([1:height(data)],strmatchIQM('',data.VALUETXT,'exact'));
+ix_handle               = intersect(ix_VALUE_undefined,ix_VALUE_TEXT_defined);
+dataHandle              = unique(data(ix_handle,{'NAME','VALUETXT'}));
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Assign numeric values to NAME/VALUETXT combinations
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+allNAMEs = unique(dataHandle.NAME);
+data_change = table();
+for k=1:length(allNAMEs),
+    datak = dataHandle(strcmp(dataHandle.NAME,allNAMEs{k}),:);
+    datak.VALUE = [1:height(datak)]';
+    data_change = [data_change; datak];
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Enter the combinations in the dataset
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+dataOut = data;
+for k=1:height(data_change),
+    dataOut.VALUE(strcmp(dataOut.NAME,data_change.NAME{k}) & strcmp(dataOut.VALUETXT,data_change.VALUETXT{k}),:) = data_change.VALUE(k);  
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Output mapping table
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+disp('Generated mappings between VALUETXT and VALUE for each NAME:');
+ix_handle       = setdiff([1:height(dataOut)],strmatchIQM('',dataOut.VALUETXT,'exact'));
+disp(unique(dataOut(ix_handle,{'NAME','VALUETXT','VALUE'})));
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% One more check checkGeneralVALUE_VALUEtextIQM
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+message = checkGeneralVALUE_VALUEtextIQM(dataOut);
+if ~isempty(message),
+    warning(message);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Report mapped NAMEs
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(data_change),
+    changed_NAMEs = unique(data_change.NAME);
+end
+
+
+
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/01-GeneralDataFormat/auxiliary/checkGeneralVALUE_VALUEtextIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/01-GeneralDataFormat/auxiliary/checkGeneralVALUE_VALUEtextIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..1a739550f1bd61325507fce55da864b5a2f6bca3
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/01-GeneralDataFormat/auxiliary/checkGeneralVALUE_VALUEtextIQM.m	
@@ -0,0 +1,85 @@
+function [message] = checkGeneralVALUE_VALUEtextIQM(data)
+% Checking specifically VALUE and VALUETXT in the general dataset format.
+% - Both VALUE and VALUETXT can be defined - but in this case the pairs
+%   have always to match for a specific event NAME
+% - It is allowed to have only VALUE or VALUETXT defined - but it has to be
+%   consistent for a specific event name.
+% - At least one of them needs to be defined.
+%
+% [SYNTAX]
+% [message] = checkGeneralVALUE_VALUEtextIQM(data)
+%
+% [INPUT]
+% data:         MATLAB dataset in the general dataset format to be checked
+%               or path to dataset
+%
+% [OUTPUT]
+% message:      Warning message returned as string. Empty ('') is no warning
+
+message = '';
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check if both VALUE and VALUETXT are populated
+% If it is the case then check if the pairs are unique for each NAME
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ix_VALUE        = find(~isnan(data.VALUE));
+ix_VALUE_TEXT   = setdiff([1:height(data)],strmatchIQM('',data.VALUETXT,'exact'));
+ix_both         = intersect(ix_VALUE,ix_VALUE_TEXT);
+dataTemp        = data(ix_both,:);
+% Check by NAME
+allNAME         = unique(dataTemp.NAME);
+for k0=1:length(allNAME),
+    dataTempk   = dataTemp(strmatchIQM(allNAME{k0},dataTemp.NAME,'exact'),:);
+    try
+        values_text = unique(dataTempk.VALUETXT);
+    catch
+        for kkk=1:height(dataTempk),
+            if isempty(dataTempk.VALUETXT{kkk}), dataTempk.VALUETXT{kkk} = ''; end
+        end
+        values_text = unique(dataTempk.VALUETXT);
+    end
+    
+    for k=1:length(values_text),
+        datak       = dataTempk(strcmp(dataTempk.VALUETXT,values_text{k}),:);
+        values      = unique(datak.VALUE);
+        if length(values) > 1,
+            message = sprintf('%sNAME "%s" has different VALUEs for same VALUETXT "%s"\n',message,allNAME{k0},values_text{k});
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check NaN in VALUE if not defined by VALUETXT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ix_VALUE        = find(isnan(data.VALUE));
+ix_VALUE_TEXT   = setdiff([1:height(data)],strmatchIQM('',data.VALUETXT,'exact'));
+ix_NaN          = setdiff(ix_VALUE,ix_VALUE_TEXT);
+if ~isempty(ix_NaN) > 0,
+    message = sprintf('%sRecords present that have neither VALUE nor VALUETXT defined.\n',message);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check if per NAME either VALUE or VALUETXT are defined
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check by NAME
+allNAME             = unique(data.NAME);
+for k0=1:length(allNAME),
+    datak           = data(strcmp(data.NAME,allNAME{k0}),:);
+    ix_VALUE        = find(~isnan(datak.VALUE));
+    ix_VALUE_TEXT   = setdiff([1:height(datak)],strmatchIQM('',datak.VALUETXT,'exact'));
+    
+    if ~isempty(ix_VALUE) && ~isempty(ix_VALUE_TEXT),
+        ix = [setdiff(ix_VALUE,ix_VALUE_TEXT) setdiff(ix_VALUE_TEXT,ix_VALUE)];
+        if ~isempty(ix),
+            message = sprintf('%sFor NAME "%s" sometimes VALUE and sometimes VALUETXT is defined without the other. Define either one only or both!\n',message,allNAME{k0});
+        end
+    end
+end
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Display message if no output argument
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(message),
+    disp(message);
+end
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/01-GeneralDataFormat/auxiliary/expandGeneralNR_DOSES_intervalIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/01-GeneralDataFormat/auxiliary/expandGeneralNR_DOSES_intervalIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..fbabc017de44674185aebf30cb6cdc4ff85fac7f
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/01-GeneralDataFormat/auxiliary/expandGeneralNR_DOSES_intervalIQM.m	
@@ -0,0 +1,58 @@
+function [dataOut] = expandGeneralNR_DOSES_intervalIQM(data,DOSENAME)
+% This function expands the doses that are defined to repeat by the columns
+% NRDOSES and INTERVAL. In order to be expanded both NRDOSES and INTERVAL
+% needs to be defined. Otherwise an error will be given.
+% VIST, VISNAME, DATEDAY/TIME and DURATION entries are kept on the
+% original dose definitions, as well as IXGDF. TIME and NT will be adjusted.
+%
+% NOTE THAT NRDOSES codes for ADDITIONAL doses ... so NRDOSES=1 codes for 2
+% doses, etc. Spacing of doses is defined by the column INTERVAL.
+%
+% [SYNTAX]
+% [dataOut] = expandGeneralNR_DOSES_intervalIQM(data,DOSENAME)
+%
+% [INPUT]
+% data:             General clinical dataset format as used by IQM Tools
+% DOSENAME:         String defining the NAME of the dose event to consider
+%                   a dose event
+%
+% [OUTPUT]
+% dataOut:  Dataset with doses expanded.
+
+% Check if expansion needed
+if isempty(find(~isnan(data.NRDOSES))),
+    % No need to expand, since nothing defined
+    dataOut = data;
+    return
+end
+
+% Expand the doses that are defined by INTERVAL and NRDOSES
+dataDOSES = data(strcmp(data.NAME,DOSENAME),:);
+dataOTHER = data(~strcmp(data.NAME,DOSENAME),:);
+% Expand doses if both INTERVAL and NRDOSES defined
+% NRDOSES+1 DOSES need to be created if expansion is done...
+dataDOSES_expanded = table();
+for k=1:height(dataDOSES),
+    datak = dataDOSES(k,:);
+    if ~isnan(datak.INTERVAL) && ~isnan(datak.NRDOSES),
+        NREXPANDED_DOSES = datak.NRDOSES + 1;
+        
+        dataexp = datak(ones(1,NREXPANDED_DOSES),:);
+        dataexp.TIME            = dataexp.TIME+[0:datak.INTERVAL:datak.INTERVAL*(NREXPANDED_DOSES-1)]';
+        dataexp.NT              = dataexp.NT+[0:datak.INTERVAL:datak.INTERVAL*(NREXPANDED_DOSES-1)]';
+        dataexp.INTERVAL(1:end) = NaN;
+        dataexp.NRDOSES(1:end)  = NaN;
+        dataDOSES_expanded      = [dataDOSES_expanded; dataexp];
+    elseif isnan(datak.INTERVAL) && isnan(datak.NRDOSES),
+        % Nothing to expand (single dose definition)
+        dataDOSES_expanded = [dataDOSES_expanded; datak];
+    else
+        error('Somewhere either INTERVAL or NRDOSES is defined but not the other column.')
+    end
+end
+
+dataOut = sortrows([dataDOSES_expanded; dataOTHER],{'STUDY','USUBJID','TIME','TYPENAME','NAME'});
+
+if height(dataOut) ~= height(data),
+    disp('Some doses have been expanded. The VIST, VISNAME, DATEDAY/TIME and DURATION entries have been kept on the original dose definitions.');
+end
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/01-GeneralDataFormat/auxiliary/mapGeneralTextColumns2ValuesIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/01-GeneralDataFormat/auxiliary/mapGeneralTextColumns2ValuesIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..70d8d97a98918b046cff587eeef92a2e97add65e
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/01-GeneralDataFormat/auxiliary/mapGeneralTextColumns2ValuesIQM.m	
@@ -0,0 +1,68 @@
+function [dataOut] = mapGeneralTextColumns2ValuesIQM(data,COLUMN_STRING,COLUMN_NUMERIC,REFERENCE_ENTRY)
+% Several columns in the general dataset format are defined as strings.
+% STUDY, IND, TRT columns and these need to be mapped to columns
+% with numeric entries that are generated automatically. Simple 1,2,3, ...
+% Mappings will be used according to alphabetic ordering.
+%
+% A reference entry for the column can be defined which will obtain 1 as
+% the numeric value.
+%
+% [SYNTAX]
+% [dataOut] = mapGeneralTextColumns2ValuesIQM(data,COLUMN_STRING,COLUMN_NUMERIC)
+% [dataOut] = mapGeneralTextColumns2ValuesIQM(data,COLUMN_STRING,COLUMN_NUMERIC,REFERENCE_ENTRY)
+%
+% [INPUT]
+% data:             General clinical dataset format as used by IQM Tools
+% COLUMN_STRING:    String with name of the column containing the strings
+% COLUMN_NUMERIC:   String with name of the numeric column to be created
+% REFERENCE_ENTRY:  String with an entry of the COLUMN_STRING to get 1 as
+%                   numeric identifier.
+%
+% [OUTPUT]
+% dataOut:  Dataset with added numeric column.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle variable input arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin == 3,
+    REFERENCE_ENTRY = '';
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check dataset to be in the general format
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+data = IQMcheckGeneralDataFormatHeader(data);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check presence of COLUMN_STRING
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(strmatchIQM(COLUMN_STRING,data.Properties.VariableNames,'exact')),
+    error('Column "%s" is not present in the dataset.',COLUMN_STRING);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get values and map to numbers
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+strings = unique(data.(COLUMN_STRING));
+numbers = [1:length(strings)]';
+if ~isempty(REFERENCE_ENTRY),
+    strings(strcmp(strings,REFERENCE_ENTRY)) = [];
+    strings = [{REFERENCE_ENTRY}; strings(:)];
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Create numeric column
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+dataOut = data;
+dataOut.(COLUMN_NUMERIC) = NaN(height(dataOut),1);
+for k=1:length(strings),
+    dataOut.(COLUMN_NUMERIC)(strcmp(dataOut.(COLUMN_STRING),strings{k})) = numbers(k);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Report results
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+disp('Generated mapping between the string and numeric column:');
+disp(unique(dataOut(:,{COLUMN_STRING,COLUMN_NUMERIC})))
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/01-GeneralDataFormat/isGeneralDatasetIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/01-GeneralDataFormat/isGeneralDatasetIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..1620536ad9a59f188f9556c8a46437003053f257
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/01-GeneralDataFormat/isGeneralDatasetIQM.m	
@@ -0,0 +1,38 @@
+function [output] = isGeneralDatasetIQM(data)
+% This function checks if the dataset "data" is in the general dataset
+% format. Essentially only the column names are checked. Additional
+% columns are allowed in the general data format but not checked.
+%
+% [SYNTAX]
+% [output] = isGeneralDatasetIQM(data)
+%
+% [INPUT]
+% data:         MATLAB dataset in the general dataset format to be checked
+%               or path to dataset
+%
+% [OUTPUT]
+% output:   1: it is in the general dataset format
+%           0: it is not
+%
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check input arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ischar(data),
+    data = IQMloadCSVdataset(data);
+end
+if ~istable(data),
+    error('Input argument is not a MATLAB table.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check header
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try
+    IQMcheckGeneralDataFormatHeader(data);
+    output = 1;
+catch
+    output = 0;
+end
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/02-ProcessData/IQMdataGetBaselineValues.m b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/02-ProcessData/IQMdataGetBaselineValues.m
new file mode 100644
index 0000000000000000000000000000000000000000..1691cb8e0b9eecf3e521663e2de05d734dc022c0
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/02-ProcessData/IQMdataGetBaselineValues.m	
@@ -0,0 +1,113 @@
+function [baselineInfo] = IQMdataGetBaselineValues(data,NAMES)
+% This function allows to calculate the baseline values of specified
+% readouts. For this to work the dataset provided has to be in the
+% general dataset format - additional columns are allowed.
+%
+% Baseline values are determined for each individual according to the
+% following rules:
+%
+%  - If baseline assessments are determined in the data using the BASE flag
+%    then use the mean value across all values defined by BASE flag
+%    different from 0.
+%  - If for a subject BASE is not different from 0 then use the same
+%    approach with the SCREEN flag.
+%  - If neither BASE nor SCREEN allows to determine the baseline values,
+%    then use the mean of pre-first-dose assessments. 
+%  - If still undefined, then set it to unknown (NaN).
+% 
+% [SYNTAX]
+% [baselineInfo] = IQMdataGetBaselineValues(data,NAMES)
+%
+% [INPUT]
+% data:             Dataset in general dataset format used in IQM Tools
+% NAMES:            String or cell-array of strings with the nareadouts to
+%                   determine the baseline for. 
+%
+% [OUTPUT]
+% baselineInfo:     MATLAB table, linking USUBJID to baselines of the
+%                   different readouts. If NAMES contain spaces
+%                   or other characters not suitable for variable names,
+%                   then these are removed.
+% NAMES_changed:    This function returns
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check if required columns present in dataset
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+data = IQMcheckGeneralDataFormatHeader(data);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle input argument
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ischar(NAMES),
+    NAMES = {NAMES};
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check names
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+allNames = unique(data.NAME);
+for k=1:length(NAMES),
+    ix = strmatchIQM(NAMES{k},allNames,'exact');
+    if isempty(ix),
+        error('Event NAME "%s" not present in the dataset.',NAMES{k});
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Initialize output
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+baselineInfo = unique(data(:,'USUBJID'));
+for k=1:length(NAMES),
+    baselineInfo.(regexprep(NAMES{k},'\W','')) = NaN(height(baselineInfo),1);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get baselines
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+allID = baselineInfo.USUBJID;
+for k=1:length(allID),
+    datak = data(strcmp(data.USUBJID,allID{k}),:);
+    for k2=1:length(NAMES),
+        datak2          = datak(strcmp(datak.NAME,NAMES{k2}),:);
+        
+        value_BASE      = NaN;
+        value_SCREEN    = NaN;
+        value_PREDOSE   = NaN;
+
+        if ~isempty(datak2),
+            % Get baseline
+            datak2_BASE = datak2(datak2.BASE~=0,:);
+            if ~isempty(datak2_BASE),
+                value_BASE = mean(datak2_BASE.VALUE);
+            end
+            
+            % Get screening
+            datak2_SCREEN = datak2(datak2.SCREEN~=0,:);
+            if ~isempty(datak2_SCREEN),
+                value_SCREEN = mean(datak2_SCREEN.VALUE);
+            end
+            
+            % Get pre-dose
+            datak2_PREDOSE = datak2(datak2.TIME<0,:);
+            if ~isempty(datak2_PREDOSE),
+                value_PREDOSE = mean(datak2_PREDOSE.VALUE);
+            end
+        end
+        
+        if ~isnan(value_BASE),
+            value = value_BASE;
+        elseif ~isnan(value_SCREEN),
+            value = value_SCREEN;
+        elseif ~isnan(value_PREDOSE),
+            value = value_PREDOSE;
+        else
+            value = NaN;
+        end        
+        
+        baselineInfo.(regexprep(NAMES{k2},'\W',''))(k) = value;
+    end
+end
+    
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/02-ProcessData/IQMdataGetValues.m b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/02-ProcessData/IQMdataGetValues.m
new file mode 100644
index 0000000000000000000000000000000000000000..6836ba36a4461085831b67f9ef74d3846f755c19
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/02-ProcessData/IQMdataGetValues.m	
@@ -0,0 +1,81 @@
+function [Values] = IQMdataGetValues(data,NAME,SELECTORNAME,SELECTORVALUE,TOLERANCE)
+% This function allows to extract values for each individual for event NAME
+% from the dataset data. The selector is used to identify the row for each
+% NAME and subject for which to return the value.
+%
+% Example: NAME = 'X', SELECTORNAME = 'NT', SELECTORVALUE = 84
+%
+%   This will return for each USUBJID the VALUE of NAME that is defined by
+%   having NT closest to 84. If more than one point fulfill this
+%   requirement, the mean is returned.
+%
+% [SYNTAX]
+% [Values] = IQMdataGetValues(data,NAME,SELECTORNAME,SELECTORVALUE)
+% [Values] = IQMdataGetValues(data,NAME,SELECTORNAME,SELECTORVALUE,TOLERANCE)
+%
+% [INPUT]
+% data:             Dataset in general dataset format used in IQM Tools
+% NAME:             String with the name of the event to consider
+% SELECTORNAME:     String with name of column to use as selector
+% SELECTORVALUE:    Numeric value to use for selection
+% TOLERANCE:        Numeric value defining the threshold for how different
+%                   the value is allowed to be from the SELECTORVALUE. Here
+%                   the relative difference from SELECTORVALUE can be
+%                   defined. If larger then removed from output. Default:
+%                   all values kept. Definition in PERCENT!
+%
+% [OUTPUT]
+% Values:           MATLAB table, linking USUBJID to corresponding value
+%                   and the closest value to SELECTORVALUE that has been
+%                   used to get the value. 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle input arguments
+if ischar(NAME),
+    NAME = {NAME};
+end
+if length(NAME) > 1,
+    error('NAME not allowed to have more than 1 entries.');
+end
+
+if nargin<5,
+    TOLERANCE = Inf;
+end
+
+% Check names
+allNames = unique(data.NAME);
+for k=1:length(NAME),
+    ix = strmatchIQM(NAME{k},allNames,'exact');
+    if isempty(ix),
+        error('"%s" not present in the dataset.',NAME{k});
+    end
+end
+
+% Convert NAME to char
+NAME = NAME{1};
+
+% Select NAME event only
+data = IQMselectDataEvents(data,NAME);
+
+% Initialize output
+Values = unique(data(:,'USUBJID'));
+Values.VALUE = NaN(height(Values),1);
+Values.SELECTORVALUEUSED = NaN(height(Values),1);
+
+% Get values
+allID = Values.USUBJID;
+for k=1:length(allID),
+    datak = subsetIQM(data,'USUBJID',allID(k));
+    
+    % Compare SELECTORNAME to SELECTORVALUE
+    [~,ix] = min(abs(datak.(SELECTORNAME)-SELECTORVALUE));
+    
+    % Get the value and the corresponding SELECTORNAME value
+    Values.VALUE(k) = mean(datak.VALUE(ix));
+    Values.SELECTORVALUEUSED(k) = mean(datak.(SELECTORNAME)(ix));
+end
+    
+% Remove if true time different by 25% of TIME
+ix = find(abs(100*(Values.SELECTORVALUEUSED-SELECTORVALUE)/SELECTORVALUE) > TOLERANCE);
+Values(ix,:) = [];
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/02-ProcessData/IQMselectDataEvents.m b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/02-ProcessData/IQMselectDataEvents.m
new file mode 100644
index 0000000000000000000000000000000000000000..4c8deba63e70afee3e776568dd50a5a9996f48a4
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/02-ProcessData/IQMselectDataEvents.m	
@@ -0,0 +1,62 @@
+function [dataOut] = IQMselectDataEvents(data,NAMEs)
+% This function allows to select events to retain in the dataset, specified
+% by their names in the NAME column. It is assumed that the provided
+% dataset has at least a NAME column.
+%
+% [SYNTAX]
+% [dataOut] = IQMselectDataEvents(data,NAMEs)
+%
+% [INPUT]
+% data:             Dataset in MATLAB table format
+% NAMEs:            String or cell-array of strings with the names of the
+%                   events in the dataset to keep. Non-named events are
+%                   removed. 
+%
+% [OUTPUT]
+% dataOut:          Dataset with only events specified by their names in
+%                   NAMEs
+%
+% [EXAMPLES]
+%                   Using this function to select certain readouts for
+%                   analysis:
+%
+%                   dataOut = IQMselectDataEvents('data/data_popPK_HS01.csv',{'Bodyweight','Dose HS01','Plasma concentration HS01'});
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+
+% Check input arguments
+if ischar(data),
+    data = IQMloadCSVdataset(data);
+end
+
+if ~istable(data),
+    error('Input argument is not a MATLAB table.');
+end
+if ischar(NAMEs),
+    NAMEs = {NAMEs};
+end
+
+% Check if NAME present in dataset
+VarNames = data.Properties.VariableNames;
+if isempty(strmatchIQM('NAME',VarNames,'exact')),
+    error('Input argument "data" does not contain a "NAME" column".');
+end
+
+% Check if desired events are present
+for k=1:length(NAMEs),
+    ix = strmatchIQM(NAMEs{k},unique(data.NAME),'exact');
+    if isempty(ix),
+        error('Readout "%s" not in the dataset.',NAMEs{k});
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Do the selection
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+availableNAMEs = unique(data.NAME);
+remove_NAMEs = setdiff(availableNAMEs,NAMEs);
+dataOut = data;
+for k=1:length(remove_NAMEs),
+    dataOut(strcmp(dataOut.NAME,remove_NAMEs{k}),:) = [];
+end
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/02-ProcessData/IQMsubsetData.m b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/02-ProcessData/IQMsubsetData.m
new file mode 100644
index 0000000000000000000000000000000000000000..8ac6a17e2e48e715d8721d24a9ad0dd6761ca288
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/02-ProcessData/IQMsubsetData.m	
@@ -0,0 +1,94 @@
+function [dataOut] = IQMsubsetData(data,NAME,VALUE,condition)
+% This function allows to subset individual subjects in clinical datasets. 
+% It is assumed that the passed dataset does have the standard column names 
+% that are used within IQM Tools for describing clinical data. At least the 
+% following columns need to be present: "USUBJID", "NAME", "VALUE".
+%
+% A provided NAME is allowed to appear only once per subject. Otherwise an
+% error will be displayed.
+%
+% [SYNTAX]
+% [dataOut] = IQMsubsetData(data,NAME,VALUE)
+% [dataOut] = IQMsubsetData(data,NAME,VALUE,condition)
+%
+% [INPUT]
+% data:             Dataset in MATLAB table format
+% NAME:             String with the name of the readout to consider for
+%                   subsetting. It needs to be present in the NAME column
+%                   of the dataset.
+% VALUE:            Numeric value to consider in the condition evaluation.
+%                   If condition is true then this subject will be included
+%                   in the dataOut dataset. If false then not. 
+% condition:        Optional string. Default: '==' and equality is checked.
+%                   Other conditions can be specified ('>','<','>=','<=' ...)
+%
+% [OUTPUT]
+% dataOut:          Dataset with subset of subjects.
+%
+% [EXAMPLES]
+%                   Using this function to select a certain sub population
+%                   from the clinical dataset:
+%
+%                   dataOut = IQMsubsetData('data/PKPD example data 2.csv','Efficacy Population',1);
+%                   dataOut = IQMsubsetData('data/data_popPK_HS01.csv','Bodyweight',60,'<=');
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check input arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ischar(data),
+    data = IQMloadCSVdataset(data);
+end
+
+if ~istable(data),
+    error('Input argument is not a MATLAB table.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle variable input arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin == 3,
+    condition = '==';
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check if NAME, VALUE and USUBJID present in dataset
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+VarNames = data.Properties.VariableNames;
+if isempty(strmatchIQM('NAME',VarNames,'exact')),
+    error('Input argument "data" does not contain a "NAME" column".');
+end
+if isempty(strmatchIQM('VALUE',VarNames,'exact')),
+    error('Input argument "data" does not contain a "VALUE" column".');
+end
+if isempty(strmatchIQM('USUBJID',VarNames,'exact')),
+    error('Input argument "data" does not contain a "USUBJID" column".');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Do the split and also check 
+% if multiple values of the provided 
+% NAME are present per subject
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+allID = unique(data.USUBJID);
+dataOut = table();
+for k=1:length(allID),
+    datak = data(strcmp(data.USUBJID,allID{k}),:);
+    % Find the defined NAME
+    namerows = datak(strcmp(datak.NAME,NAME),:);
+    % Only consider for inclusion if non-empty
+    if ~isempty(namerows),
+        if height(namerows)>1,
+            error('NAME "%s" appears multiple times in subject "%s". Not allowed when subsetting data with this function.',NAME,allID{k});
+        else
+            % Check if condition fulfilled
+            value = namerows.VALUE;
+            CONDITION = eval(sprintf('value %s %g;',condition,VALUE));
+            if CONDITION,
+                % Condition fulfilled => Include subject in dataOut
+                dataOut = [dataOut; datak];
+            end
+        end
+    end
+end
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/03-TaskDataset/IQMcheckTaskDataset.m b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/03-TaskDataset/IQMcheckTaskDataset.m
new file mode 100644
index 0000000000000000000000000000000000000000..d31ee1f5b23e2d940375d23119d77815fe1837a9
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/03-TaskDataset/IQMcheckTaskDataset.m	
@@ -0,0 +1,215 @@
+function [dataOut] = IQMcheckTaskDataset(data)
+% Based on a general dataset format used by IQM Tools a derived analysis
+% task specific dataset can be generated using the function
+% IQMconvertGeneral2TaskDataset. This augmented format contains additional
+% columns that are needed for modeling and final conversion to a modeling
+% dataset. The functions in the IQM workflows work on this augmented data
+% format. Since the augmented dataset still contains the a part with the
+% same format as the general dataset, also the general dataset check will
+% be performed.
+%
+% [SYNTAX]
+% [dataOut] = IQMcheckTaskDataset(data)
+%
+% [INPUT]
+% data:         Analysis task specific dataset, as used in IQM Tools.
+%
+% [OUTPUT]
+% dataOut:      Same dataset as input. Due to also checking the general
+%               data format, some modifications might be done - but data is
+%               not changed. This is then returned. All changes are
+%               recorded in the output in the command window.
+%
+% ADDITIONALLY to the columns in the general dataset format, the 
+% following columns are required in this task dependent dataset:
+%
+%   ID:         Numeric unique subject ID 
+%   TIMEPOS:    Individual shifter TIME with 0 at first event in each
+%               subject. Needed for good old NONMEM
+%   TAD:        Time since last dose (pre-first-dose values same as TIME
+%   DV:         Observation value (0 for dose records)
+%   MDV:        Missing data value columns (0 if observation value is
+%               defined and not IGNORE set, 1 for dose records and for
+%               unknown observation values, 1 for all records that do have
+%               IGNORE not empty) 
+%   EVID:       Event ID. 0 for observations, 1 for dosing records.
+%   CENS:       Censoring column - only populated with 0. Handled later.
+%   AMT:        Dose given at dosing instant (0 for observation records).
+%               Placebo subjects need AMT=0 at times of placebo
+%               administration
+%   ADM:        Administration column (0 for observation records, 2 for IV
+%               infusion or bolus, 1 for first order absorption into
+%               central compartment)  
+%   TINF:       Infusion time. (0 for observation records, 0 for "Bolus" or
+%               "first order absorption" dose records, Infusion time in
+%               TIMEUNIT unit if infusion dose record). Calculated from
+%               DURATION.
+%   RATE:       TIME column changed to start from 0 at first event
+%               Needed for good old NONMEM, Calculated from AMT and TINF.
+%   IND: Numeric indication flag
+%   STUDYN:     Numeric study number
+%   TRT: Numeric actual treatment group code
+%   TRTR: Numeric randomized treatment group code
+%   DOSE:       Dose as time varying covariate (carry forward used)
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check first the general dataset parts 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+data = IQMcheckGeneralDataFormat(data,1);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check column names
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+datanames = data.Properties.VariableNames;
+requiredColumns = {'ID','TIMEPOS','TAD','DURATION','DV','MDV','EVID','CENS','AMT','ADM','TINF','RATE','IND','STUDYN','TRT','TRTR'};
+errorText = '';
+for k=1:length(requiredColumns),
+    ix = strmatchIQM(requiredColumns{k},datanames,'exact');
+    if isempty(ix), 
+        errorText = sprintf('%sThe dataset does not contain the column ''%s''.\n',errorText,requiredColumns{k});  %#ok<*SPERR>
+    end    
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Show error if needed
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(errorText),
+    error(errorText);
+end
+
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Do additional checks
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check monotonous non decreasing TIMEPOS per ID
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+allID = unique(data.ID);
+for k=1:length(allID),
+    datak = data(data.ID==allID(k),:);
+    if sum(diff(datak.TIMEPOS) < 0),
+        fprintf('TIMEPOS non monotonously increasing for ID=%d.\n',allID(k));
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check NaN in TIMEPOS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if sum(isnan(data.TIMEPOS)) > 0,
+    fprintf('Undefined (NaN or empty) values are present in the TIMEPOS column..\n');
+end    
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check NaN in TAD 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if sum(isnan(data.TAD)) > 0,
+    fprintf('Undefined (NaN or empty) values are present in the TAD column.\n');
+end    
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check NaN in DV 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if sum(isnan(data.DV)) > 0,
+    fprintf('Undefined (NaN or empty) values are present in the DV column..\n');
+end   
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check NaN in ID
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if sum(isnan(data.ID)) > 0,
+    fprintf('Undefined (NaN or empty) values are present in the ID column.\n');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check NaN in AMT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if sum(isnan(data.AMT)) > 0,
+    fprintf('Undefined (NaN or empty) values are present in the AMT column. For observation records, use "0".\n');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check NaN in ADM
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if sum(isnan(data.ADM)) > 0,
+    fprintf('Undefined (NaN or empty) values are present in the ADM column. For observation records, use "0".\n');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check NaN in MDV
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if sum(isnan(data.MDV)) > 0,
+    fprintf('Undefined (NaN or empty) values are present in the MDV column.\n');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check NaN in STUDYN
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if sum(isnan(data.STUDYN)) > 0,
+    fprintf('Undefined (NaN or empty) values are present in the STUDYN column.\n');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check NaN in TRT
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if sum(isnan(data.TRT)) > 0,
+    fprintf('Undefined (NaN or empty) values are present in the TRT column.\n');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check NaN in TRTR
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if sum(isnan(data.TRTR)) > 0,
+    fprintf('Undefined (NaN or empty) values are present in the TRTR column.\n');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check that TRT is unique in each ID
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+allID = unique(data.ID);
+for k=1:length(allID),
+    datak = data(data.ID==allID(k),:);
+    % Check TRT
+    if length(unique(datak.TRT)) ~= 1,
+        fprintf('Different entries for TRT in subject "%d" are present.\n',allID(k));
+    end
+    % Check TRTR
+    if length(unique(datak.TRTR)) ~= 1,
+        fprintf('Different entries for TRTR in subject "%d" are present.\n',allID(k));
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check NaN in TINF 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if sum(isnan(data.TINF)) > 0,
+    fprintf('Undefined (NaN or empty) values are present in the TINF column. For observation records, use "0".\n');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check NaN in RATE 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if sum(isnan(data.RATE)) > 0,
+    fprintf('Undefined (NaN or empty) values are present in the RATE column. For observation records, use "0".\n');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check IND, STUDYN, TRT, TRTR against the string
+% versions
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+check_1 = {'INDNAME','STUDY','TRTNAME','TRTNAMER'};
+check_2 = {'IND','STUDYN','TRT','TRTR'};
+for k=1:length(check_1),
+    x = unique(data(:,{check_1{k},check_2{k}}));
+    if length(unique(x.(check_1{k}))) ~= length(unique(x.(check_2{k}))),
+        fprintf('Match between "%s" and "%s" is not unique.\n',check_1{k},check_2{k})
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Define the output
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+dataOut = data;
+
+fprintf('\nIQMcheckTaskDataset: If no output (except this here) is produced then all checks are passed.\nOtherwise, please consider all outputs and handle accordingly.\n\n');
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/03-TaskDataset/IQMcheckTaskDatasetHeader.m b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/03-TaskDataset/IQMcheckTaskDatasetHeader.m
new file mode 100644
index 0000000000000000000000000000000000000000..a87ea1d9bce2f5b9a80fc3a073bdd53e3a17990a
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/03-TaskDataset/IQMcheckTaskDatasetHeader.m	
@@ -0,0 +1,51 @@
+function [dataOut] = IQMcheckTaskDatasetHeader(data)
+% The IQM Tools' workflow functions use a task specific dataset that is 
+% generated from the general dataset specification. This function here will
+% check the availability of the required columns. For a more thorough
+% check, please consider the function "IQMcheckTaskDataset".
+%
+% Short column names are recognized and converted to standard ones and the
+% potentially changed dataset is returned in dataOut.
+%
+% [SYNTAX]
+% []        = IQMcheckTaskDatasetHeader(data)
+% [dataOut] = IQMcheckTaskDatasetHeader(data)
+%
+% [INPUT]
+% data:         MATLAB dataset in the general dataset format to be checked
+%               or path to dataset
+%
+% [OUTPUT]
+% dataOut:      Same dataset as input but with extended column names if
+%               short ones were used.
+%
+% If at least one of the required columns is not present an error will be
+% shown. 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Check first the general dataset parts 
+data = IQMcheckGeneralDataFormatHeader(data);
+
+% Check task specific dataset column names
+datanames = data.Properties.VariableNames;
+requiredColumns = {'ID','TIMEPOS','TAD','DURATION','DV','MDV','EVID','CENS','AMT','ADM','TINF','RATE','IND','STUDYN','TRT','TRTR'};
+errorText = '';
+for k=1:length(requiredColumns),
+    ix = strmatchIQM(requiredColumns{k},datanames,'exact');
+    if isempty(ix), 
+        errorText = sprintf('%sThe dataset does not contain the column ''%s''.\n',errorText,requiredColumns{k});  %#ok<*SPERR>
+    end    
+end
+
+% Show error if needed
+if ~isempty(errorText),
+    error(errorText);
+end
+
+dataOut = data;
+
+
+
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/03-TaskDataset/IQMconvertGeneral2TaskDataset.m b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/03-TaskDataset/IQMconvertGeneral2TaskDataset.m
new file mode 100644
index 0000000000000000000000000000000000000000..37e04cd8c360cc9b17fa5fa57c687a19b4f1a177
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/03-TaskDataset/IQMconvertGeneral2TaskDataset.m	
@@ -0,0 +1,256 @@
+function [dataOut] = IQMconvertGeneral2TaskDataset(data,DOSENAMES,OBSNAMES,covariateInfoTimeIndependent,covariateInfoTimeDependent,FLAG_EXPAND_REPEATED_DOSES)
+% This function augments a dataset in the general data format, used in IQM
+% Tools, with information needed for analysis. In this way, from the
+% general dataset an "Analysis Task Specific" dataset is generated that
+% still is tool independent. 
+%
+% Repeated doses, defined by entries in columns INTERVAL and NRDOSES are
+% NOT expanded by default. Expansion can be done by setting input argument 
+% FLAG_EXPAND_REPEATED_DOSES = 1 (default: 0).
+%
+% The following columns are added (if already present they are overwritten):
+%
+%   ID:         Numeric unique subject ID 
+%   TIMEPOS:    Individual shifter TIME with 0 at first event in each
+%               subject. Needed for good old NONMEM
+%   TAD:        Time since last dose (pre-first-dose values same as TIME)
+%               This columns does not make a difference between different
+%               dose names. It contains the time since last dose,
+%               independently of the DOSENAME.
+%   DV:         Observation value (0 for dose records)
+%   MDV:        Missing data value columns (0 if observation value is
+%               defined and not IGNORE set, 1 for dose records and for
+%               unknown observation values, 1 for all records that do have
+%               IGNORE not empty) 
+%   EVID:       Event ID. 0 for observations, 1 for dosing records.
+%   CENS:       Censoring column - only populated with 0. Handled later.
+%   AMT:        Dose given at dosing instant (0 for observation records).
+%               Placebo subjects need AMT=0 at times of placebo
+%               administration
+%   ADM:        Administration column:
+%                   0 for observation records
+%
+%               If only a single entry is defined for DOSENAMES, then the
+%               following mapping is used:
+%
+%                   ROUTE                 ADM INDEX
+%                   iv                        2
+%                   subcut                    1 
+%                   oral                      1
+%                   intramuscular             1
+%                   intraarticular            1
+%                   inhaled                   1
+%                   rectal                    1
+%                   topical                   3
+%
+%               If more than one entries are defined in DOSENAMES, then 
+%               each combination of DOSENAMES and ROUTE obtains a unique
+%               ADM value, starting from 1.
+% 
+%               The results of this mapping are shown in a table. The user
+%               then can afterwards still make changes.
+%
+%   TINF:       Infusion time. (0 for observation records, 0 for "Bolus" or
+%               "first order absorption" dose records, Infusion time in
+%               TIMEUNIT unit if infusion dose record). Calculated from
+%               DURATION.
+%   RATE:       TIME column changed to start from 0 at first event
+%               Needed for good old NONMEM, Calculated from AMT and TINF.
+%
+% In the case that DOSENAMES contains more than one entry, then additional
+% TAD columns are added:
+%   TAD_"name"  "name" is the dose NAME with replaced non variable
+%               characters. If a certain dose name does not appear in a
+%               subject, the TAD_"name" values are all set to NaN. Values
+%               prior to the first specified dose are negative.
+%
+% The following columns are generated additionally, but if already present
+% then these will not be overwritten:
+% IND:       Numeric indication flag (if already available in the data it will not be overwritten) 
+% STUDYN:           Numeric study flag (if already available in the data it will not be overwritten) 
+% TRT:              Numeric actual treatment flag (if already available in the data it will not be overwritten) 
+% TRTR:   Numeric randomized treatment flag (if already available in the data it will not be overwritten) 
+%
+% 
+% DOSE:             Time dependent DOSE amount (carry forward imputation)
+%                   This column is only present in the case that a single
+%                   element in DOSENAMES is defined.
+% DOSE"name"       where "name" is generated from the DOSENAMES entries.
+%                   These columns are only present if DOSENAMES contains
+%                   multiple entries. 
+%
+% For DOSE and DOSE"name" columns. Prior to the first dose the entries are
+% NaN, since dose undefined.
+%
+% [SYNTAX]
+% [dataOut] = IQMconvertGeneral2TaskDataset(data,DOSENAMES)
+% [dataOut] = IQMconvertGeneral2TaskDataset(data,DOSENAMES,OBSNAMES)
+% [dataOut] = IQMconvertGeneral2TaskDataset(data,DOSENAMES,OBSNAMES,covariateInfoTimeIndependent)
+% [dataOut] = IQMconvertGeneral2TaskDataset(data,DOSENAMES,OBSNAMES,covariateInfoTimeIndependent,covariateInfoTimeDependent)
+% [dataOut] = IQMconvertGeneral2TaskDataset(data,DOSENAMES,OBSNAMES,covariateInfoTimeIndependent,covariateInfoTimeDependent,FLAG_EXPAND_REPEATED_DOSES)
+%
+% [INPUT]
+% data:                 MATLAB dataset in the general dataset format
+% DOSENAMES:             String defining the NAME of the dose event to consider
+%                       a dose event
+% OBSNAMES:             Optional - string or cell-array of strings. Defining
+%                       the names of all events to consider observations. If
+%                       provided all undefined events will be removed. If not
+%                       provided or set to empty ({}), then all non-dose
+%                       events considered observations.   
+% covariateInfoTimeIndependent:    MATLAB cell-array, defining which readouts in the
+%                       general dataset should be added as time independent
+%                       covariates. The format for this argument is as
+%                       follows (documented by example):
+% 
+%                       covariateInfo = {
+%                           % NAME              USENAME      
+%                            'Gender'            'SEX'       
+%                            'Age'               'AGE0'      
+%                            'Bodyweight'        'WT0'       
+%                            'Height'            'HT0'       
+%                            'BMI'               'BMI0'      
+%                       };
+%
+%                   The first columns defines the name of the readout in
+%                   the original general dataset format. The second column
+%                   defines the name of the covariate column to be created.
+%                   The values for the covariates will be determined as follows:
+%                   - Use mean of BASEline assessments by default.
+%                   - If BASE not defined then use mean of SCREEN assessments.
+%                   - BASE and SCREEN not defined then use mean of pre-first-dose assessments.
+%                   - If still undefined then covariate is undefined (NaN)
+%
+% covariateInfoTimeDependent:    MATLAB cell-array, defining which readouts in the
+%                   general dataset should be added as time Dependent
+%                   covariates. The format for this argument is as
+%                   follows (documented by example):
+% 
+%                   covariateInfo = {
+%                        % NAME              USENAME     
+%                         'Weight'            'WT'       
+%                         'Biomarker X'       'X'        
+%                         'Efficacy marker'   'EFF'      
+%                   };
+%
+%                   The first column defines the name of the readout in
+%                   the original general dataset format. The second column
+%                   defines the name of the covariate column to be created.
+%
+%                   Carry forward of last measured value will be used to
+%                   define the values of the time dependent covariate
+%                   columns. Before the first definition of a value NaN
+%                   will be used (undefined). 
+% FLAG_EXPAND_REPEATED_DOSES: Repeated doses, defined by entries in columns
+%                   INTERVAL and NRDOSES are NOT expanded by default.
+%                   Expansion can be done by setting input argument
+%                   FLAG_EXPAND_REPEATED_DOSES = 1 (default: 0). 
+%
+% [OUTPUT]
+% dataOut:          Analysis task specific datasetm, tool independent.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle variable input arguments
+if nargin < 2,
+    error('Incorrect number of input arguments.');
+end
+if nargin < 3,
+    OBSNAMES = {};
+end
+if nargin < 4,
+    covariateInfoTimeIndependent = {};
+end
+if nargin < 5,
+    covariateInfoTimeDependent = {};
+end
+if nargin < 6,
+    FLAG_EXPAND_REPEATED_DOSES = 0;
+end
+
+% Handle input arguments
+if isempty(OBSNAMES),
+    OBSNAMES = {};
+end
+
+% Handle cell thing
+if ischar(DOSENAMES),
+    DOSENAMES = {DOSENAMES};
+end
+if ischar(OBSNAMES),
+    OBSNAMES = {OBSNAMES};
+end
+
+% Check data
+dataOut = IQMcheckGeneralDataFormatHeader(data);
+
+% Generate VALUEs from VALUE_TEXTs if still undefined
+dataOut = IQMgenerateVALUEfromVALUE_TEXT(dataOut);
+
+% Add NLME info
+dataOut = IQMaddNLMEinfo2data(dataOut,DOSENAMES,{},FLAG_EXPAND_REPEATED_DOSES);
+
+% Add numeric identifiers for standard covariates (INDNAME, STUDY, TRT...)
+% Only add these if they are not yet defined
+if isempty(strmatchIQM('IND',dataOut.Properties.VariableNames,'exact')),
+    dataOut = mapGeneralTextColumns2ValuesIQM(dataOut,'INDNAME','IND',dataOut.INDNAME{1});
+else
+    TEMP = dataOut.IND;
+    dataOut.IND = [];
+    dataOut.IND = TEMP;
+end
+
+if isempty(strmatchIQM('STUDYN',dataOut.Properties.VariableNames,'exact')),
+    dataOut = mapGeneralTextColumns2ValuesIQM(dataOut,'STUDY','STUDYN',dataOut.STUDY{1});
+else
+    TEMP = dataOut.STUDYN;
+    dataOut.STUDYN = [];
+    dataOut.STUDYN = TEMP;
+end
+
+if isempty(strmatchIQM('TRT',dataOut.Properties.VariableNames,'exact')),
+    dataOut = mapGeneralTextColumns2ValuesIQM(dataOut,'TRTNAME','TRT',dataOut.TRTNAME{1});
+else
+    TEMP = dataOut.TRT;
+    dataOut.TRT = [];
+    dataOut.TRT = TEMP;
+end
+
+if isempty(strmatchIQM('TRTR',dataOut.Properties.VariableNames,'exact')),
+    dataOut = mapGeneralTextColumns2ValuesIQM(dataOut,'TRTNAMER','TRTR',dataOut.TRTNAMER{1});
+else
+    TEMP = dataOut.TRTR;
+    dataOut.TRTR = [];
+    dataOut.TRTR = TEMP;
+end
+
+% Add DOSE as standard time dependent covariate
+FLAG_CARRY_FIRST_NON_NAN_BACKWARD = 1;
+if length(DOSENAMES)==1,
+    dataOut = IQMdataAddTimeDependentCovariate(dataOut,{DOSENAMES{1} 'DOSE'},FLAG_CARRY_FIRST_NON_NAN_BACKWARD);
+    
+    % Handle cases where a subject has not received any dose in the dataset (DOSE values are NaN) ... set these to 0, since
+    % assumption that placebo was given.
+    dataOut.DOSE(isnan(dataOut.DOSE)) = 0;
+else
+    for k=1:length(DOSENAMES),
+        colname_dose = sprintf('DOSE%s',makeVariableNameIQM(DOSENAMES{k}));
+        dataOut = IQMdataAddTimeDependentCovariate(dataOut,{DOSENAMES{k} colname_dose},FLAG_CARRY_FIRST_NON_NAN_BACKWARD);
+        
+        % Handle cases where a subject has not received any dose in the dataset (DOSE values are NaN) ... set these to 0, since
+        % assumption that placebo was given.
+        dataOut.(colname_dose)(isnan(dataOut.(colname_dose))) = 0;
+    end
+end
+
+% Add time independent user defined covariates
+dataOut = IQMdataAddTimeIndependentCovariate(dataOut,covariateInfoTimeIndependent);
+
+% Add time dependent user defined covariates
+dataOut = IQMdataAddTimeDependentCovariate(dataOut,covariateInfoTimeDependent);
+          
+% Select events by name to keep in the dataset
+if ~isempty(OBSNAMES),
+    EVENTNAMEs = [DOSENAMES OBSNAMES];
+    dataOut = IQMselectDataEvents(dataOut,EVENTNAMEs);
+end
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/03-TaskDataset/isTaskDatasetIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/03-TaskDataset/isTaskDatasetIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..bc078331b288072a9cdee5ab0521819128ddb853
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/03-TaskDataset/isTaskDatasetIQM.m	
@@ -0,0 +1,38 @@
+function [output] = isTaskDatasetIQM(data)
+% This function checks if the dataset "data" is in the general task dataset
+% format. Essentially only the column names are checked. Additional
+% columns are allowed in the general data format but not checked.
+%
+% [SYNTAX]
+% [output] = isTaskDatasetIQM(data)
+%
+% [INPUT]
+% data:         MATLAB dataset in the general dataset format to be checked
+%               or path to dataset
+%
+% [OUTPUT]
+% output:   1: it is in the general dataset format
+%           0: it is not
+%
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check input arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ischar(data),
+    data = IQMloadCSVdataset(data);
+end
+if ~istable(data),
+    error('Input argument is not a MATLAB table.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check header
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try
+    IQMcheckTaskDatasetHeader(data);
+    output = 1;
+catch
+    output = 0;
+end
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMdataInfoValues.m b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMdataInfoValues.m
new file mode 100644
index 0000000000000000000000000000000000000000..cb904c8c531e65faca5adbb9e72e5256799536e0
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMdataInfoValues.m	
@@ -0,0 +1,65 @@
+function [eventInfo,specialInfo] = IQMdataInfoValues(data)
+% Function to get information about the link between VALUETXT and VALUE
+% for the events that are defined by VALUETXT. Additionally, information
+% for "special" columns that define numeric values for string columns is
+% shown. These "special" columns are:
+% 'INDNAME','STUDY','TRTNAME','TRTNAMER' 
+%
+% [SYNTAX]
+% [eventInfo,specialInfo] = IQMdataInfoValues(data)
+%
+% [INPUT]
+% data:     Dataset in task specific standard data format or in
+%           general data format
+%
+% [OUTPUT]
+% The relations between the text version and the numeric versions is shown
+% as tables in the command window. Additionally, these tables are returned
+% as output. eventInfo is the table relating VALUETXT to VALUE.
+% specialInfo is a cell-array with 0 or more tables relating the special
+% string column entries to their numeric values.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Find elements with VALUETXT defined
+data = IQMcheckGeneralDataFormatHeader(data);
+
+% Find elements with VALUETXT defined
+eventInfo = data(findNonEmptyCellsIQM(data,'VALUETXT'),{'TYPENAME','VALUETXT','VALUE'});
+eventInfo.VALUE(isnan(eventInfo.VALUE)) = -999999.999999;
+eventInfo = unique(eventInfo);
+eventInfo.VALUE(eventInfo.VALUE==-999999.999999) = NaN;
+
+% Check if special columns present 
+% IND:       Numeric indication flag (unique for each entry in INDNAME)
+% STUDYN:           Numeric study flag (unique for each entry in STUDY)
+% TRT:              Numeric actual treatment flag (unique for each entry in TRTNAME)
+% TRTR:   Numeric randomized treatment flag (unique for each entry in TRTNAMER)
+cols = {'IND','STUDYN','TRT','TRTR'};
+colsText = {'INDNAME','STUDY','TRTNAME','TRTNAMER'};
+specialInfo = {};
+for k=1:length(cols),
+    dataX = table();
+    try
+        dataX.(cols{k}) = data.(cols{k});
+        dataX.(colsText{k}) = data.(colsText{k});
+        specialInfo{end+1} = unique(dataX(:,end:-1:1));
+    catch
+        % column not present
+    end
+end
+
+disp('==================================================');
+disp('Match between VALUETXT and VALUE in the dataset:');
+disp('==================================================');
+disp(eventInfo)
+
+
+disp('==================================================');
+disp('Match between INDNAME, STUDY, TRTNAME');
+disp('and TRTNAMER and their respective');
+disp('numerical equivalents (if present in the dataset):');
+disp('==================================================');
+for k=1:length(specialInfo),
+    disp(specialInfo{k});
+end
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexploreBLLOQdata.m b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexploreBLLOQdata.m
new file mode 100644
index 0000000000000000000000000000000000000000..a14041c19a942dcf8cb1899f65d10a8b73218912
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexploreBLLOQdata.m	
@@ -0,0 +1,78 @@
+function [textCell] = IQMexploreBLLOQdata(data,filename)
+% Displays a table with information about the number of BLOQ data per NAME.
+% Additionally shows the total number of observations.
+% Only MDV=0 observations are considered.
+% Requires the task specific dataset format.
+%
+% [SYNTAX]
+% [textCell] = IQMexploreBLLOQdata(data)
+% [textCell] = IQMexploreBLLOQdata(data,filename)
+%
+% [INPUT]
+% data:         Dataset in task specific dataset format  
+% filename:     String with filename / path for export of information in
+%               same format as displayed in command window. If not defined,
+%               then no file will be created.
+%
+% [OUTPUT]
+% textCell:     Cell table for reporting purposes if to be done outside
+%               this function.
+% Table output in MATLAB window and in file if desired. 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Check dataset to be at least in the general dataset format
+data = IQMcheckTaskDatasetHeader(data);
+
+% Remove MDV==1 observations
+data(data.MDV==1 & data.EVID==0,:) = [];
+
+% Handle variable input arguments
+if nargin<2,
+    filename = '';
+end
+
+% Find all NAMEs which have LLOQ information (only observations considered)
+NAMES_BLLOQ_present = unique(data.NAME(~isnan(data.LLOQ) & data.EVID==0));
+
+% Find all records that are BLOQ for all names that have LLOQ information
+NR_BLLOQ_NAME = [];
+NR_TOTAL_NAME = [];
+for k=1:length(NAMES_BLLOQ_present),
+    % Get NAME data
+    dataNAME = subsetIQM(data,'NAME',NAMES_BLLOQ_present(k));
+    % Get total number of samples (MDV==0 and MDV==1) in NAME
+    NR_TOTAL_NAME(k) = height(dataNAME);
+    NR_BLLOQ_NAME(k) = height(dataNAME(dataNAME.VALUE<dataNAME.LLOQ,:));
+end
+
+% Prepare table cell with information about LLOQ value numbers
+textCell = {};
+for k=1:length(NAMES_BLLOQ_present),
+    textCell{end+1,1}   = '<TT>';
+    textCell{end,2}     = sprintf('Observations (MDV=0 & EVID=0) in "%s"',NAMES_BLLOQ_present{k});
+    textCell{end+1,1}   = '<TH>';
+    textCell{end,2}     = 'Total';
+    textCell{end,3}     = 'VALUE<LLOQ';
+    textCell{end+1,1}   = '<TR>';
+    textCell{end,2}   = NR_TOTAL_NAME(k);
+    textCell{end,3}     = NR_BLLOQ_NAME(k);
+end
+
+% Create table if no BLLOQ data present
+if isempty(textCell),
+    textCell{end+1,1}   = '<TR>';
+    textCell{end,2}     = 'No BLLOQ data present in dataset (might be due to lack of LLOQ information).';
+end
+
+% Convert to text and display text 
+textDisplay = IQMconvertCellTable2ReportTable(textCell,'text');     
+disp(textDisplay);
+
+% Convert to report text and export to file if filename defined
+IQMconvertCellTable2ReportTable(textCell,'report',filename);     
+
+
+
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexploreCovariateCorrelations.m b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexploreCovariateCorrelations.m
new file mode 100644
index 0000000000000000000000000000000000000000..69dc7ae7c3451838290d624c54cb2af04288abad
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexploreCovariateCorrelations.m	
@@ -0,0 +1,205 @@
+function [] = IQMexploreCovariateCorrelations(data,varargin)
+% Graphical exploration of covariates. Plots correlations between
+% continuous covariates, between continuous and categorical covariates, and
+% between categorical covariates.
+%
+% Requires either the general
+% dataset format or the task specific augmented dataset format with
+% covariate columns. In case of the general dataset format the baselines
+% are used as covariates.
+%
+% [SYNTAX]
+% Function calls to work on general dataset format (covariates need to be
+% stored in rows as events:
+% [] = IQMexploreCovariateCorrelations(data,COVARIATE_NAMES)
+% [] = IQMexploreCovariateCorrelations(data,COVARIATE_NAMES,filename)
+%
+% Function calls to work on augmented, task specific dataset format
+% (covariates need to be stored columns):
+% [] = IQMexploreCovariateCorrelations(data,covNames,catNames)
+% [] = IQMexploreCovariateCorrelations(data,covNames,catNames,filename)
+%
+% [INPUT]
+% data:         Dataset in the task specific general dataset format
+% COVARIATE_NAMES:  Cell-array of strings with names of readouts
+%                   in the NAME column to use as covariates.
+%                   Categorical covariates are identified by also having a
+%                   VALUETXT entry. If no VALUETXT entry then if having
+%                   less or equal to 10 distinct values.
+% covNames:     Cell-array with the names of the continuous covariates, as
+%               defined in the dataset
+% catNames:     Cell-array with the names of the categorical covariates, as
+%               defined in the dataset
+% filename:     Filename with path for storing the resulting PDF. If not
+%               provided then no PDF is generated.
+%
+% [OUTPUT]
+% PDF at filename location.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle variable input arguments and get type
+if nargin==2,
+    % IQMexploreCovariateCorrelations(data,COVARIATE_NAMES)
+    COVARIATE_NAMES = varargin{1};
+    filename = '';
+    FLAG_GENERAL = 1;
+elseif nargin==3,
+    if ischar(varargin{2}),
+        % IQMexploreCovariateCorrelations(data,COVARIATE_NAMES,filename)
+        COVARIATE_NAMES = varargin{1};
+        filename = varargin{2};
+        FLAG_GENERAL = 1;
+        if ischar(COVARIATE_NAMES),
+            COVARIATE_NAMES = {COVARIATE_NAMES};
+        end        
+    else
+        % IQMexploreCovariateCorrelations(data,covNames,catNames)
+        covNames = varargin{1};
+        catNames = varargin{2};
+        filename = '';
+        FLAG_GENERAL = 0;
+        % Handle cell
+        if ischar(covNames),
+            covNames = {covNames};
+        end
+        if ischar(catNames),
+            catNames = {catNames};
+        end
+    end
+elseif nargin==4,
+    % IQMexploreCovariateCorrelations(data,covNames,catNames,filename)
+        covNames = varargin{1};
+        catNames = varargin{2};
+        filename = varargin{3};
+        FLAG_GENERAL = 0;
+        % Handle cell
+        if ischar(covNames),
+            covNames = {covNames};
+        end
+        if ischar(catNames),
+            catNames = {catNames};
+        end
+else
+    error('Incorrect number of input arguments.');
+end
+
+% Handle different types
+if FLAG_GENERAL == 0,
+    % Check task specific dataset format 
+    data = IQMcheckTaskDatasetHeader(data);
+    
+    % Check cov and cat names
+    for k=1:length(covNames),
+        if isempty(strmatchIQM(covNames{k},data.Properties.VariableNames,'exact')),
+            error('Covariate column "%s" not present in the dataset.',covNames{k});
+        end
+    end
+    for k=1:length(catNames),
+        if isempty(strmatchIQM(catNames{k},data.Properties.VariableNames,'exact')),
+            error('Covariate column "%s" not present in the dataset.',catNames{k});
+        end
+    end
+    % Extract the cov and cat data
+    % Get first rows only
+    dataPlot = table();
+    allID = unique(data.USUBJID);
+    for k=1:length(allID),
+        datak = subsetIQM(data,'USUBJID',allID(k));
+        dataPlot = [dataPlot; datak(1,:)];
+    end
+    dataPlotcovcont = table();
+    for k=1:length(covNames),
+        dataPlotcovcont.(covNames{k}) = dataPlot.(covNames{k});
+    end    
+    dataPlotcovcontcat = dataPlotcovcont;
+    for k=1:length(catNames),
+        dataPlotcovcontcat.(catNames{k}) = dataPlot.(catNames{k});
+    end
+else
+    % Check general dataset format 
+    data = IQMcheckGeneralDataFormatHeader(data);
+
+    % Need to update VALUE from VALUETXT information if not available
+    [data,changed_NAMEs] = IQMgenerateVALUEfromVALUE_TEXT(data);
+    
+    % Extract the baseline info from the dataset for COVARIATE_NAMES
+    baseline_Info  = IQMdataGetBaselineValues(data,COVARIATE_NAMES);
+    
+    % Remove USUBJID
+    baseline_Info.USUBJID = [];
+    
+    % Define catNames and covNames
+    catNames = changed_NAMEs;
+    covNamesCheck = setdiff(baseline_Info.Properties.VariableNames,catNames);
+    
+    % Check number of elements in covNames and use <=10 as categorical
+    covNames = {};
+    for k=1:length(covNamesCheck),
+        x = unique(baseline_Info.(covNamesCheck{k}));
+        x(isnan(x)) = [];
+        if length(x)<=10,
+            % Assume catName
+            catNames{end+1} = covNamesCheck{k};
+        else
+            covNames{end+1} = covNamesCheck{k};
+        end
+    end
+    
+    % Get data for plotting
+    dataPlotcovcontcat = baseline_Info;
+    dataPlotcovcont = table();
+    for k=1:length(covNames),
+        dataPlotcovcont.(covNames{k}) = baseline_Info.(covNames{k});
+    end     
+end
+
+% Prepare output folder and file
+IQMstartNewPrintFigure(filename);
+
+% Correlation of continuous covariates
+if ~isempty(covNames),
+    figure; clf;
+    IQMplotpairwiseCorr(dataPlotcovcont);
+    IQMprintFigure(gcf,filename);
+    if ~isempty(filename),
+        close(gcf);
+    end
+end
+
+% Correlation of continuous and categorical covariates
+if ~isempty(catNames) && ~isempty(covNames),
+    figure; clf;    
+    IQMplotCovarianceCat(dataPlotcovcontcat,covNames,catNames);
+    IQMprintFigure(gcf,filename);
+    if ~isempty(filename),
+        close(gcf);
+    end
+end
+
+% Correlation of categorical covariates
+if ~isempty(catNames),
+    figure; clf;    
+    IQMplotCatCat(dataPlotcovcontcat,catNames);
+    IQMprintFigure(gcf,filename);
+    if ~isempty(filename),
+        close(gcf);
+    end
+end
+
+% Histograms of continuous covariates
+for k=1:length(covNames),
+    figure; clf;    
+    hist(dataPlotcovcont.(covNames{k}));
+    xlabel(covNames{k},'FontSize',18,'Interpreter','none')
+    ylabel('Numbers','FontSize',18)
+    grid on;
+    IQMprintFigure(gcf,filename);
+    
+    if ~isempty(filename),
+        close(gcf);
+    end
+end
+
+IQMconvert2pdf(filename);
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexploreDataContents.m b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexploreDataContents.m
new file mode 100644
index 0000000000000000000000000000000000000000..0220ab2b0575d0784dd7c47c3a351f5c2c112e16
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexploreDataContents.m	
@@ -0,0 +1,208 @@
+function [tableInformation] = IQMexploreDataContents(data,DOSENAMES,OBSNAMES,filename)
+% This function produces a table, showing the study numbers, the study
+% description, the contained treatment groups in the studies, the number of
+% patients per treatment group, number of active doses (min/median/max),
+% number of observations, nominal times of observations.
+%
+% [SYNTAX]
+% [tableInformation] = IQMexploreDataContents(data)
+% [tableInformation] = IQMexploreDataContents(data,DOSENAMES)
+% [tableInformation] = IQMexploreDataContents(data,DOSENAMES,OBSNAMES)
+% [tableInformation] = IQMexploreDataContents(data,DOSENAMES,OBSNAMES,filename)
+%
+% [INPUT]
+% data:         MATLAB PKPD dataset in general dataset format
+% DOSENAMES:    String with the NAME of the dosing event to consider. Or
+%               cell-array of strings with several NAMEs of different
+%               dosing events to consider.  
+% OBSNAMES:     String with the NAME of the observation event to consider.
+%               Or cell-array of strings with several NAMEs of different
+%               observation events to consider.  
+% filename:     String with filename / path for export of information in
+%               same format as displayed in command window. If not defined,
+%               then no file will be created.
+%
+% [OUTPUT]
+% tableInformation: Table information in cell structure
+% Table output in MATLAB window and in file if desired.
+% For each combination of elements in DOSENAMES and OBSNAMES a single table
+% is produced.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Check data
+data = IQMcheckGeneralDataFormatHeader(data);
+
+% Remove MDV=1 observation data if information is present in the dataset
+try
+    data(data.EVID==0 & data.MDV==1,:) = [];
+end
+
+% Variable input arguments
+if nargin==1,
+    DOSENAMES = {''};
+    OBSNAMES  = {''};
+    filename  = '';
+end
+if nargin==2,
+    OBSNAMES  = {''};
+    filename  = '';
+end
+if nargin==3,
+    filename  = '';
+end
+
+% Check OBSNAME
+if ischar(OBSNAMES),
+    OBSNAMES = {OBSNAMES};
+end
+
+% Check DOSENAME
+if ischar(DOSENAMES),
+    DOSENAMES = {DOSENAMES};
+end
+
+% Create table
+tableInformation = {};
+for kDose=1:length(DOSENAMES),
+    for kObs=1:length(OBSNAMES),
+        tableInformation = [tableInformation; getTable_DOSE_OBS(data,DOSENAMES{kDose},OBSNAMES{kObs})];
+    end
+end
+
+% Convert to text and display text
+textDisplay = IQMconvertCellTable2ReportTable(tableInformation,'text');
+disp(textDisplay);
+
+% Convert to report and export to file if filename defined
+IQMconvertCellTable2ReportTable(tableInformation,'report',filename);
+
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Auxiliary function generating the table for one DOSENAME and one OBSNAME
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [tableInformation] = getTable_DOSE_OBS(data,DOSENAME,OBSNAME)
+% Initialize table
+tableInformation            = cell(1,8);
+tableInformation(1,1:2)     = {'<TT>' sprintf('Contents of dataset for DOSE: "%s" and OBSERVATION: "%s"',DOSENAME,OBSNAME)};
+tableInformation(end+1,:)   = {'<TH>' 'Study','Study Description','Treatment Groups','N subjects',['N Active Doses (' DOSENAME ')'],['N Observations (' OBSNAME ')'],sprintf('Nominal Time Observations [%s]',data.TIMEUNIT{1})};
+
+% Cycle through STUDY
+allSTUDY = unique(data.STUDY);
+row = 3;
+for kSTUDY=1:length(allSTUDY),
+    dataSTUDY = subsetIQM(data,'STUDY',allSTUDY(kSTUDY));
+    
+    % Study info
+    tableInformation{row,1}   = '<TR>';
+    tableInformation{row,2}   = dataSTUDY.STUDY{1};
+    tableInformation{row,3}   = dataSTUDY.STUDYDES{1};
+    % Indication info - add to study description
+    allIND = unique(dataSTUDY.INDNAME);
+    indText = '';
+    for k=1:length(allIND),
+        indText = sprintf('%s%s,',indText,allIND{k});
+    end
+    tableInformation{row,3} = sprintf('%s\n(%s)',tableInformation{end,3},indText(1:end-1));
+    
+    % Cycle trough actual treatment groups
+    allTRT = unique(dataSTUDY.TRTNAME);
+    for kTRT=1:length(allTRT),
+        dataTRT = subsetIQM(dataSTUDY,'TRTNAME',allTRT(kTRT));
+        
+        % TRT group info
+        tableInformation{row,1} = '<TR>';
+        tableInformation{row,4} = allTRT{kTRT};
+        tableInformation{row,5} = length(unique(dataTRT.USUBJID));
+        
+        if ~isempty(OBSNAME) || ~isempty(DOSENAME),
+            % Cycle through individuals and get number of doses and number
+            % of observations per subject (min, mean, max). for now do not
+            % care about route ...
+            allID           = unique(dataTRT.USUBJID);
+            
+            dataDOSE        = subsetIQM(dataTRT,'NAME',DOSENAME);
+            
+            if isempty(dataDOSE),
+                nrDosesperID    = zeros(1,length(allID));
+            else
+                
+                ROUTES          = unique(dataDOSE.ROUTE);
+                
+                nrDosesperID    = zeros(length(ROUTES),length(allID));
+                
+                for kID=1:length(allID),
+                    dataID      = subsetIQM(dataTRT,'USUBJID',allID(kID));
+                    
+                    % Number of doses
+                    if ~isempty(DOSENAME),
+                        dataDOSE        = subsetIQM(dataID,'NAME',DOSENAME);
+                        if ~isempty(dataDOSE),
+                            dataDOSE(dataDOSE.VALUE==0,:) = [];
+                            if ~isempty(dataDOSE),
+                                for kR=1:length(ROUTES),
+                                    nrDosesperID(kR,kID) = length(strmatchIQM(ROUTES{kR},dataDOSE.ROUTE,'exact'));
+                                end
+                            end
+                        end
+                    end
+                end
+            end
+            
+            % Number observation information
+            if ~isempty(OBSNAME),
+                nrObsperID      = zeros(1,length(allID));
+                
+                for kID=1:length(allID),
+                    dataID      = subsetIQM(dataTRT,'USUBJID',allID(kID));
+                    % Number of observations
+                    if ~isempty(OBSNAME),
+                        dataOBS         = subsetIQM(dataID,'NAME',OBSNAME);
+                        nrObsperID(kID) = height(dataOBS);
+                    end
+                end
+                
+                minObsID = min(nrObsperID);
+                maxObsID = max(nrObsperID);
+                medianObsID = median(nrObsperID);
+                textObsNr = sprintf('min/median/max: %d/%g/%d',minObsID,medianObsID,maxObsID);
+                tableInformation{row,7} = textObsNr;
+                
+                % Nominal time observations
+                NT = unique(dataTRT.NT(ixdataIQM(dataTRT,'NAME',OBSNAME)));
+                if ~isempty(NT),
+                    NTtext = sprintf('%1.4g,',NT);
+                else
+                    NTtext = ',';
+                end
+                tableInformation{row,8} = NTtext(1:end-1);
+                
+                if isempty(DOSENAME),
+                    row = row+1;
+                end
+            end
+            
+            % Number of doses per route
+            if ~isempty(DOSENAME) && ~isempty(dataDOSE),
+                textDoseNr = '';
+                for kR=1:length(ROUTES),
+                    textDoseNr = sprintf('%s%s (min/median/max: %d/%g/%d)\n',textDoseNr,ROUTES{kR},min(nrDosesperID(kR,:)),median(nrDosesperID(kR,:)),max(nrDosesperID(kR,:)));
+                end
+                tableInformation{row,6} = textDoseNr(1:end-1);
+                row = row+1;
+            elseif ~isempty(DOSENAME) && isempty(dataDOSE),
+                tableInformation{row,6} = 'No active doses';
+                row = row+1;
+            end
+        else
+            row = row + 1;
+        end
+    end
+    if kSTUDY<length(allSTUDY),
+        tableInformation{row,1} = '<HR>';
+        row = row+1;
+    end
+end
+return
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexploreDataMedian.m b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexploreDataMedian.m
new file mode 100644
index 0000000000000000000000000000000000000000..6590a9f5f9f156221319e11075fa898ccc60bbb4
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexploreDataMedian.m	
@@ -0,0 +1,289 @@
+function [] = IQMexploreDataMedian(data,NAMES,TYPE,GROUP,options)
+% This function allows to analyze the general dataset format (or some
+% augmented form of it) with respect to the medians of selected readouts.
+% For continuous data the medians are displayed (absolute or relative
+% change from baseline) and for categorical data the responder rates are
+% displayd.
+%
+% [SYNTAX]
+% [] = IQMexploreDataMedian(data,NAMES,TYPE)
+% [] = IQMexploreDataMedian(data,NAMES,TYPE,GROUP)
+% [] = IQMexploreDataMedian(data,NAMES,TYPE,GROUP,options)
+%
+% [INPUT]
+% data:     Dataset in task specific standard data format or in
+%           general data format
+% NAMES:    String or cell-array with names of readouts in the dataset
+%           (NAME column) to plot
+% TYPE:     'categorical' or 'continuous'. For continuous readouts the
+%           medians are plotted. For categorical readouts the responder
+%           rates are plotted. All readouts in NAMES will be treated as the
+%           same TYPE.
+% GROUP:    Name of the column to use as grouping variable. By default
+%           "TRTNAME" is used.
+% options:  Matlab structure with additional optional information:
+%   options.singleplot:     1: plot all groups in one figure
+%                           0: create one subplot per group
+%   options.error_bars:     1: show standard error-bars (default) 
+%                           0: do not 
+%   options.absolute:       1: show absolute values (default)
+%                           0: show relative change from baseline (ignored
+%                           for categorical data and responder rates)
+%   options.showN:          1: shows number of subjects per datapoint
+%                           0: does not show (default)
+%   options.fontsize:       Fontsize for annotation (default: 12)
+%   options.filename:       Filename for export of plots to PDF
+%   options.fileappend:     0: PDF will be created in this function
+%                           1: PDF created outside of function and plots
+%                           will be appended to a PDF created outside with
+%                           the same name as "filename"
+%
+% [OUTPUT]
+% One figure per entry in NAMES.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Check data
+data = IQMcheckGeneralDataFormatHeader(data);
+
+% Remove NaN in NT
+data(isnan(data.NT),:) = [];
+
+% Handle string name
+if ischar(NAMES),
+    NAMES = {NAMES};
+end
+
+% Handle variable input arguments
+if nargin < 4,
+    GROUP = 'TRTNAME';
+end
+if nargin < 5,
+    options = [];
+end
+
+% Handle default group if empty
+if isempty(GROUP),
+    GROUP = 'TRTNAME';    
+end
+
+% Handle values in options
+try error_bars      = options.error_bars;                   catch, error_bars           = 1;        end
+try absolute        = options.absolute;                   	catch, absolute             = 1;        end
+try filename        = options.filename;                     catch, filename             = '';       end
+try fileappend      = options.fileappend;                   catch, fileappend           = 0;        end
+try fontsize     	= options.fontsize;                     catch, fontsize             = 12;       end
+try singleplot     	= options.singleplot;                   catch, singleplot           = 1;        end
+try showN           = options.showN;                        catch, showN                = 0;        end
+
+% Check absolute and TYPE
+if strcmp(TYPE,'categorical') && ~absolute,
+    absolute = 1;
+end
+
+% Start new output file
+if ~fileappend,
+    IQMstartNewPrintFigure(filename);
+end
+
+% Get colors
+colors = IQMgetcolors();
+
+% Keep only NAMES event in dataset
+data = IQMselectDataEvents(data,NAMES);
+
+% Add time independent covariates ... baseline of NAMES
+% Only needed if not absolute plot ... relative change from baseline
+if ~absolute && strcmp(TYPE,'continuous'),
+    covariateInfo = {};
+    for k=1:length(NAMES),
+        covariateInfo{k,1} = NAMES{k};
+        covariateInfo{k,2} = [regexprep(NAMES{k},'\W','') '0'];
+    end
+    data = IQMdataAddTimeIndependentCovariate(data,covariateInfo);
+end
+
+% Determine min and max NT
+minNT = min(data.NT);
+maxNT = max(data.NT);
+
+% Cycle through NAMES
+for k=1:length(NAMES),
+    
+    % Select only current NAME
+    dataNAME = IQMselectDataEvents(data,NAMES{k});
+    
+    % Determine relative change from baseline if absolute=0
+    if ~absolute,
+        dataNAME.VALUE = 100*(dataNAME.VALUE-dataNAME.(covariateInfo{k,2}))./dataNAME.(covariateInfo{k,2});
+        % Remove NaN and Inf rows
+        dataNAME(isnan(dataNAME.VALUE),:) = [];
+        dataNAME(isinf(dataNAME.VALUE),:) = [];
+    end
+    
+    % Calculate Median data for current NAME
+    dataMedian  = getMedianPlottingDataStructIQM(dataNAME,NAMES{k},TYPE,GROUP);
+    
+    % Get unique group identifiers
+    allGROUP = dataMedian.GROUP;
+
+    % Plot results
+    % if singleplot=1 then plot all in the same figure.
+    % if =0 then per group item one subplot.
+    if ~singleplot,
+        ncols = ceil(sqrt(length(allGROUP)));
+        nrows = ceil(length(allGROUP)/ncols);
+    end
+    
+    figure; clf;
+    
+    % Plot main
+    legendText = {};
+    for kTRT=1:length(dataMedian.GROUP),
+        if ~singleplot,
+            subplot(nrows,ncols,kTRT);
+        end
+        plot(dataMedian.NT{kTRT},dataMedian.DATA{kTRT}(1,:),'.-','Color',colors(kTRT,:),'LineWidth',3,'MarkerSize',20); hold on
+        if isnumeric(allGROUP),
+            legendText{kTRT} = sprintf('%s: %d',GROUP,dataMedian.GROUP(kTRT));
+        else
+            legendText{kTRT} = sprintf('%s: %s',GROUP,dataMedian.GROUP{kTRT});
+        end
+    end
+
+    % Plot error bars
+    if error_bars,        
+        for kTRT=1:length(dataMedian.GROUP),
+            if ~singleplot,
+                subplot(nrows,ncols,kTRT);
+            end
+            errorbar(dataMedian.NT{kTRT}',dataMedian.DATA{kTRT}(1,:),dataMedian.DATA_STDERR{kTRT}(1,:),'Color',colors(kTRT,:),'LineWidth',2); hold on
+        end
+    end
+    
+    % Show number of subjects for each point
+    if showN,
+        for kTRT=1:length(dataMedian.GROUP),
+            fontsizeText = fontsize;
+            if ~singleplot,
+                subplot(nrows,ncols,kTRT);
+                fontsizeText = fontsize-2;
+            end
+            
+            NT = dataMedian.NT{kTRT};
+            N_NT = dataMedian.N_NT{kTRT};
+            
+            for kt=1:length(NT),
+                text(NT(kt),dataMedian.DATA{kTRT}(1,kt)*1.03,sprintf('N=%d',N_NT(kt)),'FontSize',fontsizeText,'Interpreter','none','Color',colors(kTRT,:))
+            end
+        end
+    end
+    
+    % Add title
+    if error_bars,
+        errbarText = ' with standard errors';
+        errbarTextShort = '+stderr';
+    else
+        errbarText = '';
+        errbarTextShort = '';
+    end
+    if absolute,
+        absText = 'absolute';
+        absTextShort = 'abs';
+    else
+        absText = 'relative';  
+        absTextShort = 'rel';        
+    end
+    
+    if singleplot,
+        if strcmp(TYPE,'continuous'),
+            title(sprintf('Median %s (%s)%s',dataMedian.NAME,absText,errbarText),'FontSize',fontsize,'Interpreter','none');
+        else    
+            title(sprintf('%s Responder Rates%s',dataMedian.NAME,errbarText),'FontSize',fontsize,'Interpreter','none');  
+        end
+    else
+        for kTRT=1:length(dataMedian.GROUP),
+            subplot(nrows,ncols,kTRT);
+            if strcmp(TYPE,'continuous'),
+                title(sprintf('%s (%s)%s',dataMedian.NAME,absTextShort,errbarTextShort),'FontSize',fontsize,'Interpreter','none');
+            else    
+                title(sprintf('%s Responder Rates%s',dataMedian.NAME,errbarTextShort),'FontSize',fontsize,'Interpreter','none');    
+            end
+        end 
+    end
+    
+    % xlabel
+    if singleplot,
+        xlabel(sprintf('Nominal Time [%s]',data.TIMEUNIT{1}),'FontSize',fontsize,'Interpreter','none');
+    else
+        for kTRT=length(dataMedian.GROUP)-ncols+1:length(dataMedian.GROUP),
+            subplot(nrows,ncols,kTRT);
+            xlabel(sprintf('Nominal Time [%s]',data.TIMEUNIT{1}),'FontSize',fontsize,'Interpreter','none');
+        end
+    end
+        
+    % ylabel
+    if absolute,
+        unit = dataNAME.UNIT{1};
+        unitShort = dataNAME.UNIT{1};
+    else
+        unit = '% change from baseline';
+        unitShort = '%';        
+    end
+    
+    if singleplot,
+        if strcmp(TYPE,'continuous'),
+            ylabel(sprintf('%s [%s]',dataMedian.NAME,unit),'FontSize',fontsize,'Interpreter','none');
+        else
+            ylabel(sprintf('Observed responder rates [%%]'),'FontSize',fontsize,'Interpreter','none');
+        end
+    else
+        for kTRT=1:ncols:length(dataMedian.GROUP),
+            subplot(nrows,ncols,kTRT);            
+            if strcmp(TYPE,'continuous'),
+                ylabel(sprintf('%s [%s]',dataMedian.NAME,unitShort),'FontSize',fontsize,'Interpreter','none');
+            else
+                ylabel(sprintf('RR [%%]'),'FontSize',fontsize,'Interpreter','none');
+            end
+        end
+    end
+    
+    % Additional annotation
+    if singleplot,
+        set(gca,'FontSize',fontsize);
+        grid on;
+        set(gca,'XLim',[minNT maxNT]);
+        h = legend(legendText,'Location','Best','Interpreter','none');
+        set(h,'FontSize',fontsize-2);
+    else
+        % get max and min Y
+        YLIM = [];
+        for kTRT=1:length(dataMedian.GROUP),
+            subplot(nrows,ncols,kTRT);
+            YLIM = [YLIM; get(gca,'YLim')];
+        end
+        minY = min(YLIM(:,1));
+        maxY = max(YLIM(:,2));
+        
+        for kTRT=1:length(dataMedian.GROUP),
+            subplot(nrows,ncols,kTRT);
+            set(gca,'FontSize',fontsize-2);
+            grid on;
+            set(gca,'XLim',[minNT maxNT]);
+            set(gca,'YLim',[minY maxY]);
+            h = legend(legendText{kTRT},'Location','Best');
+            set(h,'Interpreter','none');
+            set(h,'FontSize',fontsize-2);
+        end
+    end
+    
+    % Handle printing of figure
+    IQMprintFigure(gcf,filename)
+    if ~isempty(filename),
+        close(gcf);
+    end
+end
+
+if ~fileappend,
+    IQMconvert2pdf(filename);
+end
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexploreDataMedianCovariates.m b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexploreDataMedianCovariates.m
new file mode 100644
index 0000000000000000000000000000000000000000..4cd3fa70198ae8ae2486aa32628e28434dd799aa
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexploreDataMedianCovariates.m	
@@ -0,0 +1,294 @@
+function [] = IQMexploreDataMedianCovariates(data,NAME,TYPE,COVARIATE_NAMES,GROUP,options)
+% This function allows to analyze the general dataset format (or some
+% augmented form of it) with respect to the medians of a selected readout
+% and its dependency on baseline covariates.
+% For continuous data the medians are displayed (absolute or relative
+% change from baseline) and for categorical data the responder rates are
+% displayd.
+%
+% [SYNTAX]
+% [] = IQMexploreDataMedianCovariates(data,NAME,TYPE,COVARIATE_NAMES)
+% [] = IQMexploreDataMedianCovariates(data,NAME,TYPE,COVARIATE_NAMES,GROUP)
+% [] = IQMexploreDataMedianCovariates(data,NAME,TYPE,COVARIATE_NAMES,GROUP,options)
+%
+% [INPUT]
+% data:     Dataset in task specific standard data format or in
+%           general data format
+% NAME:     String with name of readouts in the dataset
+%           (NAME column) to plot
+% TYPE:     'categorical' or 'continuous'. For continuous readouts the
+%           medians are plotted. For categorical readouts the responder
+%           rates are plotted. All readouts in NAME will be treated as the
+%           same TYPE.
+% COVARIATE_NAMES:  String or cell-array of strings with names of readouts
+%                   in the NAME column to use as covariates for the correlation.
+%                   Plots will be stratified according to covariate values.
+%                   By default plots will be done for <median(cov) and
+%                   >=median(cov). The option COV_STRATIFICATION allows for
+%                   each covariate to define custom stratification settings.
+%                   COVARIATE_NAMES can also contain names of columns that
+%                   are to be used as covariates. In this way the function
+%                   is also applicable to the task specific dataset format.
+% GROUP:    Name of the column to use as grouping variable. By default
+%           "TRTNAME" is used.
+% options:  Matlab structure with additional optional information:
+%   options.COV_STRATIFICATON:  Cell-array with numeric vectors. One vector
+%                               per entry in COVARIATE_NAMES. The values
+%                               define the ranges for the stratification.
+%                               Default: median.
+%   options.absolute:           1: show absolute values (default)
+%                               0: show relative change from baseline (ignored
+%                               for categorical data and responder rates)
+%   options.showN:              1: shows number of subjects per datapoint
+%                               0: does not show (default)
+%   options.fontsize:           Fontsize for annotation (default: 12)
+%   options.filename:           Filename for export of plots to PDF
+%   options.fileappend:         0: PDF will be created in this function
+%                               1: PDF created outside of function and plots
+%                               will be appended to a PDF created outside with
+%                               the same name as "filename"
+%
+% [OUTPUT]
+% One figure per entry in NAME.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Check data
+data = IQMcheckGeneralDataFormatHeader(data);
+
+% Generate VALUEs from VALUE_TEXTs if still undefined
+data = IQMgenerateVALUEfromVALUE_TEXT(data);
+
+% Remove NaN in NT
+data(isnan(data.NT),:) = [];
+
+% Handle strings
+if ischar(NAME),
+    NAME = {NAME};
+end
+NAME = NAME{1};
+if ischar(COVARIATE_NAMES),
+    COVARIATE_NAMES = {COVARIATE_NAMES};
+end
+
+% Check which ones are NAMEs and which ones are columns
+COV_TYPE_NAME       = NaN(1,length(COVARIATE_NAMES));
+[~,y]               = intersect(COVARIATE_NAMES,data.Properties.VariableNames);
+COV_TYPE_NAME(y)    = 0;
+[~,y]               = intersect(COVARIATE_NAMES,unique(data.NAME));
+COV_TYPE_NAME(y)    = 1;
+if ~isempty(find(isnan(COV_TYPE_NAME))),
+    error('Please check your COVARIATE_NAMES. Some of the names are neither present in the NAME column or as column names.');
+end
+
+% Handle variable input arguments
+if nargin < 5,
+    GROUP = 'TRTNAME';
+end
+if nargin < 6,
+    options = [];
+end
+
+% Handle default group if empty
+if isempty(GROUP),
+    GROUP = 'TRTNAME';    
+end
+
+% Handle values in options
+try absolute            = options.absolute;                   	catch, absolute             = 1;        end
+try filename            = options.filename;                     catch, filename             = '';       end
+try fileappend          = options.fileappend;                   catch, fileappend           = 0;        end
+try fontsize            = options.fontsize;                     catch, fontsize             = 12;       end
+try showN               = options.showN;                        catch, showN                = 0;        end
+try COV_STRATIFICATON   = options.COV_STRATIFICATON;            catch, COV_STRATIFICATON    = {};       end
+
+% Check absolute and TYPE
+if strcmp(TYPE,'categorical') && ~absolute,
+    absolute = 1;
+end
+
+% Check COV_STRATIFICATON
+if ~isempty(COV_STRATIFICATON),
+    if isnumeric(COV_STRATIFICATON),
+        COV_STRATIFICATON = {COV_STRATIFICATON};
+    end
+    if length(COV_STRATIFICATON) ~= length(COVARIATE_NAMES),
+        error('Option COV_STRATIFICATON must be empty or have same length as COVARIATE_NAMES.');
+    end
+end
+
+% Start new output file
+if ~fileappend,
+    IQMstartNewPrintFigure(filename);
+end
+
+% Get colors
+colors = IQMgetcolors();
+
+% Add baseline of NAME
+data = IQMdataAddTimeIndependentCovariate(data,{NAME 'BASELINE'});
+
+% Determine min and max NT
+minNT = min(data.NT);
+maxNT = max(data.NT);
+
+% Cycle through COVARIATE_NAMES
+for k=1:length(COVARIATE_NAMES),
+    
+    % Create figure for each COVARIATE_NAMES
+    figure(k); clf;
+
+    % Add current covariate to data
+    if COV_TYPE_NAME(k)==1,
+        dataCOV = IQMdataAddTimeIndependentCovariate(data,{COVARIATE_NAMES{k} 'COVARIATE'});
+    else
+        dataCOV           = data;
+        dataCOV.COVARIATE = dataCOV.(COVARIATE_NAMES{k});
+    end        
+    
+    % Get current covariate values 
+    if COV_TYPE_NAME(k)==1,
+        COVARIATE_BASELINES = IQMdataGetBaselineValues(dataCOV,COVARIATE_NAMES{k});
+    else
+        COVARIATE_BASELINES = unique(dataCOV(:,{'USUBJID','COVARIATE'}));
+    end
+    
+    % Keep only NAME readouts in data
+    dataNAME = IQMselectDataEvents(dataCOV,NAME);
+    
+    % Determine relative change from baseline if absolute=0
+    if ~absolute,
+        dataNAME.VALUE = 100*(dataNAME.VALUE-dataNAME.BASELINE)./dataNAME.BASELINE;
+        % Remove NaN and Inf rows
+        dataNAME(isnan(dataNAME.VALUE),:) = [];
+        dataNAME(isinf(dataNAME.VALUE),:) = [];
+    end
+    
+    % Determine stratification ranges for the covariate
+    if isempty(COV_STRATIFICATON),
+        stratification_Covariate = nanmedianIQM(table2array(COVARIATE_BASELINES(:,2)));
+    else
+        stratification_Covariate = COV_STRATIFICATON{k};
+    end
+    % Add -Inf and +Inf
+    stratification_Covariate = [-Inf stratification_Covariate +Inf];
+    
+    % Get nrows and ncols
+    ncols = ceil(sqrt(length(stratification_Covariate)-1));
+    nrows = ceil((length(stratification_Covariate)-1)/ncols);
+    
+    % Cycle through the stratification ranges and plot
+    for kstrat=2:length(stratification_Covariate),
+        
+        % Get data in range of covariate
+        dataSTRAT = dataNAME(dataNAME.COVARIATE>stratification_Covariate(kstrat-1) & dataNAME.COVARIATE<=stratification_Covariate(kstrat),:);
+        
+        % Select subplot
+        subplot(nrows,ncols,kstrat-1);
+            
+        if ~isempty(dataSTRAT),
+            % Calculate Median data for current NAME
+            dataMedian  = getMedianPlottingDataStructIQM(dataSTRAT,NAME,TYPE,GROUP);
+            
+            % Get unique group identifiers
+            allGROUP = dataMedian.GROUP;
+            
+            % Plot main
+            legendText = {};
+            for kTRT=1:length(dataMedian.GROUP),
+                plot(dataMedian.NT{kTRT},dataMedian.DATA{kTRT}(1,:),'.-','Color',colors(kTRT,:),'LineWidth',3,'MarkerSize',20); hold on
+                if isnumeric(allGROUP),
+                    legendText{kTRT} = sprintf('%s: %d',GROUP,dataMedian.GROUP(kTRT));
+                else
+                    legendText{kTRT} = sprintf('%s: %s',GROUP,dataMedian.GROUP{kTRT});
+                end
+            end
+            
+            % Show number of subjects for each point
+            if showN,
+                for kTRT=1:length(dataMedian.GROUP),
+                    fontsizeText = fontsize;
+                    
+                    NT = dataMedian.NT{kTRT};
+                    N_NT = dataMedian.N_NT{kTRT};
+                    
+                    for kt=1:length(NT),
+                        text(NT(kt),dataMedian.DATA{kTRT}(1,kt)*1.03,sprintf('N=%d',N_NT(kt)),'FontSize',fontsizeText,'Interpreter','none','Color',colors(kTRT,:))
+                    end
+                end
+            end
+            % ylabel
+            if absolute,
+                unit = dataNAME.UNIT{1};
+            else
+                unit = '%';
+            end
+            
+            if ismember(kstrat-1,1:ncols:length(stratification_Covariate)-1),
+                if strcmp(TYPE,'continuous'),
+                    ylabel(sprintf('Median %s [%s]',dataMedian.NAME,unit),'FontSize',fontsize,'Interpreter','none');
+                else
+                    ylabel(sprintf('%s RRs [%%]',dataMedian.NAME),'FontSize',fontsize,'Interpreter','none');
+                end
+            end
+            
+            % Show legend
+            h = legend(legendText,'Location','Best');
+            set(h,'Interpreter','none');
+            set(h,'FontSize',fontsize-2);
+        end
+        % Add title
+        if absolute,
+            absText = 'absolute';
+            absTextShort = 'abs';
+        else
+            absText = 'relative';
+            absTextShort = 'rel';
+        end
+        
+        % Show title with stratification information
+        lowValue = stratification_Covariate(kstrat-1);
+        highValue = stratification_Covariate(kstrat);
+        if isinf(lowValue),
+            titleText = sprintf('%s (baseline) <= %g',COVARIATE_NAMES{k},highValue);
+        elseif isinf(highValue),
+            titleText = sprintf('%g < %s (baseline)',lowValue,COVARIATE_NAMES{k});
+        else
+            titleText = sprintf('%g < %s (baseline) <= %g',lowValue,COVARIATE_NAMES{k},highValue);
+        end
+        title(titleText,'FontSize',fontsize,'Interpreter','none');
+        
+        % xlabel
+        if kstrat-1>length(stratification_Covariate)-1-ncols,
+            xlabel(sprintf('Nominal Time [%s]',data.TIMEUNIT{1}),'FontSize',fontsize,'Interpreter','none');
+        end
+        
+    end
+    
+    % Get max and min Y and set to same X and Y Lims
+    YLIM = [];
+    for kstrat=2:length(stratification_Covariate),
+        subplot(nrows,ncols,kstrat-1);
+        YLIM = [YLIM; get(gca,'YLim')];
+    end
+    minY = min(YLIM(:,1));
+    maxY = max(YLIM(:,2));
+    for kstrat=2:length(stratification_Covariate),
+        subplot(nrows,ncols,kstrat-1);
+        set(gca,'FontSize',fontsize-2);
+        grid on;
+        set(gca,'XLim',[minNT maxNT]);
+        set(gca,'YLim',[minY maxY]);
+    end
+    
+    % Handle printing of figure
+    IQMprintFigure(gcf,filename)
+    if ~isempty(filename),
+        close(gcf);
+    end
+end
+
+if ~fileappend,
+    IQMconvert2pdf(filename);
+end
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexploreDataVariability.m b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexploreDataVariability.m
new file mode 100644
index 0000000000000000000000000000000000000000..20c9a6f46b10dd79ba79c3d2e940cd62ba9334cd
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexploreDataVariability.m	
@@ -0,0 +1,252 @@
+function [] = IQMexploreDataVariability(data,NAMES,GROUP,options)
+% This function allows to analyze the general dataset format (or some
+% augmented form of it) with respect to the variability of readouts, by
+% plotting either individual profiles for each GROUP or plotting median and
+% 90% range for each GROUP.
+%
+% [SYNTAX]
+% [] = IQMexploreDataVariability(data,NAMES)
+% [] = IQMexploreDataVariability(data,NAMES,GROUP)
+% [] = IQMexploreDataVariability(data,NAMES,GROUP,options)
+%
+% [INPUT]
+% data:     Dataset in task specific standard data format or in
+%           general data format
+% NAMES:    String or cell-array with names of readouts in the dataset
+%           (NAME column) to plot
+% GROUP:    Name of the column to use as grouping variable. By default
+%           "TRTNAME" is used.
+% options:  Matlab structure with additional optional information:
+%   options.individual:     1: plot individual profiles
+%                           0: plot median and 90% variability band
+%   options.singleplot:     1: plot all groups in one figure each
+%                           0: create one subplot per group in one figure
+%   options.absolute:       1: show absolute values (default)
+%                           0: show relative change from baseline 
+%   options.showN:          1: shows number of subjects per datapoint
+%                           0: does not show (default)
+%                           Only used if individual=0
+%   options.fontsize:       Fontsize for annotation (default: 12)
+%   options.filename:       Filename for export of plots to PDF
+%   options.fileappend:     0: PDF will be created in this function
+%                           1: PDF created outside of function and plots
+%                           will be appended to a PDF created outside with
+%                           the same name as "filename"
+%
+% [OUTPUT]
+% Figures in MATLAB or exported to PDF.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Check data
+data = IQMcheckGeneralDataFormatHeader(data);
+
+% Remove NaN in NT
+data(isnan(data.NT),:) = [];
+
+% Remove NaN values
+data(isnan(data.VALUE),:) = [];
+
+% Handle string name
+if ischar(NAMES),
+    NAMES = {NAMES};
+end
+
+% Handle variable input arguments
+if nargin < 3,
+    GROUP = 'TRTNAME';
+end
+if nargin < 4,
+    options = [];
+end
+
+% Handle default group if empty
+if isempty(GROUP),
+    GROUP = 'TRTNAME';    
+end
+
+% Handle values in options
+try individual      = options.individual;                   catch, individual           = 1;        end
+try absolute        = options.absolute;                   	catch, absolute             = 1;        end
+try filename        = options.filename;                     catch, filename             = '';       end
+try fileappend      = options.fileappend;                   catch, fileappend           = 0;        end
+try fontsize     	= options.fontsize;                     catch, fontsize             = 12;       end
+try showN           = options.showN;                        catch, showN                = 0;        end
+try singleplot      = options.singleplot;                   catch, singleplot           = 0;        end
+
+% Start new output file
+if ~fileappend,
+    IQMstartNewPrintFigure(filename);
+end
+
+% Get colors
+colors = IQMgetcolors();
+
+% Keep only NAME event in dataset
+data = IQMselectDataEvents(data,NAMES);
+
+% Add time independent covariates ... baseline of NAME
+% Only needed if not absolute plot ... relative change from baseline
+if ~absolute,
+    covariateInfo = {};
+    for k=1:length(NAMES),
+        covariateInfo{k,1} = NAMES{k};
+        covariateInfo{k,2} = [regexprep(NAMES{k},'\W','') '0'];
+    end
+    data = IQMdataAddTimeIndependentCovariate(data,covariateInfo);
+end
+
+% Determine min and max NT
+minNT = min(data.NT);
+maxNT = max(data.NT);
+
+% Cycle through NAMES
+for k=1:length(NAMES),
+    
+    % Open figure if singeplot = 0
+    if ~singleplot,
+        figure; clf;
+    end
+    
+    % Select only current NAME
+    dataNAME = IQMselectDataEvents(data,NAMES{k});
+
+    % Determine relative change from baseline if absolute=0
+    if ~absolute,
+        dataNAME.VALUE = 100*(dataNAME.VALUE-dataNAME.(covariateInfo{k,2}))./dataNAME.(covariateInfo{k,2});
+        % Remove NaN and Inf rows
+        dataNAME(isnan(dataNAME.VALUE),:) = [];
+        dataNAME(isinf(dataNAME.VALUE),:) = [];
+    end
+    
+    % Determine min and max NT
+    minY = min(dataNAME.VALUE);
+    maxY = max(dataNAME.VALUE);
+
+    % Get unique group identifiers
+    allGROUP = unique(dataNAME.(GROUP));
+
+    % Get nrows and ncols
+    nrows = ceil(sqrt(length(allGROUP)));
+    ncols = ceil(length(allGROUP)/nrows);
+
+    % Plot main
+    for kGROUP=1:length(allGROUP),
+        dataGROUP = subsetIQM(dataNAME,GROUP,allGROUP(kGROUP));
+        allNT = unique(dataGROUP.NT); 
+        % Define subplot or figure
+        if ~singleplot,
+            subplot(nrows,ncols,kGROUP);
+        else
+            figure(kGROUP + (k-1)*length(allGROUP)); clf;
+        end    
+        % Plot 
+        if ~individual,
+            % Plot median and quantiles
+            binningInfo = {allNT,1e5*eps*ones(1,length(allNT))};
+            % Calculate median absolute
+            [xbin,ymedian] = binnedquantilesIQM(dataGROUP.NT,dataGROUP.VALUE,0.5,binningInfo,0);
+            % Calculate 5%Q absolute
+            [xbin,q05] = binnedquantilesIQM(dataGROUP.NT,dataGROUP.VALUE,0.05,binningInfo,0);
+            % Calculate 95%Q absolute
+            [xbin,q95] = binnedquantilesIQM(dataGROUP.NT,dataGROUP.VALUE,0.95,binningInfo,0);
+            plot(xbin,ymedian,'k-','LineWidth',3); hold on;
+            IQMplotfill(xbin(:)',q05(:)',q95(:)',0.8*[1 1 1],1); hold on
+            plot(xbin,ymedian,'k-','LineWidth',3); hold on;
+            
+            % Show N text if desired
+            if showN,
+                for kt=1:length(allNT),
+                    N_TRT_NT = length(unique(dataGROUP.USUBJID(dataGROUP.NT==allNT(kt))));
+                    text(allNT(kt),0.5*(ymedian(kt)+q95(kt)),sprintf('N=%d',N_TRT_NT),'FontSize',fontsize-2,'Interpreter','none')
+                end
+            end            
+        else
+            % Plot individual data
+            allID = unique(dataGROUP.USUBJID);
+            for kk=1:length(allID),
+                datakk = subsetIQM(dataGROUP,'USUBJID',allID(kk));
+                plot(datakk.NT,datakk.VALUE,'k-'); hold on;
+            end
+        end
+    end
+            
+    % Add title
+    for kGROUP=1:length(allGROUP),
+        % Define subplot or figure
+        if ~singleplot,
+            subplot(nrows,ncols,kGROUP);
+        else
+            figure(kGROUP + (k-1)*length(allGROUP));
+        end    
+        if isnumeric(allGROUP),
+            title(sprintf('%s: %d',GROUP,allGROUP(kGROUP)),'FontSize',fontsize,'Interpreter','none')
+        else
+            title(sprintf('%s\n%s',GROUP,allGROUP{kGROUP}),'FontSize',fontsize,'Interpreter','none')
+        end
+    end
+    
+    % xlabel
+    if ~singleplot,
+        for kGROUP=length(allGROUP)-ncols+1:length(allGROUP),
+            subplot(nrows,ncols,kGROUP);
+            xlabel(sprintf('Nominal Time [%s]',dataNAME.TIMEUNIT{1}),'FontSize',fontsize,'Interpreter','none');
+        end
+    else
+        for kGROUP=1:length(allGROUP),
+            figure(kGROUP + (k-1)*length(allGROUP)),
+            xlabel(sprintf('Nominal Time [%s]',dataNAME.TIMEUNIT{1}),'FontSize',fontsize,'Interpreter','none');
+        end
+    end
+    
+    % ylabel    
+    if absolute,
+        unit = dataNAME.UNIT{1};
+        unitShort = dataNAME.UNIT{1};
+    else
+        unit = '% change from baseline';
+        unitShort = '%';        
+    end    
+    if ~singleplot,
+        for kTRT=1:ncols:length(allGROUP),
+            subplot(nrows,ncols,kTRT);
+            ylabel(sprintf('%s [%s]',NAMES{k},unitShort),'FontSize',fontsize,'Interpreter','none');
+        end
+    else
+        for kGROUP=1:length(allGROUP),
+            figure(kGROUP + (k-1)*length(allGROUP)),
+            ylabel(sprintf('%s [%s]',NAMES{k},unit),'FontSize',fontsize,'Interpreter','none');
+        end
+    end
+    
+    % Additional
+    for kGROUP=1:length(allGROUP),
+        % Define subplot or figure
+        if ~singleplot,
+            subplot(nrows,ncols,kGROUP);
+            set(gca,'FontSize',fontsize-2);
+            set(gca,'YLim',[minY maxY]);            
+        else
+            figure(kGROUP + (k-1)*length(allGROUP));
+            set(gca,'FontSize',fontsize);
+        end    
+        grid on
+        set(gca,'XLim',[min(data.NT) max(data.NT)]);
+        if ~individual,
+            legend('Median','90% range','Location','Best')
+        else
+            legend('Individual Data','Location','Best')
+        end
+    end
+        
+    % Handle printing of figure
+    IQMprintFigure(gcf,filename)
+    if ~isempty(filename),
+        close(gcf);
+    end
+end
+
+if ~fileappend,
+    IQMconvert2pdf(filename);
+end
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexploreDistribution.m b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexploreDistribution.m
new file mode 100644
index 0000000000000000000000000000000000000000..3da268b71a58ba1f7cc710251fd78a92e6b1103a
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexploreDistribution.m	
@@ -0,0 +1,185 @@
+function [] = IQMexploreDistribution(data,NAME,GROUP,TIME,options)
+% This function allows to analyze the general dataset format (or some
+% augmented form of it) with respect to the distribution of a readout,
+% defined by NAME at different timepoints. Histograms will be plotted.
+% Readouts at baseline or at defined timepoints can be considered.
+% Additionally, relative and absolute changes from baseline can be
+% displayed.
+%
+% [SYNTAX]
+% [] = IQMexploreDistribution(data,NAME)
+% [] = IQMexploreDistribution(data,NAME,GROUP)
+% [] = IQMexploreDistribution(data,NAME,GROUP,TIME)
+% [] = IQMexploreDistribution(data,NAME,GROUP,TIME,options)
+%
+% [INPUT]
+% data:     Dataset in task specific standard data format or in
+%           general data format
+% NAME :    String with name of readout in the dataset
+%           (NAME column) to plot
+% GROUP:    Name of the column to use as grouping variable. By default
+%           "TRTNAME" is used.
+% TIME:     By default the baselines are plotted. If TIME is defined then
+%           values from the dataset are plotted that have NT
+%           closest to TIME.
+% options:  Matlab structure with additional optional information:
+%   options.absolute:       Only used if TIME defined to a numeric value
+%                           1: show absolute values (default)
+%                           0: show relative change from baseline 
+%   options.change:         Only used if TIME defined to a numeric value
+%                           and if absolute=1
+%                           1: shows absolute change from baseline at
+%                           defined TIME
+%                           0: shows absolute value at defined TIME  (default)
+%   options.Nbins:          Number of bins for histogram (default: 15)
+%                           Only used if individual=0
+%   options.fontsize:       Fontsize for annotation (default: 10)
+%   options.filename:       Filename for export of plots to PDF
+%   options.fileappend:     0: PDF will be created in this function
+%                           1: PDF created outside of function and plots
+%                           will be appended to a PDF created outside with
+%                           the same name as "filename"
+%
+% [OUTPUT]
+% Figures in MATLAB or exported to PDF.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Check data
+data = IQMcheckGeneralDataFormatHeader(data);
+
+% Remove NaN in NT
+data(isnan(data.NT),:) = [];
+
+% Remove NaN values
+data(isnan(data.VALUE),:) = [];
+
+% Handle string name
+if ischar(NAME),
+    NAME = {NAME};
+end
+NAME = NAME{1};
+
+% Get colors
+colors = IQMgetcolors();
+
+% Keep only NAME event in dataset
+data = IQMselectDataEvents(data,NAME);
+
+% Handle variable input arguments
+if nargin < 3,
+    GROUP = 'TRTNAME';
+end
+if nargin < 4,
+    TIME = [];
+end
+if nargin < 5,
+    options = [];
+end
+
+% Handle default group if empty
+if isempty(GROUP),
+    GROUP = 'TRTNAME';    
+end
+
+% Handle values in options
+try absolute        = options.absolute;                   	catch, absolute             = 1;        end
+try change          = options.change;                   	catch, change               = 0;        end
+try filename        = options.filename;                     catch, filename             = '';       end
+try fileappend      = options.fileappend;                   catch, fileappend           = 0;        end
+try fontsize     	= options.fontsize;                     catch, fontsize             = 10;       end
+try Nbins           = options.Nbins;                        catch, Nbins                = 15;       end
+
+% Start new output file
+if ~fileappend,
+    IQMstartNewPrintFigure(filename);
+end
+
+% Get unique group identifiers
+allGROUP = unique(data.(GROUP));
+
+% Get nrows and ncols
+nrows = ceil(sqrt(length(allGROUP)));
+ncols = ceil(length(allGROUP)/nrows);
+
+% Initialize figure
+figure; clf
+
+% Cycle through GROUPs
+for kGROUP=1:length(allGROUP),
+    dataGROUP = subsetIQM(data,GROUP,allGROUP(kGROUP));
+    
+    % Select what to plot
+    if isempty(TIME),
+        % Get baseline values
+        dataPlot            = IQMdataGetBaselineValues(dataGROUP,NAME);
+        % Create data plot info
+        dataPlot.VALUE_PLOT = table2array(dataPlot(:,2));
+        XLABEL = sprintf('BASELINE [%s]',data.UNIT{1});        
+    else
+        % Plot info around given TIME
+        % Add baseline column
+        covariateInfo       = {NAME 'BASELINE'};
+        data2               = IQMdataAddTimeIndependentCovariate(dataGROUP,covariateInfo);
+        % Get data that is needed
+        data2               = data2(:,{'USUBJID',GROUP,'NT','VALUE','NAME','UNIT','BASELINE'});
+        % Handle absolute and relative
+        if absolute,
+            if change,
+                % Absolute changes from baseline at TIME
+                data2.VALUE = data2.VALUE-data2.BASELINE;
+                XLABEL = sprintf('Abs change from BASE [%s]\n@ NT~%g',data.UNIT{1},TIME);        
+            else
+                % Absolute values at TIME
+                data2.VALUE = data2.VALUE;
+                XLABEL = sprintf('[%s]\n@ NT~%g',data.UNIT{1},TIME);        
+            end
+        else
+            % Relative change from baseline
+            data2.VALUE = 100*(data2.VALUE-data2.BASELINE)./data2.BASELINE;
+            data2(isnan(data2.VALUE),:) = [];
+            data2(isinf(data2.VALUE),:) = [];
+            XLABEL = sprintf('Rel change from BASE [%%]\n@ NT~%g',TIME);
+       end
+        % Select values and allow NT max different be 25% from
+        % TIME.
+        dataPlot = IQMdataGetValues(data2,NAME,'NT',TIME,25);
+        dataPlot.VALUE_PLOT = dataPlot.VALUE;
+    end
+    
+    % Create subplot
+    subplot(nrows,ncols,kGROUP);
+    
+    % Get histogram and plot
+    [n,x] = hist(dataPlot.VALUE_PLOT,Nbins);
+    try
+        bar(x,n)
+    end
+    
+    % Annotate
+    grid on
+    set(gca,'FontSize',fontsize)
+    
+    % If in last row then add xlabel
+    if kGROUP>length(allGROUP)-ncols,
+        xlabel(sprintf('%s\n%s',NAME,XLABEL),'FontSize',fontsize,'Interpreter','none');
+    end
+    
+    if isnumeric(allGROUP),
+        title(sprintf('%s: %d',GROUP,allGROUP(kGROUP)),'FontSize',fontsize,'Interpreter','none')
+    else
+        title(sprintf('%s\n%s',GROUP,allGROUP{kGROUP}),'FontSize',fontsize,'Interpreter','none')
+    end
+end
+
+IQMprintFigure(gcf,filename)
+if ~isempty(filename),
+    close(gcf);
+end
+if ~fileappend,
+    IQMconvert2pdf(filename);
+end
+
+
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexploreDistributionCorrelation.m b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexploreDistributionCorrelation.m
new file mode 100644
index 0000000000000000000000000000000000000000..de097b6cf7155f1d1cfdabcb34b411156deec5cf
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexploreDistributionCorrelation.m	
@@ -0,0 +1,245 @@
+function [] = IQMexploreDistributionCorrelation(data,NAME,COVARIATE_NAMES,TIME,GROUP,options)
+% This function allows to analyze the general dataset format (or some
+% augmented form of it) with respect to changes in readout NAME at TIME
+% from baseline (absolute or relative to baseline) and correlation of these
+% changes to selected other readouts at baseline (COVARIATE_NAMES).
+%
+% [SYNTAX]
+% [] = IQMexploreDistributionCorrelation(data,NAME,COVARIATE_NAMES,TIME)
+% [] = IQMexploreDistributionCorrelation(data,NAME,COVARIATE_NAMES,TIME,GROUP)
+% [] = IQMexploreDistributionCorrelation(data,NAME,COVARIATE_NAMES,TIME,GROUP,options)
+%
+% [INPUT]
+% data:             Dataset in task specific standard data format or in
+%                   general data format
+% NAME :            String with name of readout in the dataset
+%                   (NAME column) to plot
+% COVARIATE_NAMES:  String or cell-array of strings with names of readouts
+%                   in the NAME column to use as covariates for the correlation.
+%                   COVARIATE_NAMES can also contain names of columns that
+%                   are to be used as covariates. In this way the function
+%                   is also applicable to the task specific dataset format.
+% TIME:             Time at which to calculate the changes from baseline.
+%                   NT is used. TIME does not need to match times
+%                   exactly. For each individual the closest value will be
+%                   taken. 
+% GROUP:            Name of the column to use as grouping variable. By default
+%                   "TRTNAME" is used.
+% options:          Matlab structure with additional optional information:
+%   options.absolute:       1: show absolute values (default)
+%                           0: show relative change from baseline 
+%   options.fontsize:       Fontsize for annotation (default: 10)
+%   options.filename:       Filename for export of plots to PDF
+%   options.fileappend:     0: PDF will be created in this function
+%                           1: PDF created outside of function and plots
+%                           will be appended to a PDF created outside with
+%                           the same name as "filename"
+%
+% [OUTPUT]
+% Figures in MATLAB or exported to PDF.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Check data
+data = IQMcheckGeneralDataFormatHeader(data);
+
+% Remove NaN in NT
+data(isnan(data.NT),:) = [];
+
+% Remove NaN values
+data(isnan(data.VALUE),:) = [];
+
+% Handle strings
+if ischar(NAME),
+    NAME = {NAME};
+end
+NAME = NAME{1};
+if ischar(COVARIATE_NAMES),
+    COVARIATE_NAMES = {COVARIATE_NAMES};
+end
+
+% Check which ones are NAMEs and which ones are columns
+COV_TYPE_NAME       = NaN(1,length(COVARIATE_NAMES));
+[~,y]               = intersect(COVARIATE_NAMES,data.Properties.VariableNames);
+COV_TYPE_NAME(y)    = 0;
+[~,y]               = intersect(COVARIATE_NAMES,unique(data.NAME));
+COV_TYPE_NAME(y)    = 1;
+if ~isempty(find(isnan(COV_TYPE_NAME))),
+    error('Please check your COVARIATE_NAMES. Some of the names are neither present in the NAME column or as column names.');
+end
+
+% Get baselines for defined covariates either as NAME or as column
+baseline_covariates_NAME = IQMdataGetBaselineValues(data,COVARIATE_NAMES(COV_TYPE_NAME==1));
+
+dataTemp = data;
+for k=1:length(COVARIATE_NAMES),
+    if COV_TYPE_NAME(k)==0,
+        x = dataTemp.(COVARIATE_NAMES{k});
+        x(isnan(x)) = -9999.9999;
+        dataTemp.(COVARIATE_NAMES{k}) = x;
+    end
+end
+baseline_covariates_COL  = unique(dataTemp(:,{'USUBJID',COVARIATE_NAMES{COV_TYPE_NAME==0}}));
+vn = baseline_covariates_COL.Properties.VariableNames;
+for k=2:length(vn),
+    x = baseline_covariates_COL.(vn{k});
+    x(x==-9999.9999) = NaN;
+    baseline_covariates_COL.(vn{k}) = x;
+end
+
+try
+    baseline_covariates      = join(baseline_covariates_NAME,baseline_covariates_COL);
+catch
+    % If an error appears then this is due to time varying covariates being present. In this case we only take the 
+    % first covariate
+    dataXXX = table();
+    allID = unique(baseline_covariates_COL.USUBJID);
+    for k=1:length(allID),
+        datak = baseline_covariates_COL(ixdataIQM(baseline_covariates_COL,'USUBJID',allID(k)),:);
+        dataXXX = [dataXXX; datak(1,:)];
+    end
+    baseline_covariates      = join(baseline_covariates_NAME,dataXXX);
+end
+
+COVARIATE_NAMES          = baseline_covariates.Properties.VariableNames(2:end);
+COV_TYPE_NAME            = [ones(1,size(baseline_covariates_NAME,2)-1) zeros(1,size(baseline_covariates_COL,2)-1)];
+
+% Add baseline covariate to dataset
+data = IQMdataAddTimeIndependentCovariate(data,{NAME 'BASELINE'});
+
+% Select only readout
+data = IQMselectDataEvents(data,NAME);
+
+% Get colors
+colors = IQMgetcolors();
+
+% Handle variable input arguments
+if nargin < 4,
+    TIME = [];
+end
+if nargin < 5,
+    GROUP = 'TRTNAME';
+end
+if nargin < 6,
+    options = [];
+end
+
+% Handle default group if empty
+if isempty(GROUP),
+    GROUP = 'TRTNAME';    
+end
+
+% Check time
+if isempty(TIME),
+    error('TIME needs to be defined.');
+end
+
+% Handle values in options
+try absolute        = options.absolute;                   	catch, absolute             = 1;        end
+try filename        = options.filename;                     catch, filename             = '';       end
+try fileappend      = options.fileappend;                   catch, fileappend           = 0;        end
+try fontsize     	= options.fontsize;                     catch, fontsize             = 10;       end
+
+% Start new output file
+if ~fileappend,
+    IQMstartNewPrintFigure(filename);
+end
+
+% Get unique group identifiers
+allGROUP = unique(data.(GROUP));
+
+% Get nrows and ncols
+nrows = ceil(sqrt(length(allGROUP)));
+ncols = ceil(length(allGROUP)/nrows);
+
+for k=1:length(COVARIATE_NAMES),
+    figure(k); clf;
+end
+
+% Cycle through GROUPs
+for kGROUP=1:length(allGROUP),
+    
+    % Get data that is needed
+    dataGROUP = subsetIQM(data,GROUP,allGROUP(kGROUP));
+    dataGROUP = dataGROUP(:,{'USUBJID',GROUP,'NT','VALUE','NAME','UNIT','BASELINE'});
+    
+    % Handle absolute and relative
+    if absolute,
+        % Absolute change from baseline
+        dataGROUP.VALUE = dataGROUP.VALUE-dataGROUP.BASELINE;
+        YLABEL = sprintf('Abs change [%s]\n%g %s vs. BASE',data.UNIT{1},TIME,data.TIMEUNIT{1});
+    else
+        % Relative change from baseline
+        dataGROUP.VALUE = 100*(dataGROUP.VALUE-dataGROUP.BASELINE)./dataGROUP.BASELINE;
+        dataGROUP(isnan(dataGROUP.VALUE),:) = [];
+        dataGROUP(isinf(dataGROUP.VALUE),:) = [];
+        YLABEL = sprintf('Rel change [%%]\n%g %s vs. BASE',TIME,data.TIMEUNIT{1});
+    end
+    
+    % Get values close to TIME
+    dataGROUP = IQMdataGetValues(dataGROUP,NAME,'NT',TIME,25);
+    
+    % Add covariates
+    dataGROUP = join(dataGROUP,baseline_covariates);
+    
+    for kcov=1:length(COVARIATE_NAMES),
+        figure(kcov);
+        % Create subplot
+        subplot(nrows,ncols,kGROUP);
+        if ~isempty(dataGROUP),
+            % Plot
+            plot(dataGROUP.(regexprep(COVARIATE_NAMES{kcov},'\W','')),dataGROUP.VALUE,'.','MarkerSize',20,'Color',colors(kcov,:));
+        end
+        % Annotate
+        grid on;
+        if kGROUP>length(allGROUP)-ncols,
+            if COV_TYPE_NAME(kcov)==1,
+                xlabel(sprintf('%s\nBaseline',COVARIATE_NAMES{kcov}),'FontSize',fontsize,'Interpreter','none');
+            else
+                xlabel(sprintf('%s',COVARIATE_NAMES{kcov}),'FontSize',fontsize,'Interpreter','none');
+            end                
+        end
+        if isnumeric(allGROUP),
+            title(sprintf('%s: %d',GROUP,allGROUP(kGROUP)),'FontSize',fontsize,'Interpreter','none')
+        else
+            title(sprintf('%s\n%s',GROUP,allGROUP{kGROUP}),'FontSize',fontsize,'Interpreter','none')
+        end
+        set(gca,'FontSize',fontsize-2);
+        if ismember(kGROUP,1:ncols:length(allGROUP)),
+            ylabel(sprintf('%s\n%s',NAME,YLABEL),'FontSize',fontsize,'Interpreter','none');
+        end
+        
+        if ~isempty(dataGROUP),
+            % Correlation
+            XX = [dataGROUP.(regexprep(COVARIATE_NAMES{kcov},'\W','')) dataGROUP.VALUE];
+            ixnan = find(isnan(XX(:,1)));
+            XX(ixnan,:) = [];
+            ixnan = find(isnan(XX(:,2)));
+            XX(ixnan,:) = [];
+            if ~isempty(XX),
+                [corr_v,corr_p] = corrcoef(XX(:,1),XX(:,2));
+                corr_v = corr_v(1,2);
+                corr_p = corr_p(1,2);
+                YLim = get(gca,'YLim');
+                set(gca,'YLim',YLim);
+                XLim = get(gca,'XLim');
+                set(gca,'XLim',XLim);
+                XLim = get(gca,'XLim');
+                YLim = get(gca,'YLim');
+                text(min(XLim),max(YLim),sprintf('CORR=%1.3g (p=%1.3g)',corr_v,corr_p),'Interpreter','none','HorizontalAlign','Left','VerticalAlign','top','FontSize',fontsize-2)
+            end
+        end
+    end
+end
+
+for kcov=1:length(COVARIATE_NAMES),
+    figure(kcov);
+    IQMprintFigure(gcf,filename)
+    if ~isempty(filename),
+        close(gcf);
+    end
+end
+
+if ~fileappend,
+    IQMconvert2pdf(filename);
+end
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexploreIndivData.m b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexploreIndivData.m
new file mode 100644
index 0000000000000000000000000000000000000000..7d95310bbca16b2a7c148294dd13886849799daf
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexploreIndivData.m	
@@ -0,0 +1,219 @@
+function [] = IQMexploreIndivData(data,OBSNAME,DOSENAME,options)
+% This function allows to plot individual data from the task specific
+% dataset used in IQM Tools.
+%
+% MDV=1 observations (if MDV column present) and observations with IGNORE
+% entry are NOT considered in the plotting. 
+%
+% [SYNTAX]
+% [] = IQMexploreIndivData(data,OBSNAME)
+% [] = IQMexploreIndivData(data,OBSNAME,DOSENAME)
+% [] = IQMexploreIndivData(data,OBSNAME,DOSENAME,options)
+%
+% [INPUT]
+% data:         MATLAB PKPD dataset in task specific standard data format.
+%               The general dataset is covered as well with certain
+%               limitations (if no DOSENAME given then TAD can not be
+%               displayed in the text). 
+% OBSNAME:      Name (as in the NAME column) of the readout to do the plots 
+% DOSENAME:     Name (as in the NAME column) of the event to consider as
+%               dose. If specified then dose information will be added to
+%               the plots. If not specified or empty ('') then no dose
+%               information will be added. Default: '' (empty)
+% options:      MATLAB structure with additional options
+%
+%       options.filename    = Filename with path for storing PDF. If empty
+%                             ('') then no file is produced. Default:
+%                             'indiv_plot.pdf' 
+%       options.logY        = 0: linear Y axis (default), 1: log Y axis
+%       options.showText    = 1: do show text info next to each observed
+%                             datapoint (shows index in dataset data -
+%                             these are the indices stored in the IXGDF
+%                             column and relate to the indices in the
+%                             general dataset format, TAD,   
+%                             and DV values), 0: do not show (default)
+%       options.nIDperPage  = Numeric value, defining number of individual
+%                             subjects per page (rounded to fit). (default: 1)
+%       options.sameaxes    = Use same X and Y axes for all plots (default: 1 if nIDperPage>1 otherwise 0)
+%       options.nameGroup   = Name for grouping ... default: "USUBJID"
+%       options.titlefontsize = Size for the title text (default: 16 if nIDperPage>1 otherwise 10 )
+%
+% [OUTPUT]
+% One plot per USUBJID or unique group entry. If filename is specified the 
+% output is directly made to file.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%% If dataset empty then return
+if isempty(data),
+    disp('Empty dataset.');
+    return;
+end
+
+if nargin<2,
+    error('Incorrect number of input arguments.');
+end
+if nargin<3,
+    DOSENAME = '';
+end
+if nargin<4,
+    options = [];
+end
+
+% Check
+if ischar(DOSENAME),
+   DOSENAME = {DOSENAME};
+end
+if ischar(OBSNAME),
+   OBSNAME = {OBSNAME};
+end
+if length(DOSENAME)>1,
+    error('Only a single DOSENAME is allowed.');
+end
+if length(OBSNAME)>1,
+    error('Only a single OBSNAME is allowed.');
+end
+DOSENAME = DOSENAME{1};
+OBSNAME  = OBSNAME{1};
+
+%% Check if data in task specific data format
+try
+    data = IQMcheckTaskDatasetHeader(data);
+    FLAG_TASK = 1;
+catch
+    % It is not - check if in general data format
+    data = IQMcheckGeneralDataFormatHeader(data);
+    FLAG_TASK = 0;
+end
+
+%% Check if DOSENAME given and then create Task dataset if GENERAL
+if ~isempty(DOSENAME) && ~FLAG_TASK,
+    data = IQMaddNLMEinfo2data(data,DOSENAME,OBSNAME);
+    FLAG_TASK = 1;
+end
+
+%% Remove MDV=1 observations
+data(data.MDV==1 & data.EVID==0,:) = [];
+
+%% Remove IGNOREs records
+data(~strcmp(data.IGNORE,''),:) = [];
+
+%% Handle options
+try filename            = options.filename;                 catch, filename             = 'indiv_plot.pdf'; end; %#ok<*CTCH>
+try logY                = options.logY;                     catch, logY                 = 0;                end;
+try showText            = options.showText;                 catch, showText             = 0;                end;
+try nIDperPage          = options.nIDperPage;               catch, nIDperPage           = 1;                end;
+try sameaxes            = options.sameaxes;                 catch
+    if nIDperPage > 1,
+        sameaxes             = 1;                
+    else
+        sameaxes             = 0;                
+    end
+end
+try nameGroup           = options.nameGroup;                catch, nameGroup            = 'USUBJID';             end;
+try titlefontsize       = options.titlefontsize;            catch
+    if nIDperPage > 1,
+        titlefontsize        = 10;
+    else
+        titlefontsize        = 16;
+    end
+end
+
+%% Check availability of TAD_"name" ... and in this case use this as TAD
+check_TAD_column = sprintf('TAD_%s',makeVariableNameIQM(DOSENAME));
+ix = strmatchIQM(check_TAD_column,data.Properties.VariableNames,'exact');
+if ~isempty(ix),
+    % Update TAD column with the correct one for the selected dose
+    data.TAD = data.(check_TAD_column);
+end
+
+%% Determine number of rows and cols
+ncols = ceil(sqrt(nIDperPage));
+nrows = ceil(nIDperPage/ncols);
+
+%% Prepare the dataset for plotting
+% Get observations
+dataObs  = data(strcmp(data.NAME,OBSNAME),:);
+
+% Get doses - only if DOSENAME defined
+if ~isempty(DOSENAME),
+    dataDose = subsetIQM(data,'NAME',DOSENAME);
+else
+    dataDose = table();
+end
+
+%% Set up plotting function options (IQMplottrellis)
+dataPlot                = dataObs;
+nameX                   = 'TIME';
+nameY                   = 'VALUE';
+options                 = [];
+options.xlabelText      = ['Time [' dataObs.TIMEUNIT{1} ']'];
+options.ylabelText      = [dataObs.NAME{1} ' [' dataObs.UNIT{1} ']'];
+options.nameSubGroup    = nameGroup;
+options.logX            = 0;
+options.logY            = logY;
+options.markersize      = 20;
+options.sameaxes        = 0;
+options.showgrid        = 1;
+options.nrows           = nrows;
+options.ncols           = ncols;
+options.linecolor       = 0.2*[1 1 1];
+options.filename        = filename;
+if ~isempty(DOSENAME),
+    options.verticallines.data                  = dataDose;
+    options.verticallines.nameDataVertical      = 'AMT';
+    options.verticallines.showtext              = 1;
+    options.verticallines.shownameDataVertical  = 1;
+    options.verticallines.linecolor             = 0.2*[1 1 1];
+end
+if nrows>1,
+    options.ylabelfirstonly = 1;
+end
+
+options.heighttitlebar  = 0.05+0.03*nrows;
+options.sameaxes        = sameaxes;
+
+%% Generate text to show next to observations 
+% By default IXGDF, TAD, DV
+if showText,
+    options.nameText        = 'nameText';
+    options.nameTextLines   = 1; % Show text AND lines
+    options.textFontsize    = 8;
+    dataPlot.nameText = cell(height(dataPlot),1);
+    for k=1:height(dataObs),
+        if FLAG_TASK,
+            dataPlot.nameText{k} = sprintf('  IX%d (%g,%g)',dataPlot.IXGDF(k),dataPlot.TAD(k),dataPlot.DV(k));
+        else
+            dataPlot.nameText{k} = sprintf('  IX%d (%g)',dataPlot.IXGDF(k),dataPlot.DV(k));
+        end
+    end
+end
+
+if ~isempty(titlefontsize),
+    options.titlefontsize = titlefontsize;
+end
+
+%% Handle case of BLOQ data present
+BLLOQdataPresent = 0;
+% Check if dataPlot contains LLOQ information and if yes then check if BLLOQ data are present
+if sum(~isnan(dataPlot.LLOQ)) > 0,
+    % LLOQ information present
+    if sum(dataPlot.DV<dataPlot.LLOQ) > 0,
+        % BLLOQ data present
+        BLLOQdataPresent = 1;
+    end
+end
+
+if BLLOQdataPresent,
+    dataPlot.isBLLOQ            = double(dataPlot.DV<dataPlot.LLOQ);
+    options.nameColorGroup      = 'isBLLOQ';
+    options.linecolorsCustom    = [0.2 0.2 0.2; 0.8500    0.3250    0.0980];
+    options.linetypesCustom     = {'.','x'};
+    options.showmarkers         = 1;
+    options.markersize          = 12;
+end
+
+%% Do the plotting
+IQMplottrellis(dataPlot,nameGroup,nameX,nameY,options)
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexploreIndivDataRelation.m b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexploreIndivDataRelation.m
new file mode 100644
index 0000000000000000000000000000000000000000..1757e08e36fce502a4b704b553a75c71acd65d46
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexploreIndivDataRelation.m	
@@ -0,0 +1,156 @@
+function [] = IQMexploreIndivDataRelation(data,OBSNAMES,GROUP,options)
+% This function allows to plot individual data from the task specific
+% dataset used in IQM Tools.
+% 
+% [SYNTAX]
+% [] = IQMexploreIndivDataRelation(data,OBSNAMES)
+% [] = IQMexploreIndivDataRelation(data,OBSNAMES,GROUP)
+% [] = IQMexploreIndivDataRelation(data,OBSNAMES,GROUP,options)
+%
+% [INPUT]
+% data:         MATLAB PKPD dataset in general standard data format.
+% OBSNAMES:     String or cell-array with NAMEs to plot
+% GROUP:        Group plots by this column in the dataset (default: USUBJID
+%               leading to one figure per subject).
+% options:      MATLAB structure with additional options
+%
+%       options.filename        = Filename with path for storing PDF. If empty
+%                                 ('') then no file is produced. Default:
+%                                 'indiv_plot.pdf' 
+%       options.logY            = Scalar or vector with same size as
+%                                 OBSNAMES. 0 for linY axis, 1 for logY
+%                                 axis. (default: all linear).
+%       options.relative        = Scalar or vector with same size as
+%                                 OBSNAMES. 0 for absolute values, 1 for
+%                                 relative change from baseline (default: 0).
+%       options.titlefontsize  = Size for the title text (default: 12)
+%       options.linewidth      = Width of line plots (default: 2)
+%
+% [OUTPUT]
+% One plot per USUBJID or unique group entry. If filename is specified the 
+% output is directly made to file.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% If dataset empty then return
+if isempty(data),
+    disp('Empty dataset.');
+    return;
+end
+
+% Check if required columns present in dataset
+data = IQMcheckGeneralDataFormatHeader(data);
+
+% Handle variable input arguments
+if nargin<2,
+    error('Incorrect number of input arguments.');
+end
+if nargin<3,
+    GROUP = 'USUBJID';
+end
+if nargin<4,
+    options = [];
+end
+
+% Handle cell thing
+if ~iscell(OBSNAMES),
+    OBSNAMES = {OBSNAMES};
+end
+
+% Handle options
+try filename            = options.filename;                 catch, filename             = 'indiv_plot.pdf';         end
+try logY                = options.logY;                     catch, logY                 = 0;                        end
+try relative            = options.relative;                 catch, relative             = zeros(size(OBSNAMES));    end
+try titlefontsize       = options.titlefontsize;            catch, titlefontsize        = 12;                       end
+try linewidth           = options.linewidth;                catch, linewidth            = 2;                        end
+
+% Handle relative
+if length(relative)==1,
+    relative = relative*ones(size(OBSNAMES));
+end
+
+% Determine number of rows and cols 
+ncols                   = 1;
+nrows                   = length(OBSNAMES);
+
+% Define nameX to always be TIME
+nameX                   = 'TIME';
+
+% Subset the data to only include the OBSNAMES
+data                    = IQMselectDataEvents(data,OBSNAMES);
+
+% Change obsnames to be valid variable names
+OBSNAMES_changed        = regexprep(OBSNAMES,'\W','');
+data.NAMES_changed     	= regexprep(data.NAME,'\W',''); % Same change as in IQMdataGetBaselineValues
+
+% Get Baseline values
+baselineInfo            = IQMdataGetBaselineValues(data,OBSNAMES);
+
+% Join data with baselineinfo
+data                    = join(data,baselineInfo);
+
+% Calculate relative changes from baseline if desired
+for k=1:length(OBSNAMES_changed),
+    if relative(k),
+        VALUE       = data.VALUE(ixdataIQM(data,'NAMES_changed',OBSNAMES_changed{k}));
+        BASE        = data.(OBSNAMES_changed{k})(ixdataIQM(data,'NAMES_changed',OBSNAMES_changed{k}));
+        RELVAL      = 100*(VALUE-BASE)./BASE;
+        data.VALUE(ixdataIQM(data,'NAMES_changed',OBSNAMES_changed{k})) = RELVAL;
+    end
+end
+
+% Remove isnan and isinf from data.VALUE
+data(isnan(data.VALUE),:) = [];
+data(isinf(data.VALUE),:) = [];
+
+% Get obsnames with units
+OBSNAMES_units = {};
+for k=1:length(OBSNAMES),
+    if relative(k),
+        OBSNAMES_units{k} = sprintf('%s [%%]',OBSNAMES{k});
+    else
+        x = data.UNIT(ixdataIQM(data,'NAME',OBSNAMES(k)),:);
+        OBSNAMES_units{k} = sprintf('%s [%s]',OBSNAMES{k},x{1});
+    end
+end
+
+% Reduce data and create a wide dataset for plotting
+datared                	= data(:,{'USUBJID','NAMES_changed',nameX,'VALUE',GROUP});
+datawide              	= IQMdataset2wide(datared,'NAMES_changed','VALUE');
+
+% Start figure if desitred
+IQMstartNewPrintFigure(filename);
+
+% Plot it
+allID = unique(data.(GROUP));
+for k=1:length(allID),
+    datak                   = datawide(ixdataIQM(datawide,GROUP,allID{k}),:);
+    
+    options.ncols           = ncols;
+    options.nrows           = nrows;
+    options.linetype        = '.-';
+    options.linecolor       = 0.2*[1 1 1];
+    options.ylabelText      = OBSNAMES_units;
+    options.xlabelText      = sprintf('Time [%s]',data.TIMEUNIT{1});
+    options.removeNaNs      = 1;
+    options.heighttitlebar  = 0.1;
+    options.titleText       = sprintf('%s: %s ',GROUP,allID{k}); 
+    options.logY            = logY;
+    options.linewidth       = linewidth;
+    options.titlefontsize   = titlefontsize;
+    options.nameSubGroup    = 'USUBJID';
+    IQMplotXY(datak,nameX,OBSNAMES_changed,options)
+    
+    % Print the figure
+    IQMprintFigure(gcf,filename);
+    
+    % Close figure if printed
+    if ~isempty(filename),
+        close(gcf);
+    end
+end
+
+% Convert to PDF
+IQMconvert2pdf(filename);
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexploreMissingEventRate.m b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexploreMissingEventRate.m
new file mode 100644
index 0000000000000000000000000000000000000000..3cd817673f7189486344f5009b7e0a42938482f8
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexploreMissingEventRate.m	
@@ -0,0 +1,107 @@
+function [] = IQMexploreMissingEventRate(data,GROUP,options)
+% Rate of missing events over NT by group.
+% Assess missing events in the dataset. For each GROUP the
+% total number of available subjects is calculated (across all nominal
+% times). Then for each nominal time in each group the number of subjects
+% is determined. 
+%
+% This function is useful to get a first idea about potential drop-out
+% rates.
+%
+% [SYNTAX]
+% [] = IQMplotMissingEventRate(data)
+% [] = IQMplotMissingEventRate(data,GROUP)
+% [] = IQMplotMissingEventRate(data,GROUP,options)
+%
+% [INPUT]
+% data:     Dataset in task specific standard data format or in
+%           general data format
+% GROUP:    Name of the column to use as grouping variable. By default
+%           "TRTNAME" is used.
+% options:  Matlab structure with additional optional information:
+%   options.fontsize: Fontsize for the annotation of the plots (default: 12)
+%
+% [OUTPUT]
+% Single plot with desired information.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Check data
+data = IQMcheckGeneralDataFormatHeader(data);
+
+% Remove NaN in NT
+data(isnan(data.NT),:) = [];
+
+% Handle variable input arguments
+if nargin < 2,
+    GROUP = 'TRTNAME';
+end
+if nargin < 3,
+    options = [];
+end
+
+% Handle values in options
+try fontsize = options.fontsize;             catch, fontsize        = 12; end
+
+% Get colors
+colors = IQMgetcolors();
+
+% Get unique group identifiers
+allGROUP = unique(data.(GROUP));
+
+% Get nrows and ncols
+nrows = ceil(sqrt(length(allGROUP)));
+ncols = ceil(length(allGROUP)/nrows);
+
+figure; clf;
+for k=1:length(allGROUP),
+    datak = subsetIQM(data,GROUP,allGROUP(k));
+    if ~isempty(datak),
+        % Determine max number of patients in TRT
+        N_TRT = length(unique(datak.USUBJID));
+        % Determine number of patients at NT samples
+        N_TRT_NT = [];
+        allNT = unique(datak.NT);
+        for k3=1:length(allNT),
+            datak3 = subsetIQM(datak,'NT',allNT(k3));
+            N_TRT_NT = [N_TRT_NT length(unique(datak3.USUBJID))];
+        end
+        % Determine relative change
+        NmissingRel = -100*(N_TRT_NT-N_TRT)/N_TRT;
+        
+        % Plot
+        subplot(nrows,ncols,k);
+        plot(allNT,NmissingRel,'Color',colors(1,:),'LineWidth',2); hold on
+        grid on
+        
+        % If in last row then add xlabel
+        if k>length(allGROUP)-ncols,
+            xlabel('Nominal Time','FontSize',fontsize,'Interpreter','none');
+        end
+        % If in first column add ylabel
+        if mod(k+ncols,ncols*2) == 1 || length(allGROUP)==1,
+            ylabel(sprintf('Missing events [%%]'),'FontSize',fontsize,'Interpreter','none');
+        end
+        
+        axis([min(allNT) max(allNT) 0 max(max(NmissingRel),1)    ]);
+        
+        % Add title in figure
+        XLim = get(gca,'XLim');
+        YLim = get(gca,'YLim');
+        if isnumeric(allGROUP(k)),
+            title(sprintf('%s: %d',GROUP,allGROUP(k)),'FontSize',fontsize,'Interpreter','none')
+        else
+            title(sprintf('%s: %s',GROUP,allGROUP{k}),'FontSize',fontsize,'Interpreter','none')
+        end
+        text(XLim(1),YLim(2),sprintf('Nmax=%d',N_TRT),'FontSize',fontsize,'Interpreter','none','VerticalAlign','top','HorizontalAlign','left')
+    else
+        subplot(nrows,ncols,k);
+        set(gca,'XTick',[]);
+        set(gca,'YTick',[]);
+        if isnumeric(allGROUP(k)),
+            title(sprintf('%s: %d (Nmax=0)',GROUP,allGROUP(k)),'FontSize',fontsize,'Interpreter','none')
+        else
+            title(sprintf('%s\n%s (Nmax=0)',GROUP,allGROUP{k}),'FontSize',fontsize,'Interpreter','none')
+        end
+    end
+end
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexploreMissingObservationGraphics.m b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexploreMissingObservationGraphics.m
new file mode 100644
index 0000000000000000000000000000000000000000..84f8734ca4a0a01aed2e2c1aea5fda7bbd37d69d
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexploreMissingObservationGraphics.m	
@@ -0,0 +1,208 @@
+function [] = IQMexploreMissingObservationGraphics(data,NAME,GROUP,options)
+% Assess missing observations in the dataset. For each GROUP a plot is done
+% showing visits of subjects in which at least one visit is missing.
+% Missing visits are determined by missing readout (NAME) at a nominal
+% time. Reference nominal times will be determined by considering all
+% subjects within a GROUP. Non available readout (NAME) information will be
+% shown as red X. Available readouts will be shown as dots. The dots are
+% black by default. If the options.PD_IMPROVEMENT argument is set (percent
+% change from baseline) then dots that indicate a better response than
+% PD_IMPROVEMENT will be shown in blue.
+%
+% [SYNTAX]
+% [] = IQMplotMissingObservationGraphics(data,NAME)
+% [] = IQMplotMissingObservationGraphics(data,NAME,GROUP)
+% [] = IQMplotMissingObservationGraphics(data,NAME,GROUP,options)
+%
+% [INPUT]
+% data:     Dataset in task specific standard data format or in
+%           general data format
+% GROUP:    Name of the column to use as grouping variable. By default
+%           "TRTNAME" is used.
+% options:  Matlab structure with additional optional information:
+%   options.PD_IMPROVEMENT: Numeric value indicating percent change from
+%       baseline that is considered to be a reasonable response. If a
+%       subject has this or a better response the corresponding
+%       observations will be displayed in blue, otherwise in black. If this
+%       optional argument is missing, then all available visits will be
+%       colored in black.
+%   options.filename:       Filename for export of plots to PDF
+%   options.fileappend:     0: PDF will be created in this function (default)
+%                           1: PDF created outside of function and plots
+%                           will be appended to a PDF created outside with
+%                           the same name as "filename"
+%
+% [OUTPUT]
+% Single plot with desired information.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Check data
+data = IQMcheckGeneralDataFormatHeader(data);
+
+% Check NAME and make char out of it
+if iscell(NAME),
+    if length(NAME)>1,
+        error('Function can only handle single NAMEs.');
+    end
+    NAME = NAME{1};
+end
+    
+% Remove NaN in NT
+data(isnan(data.NT),:) = [];
+
+% Keep only NAME event in dataset
+data = IQMselectDataEvents(data,NAME);
+
+% Handle variable input arguments
+if nargin < 3,
+    GROUP = 'TRTNAME';
+end
+if nargin < 4,
+    options = [];
+end
+
+% Handle values in options
+try PD_IMPROVEMENT  = options.PD_IMPROVEMENT;               catch, PD_IMPROVEMENT       = [];       end
+try filename        = options.filename;                     catch, filename             = '';       end
+try fileappend      = options.fileappend;                   catch, fileappend           = 0;        end
+
+% Get unique group identifiers
+allGROUP = unique(data.(GROUP));
+
+% Start new output file
+if ~fileappend,
+    IQMstartNewPrintFigure(filename);
+end
+
+% Cycle through each group
+for k = 1:length(allGROUP),
+    datak = subsetIQM(data,GROUP,allGROUP(k));
+    
+    % Get nominal times for this TRT groups
+    NT_TRT = unique(datak.NT);
+    
+    % Determine missing IDs at each nominal time point
+    MISSING_OVER_TIME = {};
+    allID = unique(datak.USUBJID);
+    for k2=1:length(NT_TRT),
+        datak2 = datak(datak.NT==NT_TRT(k2),:);
+        IDs_NT = unique(datak2.USUBJID);
+        MISSING_OVER_TIME{k2} = setdiff(allID,IDs_NT);
+    end
+    
+    % Determine all IDs that are missing at least one of the cumulative
+    % nominal times across the whole GROUP.
+    allIDmissing = [];
+    for k2=1:length(MISSING_OVER_TIME),
+        allIDmissing = [allIDmissing; MISSING_OVER_TIME{k2}];
+    end
+    allIDmissing = unique(allIDmissing);
+    
+    % If there are some subjects in which NOMINAL TIMES are missing, then
+    % analyze more in detail
+    if ~isempty(allIDmissing),
+        
+        VISIT_DONE = zeros(length(allIDmissing),length(NT_TRT));
+        
+        % Loop through all the nominal times to determine which visit was
+        % done and which was not done.
+        for k2=1:length(allIDmissing),
+            
+            % Get subject data
+            datak2 = subsetIQM(datak,'USUBJID',allIDmissing(k2));
+            
+            % Determine baseline value for NAME
+            baseline_list = IQMdataGetBaselineValues(datak2,NAME);
+            BASELINE_NAME = table2array(baseline_list(1,2));
+            
+            % Cycle through all NT points across GROUP
+            for k3=1:length(NT_TRT),
+                datakk3 = subsetIQM(datak2,'NT',NT_TRT(k3));
+                
+                if ~isempty(datakk3),
+                    % Determine level of response ... to be able to color
+                    % code this in the plot
+                    
+                    % Get readout of NAME
+                    VALUE_NAME = datakk3.VALUE;
+                    
+                    % Determine relative change from baseline
+                    CHANGE = 100*(VALUE_NAME-BASELINE_NAME)./BASELINE_NAME;
+                    
+                    % If change better than user specified value (need to take care
+                    % of sign)
+                    if isempty(PD_IMPROVEMENT),
+                        % Possible to have PD_IMPROVEMENT empty if not needed.
+                        if ~isnan(VALUE_NAME),
+                            VISIT_DONE(k2,k3) = 1;
+                        end
+                    elseif length(PD_IMPROVEMENT) == 1,
+                        if PD_IMPROVEMENT>0 && CHANGE>=PD_IMPROVEMENT,
+                            VISIT_DONE(k2,k3) = 2;
+                        elseif PD_IMPROVEMENT<=0 && CHANGE<=PD_IMPROVEMENT,
+                            VISIT_DONE(k2,k3) = 2;
+                        elseif ~isnan(VALUE_NAME),
+                            VISIT_DONE(k2,k3) = 1;
+                        end
+                    else
+                        error('PD_IMPROVEMENT needs to be a scalar numeric value.');
+                    end
+                end
+            end
+        end
+        Y = sortrows([allIDmissing num2cell(sum(VISIT_DONE>=1,2)) num2cell(VISIT_DONE)],2);
+        figure; clf
+        % plot for legend purposes
+        plot(0,-10,'rx','MarkerSize',15,'LineWidth',2); hold on;
+        plot(0,-10,'k.','MarkerSize',25);
+        plot(0,-10,'b.','MarkerSize',25);
+        
+        for k2=1:length(allIDmissing),
+            IDk = Y{k2,1};
+            datak = cell2mat(Y(k2,3:end));
+            TIMEk = NT_TRT(find(datak==0));
+            if ~isempty(TIMEk), plot(TIMEk,k2,'rx','MarkerSize',15,'LineWidth',2); hold on; end
+            TIMEk = NT_TRT(find(datak==1));
+            if ~isempty(TIMEk), plot(TIMEk,k2,'k.','MarkerSize',25); hold on; end
+            TIMEk = NT_TRT(find(datak==2));
+            if ~isempty(TIMEk), plot(TIMEk,k2,'b.','MarkerSize',25); hold on; end
+        end
+        xlabel(sprintf('Nominal Time [%s]',data.TIMEUNIT{1}),'FontSize',14,'Interpreter','none');
+        set(gca,'YTick',[1:length(allIDmissing)]);
+        set(gca,'YTickLabel',strrep(Y(:,1),'_','-'));
+        set(gca,'FontSize',12);
+        grid on
+        if ~isempty(PD_IMPROVEMENT),
+            if isnumeric(allGROUP(1)),
+            	title(sprintf('Missing observations assessment (%s)\n%s: %d\nBlue: improvement by at least %g%%',NAME,GROUP,allGROUP(k),PD_IMPROVEMENT),'FontSize',16,'Interpreter','none')
+            else
+            	title(sprintf('Missing observations assessment (%s)\n%s: %s\nBlue: improvement by at least %g%%',NAME,GROUP,allGROUP{k},PD_IMPROVEMENT),'FontSize',16,'Interpreter','none')
+            end
+        else
+            if isnumeric(allGROUP(1)),            
+                title(sprintf('Missing observations assessment (%s)\n%s: %d',NAME,GROUP,allGROUP(k)),'FontSize',16,'Interpreter','none')
+            else
+                title(sprintf('Missing observations assessment (%s)\n%s: %s',NAME,GROUP,allGROUP{k}),'FontSize',16,'Interpreter','none')
+            end
+        end
+        YLim = get(gca,'YLim');
+        set(gca,'YLim',[0.5 YLim(2)+0.5])
+        % Legend
+        if ~isempty(PD_IMPROVEMENT),
+            legend({'Missed observation','Observation', [num2str(PD_IMPROVEMENT) '% improvement or more']},'Location','EastOutside')
+        else
+            legend({'Missed observation','Observation'},'Location','EastOutside')
+        end
+        
+        IQMprintFigure(gcf,filename)
+        if ~isempty(filename),
+            close(gcf);
+        end
+    
+    end
+end
+
+if ~fileappend,
+    IQMconvert2pdf(filename);
+end
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexploreNTvsTIME.m b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexploreNTvsTIME.m
new file mode 100644
index 0000000000000000000000000000000000000000..d2c5a7d395446a4ed468364942c006b7af227d9d
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexploreNTvsTIME.m	
@@ -0,0 +1,52 @@
+function [] = IQMexploreNTvsTIME(data,GROUP)
+% Function plotting NT vs TIME. Using the general dataset format
+% or the general task specific dataset.
+%
+% [SYNTAX]
+% [] = IQMplotNTvsTIME(data)
+% [] = IQMplotNTvsTIME(data,GROUP)
+%
+% [INPUT]
+% data:     Dataset in task specific standard data format or in
+%           general data format
+% GROUP:    Name of the column to use as grouping variable. By default
+%           "TRTNAME" is used.
+%
+% [OUTPUT]
+% Single plot with desired information.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Check data
+data = IQMcheckGeneralDataFormatHeader(data);
+
+% Handle variable input arguments
+if nargin == 1,
+    GROUP = 'TRTNAME';
+end
+
+% Get needed columns
+data2 = data(:,{'TIME' 'NT' GROUP});
+
+% Get colors
+colors = IQMgetcolors();
+
+% Plot TIME vs. NT
+figure; clf
+allGROUP    = unique(data2.(GROUP));
+legendText  = {};
+for k=1:length(allGROUP),  
+    datax           = subsetIQM(data2,GROUP,allGROUP(k));
+    plot(datax.TIME,datax.NT,'.','MarkerSize',25,'Color',colors(k,:)); hold on
+    if isnumeric(allGROUP(k)),
+        legendText{k}   = sprintf('%s: %d',GROUP,allGROUP(k));
+    else
+        legendText{k}   = sprintf('%s: %s',GROUP,allGROUP{k});
+    end        
+end
+grid on;
+xlabel('TIME','FontSize',14,'Interpreter','none')
+ylabel('NOMINAL_TIME (NT)','FontSize',14,'Interpreter','none')
+title('Comparison between TIME and NOMINAL_TIME (NT)','FontSize',16,'Interpreter','none')
+set(gca,'FontSize',12)
+legend(legendText,'Location','Best','Interpreter','none')
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexplorePDdataWrapper.m b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexplorePDdataWrapper.m
new file mode 100644
index 0000000000000000000000000000000000000000..3d15eef6073b04c91003c4c082a186e56c54ac08
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexplorePDdataWrapper.m	
@@ -0,0 +1,492 @@
+function [] = IQMexplorePDdataWrapper(data,DOSENAMES,OBSNAMES,TYPE,TIME,covNames,catNames,options)
+% Function generating typical plots for PD data - bot continuous and
+% categorical. Giving a reasonably fast overview of the available data to
+% support further analysis by modeling. 
+%
+% The function works both on the general dataset format and the task
+% specific dataset format. 
+%
+% MDV=1 observations and observations with IGNORE entry are NOT considered
+% in the plotting. 
+%
+% [SYNTAX]
+% [] = IQMexplorePDdataWrapper(data,DOSENAMES,OBSNAMES)
+% [] = IQMexplorePDdataWrapper(data,DOSENAMES,OBSNAMES,TYPE)
+% [] = IQMexplorePDdataWrapper(data,DOSENAMES,OBSNAMES,TYPE,TIME)
+% [] = IQMexplorePDdataWrapper(data,DOSENAMES,OBSNAMES,TYPE,TIME,covNames)
+% [] = IQMexplorePDdataWrapper(data,DOSENAMES,OBSNAMES,TYPE,TIME,covNames,catNames)
+% [] = IQMexplorePDdataWrapper(data,DOSENAMES,OBSNAMES,TYPE,TIME,covNames,catNames,options)
+%
+% [INPUT]
+% data:         Dataset in general or task specific format.
+% DOSENAMES:    String with the NAME of the dose event as stored in the
+%               NAME column. Can also be a cell-array with all event NAMES
+%               to be considered dosing. 
+% OBSNAMES:     String with the NAME of the observation (PD) event as
+%               stored in the NAME column. Can also be a cell-array with
+%               all event NAMES to be considered PD observations. 
+% TYPE:         'continuous' for continuous PD readout
+%               'categorical' for categorical PD readout
+%               default: inferred ... if two elements (0 and 1) in VALUE
+%               then assume it to be categorical - otherwise continuous.
+% TIME:         Approximate time(NT) to consider for change from
+%               baseline calculations for distributions etc.
+%               Default: [] => no assessment of change from baseline for
+%               these plots
+% covNames:     Cell-array with the names of the continuous covariates, as
+%               defined in the dataset as columns.
+%               Default: {} => no covariate assessments
+% catNames:     Cell-array with the names of the categorical covariates, as
+%               defined in the dataset as columns.
+%               Default: {} => no covariate assessments
+% options:      MATLAB structure with additional options
+%
+%               options.outputPath: path where
+%                                 outputs are exported to. Default:
+%                                 '../Output/DataExploration_"OBSNAME"/';
+%
+% [OUTPUT]
+% Several PDF documents with plots. The names of the
+% files tell what is shown. also a summary statistic of the data as an
+% exported file. Covariate information, etc.
+% In case of multiple elements in DOSENAMES and OBSNAMES, the same plots
+% will be generated for each combination of the elements.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Variable input arguments
+if nargin < 4,
+    TYPE = '';
+end
+if nargin < 5,
+    TIME = [];
+end
+if nargin < 6,
+    covNames = {};
+end
+if nargin < 7,
+    catNames = {};
+end
+if nargin < 8,
+    options = [];
+end
+
+% Handle options
+try outputPath          = [options.outputPath '/'];     catch, outputPath           = '';       end
+
+% Check dataset to be at least in the general dataset format
+data = IQMcheckGeneralDataFormatHeader(data);
+
+% Handle missing VALUEs for VALUE_TEXTs
+data = IQMgenerateVALUEfromVALUE_TEXT(data);
+
+% Check if task specific dataset and if not then convert
+try
+    data = IQMcheckTaskDatasetHeader(data);
+catch
+    data = IQMconvertGeneral2TaskDataset(data,DOSENAMES,OBSNAMES);
+end
+
+% Check cell
+if ischar(OBSNAMES),
+    OBSNAMES = {OBSNAMES};
+end
+if ischar(DOSENAMES),
+    DOSENAMES = {DOSENAMES};
+end
+
+% Check covariates
+checkDataColumnsIQM(data,covNames)
+checkDataColumnsIQM(data,catNames)
+
+% Handle default TYPE
+if isempty(TYPE),
+    TYPE = 'continuous';
+    VALUES = unique(data.VALUE(ixdataIQM(data,'NAME',OBSNAMES)));
+    if length(VALUES) == 2,
+        if min(VALUES) == 0 && max(VALUES) == 1,
+            TYPE = 'categorical';
+        end
+    end
+end
+
+% Generate plots for all combinations of DOSENAME and OBSNAME
+for kDose=1:length(DOSENAMES),
+    dataUSE = data;
+    % Check availability of TAD_"name" ... and in this case use this as TAD
+    check_TAD_column = sprintf('TAD_%s',makeVariableNameIQM(DOSENAMES{1}));
+    ix = strmatchIQM(check_TAD_column,dataUSE.Properties.VariableNames,'exact');
+    if ~isempty(ix),
+        % Update TAD column with the correct one for the selected dose
+        dataUSE.TAD = dataUSE.(check_TAD_column);
+    end
+    % Check availability of DOSE_"name" and in this case use this as DOSE
+    check_DOSE_column = sprintf('DOSE_%s',makeVariableNameIQM(DOSENAMES{1}));
+    ix = strmatchIQM(check_DOSE_column,dataUSE.Properties.VariableNames,'exact');
+    if ~isempty(ix),
+        % Update DOSE column with the correct one for the selected dose
+        dataUSE.DOSE = dataUSE.(check_DOSE_column);
+    end
+    
+    for kObs=1:length(OBSNAMES),
+        % Use this output path 
+        outputPathCombination = sprintf('%s%s_%s',outputPath,regexprep(DOSENAMES{kDose},'\W',''),regexprep(OBSNAMES{kObs},'\W',''));
+        % Exept in the case where only one combination and an outputPath
+        % defined by the user.
+        if length(DOSENAMES)*length(OBSNAMES) == 1,
+            if ~isempty(outputPath),
+                outputPathCombination = outputPath;
+            end
+        end
+        doPlot_DOSE_OBS(dataUSE,DOSENAMES(kDose),OBSNAMES(kObs),TYPE,TIME,covNames,catNames,outputPathCombination)
+    end
+end
+
+return
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Auxiliary function to do the plotting for a single DOSE/OBS combination
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [] = doPlot_DOSE_OBS(data,DOSENAME,OBSNAME,TYPE,TIME,covNames,catNames,outputPath)
+
+% Remove MDV=1 observations
+data(data.MDV==1 & data.EVID==0,:) = [];
+
+% Remove IGNOREs records
+data(~strcmp(data.IGNORE,''),:) = [];
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Data contents information
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+IQMexploreDataContents(data,DOSENAME,OBSNAME,[outputPath '/00_Data_Contents']);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Summary plot individual data on linear Y axis
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+options                 = [];
+options.logY            = 0;
+options.showDose        = 0;
+options.showText        = 0;
+options.nIDperPage      = 36;
+options.sameaxes        = 1;
+options.nameGroup       = 'USUBJID';
+options.titlefontsize   = 8;
+options.filename        = [outputPath '/01_Individual_Summary_Linear'];
+IQMexploreIndivData(data,OBSNAME,'',options)
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Plot individual data - 1 page per ID - linear Y axis
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+options                 = [];
+options.logY            = 0;
+options.showDose        = 1;
+options.showText        = 1;
+options.nIDperPage      = 1;
+options.sameaxes        = 0;
+options.nameGroup       = 'USUBJID';
+options.filename        = [outputPath '/02_Individual_Single_Linear'];
+IQMexploreIndivData(data,OBSNAME,DOSENAME,options)
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Assessment of data availability TRT/STUDY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+filename    = [outputPath '/03_Summary_Study_Treatment'];
+IQMstartNewPrintFigure(filename);
+dataPlot                    = subsetIQM(data,'NAME',OBSNAME);
+% Do the plot
+nameGroupX                  = 'TRTNAME';
+nameGroupY                  = 'STUDY';
+nameY                       = 'VALUE';
+nameX                       = 'TIME';
+options                     = [];
+options.nameSubGroup        = 'USUBJID';
+options.linetype            = '--';
+options.linewidth           = 1;
+options.xlabelText          = sprintf('Time [%s]',dataPlot.TIMEUNIT{1});
+nY                          = length(unique(dataPlot.(nameGroupY)));
+options.ylabelText          = {};
+for k=1:nY, options.ylabelText{k} = ''; end
+if nY==1,
+    options.ylabelText{1}   = sprintf('%s [%s]',dataPlot.NAME{1},dataPlot.UNIT{1});
+else
+    options.ylabelText{floor(nY/2)} = sprintf('%s [%s]',dataPlot.NAME{1},dataPlot.UNIT{1});
+end
+options.logY                = 1;
+options.sameaxes            = 1;
+options.linecolor           = 0.2*[1 1 1];
+options.axescolor           = 0.2*[1 1 1];
+options.maxlegendentries    = 20;
+options.titlefontsize       = 8;
+options.labeltextsize       = 8;
+options.ticklabeltextsize   = 8;
+IQMplotfacetgrid(dataPlot,nameX,nameY,nameGroupX,nameGroupY,options)
+IQMprintFigure(gcf,filename);
+close(gcf);
+IQMconvert2pdf(filename);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Summary statistics covariates
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(covNames) || ~isempty(catNames),
+    filename    = [outputPath '/04_Summary_Statistics'];
+    IQMexploreSummaryStats(subsetIQM(data,'NAME',OBSNAME),covNames,catNames,filename);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Graphical exploration of covariates
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(covNames) || ~isempty(catNames),
+    filename    = [outputPath '/05_Covariates'];
+    IQMexploreCovariateCorrelations(subsetIQM(data,'NAME',OBSNAME),covNames,catNames,filename);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Nominal time vs. actual time by TRTNAME
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+figure(1); clf
+IQMexploreNTvsTIME(subsetIQM(data,'NAME',OBSNAME),'TRTNAME')
+IQMprintFigure(gcf,[outputPath '/06_NOMINAL_TIME_vs_TIME'],'pdf');
+close(gcf);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Rate of missing observations over time by TRTNAME
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+options = [];
+options.fontsize = 10;
+IQMexploreMissingEventRate(subsetIQM(data,'NAME',OBSNAME),'TRTNAME',options)
+IQMprintFigure(gcf,[outputPath '/07_Missing_Observations_Rate'],'pdf');
+close(gcf);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Rate of missing observations over time by TRTNAME
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+options = [];
+options.filename = [outputPath '/08_Missing_Observations_Graphics'];
+try
+    IQMexploreMissingObservationGraphics(data,OBSNAME,'TRTNAME',options)
+catch
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Plot 
+% - Median for continuous
+% - Responder rates for categorical
+%
+% 1) with error bars
+% 2) without error bars
+% 3) if continuous then also relative change from baseline with error bars
+% 4) if continuous then also relative change from baseline without bars
+%
+% Same plots once in same figure and once split in subplots by TRTNAME
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try
+    filename = [outputPath '/09_Median_RR_Information'];
+    IQMstartNewPrintFigure(filename);
+    
+    % Absolute with error bars
+    options = [];
+    options.filename        = filename;
+    options.fileappend      = 1;
+    options.singleplot      = 1;
+    options.error_bars      = 1;
+    options.absolute        = 1;
+    options.showN           = 0;
+    options.fontsize        = 12;
+    IQMexploreDataMedian(data,OBSNAME,TYPE,'TRTNAME',options)
+    % Absolute without error bars
+    options.error_bars      = 0;
+    IQMexploreDataMedian(data,OBSNAME,TYPE,'TRTNAME',options)
+    if strcmp(TYPE,'continuous'),
+        % Relative with error bars
+        options.error_bars      = 1;
+        options.absolute        = 0;
+        IQMexploreDataMedian(data,OBSNAME,TYPE,'TRTNAME',options)
+        
+        % Relative without error bars
+        options.error_bars      = 0;
+        options.absolute        = 0;
+        IQMexploreDataMedian(data,OBSNAME,TYPE,'TRTNAME',options)
+    end
+    
+    % Absolute with error bars
+    options.singleplot      = 0;
+    options.error_bars      = 1;
+    options.absolute        = 1;
+    options.showN           = 1;
+    options.fontsize        = 10;
+    IQMexploreDataMedian(data,OBSNAME,TYPE,'TRTNAME',options)
+    % Absolute without error bars
+    options.error_bars      = 0;
+    IQMexploreDataMedian(data,OBSNAME,TYPE,'TRTNAME',options)
+    if strcmp(TYPE,'continuous'),
+        % Relative with error bars
+        options.error_bars      = 1;
+        options.absolute        = 0;
+        IQMexploreDataMedian(data,OBSNAME,TYPE,'TRTNAME',options)
+        
+        % Relative without error bars
+        options.error_bars      = 0;
+        options.absolute        = 0;
+        IQMexploreDataMedian(data,OBSNAME,TYPE,'TRTNAME',options)
+    end
+    IQMconvert2pdf(filename);
+catch
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Plot stratified by median covariate
+% - Median for continuous
+% - Responder rates for categorical
+%
+% 1) absolute
+% 2) if continuous then also relative change from baseline
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try
+    filename = [outputPath '/10_Median_RR_Information_Covariates'];
+    IQMstartNewPrintFigure(filename);
+    
+    % Median curves over nominal time for each TRT group stratified by covariates (>median, <=median)
+    options = [];
+    options.absolute    = 1;
+    options.filename    = filename;
+    options.fileappend  = 1;
+    options.fontsize    = 10;
+    IQMexploreDataMedianCovariates(data,OBSNAME,TYPE,[covNames catNames],'TRTNAME',options)
+    
+    if strcmp(TYPE,'continuous'),
+        % Median curves (relative change from first measurement) over nominal time for each TRT group stratified by covariates (>median, <=median)
+        options.absolute    = 0;
+        IQMexploreDataMedianCovariates(data,OBSNAME,TYPE,[covNames catNames],'TRTNAME',options)
+    end
+    IQMconvert2pdf(filename);
+catch
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Plot variability range of data and individual plots
+% Only for continuous data
+% Absolute
+% Relative change from baseline
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try
+    if strcmp(TYPE,'continuous'),
+        filename = [outputPath '/11_Data_Variability'];
+        IQMstartNewPrintFigure(filename);
+        
+        options = [];
+        options.singleplot = 0;
+        options.filename   = filename;
+        options.fileappend = 1;
+        
+        % Absolute PD - NOMINAL TIME / Median+Range
+        options.individual = 0;
+        options.absolute   = 1;
+        IQMexploreDataVariability(data,OBSNAME,'TRTNAME',options);
+        
+        % Absolute PD - TIME / Individual plots
+        options.individual = 1;
+        options.absolute   = 1;
+        IQMexploreDataVariability(data,OBSNAME,'TRTNAME',options);
+        
+        % Relative PD - only if baseline not 0
+        options.individual = 0;
+        options.absolute   = 0;
+        IQMexploreDataVariability(data,OBSNAME,'TRTNAME',options);
+        
+        % Relative PD - TIME / Individual plots - if baseline not 0
+        options.individual = 1;
+        options.absolute   = 0;
+        IQMexploreDataVariability(data,OBSNAME,'TRTNAME',options);
+        
+        IQMconvert2pdf(filename);
+    end
+catch
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Plot distribution at different time points
+% Only for continuous data
+% Absolute at baseline
+% Absolute at defined timepoint
+% Absolute change at defined timepoint (from baseline)
+% Relative change at defined timepoint (from baseline)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try
+    if strcmp(TYPE,'continuous'),
+        filename = [outputPath '/12_Data_Distribution'];
+        IQMstartNewPrintFigure(filename);
+        
+        options = [];
+        options.singleplot = 0;
+        options.filename   = filename;
+        options.fileappend = 1;
+        
+        % Plot distribution of data at baseline
+        options.absolute    = 1;
+        options.change      = 0;
+        IQMexploreDistribution(data,OBSNAME,'TRTNAME',[],options);
+        
+        if ~isempty(TIME),
+            % Plot at user defined timepoint - if time point defined
+            options.absolute    = 1;
+            options.change      = 0;
+            IQMexploreDistribution(data,OBSNAME,'TRTNAME',TIME,options);
+            
+            % Absolute change at user defined time point (if time point is defined)
+            options.absolute    = 1;
+            options.change      = 1;
+            IQMexploreDistribution(data,OBSNAME,'TRTNAME',TIME,options);
+            
+            % Relative change from baseline in percent at user defined time point (if defined)
+            options.absolute    = 0;
+            options.change      = 0;
+            IQMexploreDistribution(data,OBSNAME,'TRTNAME',TIME,options);
+        end
+        IQMconvert2pdf(filename);
+    end
+catch
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Plot correlation between absolute and relative changes (TIME vs.
+% baseline) and covariates. Only if TIME defined and only for continuous
+% data 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try
+    if strcmp(TYPE,'continuous') && ~isempty(TIME),
+        filename = [outputPath '/13_Changes_vs_Covariates'];
+        IQMstartNewPrintFigure(filename);
+        
+        options = [];
+        options.filename   = filename;
+        options.fileappend = 1;
+        
+        % Absolute changes vs. covariates
+        options.absolute   = 1;
+        IQMexploreDistributionCorrelation(data,OBSNAME,[covNames catNames],TIME,'TRTNAME',options)
+        
+        % Relative changes vs. covariates
+        options.absolute   = 0;
+        IQMexploreDistributionCorrelation(data,OBSNAME,[covNames catNames],TIME,'TRTNAME',options)
+        
+        IQMconvert2pdf(filename);
+    end
+catch
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Assessment of BLLOQ data
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+IQMexploreBLLOQdata(subsetIQM(data,'NAME',OBSNAME),[outputPath '/14_BLLOQ_Information']);
+
+close all
+
+
+
+
+
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexplorePKdataWrapper.m b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexplorePKdataWrapper.m
new file mode 100644
index 0000000000000000000000000000000000000000..201ea4ffeb2d7b00415b30a213b5d5a8fbb683fc
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexplorePKdataWrapper.m	
@@ -0,0 +1,704 @@
+function [] = IQMexplorePKdataWrapper(data,DOSENAMES,OBSNAMES,covNames,catNames,options)
+% Function generating typical standard plots for dose and PK data. Giving a
+% reasonably fast overview of the available data to support further
+% analysis by modeling. Can be used on other data than PK if desired.
+%
+% The function works both on the general dataset format and the task
+% specific dataset format. 
+%
+% MDV=1 observations and observations with IGNORE entry are NOT considered
+% in the plotting. 
+%
+% [SYNTAX]
+% [] = IQMexplorePKdataWrapper(data,DOSENAMES,OBSNAMES)
+% [] = IQMexplorePKdataWrapper(data,DOSENAMES,OBSNAMES,covNames)
+% [] = IQMexplorePKdataWrapper(data,DOSENAMES,OBSNAMES,covNames,catNames)
+% [] = IQMexplorePKdataWrapper(data,DOSENAMES,OBSNAMES,covNames,catNames,options)
+%
+% [INPUT]
+% data:         Dataset in general or task specific format.
+% DOSENAMES:    String with the NAME of the dose event as stored in the
+%               NAME column. Can also be a cell-array with all event NAMES
+%               to be considered dosing. In the case that multiple dosing
+%               event names are provided, the OBSNAMES argument has to
+%               provide the same number of observations and it will be
+%               assumed that the n-th entry of DOSENAMES corresponds to the
+%               n-th entry in OBSNAMES.
+% OBSNAMES:     String with the NAME of the observation (PK) event as
+%               stored in the NAME column. Can also be a cell-array with
+%               all event NAMES to be considered PK observations. 
+% covNames:     Cell-array with the names of the continuous covariates, as
+%               defined in the dataset as columns.
+% catNames:     Cell-array with the names of the categorical covariates, as
+%               defined in the dataset as columns.
+% options:      MATLAB structure with additional options
+%
+%               options.color:    =0: use black and white where necessary,
+%                                 =1: use color (default)
+%               options.outputPath: path where
+%                                 outputs are exported to. Default:
+%                                 '"DOSENAME_OBSNAME"';
+%
+% [OUTPUT]
+% Several PDF documents with plots. The names of the files tell what is
+% shown. also a summary statistic of the data as a text file. Covariate
+% information, etc. 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Variable input arguments
+if nargin < 4,
+    covNames = {};
+end
+if nargin < 5,
+    catNames = {};
+end
+if nargin < 6,
+    options = [];
+end
+
+% Handle options
+try outputPath          = [options.outputPath '/'];     catch, outputPath           = '';       end
+try color               = options.color;                catch, color                = 1;        end
+
+% Handle cell
+if ischar(covNames),
+    covNames = {covNames};
+end
+if ischar(catNames),
+    catNames = {catNames};
+end
+
+% Check dataset to be at least in the general dataset format
+data = IQMcheckGeneralDataFormatHeader(data);
+
+% Check if task specific dataset and if not then convert
+try
+    data = IQMcheckTaskDatasetHeader(data);
+catch
+    data = IQMconvertGeneral2TaskDataset(data,DOSENAMES,OBSNAMES);
+end
+
+% Check cell
+if ischar(OBSNAMES),
+    OBSNAMES = {OBSNAMES};
+end
+if ischar(DOSENAMES),
+    DOSENAMES = {DOSENAMES};
+end
+
+% Check numbers
+if length(DOSENAMES) > 1,
+    if length(DOSENAMES) ~= length(OBSNAMES),
+        error('If multiple DOSENAMES provided, then OBSNAMES has to have matching length with matching PK readouts.');
+    end
+end
+
+% Check covariates
+checkDataColumnsIQM(data,covNames)
+checkDataColumnsIQM(data,catNames)
+
+% Generate plots for case where single DOSENAMES entry present
+% Then combine each output with the single dose
+if length(DOSENAMES)==1,
+    dataUSE = data;
+    % Check availability of TAD_"name" ... and in this case use this as TAD
+    check_TAD_column = sprintf('TAD_%s',makeVariableNameIQM(DOSENAMES{1}));
+    ix = strmatchIQM(check_TAD_column,dataUSE.Properties.VariableNames,'exact');
+    if ~isempty(ix),
+        % Update TAD column with the correct one for the selected dose
+        dataUSE.TAD = dataUSE.(check_TAD_column);
+    end
+    % Check availability of DOSE_"name" and in this case use this as DOSE
+    check_DOSE_column = sprintf('DOSE_%s',makeVariableNameIQM(DOSENAMES{1}));
+    ix = strmatchIQM(check_DOSE_column,dataUSE.Properties.VariableNames,'exact');
+    if ~isempty(ix),
+        % Update DOSE column with the correct one for the selected dose
+        dataUSE.DOSE = dataUSE.(check_DOSE_column);
+    end
+    % Cycle through OBSNAMES and plot the PK plots
+    for kObs=1:length(OBSNAMES),
+        % Use this output path
+        outputPathCombination = sprintf('%s%s_%s',outputPath,makeVariableNameIQM(DOSENAMES{1}),makeVariableNameIQM(OBSNAMES{kObs}));
+        % Exept in the case where only one combination and an outputPath
+        % defined by the user.
+        if length(DOSENAMES)*length(OBSNAMES) == 1,
+            if ~isempty(outputPath),
+                outputPathCombination = outputPath;
+            end
+        end
+        doPlot_DOSE_OBS(dataUSE,DOSENAMES(1),OBSNAMES(kObs),covNames,catNames,color,outputPathCombination)
+    end
+else
+    % Handle multiple doses and observations and assume n-th dose
+    % corresponds to n-th observation
+    for kDose=1:length(DOSENAMES),
+        
+        % Get data to use
+        dataUSE = data;
+        
+        % Check availability of TAD_"name" ... and in this case use this as TAD
+        check_TAD_column = sprintf('TAD_%s',makeVariableNameIQM(DOSENAMES{1}));
+        ix = strmatchIQM(check_TAD_column,dataUSE.Properties.VariableNames,'exact');
+        if ~isempty(ix),
+            % Update TAD column with the correct one for the selected dose
+            dataUSE.TAD = dataUSE.(check_TAD_column);
+        end
+        % Check availability of DOSE_"name" and in this case use this as DOSE
+        check_DOSE_column = sprintf('DOSE_%s',makeVariableNameIQM(DOSENAMES{1}));
+        ix = strmatchIQM(check_DOSE_column,dataUSE.Properties.VariableNames,'exact');
+        if ~isempty(ix),
+            % Update DOSE column with the correct one for the selected dose
+            dataUSE.DOSE = dataUSE.(check_DOSE_column);
+        end
+        
+        % Use this output path
+        outputPathCombination = sprintf('%s%s_%s',outputPath,makeVariableNameIQM(DOSENAMES{kDose}),makeVariableNameIQM(OBSNAMES{kDose}));
+        
+        % Plot
+        doPlot_DOSE_OBS(dataUSE,DOSENAMES(kDose),OBSNAMES(kDose),covNames,catNames,color,outputPathCombination)
+    end
+end
+
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Auxiliary function to do the plotting for a single DOSE/OBS combination
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [] = doPlot_DOSE_OBS(data,DOSENAME,OBSNAME,covNames,catNames,color,outputPath)
+
+% Remove MDV=1 observations
+data(data.MDV==1 & data.EVID==0,:) = [];
+
+% Remove IGNOREs records
+data(~strcmp(data.IGNORE,''),:) = [];
+
+% Get colors etc
+[~,~,dots,bwcolors] = IQMgetcolors();
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Data contents information
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+IQMexploreDataContents(data,DOSENAME,OBSNAME,[outputPath '/00_Data_Contents']);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Summary plot individual data on linear Y axis
+% Show BLLOQ data by different marker and color
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+options                 = [];
+options.logY            = 0;
+options.showDose        = 0;
+options.showText        = 0;
+options.nIDperPage      = 36;
+options.sameaxes        = 1;
+options.nameGroup       = 'USUBJID';
+options.titlefontsize   = 8;
+options.filename        = [outputPath '/01_Individual_Summary_Linear'];
+IQMexploreIndivData(data,OBSNAME,'',options)
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Summary plot individual data on logarithmic Y axis
+% Show BLLOQ data by different marker and color
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+options                 = [];
+options.logY            = 1;
+options.showDose        = 0;
+options.showText        = 0;
+options.nIDperPage      = 36;
+options.sameaxes        = 1;
+options.nameGroup       = 'USUBJID';
+options.titlefontsize   = 8;
+options.filename        = [outputPath '/02_Individual_Summary_Log'];
+IQMexploreIndivData(data,OBSNAME,'',options)
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Plot individual data - 1 page per ID - linear Y axis
+% Show BLLOQ data by different marker and color
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+options                 = [];
+options.logY            = 0;
+options.showDose        = 1;
+options.showText        = 1;
+options.nIDperPage      = 1;
+options.sameaxes        = 0;
+options.nameGroup       = 'USUBJID';
+options.filename        = [outputPath '/03_Individual_Single_Linear'];
+IQMexploreIndivData(data,OBSNAME,DOSENAME,options)
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Plot individual data - 1 page per ID - log Y axis
+% Show BLLOQ data by different marker and color
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+options                 = [];
+options.logY            = 1;
+options.showDose        = 1;
+options.showText        = 1;
+options.nIDperPage      = 1;
+options.sameaxes        = 0;
+options.nameGroup       = 'USUBJID';
+options.filename        = [outputPath '/04_Individual_Single_Log'];
+IQMexploreIndivData(data,OBSNAME,DOSENAME,options)
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Assessment of data availability TRT/STUDY
+% Show BLLOQ data by different marker and color
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+filename    = [outputPath '/05_Summary_Study_Treatment'];
+IQMstartNewPrintFigure(filename);
+dataPlot                    = subsetIQM(data,'NAME',OBSNAME);
+% Do the plot
+nameGroupX                  = 'TRTNAME';
+nameGroupY                  = 'STUDY';
+nameY                       = 'VALUE';
+nameX                       = 'TIME';
+options                     = [];
+options.nameSubGroup        = 'USUBJID';
+options.linetype            = '--';
+options.linewidth           = 1;
+options.xlabelText          = sprintf('Time [%s]',dataPlot.TIMEUNIT{1});
+nY                          = length(unique(dataPlot.(nameGroupY)));
+options.ylabelText          = {};
+for k=1:nY, options.ylabelText{k} = ''; end
+if nY==1,
+    options.ylabelText{1}   = sprintf('%s [%s]',dataPlot.NAME{1},dataPlot.UNIT{1});
+else
+    options.ylabelText{floor(nY/2)} = sprintf('%s [%s]',dataPlot.NAME{1},dataPlot.UNIT{1});
+end
+options.logY                = 1;
+options.sameaxes            = 1;
+options.linecolor           = 0.2*[1 1 1];
+options.axescolor           = 0.2*[1 1 1];
+options.maxlegendentries    = 20;
+options.titlefontsize       = 8;
+options.labeltextsize       = 8;
+options.ticklabeltextsize   = 8;
+
+% Handle case of BLOQ data present
+BLLOQdataPresent = 0;
+% Check if dataPlot contains LLOQ information and if yes then check if BLLOQ data are present
+if sum(~isnan(dataPlot.LLOQ)) > 0,
+    % LLOQ information present
+    if sum(dataPlot.DV<dataPlot.LLOQ) > 0,
+        % BLLOQ data present
+        BLLOQdataPresent = 1;
+    end
+end
+if BLLOQdataPresent,
+    dataPlot.isBLLOQ            = double(dataPlot.DV<dataPlot.LLOQ);
+    options.nameColorGroup      = 'isBLLOQ';
+    options.linecolorsCustom    = [0.2 0.2 0.2; 0.8500    0.3250    0.0980];
+    options.linetypesCustom     = {'.-','x-'};
+    options.showmarkers         = 1;
+    options.markersize          = 12;
+end
+
+% Plot
+IQMplotfacetgrid(dataPlot,nameX,nameY,nameGroupX,nameGroupY,options)
+IQMprintFigure(gcf,filename);
+close(gcf);
+IQMconvert2pdf(filename);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Dose normalized plots - over TIME
+% Not considering BLOQ data (remove it prior to dose-normalization)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+filename    = [outputPath '/06_Dose_Normalized_TIME'];
+IQMstartNewPrintFigure(filename);
+
+%%%%%%%%%
+% Linear
+%%%%%%%%%
+dataPlot    = subsetIQM(data,'NAME',OBSNAME);
+% Remove BLLOQ data
+dataPlot(dataPlot.DV<dataPlot.LLOQ,:) = [];
+
+% Dose normalize the PK data
+DOSE = dataPlot.DOSE; DOSE(DOSE==0) = 1;
+dataPlot.DVnorm = dataPlot.DV./DOSE;
+% Remove inf and NaN values
+dataPlot(isnan(dataPlot.DVnorm),:) = [];
+dataPlot(isinf(dataPlot.DVnorm),:) = [];
+
+% Do the plot
+nameGroup   = 'STUDY';
+nameY       = 'DVnorm';
+nameX       = 'TIME';
+options     = [];
+options.linewidth = 1;
+options.nameSubGroup    = 'USUBJID';
+options.nameColorGroup  = 'TRTNAME';
+options.xlabelText = sprintf('Time [%s]',dataPlot.TIMEUNIT{1});
+options.ylabelText = sprintf('(DOSE NORMALIZED) %s - BLLOQ data not considered',dataPlot.NAME{1});
+options.ylabelfirstonly = 1;
+options.logY            = 0;
+options.showmedian       = 1;
+options.NbinsMedian      = 20;
+options.sameaxes        = 0;
+options.linetype        = '.';
+options.medianlinewidth  = 2;
+options.axescolor       = 0.2*[1 1 1];
+if ~color,
+    options.showmarkers      = 1;
+    options.linecolorsCustom = bwcolors;
+    options.markersize       = 8;
+    options.linetypesCustom  = dots;
+end
+options.maxlegendentries = 20;
+IQMplottrellis(dataPlot,nameGroup,nameX,nameY,options)
+IQMprintFigure(gcf,filename);
+close(gcf);
+
+%%%%%%%%%
+% Log
+%%%%%%%%%
+dataPlot    = subsetIQM(data,'NAME',OBSNAME);
+% Remove BLLOQ data
+dataPlot(dataPlot.DV<dataPlot.LLOQ,:) = [];
+
+% Dose normalize the PK data
+DOSE = dataPlot.DOSE; DOSE(DOSE==0) = 1;
+dataPlot.DVnorm = dataPlot.DV./DOSE;
+% Remove inf and NaN values
+dataPlot(isnan(dataPlot.DVnorm),:) = [];
+dataPlot(isinf(dataPlot.DVnorm),:) = [];
+
+% Do the plot
+nameGroup   = 'STUDY';
+nameY       = 'DVnorm';
+nameX       = 'TIME';
+options     = [];
+options.linewidth = 1;
+options.nameSubGroup    = 'USUBJID';
+options.nameColorGroup  = 'TRTNAME';
+options.xlabelText = sprintf('Time [%s]',dataPlot.TIMEUNIT{1});
+options.ylabelText = sprintf('(DOSE NORMALIZED) %s - BLLOQ data not considered',dataPlot.NAME{1});
+options.ylabelfirstonly = 1;
+options.logY            = 1;
+options.showmedian       = 1;
+options.NbinsMedian      = 20;
+options.sameaxes        = 0;
+options.linetype        = '.';
+options.medianlinewidth  = 2;
+options.axescolor       = 0.2*[1 1 1];
+if ~color,
+    options.showmarkers      = 1;
+    options.linecolorsCustom = bwcolors;
+    options.markersize       = 8;
+    options.linetypesCustom  = dots;
+end
+options.maxlegendentries = 20;
+IQMplottrellis(dataPlot,nameGroup,nameX,nameY,options)
+IQMprintFigure(gcf,filename);
+close(gcf);
+
+IQMconvert2pdf(filename);
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Dose normalized plots - over TAD
+% Not considering BLOQ data (remove it prior to dose-normalization)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+filename    = [outputPath '/07_Dose_Normalized_TAD'];
+IQMstartNewPrintFigure(filename);
+
+%%%%%%%%%
+% Linear
+%%%%%%%%%
+dataPlot    = subsetIQM(data,'NAME',OBSNAME);
+% Remove BLLOQ data
+dataPlot(dataPlot.DV<dataPlot.LLOQ,:) = [];
+
+% Dose normalize the PK data
+DOSE = dataPlot.DOSE; DOSE(DOSE==0) = 1;
+dataPlot.DVnorm = dataPlot.DV./DOSE;
+% Remove inf and NaN values
+dataPlot(isnan(dataPlot.DVnorm),:) = [];
+dataPlot(isinf(dataPlot.DVnorm),:) = [];
+
+% Do the plot
+nameGroup   = 'STUDY';
+nameY       = 'DVnorm';
+nameX       = 'TAD';
+options     = [];
+options.linewidth = 1;
+options.nameSubGroup    = 'USUBJID';
+options.nameColorGroup  = 'TRTNAME';
+options.xlabelText = sprintf('TAD [%s]',dataPlot.TIMEUNIT{1});
+options.ylabelText = sprintf('(DOSE NORMALIZED) %s - BLLOQ data not considered',dataPlot.NAME{1});
+options.ylabelfirstonly = 1;
+options.logY            = 0;
+options.showmedian       = 1;
+options.NbinsMedian      = 20;
+options.sameaxes        = 0;
+options.linetype        = '.';
+options.medianlinewidth  = 2;
+options.axescolor       = 0.2*[1 1 1];
+if ~color,
+    options.showmarkers      = 1;
+    options.linecolorsCustom = bwcolors;
+    options.markersize       = 8;
+    options.linetypesCustom  = dots;
+end
+options.maxlegendentries = 20;
+IQMplottrellis(dataPlot,nameGroup,nameX,nameY,options)
+IQMprintFigure(gcf,filename);
+close(gcf);
+
+%%%%%%%%%
+% Log
+%%%%%%%%%
+dataPlot    = subsetIQM(data,'NAME',OBSNAME);
+% Remove BLLOQ data
+dataPlot(dataPlot.DV<dataPlot.LLOQ,:) = [];
+
+% Dose normalize the PK data
+DOSE = dataPlot.DOSE; DOSE(DOSE==0) = 1;
+dataPlot.DVnorm = dataPlot.DV./DOSE;
+% Remove inf and NaN values
+dataPlot(isnan(dataPlot.DVnorm),:) = [];
+dataPlot(isinf(dataPlot.DVnorm),:) = [];
+
+% Do the plot
+nameGroup   = 'STUDY';
+nameY       = 'DVnorm';
+nameX       = 'TAD';
+options     = [];
+options.linewidth = 1;
+options.nameSubGroup    = 'USUBJID';
+options.nameColorGroup  = 'TRTNAME';
+options.xlabelText = sprintf('TAD [%s]',dataPlot.TIMEUNIT{1});
+options.ylabelText = sprintf('(DOSE NORMALIZED) %s - BLLOQ data not considered',dataPlot.NAME{1});
+options.ylabelfirstonly = 1;
+options.logY            = 1;
+options.showmedian       = 1;
+options.NbinsMedian      = 20;
+options.sameaxes        = 0;
+options.linetype        = '.';
+options.medianlinewidth  = 2;
+options.axescolor       = 0.2*[1 1 1];
+if ~color,
+    options.showmarkers      = 1;
+    options.linecolorsCustom = bwcolors;
+    options.markersize       = 8;
+    options.linetypesCustom  = dots;
+end
+options.maxlegendentries = 20;
+IQMplottrellis(dataPlot,nameGroup,nameX,nameY,options)
+IQMprintFigure(gcf,filename);
+close(gcf);
+
+IQMconvert2pdf(filename);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Summary statistics covariates
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(covNames) || ~isempty(catNames),
+    filename    = [outputPath '/08_Summary_Statistics'];
+    IQMexploreSummaryStats(subsetIQM(data,'NAME',OBSNAME),covNames,catNames,filename);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Graphical exploration of covariates
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(covNames) || ~isempty(catNames),
+    filename    = [outputPath '/09_Covariates'];
+    IQMexploreCovariateCorrelations(subsetIQM(data,'NAME',OBSNAME),covNames,catNames,filename);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Graphical exploration of potential covariate effect on PK
+% We only look at dose normalized information
+% Not considering BLOQ data (remove it prior to dose-normalization)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+dataPlot    = subsetIQM(data,'NAME',OBSNAME);
+% Remove BLLOQ data
+dataPlot(dataPlot.DV<dataPlot.LLOQ,:) = [];
+
+% Dose normalize the PK data
+DOSE = dataPlot.DOSE; DOSE(DOSE==0) = 1;
+dataPlot.DVnorm = dataPlot.DV./DOSE;
+% Remove inf and NaN values
+dataPlot(isnan(dataPlot.DVnorm),:) = [];
+dataPlot(isinf(dataPlot.DVnorm),:) = [];
+
+%%%%%%%%%%%%%%%%%%%%%
+% Continuous covariates
+%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(covNames),
+    % Determine median values for the continuous covariates
+    datacov             = unique(dataPlot(:,{'USUBJID',covNames{:}}));
+    covValues           = table2array(datacov(:,2:end));
+    medianCovValues     = nanmedianIQM(covValues,1);
+    
+    % Create additional categorical columns for each continuous covariate to
+    % identify >=median or <median which then is used to plot
+    newCatCovNames = {};
+    for k=1:length(covNames),
+        newCatCovName               = ['ABOVE_MEDIAN_' covNames{k}];
+        newCatCovNames{k}           = newCatCovName;
+        dataPlot.(newCatCovName)    = NaN(height(dataPlot),1);
+        dataPlot.(newCatCovName)(dataPlot.(covNames{k})>=medianCovValues(k)) = 1;
+        dataPlot.(newCatCovName)(dataPlot.(covNames{k})<medianCovValues(k))  = 0;
+    end
+    
+    filename    = [outputPath '/10_Continuous_Covariates_Stratified_Dose_Normalized_TAD'];
+    IQMstartNewPrintFigure(filename);
+    
+    for k=1:length(covNames),
+        
+        % Need to remove records with NaN data in the assessed covariate column
+        dataPlotCov = dataPlot;
+        dataPlotCov(isnan(dataPlotCov.(newCatCovNames{k})),:) = [];
+        
+        % Only plot if not empty (can happen with many NaNs)
+        if ~isempty(dataPlotCov)
+            % Do the plot by STUDY - linear axis
+            nameGroup               = 'STUDY';
+            nameY                   = 'DVnorm';
+            nameX                   = 'TAD';
+            options                 = [];
+            options.linewidth       = 1;
+            options.nameSubGroup    = 'USUBJID';
+            options.nameColorGroup  = newCatCovNames{k};
+            options.xlabelText      = sprintf('TAD [%s]',dataPlotCov.TIMEUNIT{1});
+            options.ylabelText      = sprintf('(DOSE NORMALIZED) %s - BLLOQ data not considered',dataPlotCov.NAME{1});
+            options.ylabelfirstonly = 1;
+            options.logY            = 0;
+            options.showmedian      = 1;
+            options.NbinsMedian     = 20;
+            options.sameaxes        = 0;
+            options.linetype        = '.';
+            options.medianlinewidth = 2;
+            options.axescolor       = [0.2 0.2 0.2];
+            if ~color,
+                options.showmarkers      = 1;
+                options.linecolorsCustom = bwcolors;
+                options.markersize       = 8;
+                options.linetypesCustom  = dots;
+            end
+            options.maxlegendentries = 20;
+            IQMplottrellis(dataPlotCov,nameGroup,nameX,nameY,options)
+            IQMprintFigure(gcf,filename);
+            close(gcf);
+            
+            % Do the plot by STUDY - log axis
+            nameGroup               = 'STUDY';
+            nameY                   = 'DVnorm';
+            nameX                   = 'TAD';
+            options                 = [];
+            options.linewidth       = 1;
+            options.nameSubGroup    = 'ID';
+            options.nameColorGroup  = newCatCovNames{k};
+            options.xlabelText      = sprintf('TAD [%s]',dataPlotCov.TIMEUNIT{1});
+            options.ylabelText      = sprintf('(DOSE NORMALIZED) %s - BLLOQ data not considered',dataPlotCov.NAME{1});
+            options.ylabelfirstonly = 1;
+            options.logY            = 1;
+            options.showmedian      = 1;
+            options.NbinsMedian     = 20;
+            options.sameaxes        = 0;
+            options.linetype        = '.';
+            options.medianlinewidth = 2;
+            options.axescolor       = [0.2 0.2 0.2];
+            if ~color,
+                options.showmarkers      = 1;
+                options.linecolorsCustom = bwcolors;
+                options.markersize       = 8;
+                options.linetypesCustom  = dots;
+            end
+            options.maxlegendentries = 20;
+            IQMplottrellis(dataPlotCov,nameGroup,nameX,nameY,options)
+            IQMprintFigure(gcf,filename);
+            close(gcf);
+        end
+    end
+    IQMconvert2pdf(filename);
+end
+
+%%%%%%%%%%%%%%%%%%%%%
+% Categorical covariates
+%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(catNames),
+    filename    = [outputPath '/11_Categorical_Covariates_Stratified_Dose_Normalized_TAD'];
+    IQMstartNewPrintFigure(filename);
+    
+    for k=1:length(catNames),
+        
+        % Need to remove records with NaN data in the assessed covariate column
+        dataPlotCov = dataPlot;
+        dataPlotCov(isnan(dataPlotCov.(catNames{k})),:) = [];
+        
+        % Only plot if not empty (can happen with many NaNs)
+        if ~isempty(dataPlotCov)
+            
+            % Do the plot by STUDY - linear axis
+            nameGroup               = 'STUDY';
+            nameY                   = 'DVnorm';
+            nameX                   = 'TAD';
+            options                 = [];
+            options.linewidth       = 1;
+            options.nameSubGroup    = 'ID';
+            options.nameColorGroup  = catNames{k};
+            options.xlabelText      = sprintf('TAD [%s]',dataPlotCov.TIMEUNIT{1});
+            options.ylabelText      = sprintf('(DOSE NORMALIZED) %s - BLLOQ data not considered',dataPlotCov.NAME{1});
+            options.ylabelfirstonly = 1;
+            options.logY            = 0;
+            options.showmedian      = 1;
+            options.NbinsMedian     = 20;
+            options.sameaxes        = 0;
+            options.linetype        = '.';
+            options.medianlinewidth = 2;
+            options.axescolor       = [0.2 0.2 0.2];
+            if ~color,
+                options.showmarkers      = 1;
+                options.linecolorsCustom = bwcolors;
+                options.markersize       = 8;
+                options.linetypesCustom  = dots;
+            end
+            options.maxlegendentries = 20;
+            IQMplottrellis(dataPlotCov,nameGroup,nameX,nameY,options)
+            IQMprintFigure(gcf,filename);
+            close(gcf);
+            
+            % Do the plot by STUDY - log axis
+            nameGroup               = 'STUDY';
+            nameY                   = 'DVnorm';
+            nameX                   = 'TAD';
+            options                 = [];
+            options.linewidth       = 1;
+            options.nameSubGroup    = 'ID';
+            options.nameColorGroup  = catNames{k};
+            options.xlabelText      = sprintf('TAD [%s]',dataPlotCov.TIMEUNIT{1});
+            options.ylabelText      = sprintf('(DOSE NORMALIZED) %s - BLLOQ data not considered',dataPlotCov.NAME{1});
+            options.ylabelfirstonly = 1;
+            options.logY            = 1;
+            options.showmedian      = 1;
+            options.NbinsMedian     = 20;
+            options.sameaxes        = 0;
+            options.linetype        = '.';
+            options.medianlinewidth = 2;
+            options.axescolor       = [0.2 0.2 0.2];
+            if ~color,
+                options.showmarkers      = 1;
+                options.linecolorsCustom = bwcolors;
+                options.markersize       = 8;
+                options.linetypesCustom  = dots;
+            end
+            options.maxlegendentries = 20;
+            IQMplottrellis(dataPlotCov,nameGroup,nameX,nameY,options)
+            IQMprintFigure(gcf,filename);
+            close(gcf);
+        end
+    end
+    IQMconvert2pdf(filename);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Assessment of BLLOQ data
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+IQMexploreBLLOQdata(subsetIQM(data,'NAME',OBSNAME),[outputPath '/12_BLLOQ_Information']);
+
+
+return
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexploreSummaryStats.m b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexploreSummaryStats.m
new file mode 100644
index 0000000000000000000000000000000000000000..521a0ff40584b61459888804424529c53808a22f
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/IQMexploreSummaryStats.m	
@@ -0,0 +1,155 @@
+function [continuousTable,categoricalTable] = IQMexploreSummaryStats(data,covNames,catNames,filename)
+% This function produces summary statistics for the provided dataset
+% and displays the results in a table in the MATLAB window. If a filename
+% is provdided, the results are also exported to separate files for 
+% continuous and categorical covariates. (_continuous and _categorical are 
+% postfixed to the filename).
+% The data need to be provided at least in the general dataset format or in the task
+% specific dataset format. The covariates considered need to be available
+% as columns.
+%
+% Only the first value of a covariate within a subject is considered for
+% the analysis. So time varying covariates are only handled for the first
+% value.
+%
+% [SYNTAX]
+% [continuousTable,categoricalTable] = IQMexploreSummaryStats(data,covNames,catNames)
+% [continuousTable,categoricalTable] = IQMexploreSummaryStats(data,covNames,catNames,filename)
+%
+% [INPUT]
+% data:         MATLAB PKPD dataset in general or task specific dataset
+%               format with at least additionally the covNames and colNames
+%               columns. 
+% covNames:     Cell-array with the names of the continuous covariates, as
+%               defined as columns in the dataset
+% catNames:     Cell-array with the names of the categorical covariates, as
+%               defined as columns in the dataset
+% filename:     String with filename / path for export of information in
+%               same format as displayed in command window. If not defined,
+%               then no file will be created.
+%
+% [OUTPUT]
+% Table output in MATLAB window and in file if desired.
+%
+% continuousTable:      Cell-matrix with continuous covariate information.
+% categoricalTable:     Cell-matrix with categorical covariate information.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+
+% Check data to be at least in general dataset format
+data = IQMcheckGeneralDataFormatHeader(data);
+
+% Check input arguments
+if nargin==3,
+    filename = '';
+end
+
+% Handle cell
+if ischar(covNames),
+    covNames = {covNames};
+end
+if ischar(catNames),
+    catNames = {catNames};
+end
+
+% Check cov and catnames
+datanames = data.Properties.VariableNames;
+for k=1:length(covNames),
+    if isempty(strmatchIQM(covNames{k},datanames,'exact')), error('The dataset does not contain the covariate ''%s''.',covNames{k}); end    
+end
+for k=1:length(catNames),
+    if isempty(strmatchIQM(catNames{k},datanames,'exact')), error('The dataset does not contain the covariate ''%s''.',catNames{k}); end    
+end
+
+% Get first row of each subject
+allID = unique(data.USUBJID);
+datafirst = table();
+for k=1:length(allID),
+    datak = subsetIQM(data,'USUBJID',allID(k));
+    datafirst = [datafirst; datak(1,:)];
+end
+
+% Run through continuous covariates and determine statistics
+if ~isempty(covNames),
+    continuousTable = { '<TT>' 'Summary statistics for continuous baseline values' '' '' '' '' '' '' '' ''};
+    continuousTable(end+1,:) = {'<TH>' 'Name','N','mean','std','min','Q1','median','Q3','max'};
+    for k=1:length(covNames),
+        covName = covNames{k};
+        covValues = eval(sprintf('datafirst.%s;',covName));
+        % Remove NaNs if present
+        nanINDEX = find(isnan(covValues));
+        covValues(nanINDEX) = [];
+        % Determine several measures of the covariate values
+        Nk = length(covValues);
+        meank = sprintf('%10.4g',mean(covValues));
+        stdk = sprintf('%10.4g',std(covValues));
+        maxk = sprintf('%10.4g',max(covValues));
+        Q3k = sprintf('%10.4g',quantileIQM(covValues,0.75));
+        mediank = sprintf('%10.4g',quantileIQM(covValues,0.5));
+        Q1k = sprintf('%10.4g',quantileIQM(covValues,0.25));
+        mink = sprintf('%10.4g',min(covValues));
+        % Report the results
+        continuousTable = [continuousTable; {'<TR>' covName, Nk, meank, stdk, mink, Q1k, mediank, Q3k, maxk}];
+    end
+    continuousTable(end+1,:) = { '<TF>' 'Values truncated to 4 significant digits.' '' '' '' '' '' '' '' ''};
+else
+    continuousTable             = { '<TT>' 'Summary statistics for continuous baseline values'};
+    continuousTable(end+1,:)    = { '<TR>' 'No continuous covariates defined'};
+end
+
+% Run through categorical covariates and determine statistics
+if ~isempty(catNames),
+    categoricalTable            = {'<TT>' 'Summary statistics for categorical candidate covariates' '' '' '' ''};
+    categoricalTable(end+1,:)   = {'<TH>' 'Name' 'Nr Subjects' 'Nr Levels' 'Level ID' 'N per level'};
+    for k=1:length(catNames),
+        catValues = eval(sprintf('datafirst.%s;',catNames{k}));
+        % Remove NaNs if present
+        nanINDEX = find(isnan(catValues));
+        catValues(nanINDEX) = [];
+        % Determine number of levels present
+        levels = unique(catValues);
+        % Determine number of subjects per level
+        Nlevels = [];
+        for k2=1:length(levels),
+            Nlevels(end+1) = length(find(catValues == levels(k2)));
+        end
+        % Fill table
+        categoricalTable{end+1,1} = '<TR>';
+        categoricalTable{end,2} = catNames{k};
+        categoricalTable{end,3} = length(catValues);
+        categoricalTable{end,4} = length(levels);
+        for k2=1:length(levels),
+            if k2==1,
+                categoricalTable{end,5} = sprintf('%d',levels(k2));
+            else
+                categoricalTable{end+1,5} = sprintf('%d',levels(k2));
+                categoricalTable{end,1}   = '<TR>';
+            end
+            categoricalTable{end,6} = sprintf('%d',Nlevels(k2));
+        end
+        if k<length(catNames),
+            categoricalTable{end+1,1} = '<HR>';
+        end
+    end
+else
+    categoricalTable            = { '<TT>' 'Summary statistics for categorical candidate covariates'};
+    categoricalTable(end+1,:)   = { '<TR>' 'No categorical covariates defined'};
+end
+
+% Convert to text and display text 
+textDisplay = IQMconvertCellTable2ReportTable(continuousTable,'text');     
+disp(textDisplay);
+textDisplay = IQMconvertCellTable2ReportTable(categoricalTable,'text');
+disp(textDisplay);
+
+% Convert to report text 
+text1 = IQMconvertCellTable2ReportTable(continuousTable,'report');     
+text2 = IQMconvertCellTable2ReportTable(categoricalTable,'report');     
+
+% Export to file if filename defined
+IQMwriteText2File(text1,[strrep(filename,'.txt','') '_continuous' '.txt']);
+IQMwriteText2File(text2,[strrep(filename,'.txt','') '_categorical' '.txt']);
+
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/auxiliary/getMedianPlottingDataStructIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/auxiliary/getMedianPlottingDataStructIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..f2fcc9fd332b6c9f3b0ca3d0ac39dcfa5766131c
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/03-ClinicalData/04-DataExploration/auxiliary/getMedianPlottingDataStructIQM.m	
@@ -0,0 +1,197 @@
+function [dataMedian] = getMedianPlottingDataStructIQM(data,NAME,type,GROUP)
+% Function generates a datatructure that contains information about either
+% responder rates in GROUP groups or median values of readouts in GROUP groups.
+%
+% NT column is used for binning and needs to be available in the
+% provided data. 
+%
+% The result can be used for plotting or fitting of the RR/median responses.
+%
+% [SYNTAX]
+% [dataMedian] = getMedianPlottingDataStructIQM(data,NAME,type,GROUP)
+%
+% [INPUT]
+% data:         Dataset in wide format.  
+%               USUBJID, "GROUP", NT and the columns specified in "NAME"
+%               need to be present at least
+% NAME:         String with the name of the readout to consider.
+%               Categorical and continuous can not be mixed. Categorical
+%               are limited to values of 0 and 1. 
+% type:         String defining what to do. "categorical" will assume
+%               categorical data and calculate responder rates.
+%               "continuous" will calculate medians for the readouts.
+%
+% [OUTPUT]
+% dataMedian: Matlab structure with the following contents:
+%     dataMedian.NAME              = NAME;  % Name of readout
+%     dataMedian.GROUP_NAME        = GROUP; % Name of grouping variable
+%     dataMedian.GROUP             = [];    % GROUP codes in data
+%     dataMedian.NT                = {};    % All NT values in GROUP
+%     dataMedian.N                 = [];    % Total number of subjects in GROUP
+%     dataMedian.N_NT              = {};    % Number of subjects at NT with measurement per GROUP element
+%     dataMedian.DATA              = {};    % The data ... one element per GROUP element, in each element one 
+%                                             row per names element and as many columns as nominal times in GROUP element
+%                                             Responder rates (in %) for categorical, and medians for continuous readouts 
+%     dataMedian.DATA_STDERR       = {};    % Standard errors for the DATA to be used in cost function for median fitting
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%% Check input something
+if ischar(NAME),
+    NAME = {NAME};
+end
+
+%% Only allow one NAME
+if length(NAME) > 1,
+    error('Only single NAME allowed.');
+end
+
+%% Select only NAME 
+data = IQMselectDataEvents(data,NAME);
+
+%% Remove all records which contain NaN values NAME
+data(isnan(data.VALUE),:) = [];
+
+%% Initialize output structure
+dataMedian                   = [];
+dataMedian.NAME              = NAME{1}; % Names of readouts
+dataMedian.GROUP_NAME        = GROUP;   % Grouping variable
+dataMedian.GROUP             = [];      % GROUP codes in data
+dataMedian.NT                = {};      % all NT values in GROUP
+dataMedian.N                 = [];      % total number of subjects in GROUP
+dataMedian.N_NT              = {};      % number of subjects at NT with measurement per GROUP
+dataMedian.DATA              = {};      % data for fitting per GROUP and NT
+dataMedian.DATA_STDERR       = {};      % stderr for the data per GROUP and NT
+
+    %% Handle "categorical" type
+if strcmpi(type,'categorical'),
+    
+    % If type=categorical, then require only two type of elements (0 and 1) in the NAME columns
+    for k=1:length(NAME),
+        X = sort(unique(data.VALUE));
+        if length(X) > 2,
+            error('When considering categorical data (responder rates), the "NAME" columns only are allowed to contain 0 or 1.');
+        end
+        if max(X)>1 || min(X)<0,
+            error('When considering categorical data (responder rates), the "NAME" columns only are allowed to contain 0 or 1.');
+        end
+    end
+        
+    % Determine all available TRT groups
+    allGROUP                     = unique(data.(GROUP));     % All treatment groups
+    dataMedian.GROUP             = allGROUP(:)';                % Collect info in output structure
+    
+    % Cycle through all TRT groups and collect the information
+    for k=1:length(allGROUP),
+        % Get data for GROUP group only
+        datak                    = subsetIQM(data,GROUP,allGROUP(k));
+        
+        % Get all NT values for TRT group
+        allNT                    = unique(datak.NT);
+        dataMedian.NT{k}         = allNT;                % Collect info in output structure
+        
+        % Get total number of subjects per TRT group
+        N                        = length(unique(datak.USUBJID));
+        dataMedian.N(k)          = N;                    % Collect info in output structure
+        
+        % Initialize some variables to collect information for each nominal
+        % time point
+        N_RESPONSE_NT               = NaN(1,length(allNT)); % Sum of responders based on the categorical data (1=response, 0=no response)
+        N_NT                        = []; % Number of patients in GROUP group at NT
+        
+        % Cycle through the nominal time points and collect information
+        for k2=1:length(allNT),
+            datak2                  = subsetIQM(datak,'NT',allNT(k2));
+            
+            if ~isempty(datak2),
+                N_NT(k2)                = length(unique(datak2.USUBJID));
+                % Get number of responders for each NAME in current TRT and NT
+                N_RESPONSE_NT(1,k2)     = sum(datak2.VALUE==1);
+            else
+                N_NT(k2)                = 0;
+                N_RESPONSE_NT(1,k2)     = NaN;
+            end
+        end
+        
+        % Calculate Responder Rates in percent for TRT group over
+        % NT. RAW RR ... in the sense of no imputation!
+        % Also calculate standard error for RR
+        RR                          = NaN(length(NAME),length(allNT));
+        STDERR_RR                   = NaN(length(NAME),length(allNT));
+        p                           = N_RESPONSE_NT(1,:)./N_NT;
+        RR(1,:)                     = 100*p;
+        STDERR_RR(1,:)              = max(100*sqrt(p.*(1-p)./N_NT),1);
+        
+        % Collect information
+        dataMedian.N_NT{k}            = N_NT;
+        dataMedian.DATA{k}            = RR;
+        dataMedian.DATA_STDERR{k}     = STDERR_RR;
+    end
+    
+    
+elseif strcmpi(type,'continuous'),
+    %% Handle "continuous" type
+
+    % Determine all available TRT groups
+    allGROUP                     = unique(data.(GROUP));     % All treatment groups
+    dataMedian.GROUP             = allGROUP(:)';                % Collect info in output structure
+    
+    % Cycle through all TRT groups and collect the information
+    for k=1:length(allGROUP),
+        % Get data for GROUP group only
+        datak                    = subsetIQM(data,GROUP,allGROUP(k));
+        
+        % Get all NT values for TRT group
+        allNT                    = unique(datak.NT);
+        dataMedian.NT{k}         = allNT;                % Collect info in output structure
+        
+        % Get total number of subjects per TRT group
+        N                           = length(unique(datak.USUBJID));
+        dataMedian.N(k)          = N;                    % Collect info in output structure
+        
+        % Initialize some variables to collect information for each nominal time point
+        MEDIAN_RESPONSE_NT          = NaN(1,length(allNT)); 
+        STDERR_RESPONSE_NT          = NaN(1,length(allNT)); 
+        N_NT                        = []; % Number of patients in GROUP group at NT
+        
+        % Cycle through the nominal time points and collect information
+        for k2=1:length(allNT),
+            datak2                  = subsetIQM(datak,'NT',allNT(k2));
+            
+            if ~isempty(datak2),
+                N_NT(k2)            = length(unique(datak2.USUBJID));
+                % Get number of responders for each NAME in current GROUP and NT
+                MEDIAN_RESPONSE_NT(1,k2)        = nanmedianIQM(datak2.VALUE);
+                STDERR_RESPONSE_NT(1,k2)        = nanstdIQM(datak2.VALUE)/sqrt(N_NT(k2));
+            else
+                N_NT(k2)                        = 0;
+                MEDIAN_RESPONSE_NT(1,k2)        = NaN;
+                STDERR_RESPONSE_NT(1,k2)        = NaN;                    
+            end
+        end
+        
+        % Handle 0 STDERROR things
+        % If zero then set to median of others. If all zero then set all to 1
+        % Do it rowwise
+        for k2=1:size(STDERR_RESPONSE_NT,1)
+            row = STDERR_RESPONSE_NT(k2,:);
+            % Check if all zero
+            if sum(abs(row))==0,
+                row = ones(1,length(row));
+            else
+                row(row==0) = median(row(row~=0));
+            end
+            STDERR_RESPONSE_NT(k2,:) = row;
+        end
+        
+        % Collect information
+        dataMedian.N_NT{k}            = N_NT;
+        dataMedian.DATA{k}            = MEDIAN_RESPONSE_NT;
+        dataMedian.DATA_STDERR{k}     = STDERR_RESPONSE_NT;
+    end
+else
+    error('Incorrect "type" definition.');
+end
+
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/04-NLMEdataPreparation/01-DataCleaning/IQMcleanImputeCovariates.m b/IQMtools V1.2.2.2/IQMpro/tools/04-NLMEdataPreparation/01-DataCleaning/IQMcleanImputeCovariates.m
new file mode 100644
index 0000000000000000000000000000000000000000..42d61ebdacc506112f06a84dd0d3726c76c077f3
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/04-NLMEdataPreparation/01-DataCleaning/IQMcleanImputeCovariates.m	
@@ -0,0 +1,191 @@
+function [datanew,textCovsCell,textCatsCell] = IQMcleanImputeCovariates(data,covNames,catNames,catImputationValues,filename)
+% This function does imputation of missing covariates. Continuous covs will
+% be imputed by the median and missing categorical covariates will be set
+% to "catImputationValues". 
+%
+% Important assumption: If covariate is missing in first record for a subject,
+% then it is missing for all records in a subject. The function will check
+% that the dataset complies with the IQM tools standard for clinical datasets.
+%
+% The data need to be provided, following the task specific standard
+% dataspec format or the general dataset format. Minimum requirement: the
+% covName and catNames need to be present as columns.  
+% 
+% [SYNTAX]
+% [datanew,textCovsCell,textCatsCell] = IQMcleanImputeCovariates(data,covNames,catNames,catImputationValues)
+% [datanew,textCovsCell,textCatsCell] = IQMcleanImputeCovariates(data,covNames,catNames,catImputationValues,filename)
+%
+% [INPUT]
+% data:         Dataset in general format or task specific format.  
+% covNames:     Cell-array with names of continuous covariates (as columns
+%               in dataset)
+% catNames:     Cell-array with names of categorical covariates (as columns
+%               in dataset)
+% catImputationValues:     Vector with same length as catNames, specifying
+%               the imputation values for these categorical covariates (if
+%               needed)
+% filename:     String with filename / path for export of information in
+%               same format as displayed in command window. If not defined,
+%               then no file will be created.
+%
+% [OUTPUT]
+% datanew:      Dataset as input "data" but with imputed covariates
+% textCovsCell: Report of imputations in cell-array format
+% textCatsCell: Report of imputations in cell-array format
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Variable input arguments
+if nargin < 5,
+    filename = '';
+end
+
+% Check dataset to be at least in the general dataset format
+data = IQMcheckGeneralDataFormatHeader(data);
+
+% Check arguments
+if ischar(covNames),
+    covNames = {covNames};
+end
+if ischar(catNames),
+    catNames = {catNames};
+end
+
+% Check covariates
+checkDataColumnsIQM(data,covNames)
+checkDataColumnsIQM(data,catNames)
+
+% Check catImputationValues
+if length(catImputationValues) ~= length(catNames),
+    error('Length of catImputationValues needs to be same as length of catNames.');
+end
+if ~isnumeric(catImputationValues),
+    error('catImputationValues needs to be a numeric.');
+end
+
+% Remember original dataset
+datanew = data;
+
+% Get first record of each subject
+allID = unique(data.USUBJID);
+datafirst = table();
+for k=1:length(allID),
+    datak = subsetIQM(data,'USUBJID',allID(k));
+    datafirst = [datafirst; datak(1,:)];
+end
+
+% Get covs and medians
+if isempty(covNames),
+    covMedians = [];
+else
+    covMedians = nanmedianIQM(table2array(datafirst(:,covNames)));
+end
+
+% Check if NaN included
+if ~isempty(find(isnan(covMedians))),
+    error('At least one covariate in covNames has no value defined in any subject. Please check your dataset!');
+end
+
+% Run through continuous covariates, replace and get information
+textCovsCell = {};
+for k=1:length(covNames),
+    % Get rows with missing covariate
+    ixNaN = find(isnan(datanew.(covNames{k})));
+
+    % Get USUBJID for subjects with missing covariates
+    IDmissing   = unique(data.USUBJID(ixNaN));
+
+    % Replace NaN by median in full dataset (datanew)
+    for k2=1:length(IDmissing),
+        datanew.(covNames{k})(ixdataIQM(datanew,'USUBJID',IDmissing(k2))) = covMedians(k);
+    end
+    
+    % Get info about nr missing covariates and number total subjects
+    nrIDmissing = length(IDmissing);
+    nrIDtotal   = length(unique(data.ID));
+    
+    % Report the stats
+    if nrIDmissing>0,
+        offset = size(textCovsCell,1);
+        textCovsCell{offset+1,1} = '<TT>';
+        textCovsCell{offset+1,2} = sprintf('Missing covariate information for: "%s"',covNames{k});
+        textCovsCell{offset+2,1} = '<TR>';
+        textCovsCell{offset+2,2} = 'Missing in number of subjects:';
+        textCovsCell{offset+2,3} = sprintf('%d (of total %d)',nrIDmissing,nrIDtotal);
+        textCovsCell{offset+3,1} = '<TR>';
+        textCovsCell{offset+3,2} = 'Imputed to median:';
+        textCovsCell{offset+3,3} = covMedians(k);
+        textCovsCell{offset+4,1} = '<HR>';
+        textCovsCell{offset+5,1} = '<TR>';
+        textCovsCell{offset+5,2} = 'USUBJIDs:';
+        for k2=1:nrIDmissing,
+            textCovsCell{offset+5+k2-1,1} = '<TR>';
+            textCovsCell{offset+5+k2-1,3} = IDmissing{k2};
+        end
+    end
+end
+
+% Run through categorical covariates, replace and get information
+textCatsCell = {};
+for k=1:length(catNames),
+    % Get rows with missing covariate
+    ixNaN = find(isnan(datanew.(catNames{k})));
+
+    % Get USUBJID for subjects with missing covariates
+    IDmissing   = unique(data.USUBJID(ixNaN));
+
+    % Replace NaN by median in full dataset (datanew)
+    for k2=1:length(IDmissing),
+        datanew.(catNames{k})(ixdataIQM(datanew,'USUBJID',IDmissing(k2))) = catImputationValues(k);
+    end
+    
+    % Get info about nr missing covariates and number total subjects
+    nrIDmissing = length(IDmissing);
+    nrIDtotal   = length(unique(data.ID));
+    
+    % Report the stats
+    if nrIDmissing>0,
+        offset = size(textCatsCell,1);
+        textCatsCell{offset+1,1} = '<TT>';
+        textCatsCell{offset+1,2} = sprintf('Missing covariate information for: "%s"',catNames{k});
+        textCatsCell{offset+2,1} = '<TR>';
+        textCatsCell{offset+2,2} = 'Missing in number of subjects:';
+        textCatsCell{offset+2,3} = sprintf('%d (of total %d)',nrIDmissing,nrIDtotal);
+        textCatsCell{offset+3,1} = '<TR>';
+        textCatsCell{offset+3,2} = 'Imputed to:';
+        textCatsCell{offset+3,3} = catImputationValues(k);
+        textCatsCell{offset+4,1} = '<HR>';
+        textCatsCell{offset+5,1} = '<TR>';
+        textCatsCell{offset+5,2} = 'USUBJIDs:';
+        for k2=1:nrIDmissing,
+            textCatsCell{offset+5+k2-1,1} = '<TR>';
+            textCatsCell{offset+5+k2-1,3} = IDmissing{k2};
+        end
+    end
+end
+
+% Create table if no continuous imputations needed 
+if isempty(textCovsCell),
+    textCovsCell{end+1,1}   = '<TT>';
+    textCovsCell{end,2}     = 'No continuous covariates to impute.';
+end
+
+% Create table if no categorical imputations needed 
+if isempty(textCatsCell),
+    textCatsCell{end+1,1}   = '<TT>';
+    textCatsCell{end,2}     = 'No categorical covariates to impute.';
+end
+
+% Convert to text and display text 
+textDisplay = IQMconvertCellTable2ReportTable(textCovsCell,'text');
+disp(textDisplay);
+textDisplay = IQMconvertCellTable2ReportTable(textCatsCell,'text');
+disp(textDisplay);
+
+% Convert to report text and export to file if filename defined
+text1 = IQMconvertCellTable2ReportTable(textCovsCell,'report');     
+text2 = IQMconvertCellTable2ReportTable(textCatsCell,'report');     
+text = sprintf('%s\r\n\r\n%s',text1,text2);
+IQMwriteText2File(text,[strrep(filename,'.txt','') '.txt']);
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/04-NLMEdataPreparation/01-DataCleaning/IQMcleanRemoveIGNOREDrecords.m b/IQMtools V1.2.2.2/IQMpro/tools/04-NLMEdataPreparation/01-DataCleaning/IQMcleanRemoveIGNOREDrecords.m
new file mode 100644
index 0000000000000000000000000000000000000000..292c45af1749f2c3d3e7b4b85b6d548be12f8f87
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/04-NLMEdataPreparation/01-DataCleaning/IQMcleanRemoveIGNOREDrecords.m	
@@ -0,0 +1,65 @@
+function [datanew,textCell] = IQMcleanRemoveIGNOREDrecords(data,filename)
+% This function simply removes all records from the dataset that have non
+% empty (or NaN) entries in the IGNORE column and provides a log file for
+% it.
+% This function requires the dataset to be in the general or in the task
+% specific dataset format.
+%
+% [SYNTAX]
+% [datanew,textCell] = IQMcleanRemoveIGNOREDrecords(data)
+% [datanew,textCell] = IQMcleanRemoveIGNOREDrecords(data,filename)
+%
+% [INPUT]
+% data:         Dataset in general or task specific format.  
+% filename:     String with filename / path for export of information in
+%               same format as displayed in command window. If not defined,
+%               then no file will be created.
+%
+% [OUTPUT]
+% datanew:      Dataset with removed IGNORED records 
+% textCell:     Cell table with information for reporting
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Variable input arguments
+if nargin < 2,
+    filename = '';
+end
+
+% Check dataset to be at least in the task specific dataset format
+data                    = IQMcheckGeneralDataFormatHeader(data);
+
+% Find all dose records with non-empty (or non NaN) IGNORE
+ix_remove               = findNonEmptyCellsIQM(data,'IGNORE');
+
+% Get 
+datanew                 = data;
+datanew(ix_remove,:)    = [];
+
+% Report
+% Assume entry of IGNORE column is the reason for ignoring
+textCell = {'<TT>' sprintf('N=%d IGNORED records have been removed:',length(ix_remove)) '' '' '' '' ''};
+textCell(end+1,:) = {'<TH>' 'IXGDF' 'USUBJID' 'NAME' 'TIME' 'VALUE' 'IGNORE CONTENT'};
+for k=1:length(ix_remove),
+    textCell{k+2,1} = '<TR>';
+    textCell{k+2,2} = data.IXGDF(ix_remove(k));
+    textCell{k+2,3} = data.USUBJID{ix_remove(k)};
+    textCell{k+2,4} = data.NAME{ix_remove(k)};
+    textCell{k+2,5} = data.TIME(ix_remove(k));
+    textCell{k+2,6} = data.VALUE(ix_remove(k));
+    if isnumeric(data.IGNORE),
+        textCell{k+2,7} = data.IGNORE(ix_remove(k));
+    else
+        textCell{k+2,7} = data.IGNORE{ix_remove(k)};
+    end
+end
+textCell{end+1,1}   = '<TF>';
+textCell{end,2}     = 'Records defined by non-empty IGNORE column.';
+
+% Convert to text and display text
+textDisplay = IQMconvertCellTable2ReportTable(textCell,'text');     
+disp(textDisplay);
+
+% Convert to report text and export to file if filename defined
+text = IQMconvertCellTable2ReportTable(textCell,'report');     
+IQMwriteText2File(text,[strrep(filename,'.txt','') '.txt']);
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/04-NLMEdataPreparation/01-DataCleaning/IQMcleanRemovePlaceboSubjects.m b/IQMtools V1.2.2.2/IQMpro/tools/04-NLMEdataPreparation/01-DataCleaning/IQMcleanRemovePlaceboSubjects.m
new file mode 100644
index 0000000000000000000000000000000000000000..7b41c03baaa7fe5771480df851bce26ada1d9875
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/04-NLMEdataPreparation/01-DataCleaning/IQMcleanRemovePlaceboSubjects.m	
@@ -0,0 +1,67 @@
+function [datanew,textCell] = IQMcleanRemovePlaceboSubjects(data,filename)
+% This function simply removes all subjects which only received 0 doses or
+% no doses at all. Dose records identified by EVID==1.
+% This function requires the dataset to be in the task specific dataset
+% format.
+%
+% [SYNTAX]
+% [datanew,textCell] = IQMcleanRemovePlaceboSubjects(data)
+% [datanew,textCell] = IQMcleanRemovePlaceboSubjects(data,filename)
+%
+% [INPUT]
+% data:         Dataset in task specific format.  
+% filename:     String with filename / path for export of information in
+%               same format as displayed in command window. If not defined,
+%               then no file will be created.
+%
+% [OUTPUT]
+% datanew:      dataset without determined placebo subjects. 
+% textCell:     Information about removed subjects in cell table format.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Variable input arguments
+if nargin < 2,
+    filename = '';
+end
+
+% Check dataset to be at least in the task specific dataset format
+data = IQMcheckTaskDatasetHeader(data);
+
+% Find all subjects with doses different from 0
+IDnonplacebo = unique(data.USUBJID(data.EVID==1 & data.AMT~=0));
+
+% Get subjects without doses / only 0 doses
+IDplacebo = setdiff(unique(data.USUBJID),IDnonplacebo);
+
+% Remove placebo subjects from dataset
+datanew = data;
+for k=1:length(IDplacebo),
+    datanew(ixdataIQM(datanew,'USUBJID',IDplacebo(k)),:) = [];
+end
+
+% Generate information about removed subjects
+if ~isempty(IDplacebo),
+    textCell = {'<TT>' sprintf('"IQMcleanRemovePlaceboSubjects" has removed the following %d subjects:',length(IDplacebo)) '' ''};
+    textCell(end+1,:) = {'<TH>' 'USUBJID', 'ID', 'TRTNAME'};
+    for k=1:length(IDplacebo),
+        textCell{end+1,1} = '<TR>';
+        textCell{end,2} = IDplacebo{k};
+        datak = subsetIQM(data,'USUBJID',IDplacebo{k});
+        textCell{end,3} = datak.ID(1);
+        textCell{end,4} = datak.TRTNAME{1};
+    end
+    textCell{end+1,1} = '<TF>';
+    textCell{end,2} = 'Placebo subjects defined by having NO dose records or NO non-zero AMT entry in dose records.';
+else
+    textCell = {'<TR>' 'No placebo subjects present. No subjects removed.'};
+end
+
+% Convert to text and display text
+textDisplay = IQMconvertCellTable2ReportTable(textCell,'text');     
+disp(textDisplay);
+
+% Convert to report text and export to file if filename defined
+text = IQMconvertCellTable2ReportTable(textCell,'report');     
+IQMwriteText2File(text,[strrep(filename,'.txt','') '.txt']);
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/04-NLMEdataPreparation/01-DataCleaning/IQMcleanRemoveRecordsSUBJECTs.m b/IQMtools V1.2.2.2/IQMpro/tools/04-NLMEdataPreparation/01-DataCleaning/IQMcleanRemoveRecordsSUBJECTs.m
new file mode 100644
index 0000000000000000000000000000000000000000..ca81e9404ae00aa382289f47e1a29e2555ae6d24
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/04-NLMEdataPreparation/01-DataCleaning/IQMcleanRemoveRecordsSUBJECTs.m	
@@ -0,0 +1,148 @@
+function [datanew,textRecordsCell,textSubjectsCell] = IQMcleanRemoveRecordsSUBJECTs(data,removeSUBJECT,removeREC,filename)
+% This function removes defined subjects (by USUBJID) and records (by indices,
+% defined in the IXGDF column - it is the same indices that are shown in
+% the individual data plots). The user needs to provide the 
+% information about subjects and records to remove in the input arguments.
+% 
+% Records are not actually removed ... the IGNORE entries are set to the
+% provided reason instead. And MDV is set to 1.
+% It is checked that this is only done on observation records (EVID=0). If
+% done on dose records an error is thrown.
+% 
+% Subjects are removed completely from the dataset, as this involves also
+% removing doses and to be not tool specific (e.g. MONOLIX does not know an
+% IGNORE statement) we need to ask the user to 
+% either accept removal completely or handle it outside this function.
+%
+% The data need to be provided, following the task specific dataset format.
+%
+% [SYNTAX]
+% [datanew] = IQMcleanRemoveRecordsSUBJECTs(data,removeSUBJECT,removeREC)
+% [datanew] = IQMcleanRemoveRecordsSUBJECTs(data,removeSUBJECT,removeREC,filename)
+%
+% [INPUT]
+% data:         Dataset in task specific format.  
+% removeSUBJECT:  Cell-matrix with 2 columns. First column contains the
+%                 USUBJID unique identifiers of the subjects to be removed
+%                 from the dataset. The second column contains strings,
+%                 which define the reason why this subject is removed.
+% removeREC:    Cell-matrix with 2 columns. First column contains the indices
+%               of the records to be removed from the dataset
+%               (corresponding to the indices in the column IXGDF of the
+%               dataset). The second  column contains strings, which define
+%               the reason why this record is removed.
+% filename:     String with filename / path for export of information in
+%               same format as displayed in command window. If not defined,
+%               then no file will be created.
+%
+% [OUTPUT]
+% datanew:          Dataset with subjects and records removed. 
+%                   Additionally, in the workspace it will be written out which 
+%                   subjects and records have been removed, including the
+%                   reason why.
+% textRecordsCell:  Cell table with removal information of records
+% textSubjectsCell: Cell table with removal information of subjects
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Check dataset to be at least in the task specific dataset format
+data = IQMcheckTaskDatasetHeader(data);
+
+% Handle variable input arguments
+if nargin<4,
+    filename = '';
+end
+
+% Determine indices and IDs based on the input
+if ~isempty(removeSUBJECT),
+    removeSUBJECT_IDs  = removeSUBJECT(:,1);
+else
+    removeSUBJECT_IDs = [];
+end
+if ~isempty(removeREC),
+    removeREC_ix = cell2mat(removeREC(:,1));
+else
+    removeREC_ix = [];
+end
+
+% Make copy of data to be used as output argument
+datanew = data;
+
+% Remove identified records (first)
+% Instead of removing, we set MDV=1 and set IGNORE to the provided reason.
+for k=1:length(removeREC_ix),
+    % Check if the record to be removed is present in the dataset
+    if isempty(ixdataIQM(datanew,'IXGDF',removeREC_ix(k))),
+        error('Index "%d" not available in IXGDF column.',removeREC_ix(k));
+    end
+    % Check that the record to be removed is an observation
+    if datanew.EVID(datanew.IXGDF==removeREC_ix(k)) ~= 0,
+        error('Index %d to be removed is not an observation.',removeREC_ix(k));
+    end
+    % Set MDV=1 for the record
+    datanew.MDV(datanew.IXGDF==removeREC_ix(k)) = 1;
+    % Set the IGNORE reason for the record
+    datanew.IGNORE{datanew.IXGDF==removeREC_ix(k)} = removeREC{k,2};
+end
+
+% Remove identified subjects (second)
+for k=1:length(removeSUBJECT_IDs),
+    if isempty(ixdataIQM(datanew,'USUBJID',removeSUBJECT_IDs{k})),
+        error('Subject "%s" not available in USUBJID column.',removeSUBJECT_IDs{k});
+    end
+    datanew(ixdataIQM(datanew,'USUBJID',removeSUBJECT_IDs{k}),:) = [];
+end
+
+% Prepare output text as cell table
+if ~isempty(removeREC_ix),
+    textRecordsCell = {'<TT>' sprintf('The following N=%d records have been flagged with MDV=1 and an entry in the IGNORE column:',length(removeREC_ix)) '' '' '' '' '' '' ''};
+    textRecordsCell(end+1,:) = {'<TH>' 'IXGDF' 'USUBJID' 'ID' 'DV' 'TIME' 'TAD' 'NAME' 'IGNORE'};
+    for k=1:length(removeREC_ix),
+        index_removed = removeREC_ix(k);
+        textRecordsCell{k+2,1} = '<TR>';
+        textRecordsCell{k+2,2} = index_removed;
+        textRecordsCell{k+2,3} = datanew.USUBJID{datanew.IXGDF==index_removed};
+        textRecordsCell{k+2,4} = datanew.ID(datanew.IXGDF==index_removed);
+        textRecordsCell{k+2,5} = datanew.DV(datanew.IXGDF==index_removed);
+        textRecordsCell{k+2,6} = datanew.TIME(datanew.IXGDF==index_removed);
+        textRecordsCell{k+2,7} = datanew.TAD(datanew.IXGDF==index_removed);
+        textRecordsCell{k+2,8} = datanew.NAME{datanew.IXGDF==index_removed};
+        textRecordsCell{k+2,9} = datanew.IGNORE{datanew.IXGDF==index_removed};
+    end    
+    textRecordsCell(end+1,:) = {'<TF>' 'Selection of records (number of event record in dataset) manually by the user.' '' '' '' '' '' '' ''};
+else
+    textRecordsCell = {'<TT>' 'No records flagged to be set to ignored by function IQMcleanRemoveRecordsSUBJECTs.'};
+end
+
+% Prepare output text - removed SUBJECTs
+if ~isempty(removeSUBJECT_IDs),
+        textSubjectsCell = {'<TT>' sprintf('The following N=%d SUBJECTs have been removed from the dataset:',length(removeSUBJECT_IDs)) '' ''};
+        textSubjectsCell(end+1,:) = {'<TH>' 'USUBJID' 'ID' 'REASON'};
+    for k=1:length(removeSUBJECT_IDs),
+        textSubjectsCell{k+2,1} = '<TR>';
+        textSubjectsCell{k+2,2} = removeSUBJECT_IDs{k};
+        ID = data.ID(strcmp(data.USUBJID,removeSUBJECT_IDs{k}));
+        if isempty(ID),
+            error('USUBJID %s not in dataset.',removeSUBJECT_IDs{k});
+        end
+        textSubjectsCell{k+2,3} = ID(1);
+        textSubjectsCell{k+2,4} = removeSUBJECT{k,2};
+    end    
+    textSubjectsCell(end+1,1:2) = {'<TF>' 'Selection of subjects manually by the user.'};
+else
+    textSubjectsCell = {'<TT>' 'No subjects removed by function IQMcleanRemoveRecordsSUBJECTs.'};
+end
+
+% Convert to text and display text
+textDisplay = IQMconvertCellTable2ReportTable(textRecordsCell,'text');     
+disp(textDisplay);
+textDisplay = IQMconvertCellTable2ReportTable(textSubjectsCell,'text');     
+disp(textDisplay);
+
+% Convert to report text and export to file if filename defined
+text1 = IQMconvertCellTable2ReportTable(textRecordsCell,'report');     
+text2 = IQMconvertCellTable2ReportTable(textSubjectsCell,'report');     
+text = sprintf('%s\r\n\r\n%s',text1,text2);
+IQMwriteText2File(text,[strrep(filename,'.txt','') '.txt']);
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/04-NLMEdataPreparation/01-DataCleaning/IQMcleanRemoveSubjectsNoObservations.m b/IQMtools V1.2.2.2/IQMpro/tools/04-NLMEdataPreparation/01-DataCleaning/IQMcleanRemoveSubjectsNoObservations.m
new file mode 100644
index 0000000000000000000000000000000000000000..9de801d510845418f02d1e3980e94692c0dab87a
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/04-NLMEdataPreparation/01-DataCleaning/IQMcleanRemoveSubjectsNoObservations.m	
@@ -0,0 +1,67 @@
+function [datanew,textCell] = IQMcleanRemoveSubjectsNoObservations(data,filename)
+% This function simply removes all subjects which do not have any
+% observations (defined by EVID=0 and MDV=0).
+%
+% [SYNTAX]
+% [datanew,textCell] = IQMcleanRemoveSubjectsNoObservations(data)
+% [datanew,textCell] = IQMcleanRemoveSubjectsNoObservations(data,filename)
+%
+% [INPUT]
+% data:         Dataset in task specific format.  
+% filename:     String with filename / path for export of information in
+%               same format as displayed in command window. If not defined,
+%               then no file will be created.
+%
+% [OUTPUT]
+% datanew:      Dataset only with subjects that do have observations.
+% textCell:     Information about removed subjects in cell table format.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Variable input arguments
+if nargin < 2,
+    filename = '';
+end
+
+% Check dataset to be at least in the task specific dataset format
+data = IQMcheckTaskDatasetHeader(data);
+
+% Find all subjects with observations
+IDobs = unique(data.USUBJID(data.EVID==0 & data.MDV==0));
+
+% Get subjects without doses / only 0 doses
+IDnoObs = setdiff(unique(data.USUBJID),IDobs);
+
+% Remove subjects without observations from dataset
+datanew = data;
+for k=1:length(IDnoObs),
+    datanew(ixdataIQM(datanew,'USUBJID',IDnoObs(k)),:) = [];
+end
+
+% Generate information about removed subjects
+if ~isempty(IDnoObs),
+    textCell = {'<TT>' sprintf('"IQMcleanRemoveSubjectsNoObservations" has removed the following %d subjects:',length(IDnoObs)) '' ''};
+    textCell(end+1,:) = {'<TH>' 'USUBJID', 'ID', 'TRTNAME'};
+    for k=1:length(IDnoObs),
+        textCell{end+1,1} = '<TR>';
+        textCell{end,2} = IDnoObs{k};
+        datak = subsetIQM(data,'USUBJID',IDnoObs{k});
+        textCell{end,3} = datak.ID(1);
+        textCell{end,4} = datak.TRTNAME{1};
+    end
+    textCell{end+1,1} = '<TF>';
+    textCell{end,2} = 'Removed subjects defined by NO observation records (EVID=0 and MDV=0).';
+else
+    textCell = {'<TT>' 'No subjects without observations present. No subjects removed.'};
+end
+
+% Convert to text and display text
+textDisplay = IQMconvertCellTable2ReportTable(textCell,'text');     
+disp(textDisplay);
+
+% Convert to report text and export to file if filename defined
+text = IQMconvertCellTable2ReportTable(textCell,'report');     
+IQMwriteText2File(text,[strrep(filename,'.txt','') '.txt']);
+
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/04-NLMEdataPreparation/01-DataCleaning/IQMcleanRemoveZeroDoses.m b/IQMtools V1.2.2.2/IQMpro/tools/04-NLMEdataPreparation/01-DataCleaning/IQMcleanRemoveZeroDoses.m
new file mode 100644
index 0000000000000000000000000000000000000000..656253993d4e69d9aa470ff474664228bb772147
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/04-NLMEdataPreparation/01-DataCleaning/IQMcleanRemoveZeroDoses.m	
@@ -0,0 +1,63 @@
+function [datanew,text] = IQMcleanRemoveZeroDoses(data,filename)
+% This function simply removes all dose records with 0 amount. Normally not
+% needed but poor and outdated software design of NONMEM does make this
+% function very useful.
+% This function requires the dataset to be in the task specific dataset
+% format.
+%
+% [SYNTAX]
+% [datanew,text] = IQMcleanRemoveZeroDoses(data)
+% [datanew,text] = IQMcleanRemoveZeroDoses(data,filename)
+%
+% [INPUT]
+% data:         Dataset in task specific format.  
+% filename:     String with filename / path for export of information in
+%               same format as displayed in command window. If not defined,
+%               then no file will be created.
+%
+% [OUTPUT]
+% datanew:      Dataset with removed placebo subjects. 
+% text:         Info text about removal of AMT=0 dose records
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Variable input arguments
+if nargin < 2,
+    filename = '';
+end
+
+% Check dataset to be at least in the task specific dataset format
+data = IQMcheckTaskDatasetHeader(data);
+
+% Find all dose records (EVID==1) with AMT==0
+ixZeroDoses = find(data.EVID==1 & data.AMT==0);
+
+% Remove these doses
+datanew = data;
+datanew(ixZeroDoses,:) = [];
+
+% Report
+% dose records (EVID==1) with AMT==0
+textCell = {'<TT>' sprintf('N=%d dose records with EVID=1 and AMT=0 have been removed:',length(ixZeroDoses)) '' '' '' ''};
+textCell(end+1,:) = {'<TH>' 'IXGDF' 'USUBJID' 'NAME' 'TIME' 'VALUE'};
+for k=1:length(ixZeroDoses),
+    textCell{k+2,1} = '<TR>';
+    textCell{k+2,2} = data.IXGDF(ixZeroDoses(k));
+    textCell{k+2,3} = data.USUBJID{ixZeroDoses(k)};
+    textCell{k+2,4} = data.NAME{ixZeroDoses(k)};
+    textCell{k+2,5} = data.TIME(ixZeroDoses(k));
+    textCell{k+2,6} = data.VALUE(ixZeroDoses(k));
+end
+textCell{end+1,1}   = '<TF>';
+textCell{end,2}     = 'Records defined by EVID=1 and AMT=0.';
+
+% Convert to text and display text
+textDisplay = IQMconvertCellTable2ReportTable(textCell,'text');     
+disp(textDisplay);
+
+% Convert to report text and export to file if filename defined
+text = IQMconvertCellTable2ReportTable(textCell,'report');     
+IQMwriteText2File(text,[strrep(filename,'.txt','') '.txt']);
+
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/04-NLMEdataPreparation/01-DataCleaning/IQMhandleSameTimeObservationRecords.m b/IQMtools V1.2.2.2/IQMpro/tools/04-NLMEdataPreparation/01-DataCleaning/IQMhandleSameTimeObservationRecords.m
new file mode 100644
index 0000000000000000000000000000000000000000..9cccf642f34bf82acd1648b269428fcfb47136ea
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/04-NLMEdataPreparation/01-DataCleaning/IQMhandleSameTimeObservationRecords.m	
@@ -0,0 +1,68 @@
+function [dataChanged] = IQMhandleSameTimeObservationRecords(data)
+% Both due to clinical database issues and programming issues it might
+% happen that similar records in a dataset might have exactly the same time
+% of assessment / administration. Normally, this should be solved during
+% data cleaning and validation before making its way into the modeling
+% dataset. However, it might still happen and modeling might not want to
+% wait until the final data cleaning has happened - because then modeling
+% is typically to late to impact any decisions. 
+%
+% For PK modeling such records typically are not an issue. However, for PD
+% modeling where the dataset is augmented by regression parameters
+% (concentration or PK parameters) this poses a problem, since the
+% estimation software does see two regression variable assignments at the
+% same time point and does not know what to do - and in the case of Monolix
+% fails with an error.
+% 
+% This function here solves that in a very simple way. If the same time is
+% detected more than once for the same NAME in a subject, then these times
+% are very slighlty changed by adding a tiny random noise to these time
+% points.
+%
+% This is not a function that should be used for regulatory modeling - for
+% exploratory modeling, however, it is fine.
+%
+% The function will do this for records of all NAMEs!
+%
+% If for a certain NAME for a certain USUBJID same times appear, the whole time
+% vector for this type in this USUBJID will be added with random noise of a
+% standard deviation of 0.001, corresponding to std of 3.6 seconds if time
+% unit is hours and 86 seconds if time unit is days. So no problem.
+% 
+% [SYNTAX]
+% [dataChanged] = IQMhandleSameTimeObservationRecords(data)
+%
+% [INPUT]
+% data:         MATLAB dataset in the general dataset format used in IQM tools
+%
+% [OUTPUT]
+% Changed dataset (if needed). 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Check dataset to be at least in the general dataset format
+data = IQMcheckGeneralDataFormatHeader(data);
+
+% Handle uniqueness of TIME per USUBJID and NAME
+allID = unique(data.USUBJID);
+dataChanged = table();
+for k=1:length(allID),
+    datak = subsetIQM(data,'USUBJID',allID(k));
+    allNAME = unique(datak.NAME);
+    for k2=1:length(allNAME),
+        ix = ixdataIQM(datak,'NAME',allNAME(k2));
+        % Get TIME 
+        TIME = datak.TIME(ix);
+        % Check it
+        if ~(length(TIME) == length(unique(TIME))),
+            ABSCHANGE       = 0.001; % 3.6 seconds if timeunit = hour, 86 seconds if time unit is day
+            TIMEpert        = TIME + ABSCHANGE*randn(size(TIME));
+            datak.TIME(ix)  = TIMEpert;
+        end
+    end
+    % Collect data
+    dataChanged = [dataChanged; datak];
+end
+
+% Sort changed dataset to get time vector ascending
+dataChanged = sortrows(dataChanged,{'STUDY','USUBJID','TIME','NAME'});
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/04-NLMEdataPreparation/02-BLOQhandling/IQMhandleBLOQdata.m b/IQMtools V1.2.2.2/IQMpro/tools/04-NLMEdataPreparation/02-BLOQhandling/IQMhandleBLOQdata.m
new file mode 100644
index 0000000000000000000000000000000000000000..7e4b29e418eacd28ff4a8b0dea822c5342d6c699
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/04-NLMEdataPreparation/02-BLOQhandling/IQMhandleBLOQdata.m	
@@ -0,0 +1,232 @@
+function [datanew] = IQMhandleBLOQdata(data,METHOD_BLOQ,filename)
+% This function allows to handle BLOQ data in several different ways by
+% updating the dataset according to needs.
+% It requires a dataset in the task specific data format and information
+% about the LLOQ in the LLOQ column.
+%
+% Methods in IQM Tools are considering the standard Beales Methods for NONMEM:
+%   - M1 = Ignore values below LLOQ by setting MDV=1
+%   - M3 = Estimate likelihood at times measurements are BLLOQ
+%   - M4 = Like M3 but also assume measurements are >=0
+%   - M5 = Replace all BLLOQ with LLOQ/2
+%   - M6 = Replace first BLLOQ with LLOQ/2, ignore others
+%   - M7 = Replace all BLLOQ with zero
+%
+% In IQM Tools the following methods are considered and the following
+% transformations are done to the dataset:
+%
+% METHOD_BLOQ   METHOD      DATA TRANSFORMATIONS
+%     0         M1          All BLOQ data set to MDV=1
+%     1         M3/M4       All BLOQ data obtains CENS=1 and DV=BLOQ
+%     2         M5          All BLOQ data obtains DV=LLOQ/2
+%     3         M6          All BLOQ data obtains DV=LLOQ/2 and the first
+%                           occurence in a sequence MDV=0 (unchanged) and
+%                           the following in sequence: MDV=1 
+%     4         M7          All BLOQ data obtains DV=0
+%
+% All considered methods are usable both in NONMEM and MONOLIX in a similar
+% manner. Only METHOD_BLOQ=1 might be different. In case of MONOLIX, the
+% MONOLIX internal handling of censored data is used. In case of NONMEM by
+% default the M3 method is used - M4 can be optionally selected when the
+% NONMEM code is generated.
+% 
+% Each record that obtains MDV=1 through this function will also obtain an
+% entry in the IGNORE column (if not yet present). It will be "BLLOQ (Mx)"
+% where the x is replaced by the number of the method that is being used.
+%
+% Records that are already IGNORED by having set the IGNORE column and
+% MDV=1 are not considered.
+%     
+% [SYNTAX]
+% [datanew] = IQMhandleBLOQdata(data,METHOD_BLOQ)
+% [datanew] = IQMhandleBLOQdata(data,METHOD_BLOQ,filename)
+%
+% [INPUT]
+% data:         Task specific general dataset.
+%
+% [OUTPUT]
+% Changed dataset (if needed). 
+% If filename is provided then a text file is saved with the used settings
+% for BLOQ handling and some information about the total number of samples
+% and the number of BLOQ samples.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Check dataset to be at least in the general dataset format
+data = IQMcheckTaskDatasetHeader(data);
+
+% Handle variable input arguments
+if nargin<3,
+    filename = '';
+end
+
+% Copy dataset
+datanew = data;
+
+% Find all NAMEs which have LLOQ information and are observations
+NAMES_BLLOQ_present = unique(datanew.NAME(~isnan(datanew.LLOQ) & datanew.EVID==0));
+
+% Find all records that are BLOQ for all names that have LLOQ information
+ixBLOQ = [];
+for k=1:length(NAMES_BLLOQ_present),
+    % Get indices
+    ixBLOQ = [ixBLOQ(:); find(datanew.MDV==0 & datanew.VALUE < datanew.LLOQ & strcmp(datanew.NAME,NAMES_BLLOQ_present{k}))];
+end
+
+% Also add a CENS column and initialize to 0
+datanew.CENS = zeros(height(datanew),1);
+
+% Get information about BLOQ data as table without output
+tableCell = IQMexploreBLLOQdata(data);
+
+% Handle the different approaches for BLOQ handling
+if METHOD_BLOQ==0,
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    % M1 - All BLOQ data set to MDV=1
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    
+    % Set all BLOQ data to MDV=1
+    datanew.MDV(ixBLOQ) = 1;
+    
+    % Add IGNORE statement (if not yet present)
+    for k=1:length(ixBLOQ),
+        if isempty(datanew.IGNORE{ixBLOQ(k)}),
+            datanew.IGNORE{ixBLOQ(k)} = 'BLLOQ (M1)';
+        end
+    end
+    
+    % Add footer to table
+    tableCell{end+1,1} = '<TF>';
+    tableCell{end,2}   = sprintf('All records with DV<LLOQ (N=%d) where set to MDV=1, CENS=0. (NONMEM M1 method)',length(ixBLOQ));
+    
+elseif METHOD_BLOQ==1,
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    % M3/M4 - All BLOQ data obtains CENS=1 and DV=BLOQ and MDV unchanged
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+
+    % Set DV to LLOQ for BLOQ data
+    datanew.DV(ixBLOQ) = datanew.LLOQ(ixBLOQ);
+    
+    % Set CENS to 1 for BLOQ data
+    datanew.CENS(ixBLOQ) = 1;
+    
+    % Add footer to table
+    tableCell{end+1,1} = '<TF>';
+    tableCell{end,2}   = sprintf('All records with DV<LLOQ (N=%d) where set to DV=LLOQ, CENS=1, MDV unchanged. (NONMEM M3 or M4 method - depending on model)',length(ixBLOQ));
+    
+elseif METHOD_BLOQ==2,
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    % M5 - All BLOQ data obtains DV=LLOQ/2 and MDV unchanged
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    
+    % Set all DV to LLOQ/2 for BLOQ data
+    datanew.DV(ixBLOQ) = datanew.LLOQ(ixBLOQ)/2;
+    
+    % Add footer to table
+    tableCell{end+1,1} = '<TF>';
+    tableCell{end,2}   = sprintf('All records with DV<LLOQ (N=%d) where set to DV=LLOQ/2, CENS=0, MDV unchanged. (NONMEM M5 method)',length(ixBLOQ));
+    
+elseif METHOD_BLOQ==3,
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    % M6 - All BLOQ data obtains DV=LLOQ/2 and the first occurence in a
+    % sequence MDV unchanged and the following in sequence: MDV=1 
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    
+    % Set all DV to LLOQ/2 for BLOQ data
+    datanew.DV(ixBLOQ)      = datanew.LLOQ(ixBLOQ)/2;
+    
+    % Add helper column
+    datanew.BLOQ            = zeros(height(datanew),1);
+    datanew.BLOQ(ixBLOQ)    = 1;
+
+    % Now cycle through all observations, find for each NAME the ones that
+    % are BLOQ and consecutive. Then keep first on MDV as set and set the
+    % following ones to MDV=1.
+
+    % Initialize table for updated dataset
+    datanew2    = datanew;
+    
+    % Cycle through each NAME with LLOQ info
+    for k00=1:length(NAMES_BLLOQ_present),
+        
+        % Split data for NAME and not the NAME to handle only NAME data
+        dataNAME   = subsetIQM(datanew2,'NAME',NAMES_BLLOQ_present(k00));
+        dataNONAME = datanew2(~strcmp(datanew2.NAME,NAMES_BLLOQ_present{k00}),:);
+        
+        % Get empty dataset to collect handled NAME data
+        dataNAMEhandled = table();
+        
+        % Cycle through each subject in data with NAME
+        allID = unique(dataNAME.ID);
+        
+        % Cycle through each subject in NAME data to handle observations
+        for k=1:length(allID),
+            datak       = subsetIQM(dataNAME,'ID',allID(k));
+            % get doses for this subject
+            datakDOSES  = dataNONAME(dataNONAME.ID==allID(k) & dataNONAME.EVID==1,:);
+            % Combine obs for subject and doses for subject
+            datakdecision = sortrows([datak; datakDOSES],{'TIME'});
+            
+            % Check if BLOQ available
+            ixBLOQ_k = find(datakdecision.BLOQ);
+
+            if ~isempty(ixBLOQ_k),
+                
+                % See if consecutive readouts available 
+                delta           = [NaN; diff(ixBLOQ_k)];
+                ix_consequtive  = ixBLOQ_k(delta==1);
+                
+                % Set MDV for consecutive ones to 1 (keep original MDV
+                % setting for first)
+                datakdecision.MDV(ix_consequtive) = 1;
+                
+                % Add IGNORE statement (if not yet present)
+                for kxx=1:length(ix_consequtive),
+                    if isempty(datakdecision.IGNORE{ix_consequtive(kxx)}),
+                        datakdecision.IGNORE{ix_consequtive(kxx)} = 'BLLOQ (M6)';
+                    end
+                end
+                
+                % Remove doses again
+                datak = datakdecision;
+                datak(datak.EVID==1,:) = [];
+            end
+            
+            % Combine again the NAME data after handling
+            dataNAMEhandled = [dataNAMEhandled; datak];
+        end
+        
+        % Combine again dataNAMEhandled with dataNONAME
+        datanew2 = [dataNONAME; dataNAMEhandled];
+    end
+    
+    % Sort
+    datanew = sortrows(datanew2,{'STUDY','USUBJID','TIME','TAD','NAME'},{'ascend','ascend','ascend','descend','ascend'});
+    
+    % Remove helper column
+    datanew.BLOQ = [];
+
+    % Add footer to table
+    tableCell{end+1,1} = '<TF>';
+    tableCell{end,2}   = sprintf('All records with DV<LLOQ (N=%d) where set to DV=LLOQ/2, CENS=0, MDV in first in sequence unchanged, others in sequence set to MDV=1. (NONMEM M6 method)',length(ixBLOQ));
+
+elseif METHOD_BLOQ==4,
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+    % M7 - All BLOQ data obtains DV=0 (MDV unchanged)
+    %%%%%%%%%%%%%%%%%%%%%%%%%
+
+    % Set all DV to 0 for BLOQ data
+    datanew.DV(ixBLOQ) = 0;
+    
+    % Add footer to table
+    tableCell{end+1,1} = '<TF>';
+    tableCell{end,2}   = sprintf('All records with DV<LLOQ (N=%d) where set to DV=0, CENS=0, MDV unchanged. (NONMEM M7 method)',length(ixBLOQ));
+end
+
+% Convert to text and display text only if no output argument defined
+textDisplay = IQMconvertCellTable2ReportTable(tableCell,'text');     
+disp(textDisplay);
+
+% Convert to report text and export to file if filename defined
+IQMconvertCellTable2ReportTable(tableCell,'report',filename);     
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/04-NLMEdataPreparation/03-DataNLMEConversion/IQMaddIndivRegressionParamFromNLMEproject.m b/IQMtools V1.2.2.2/IQMpro/tools/04-NLMEdataPreparation/03-DataNLMEConversion/IQMaddIndivRegressionParamFromNLMEproject.m
new file mode 100644
index 0000000000000000000000000000000000000000..6c82a5247f11eab62bcbbc3706601ae645e37d80
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/04-NLMEdataPreparation/03-DataNLMEConversion/IQMaddIndivRegressionParamFromNLMEproject.m	
@@ -0,0 +1,137 @@
+function [data_with_regression_param,regressionNames] = IQMaddIndivRegressionParamFromNLMEproject(data,model,dosing,projectPath)
+% This function checks which regression parameters are defined in the model
+% and dosing combination and attempts to add these into the data dataset by
+% taking the individual parameters from the NLME project in projectPath.
+% This, e.g., allows to add PK parameters to a PD dataset. In case that the
+% dataset "data" contains USUBJIDs for which no individual parameters are
+% present in projectPath (e.g. placebo subjects) the function will add
+% population mean parameters for those. These population mean parameters
+% are individually adjusted based on the estimated covariate relationships
+% in the NLME project. Only in the case these individualized pop mean parameters 
+% are not determinable (NaN, Inf, ...), which could happen when dose is a covariate,
+% then the population parameters are used.
+%
+% Finally, all regression parameters are added at the end of the output
+% dataset (data_with_regression_param) in the order as they appear in the
+% model. 
+% 
+% [SYNTAX]
+% [data_with_regression_param,regressionNames] = IQMaddIndivRegressionParamFromNLMEproject(data,model,dosing,projectPath)
+%
+% [INPUT]
+% data:             Dataset (or path to its file) which should be augmented
+%                   with regression parameters.
+% model:            IQMmodel to assess for regression parameters
+% dosing:           IQMdosing object to assess for regression parameters
+% projectPath:      NLME project from which indidivual parameters should be
+%                   included as regression parameters 
+%
+% [OUTPUT]
+% data_with_regression_param:   Dataset "data" augmented with regression
+%                               parameters
+% regressionNames:              Cell-array with regresssion names defined
+%                               in the model - in the order as in the
+%                               model.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle data input argument if provided as string with path
+if ischar(data),
+    % Assume path to dataset is provided
+    data        = IQMloadCSVdataset(data);
+end
+
+% Check data
+if ~istable(data),
+    error('Provided "data" is not a MATLAB table.');
+end
+
+if ~isIQMmodel(model),
+    error('Provided "model" is not an IQMmodel.');
+end
+
+if ~isIQMdosing(dosing),
+    error('Provided "dosing" is not an IQMdosing object.');
+end
+
+% Check project
+if ~isNLMEprojectIQM(projectPath),
+    error('Provided "projectPath" does not contain an NLME project.');
+end
+
+% Read the project header
+header = parseNLMEprojectHeaderIQM(projectPath);
+
+% 1) Get the names of the regression parameters from the model+dosing
+regressionNames = IQMgetRegressionParameters(model,dosing);
+
+% 2) Get individual parameter estimates
+indiv_param     = IQMgetNLMEfitIndivparam(projectPath);
+
+% 3) Get individualized (by covariates) population mean data
+popmean_param   = IQMgetNLMEfitIndivPopMeanParam(projectPath,data);
+
+% 3b) Check if some of the popmean_param are NaN or Inf ... then use pop mean parameters
+test = sum(table2array(popmean_param(:,2:end)),2);
+ix = unique([find(isnan(test)) find(isinf(test))]);
+if ~isempty(ix),
+    % Need to replace some parameters by population parameters
+    x = IQMsampleNLMEfitParam(projectPath,0,0);
+    vn = popmean_param.Properties.VariableNames(2:end);
+    for k1=1:length(vn),
+        ix2 = strmatchIQM(vn{k1},x.parameterNames,'exact');
+        popmean_param.(vn{k1})(ix) = x.parameterValuesPopulation(ix2);
+    end
+end
+
+% 4) Determine subjects in PD dataset without individual PK parameters
+pmparam_noindiv = table();
+pmparam_noindiv.USUBJID       = setdiff(popmean_param.USUBJID,indiv_param.USUBJID);
+pmparam_noindiv = join(pmparam_noindiv,popmean_param);
+
+% 5) Combine individual estimated parameters and individualized ones
+allIndiv_param  = [indiv_param; pmparam_noindiv];
+
+% 6) Remove from allIndiv_param names that are not defined in regressionNames
+vn = allIndiv_param.Properties.VariableNames;
+remove_ix = [];
+for k=2:length(vn),
+    ix = strmatchIQM(vn{k},regressionNames,'exact');
+    if isempty(ix),
+        % Remove this name from allRegressionFit - since not needed for the model
+        remove_ix = [remove_ix k];
+    end
+end
+allIndiv_param(:,remove_ix) = [];
+
+% 7) Add determined individual parameters to the PD dataset
+data_with_regression_param = join(data,allIndiv_param);
+
+% 8) Check if all needed regression parameters in the dataset data_with_regression_param
+regressionNames_NOThandled   = {};
+regressionNames_handled      = {};
+for k=1:length(regressionNames),
+    if isempty(strmatchIQM(regressionNames{k},data_with_regression_param.Properties.VariableNames,'exact')),
+        regressionNames_NOThandled{end+1} = regressionNames{k};
+    else
+        regressionNames_handled{end+1} = regressionNames{k};
+    end
+end
+if ~isempty(regressionNames_NOThandled),
+    text = sprintf('%s,',regressionNames_NOThandled{:});
+    disp(sprintf('The following regression parameters in the model are undefined in the provided NLME project: %s',text(1:end-1)));
+end
+
+% 9) Reorder regression parameters in data_with_regression_param according to how ordering in model
+regression = [];
+for k=1:length(data_with_regression_param.Properties.VariableNames),
+    ix = strmatchIQM(data_with_regression_param.Properties.VariableNames{k},regressionNames_handled,'exact');
+    if isempty(ix),
+        regression(end+1) = 0;
+    else
+        regression(end+1) = strmatchIQM(regressionNames_handled{ix},data_with_regression_param.Properties.VariableNames,'exact');
+    end
+end
+data_with_regression_param = data_with_regression_param(:,[data_with_regression_param.Properties.VariableNames(find(regression==0)) regressionNames_handled]);
+
+% Done!
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/04-NLMEdataPreparation/03-DataNLMEConversion/IQMcheckNLMEdatasetHeader.m b/IQMtools V1.2.2.2/IQMpro/tools/04-NLMEdataPreparation/03-DataNLMEConversion/IQMcheckNLMEdatasetHeader.m
new file mode 100644
index 0000000000000000000000000000000000000000..dcf921f40d66d0ce736dc66374ffe22dba006e72
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/04-NLMEdataPreparation/03-DataNLMEConversion/IQMcheckNLMEdatasetHeader.m	
@@ -0,0 +1,60 @@
+function [] = IQMcheckNLMEdatasetHeader(data)
+% This function checks if the minimal required elements are present in an
+% NLME dataset that is going to be used for fitting.
+%
+% IQM Tools requires the presence of the following columns in an NLME dataset
+% that is used for fitting:
+% 'IXGDF'     A column with index numbers of the records in the dataset
+%             either defined for this dataset alone as 1,2,3, ... or
+%             defined in a dataset from which this one here has been
+%             derived and the IXGDF entries make the link between the
+%             remaining records and the original records.
+% 'USUBJID'
+% 'ID' 
+% 'TIME' 
+% 'TIMEPOS' 
+% 'DV' 
+% 'MDV' 
+% 'EVID' 
+% 'CENS' 
+% 'AMT' 
+% 'ADM' 
+% 'RATE' 
+% 'YTYPE' 
+%
+% [SYNTAX]
+% []        = IQMcheckNLMEdatasetHeader(data)
+% [dataOut] = IQMcheckNLMEdatasetHeader(data)
+%
+% [INPUT]
+% data:         MATLAB dataset in the NLME dataset format to be checked
+%               or path to dataset
+%
+% [OUTPUT]
+% If at least one of the required columns is not present an error will be
+% shown. 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Check NLME fitting specific dataset column names
+datanames = data.Properties.VariableNames;
+requiredColumns = {'IXGDF' 'USUBJID' 'ID' 'TIME' 'TIMEPOS' 'DV' 'MDV' 'EVID' 'CENS' 'AMT' 'ADM' 'RATE' 'YTYPE'};
+errorText = '';
+for k=1:length(requiredColumns),
+    ix = strmatchIQM(requiredColumns{k},datanames,'exact');
+    if isempty(ix), 
+        errorText = sprintf('%sThe dataset does not contain the column ''%s''.\n',errorText,requiredColumns{k});  
+    end    
+end
+
+% Show error if needed
+if ~isempty(errorText),
+    error(errorText);
+end
+
+dataOut = data;
+
+
+
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/04-NLMEdataPreparation/03-DataNLMEConversion/IQMconvertTask2NLMEdataset.m b/IQMtools V1.2.2.2/IQMpro/tools/04-NLMEdataPreparation/03-DataNLMEConversion/IQMconvertTask2NLMEdataset.m
new file mode 100644
index 0000000000000000000000000000000000000000..c1c79039d0126fc05c9ba6072e28670c47addec7
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/04-NLMEdataPreparation/03-DataNLMEConversion/IQMconvertTask2NLMEdataset.m	
@@ -0,0 +1,276 @@
+function [dataNLME] = IQMconvertTask2NLMEdataset(data,DOSENAMES,OBSNAMES,covNames,catNames,regressionNames,filename)
+% This function converts a task specific general dataset into a dataset
+% that is suitable for NLME analysis in NONMEM and MONOLIX.
+% The data need to be provided in the format of the task specific dataset,
+% used in IQM Tools. If defined, then covariates and regression variables
+% need to be present in this dataset as well as columns.
+%
+% What is done:
+% - Function removes zero AMT doses from the dataset (if not removed in
+%   data cleaning step) - needed for good old NONMEM since ICON is unable
+%   to fix the OLD code into something useful. No one can tell me that
+%   crashing when doses of 0 are coded is a feature - and not a bug.
+% - Check if MDV=1 present for observations without a reason in IGNORE
+%   column. If yes, then throw an error.
+% - Function sets MDV=1 for observations that have non empty IGNORE entry
+%   (should have been done previously - but to be sure it is repeated
+%   here). It will also set DV=0 for all MDV=1 observation records that are NaN.
+% - Removal of all events, except DOSENAMES and OBSNAMES
+% - Adding a YTYPE column with numeric entries. 0 for doses, 1...N
+%   according to order of OBSNAMES
+% - Keeping important standard columns for fitting in NONMEM and MONOLIX
+% - Adding covariate columns to the NLME dataset
+% - If single DOSENAME(S) then ensure DOSE column is present
+% - If multiple DOSENAMES then ensure that DOSE_name columns are present
+%   where name is the Dose event NAME with special characters removed to
+%   make valid variable name.
+% - NaN values in DOSE columns are replaced by 0
+% - Exchanging spaces in string columns to ":::" to allow NONMEM function
+%   with a more informed dataset
+% - Displaying mapping between ADM and ROUTE, and YTYPE and OBSNAMES
+% - If NRDOSES and INTERVAL not all NaN then an ADDL and II column are
+%   added to the dataNLME dataset. NRDOSES is same as ADDL and INTERVAL
+%   same as II.
+% 
+% [SYNTAX]
+% [dataNLME] = IQMconvertTask2NLMEdataset(data,DOSENAMES,OBSNAMES,covNames,catNames,regressionNames)
+% [dataNLME] = IQMconvertTask2NLMEdataset(data,DOSENAMES,OBSNAMES,covNames,catNames,regressionNames,filename)
+%
+% [INPUT]
+% data:             Task specific dataset format as used in IQM tools. This
+%                   dataset needs to contain requested covariates and
+%                   regression variables as columns.
+% DOSENAMES:         String with NAME of dose records in dataset to use
+% OBSNAMES:         Cell-array with NAMEs of readouts to consider for
+%                   observations to fit. The order of the names will
+%                   translate to YTYPE numbers and thus to how the outputs
+%                   in the model need to be numbered. 
+% covNames:         Cell-array with names of continuous covariates.
+% catNames:         Cell-array with names of categorical covariates.
+% regressionNames:  Cell-array with names of regression variables. The
+%                   order of these variables needs to be exactly as they
+%                   appear in the model that is going to be used for
+%                   fitting (model= IQMmodel+IQMdosing).
+% filename:         Filename, including path for saving the popPK
+%                   dataset as CSV file. If not specified, then not
+%                   exported to file. 
+% 
+% [OUTPUT]
+% dataNLME:     Dataset formatted for use with NLME tool (NONMEM or MONOLIX)
+% Additionally, the dataset can be exported to desired filename.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle optional input argument
+if nargin<7,
+    filename = '';
+end
+
+% Check data to be in task format
+IQMcheckTaskDatasetHeader(data);
+
+% Check names
+if ischar(DOSENAMES),
+    DOSENAMES = {DOSENAMES};
+end
+if ischar(OBSNAMES),
+    OBSNAMES = {OBSNAMES};
+end
+
+% Check cov and cat names and regressionNames
+if ischar(covNames),
+    covNames = {covNames};
+end
+if ischar(catNames),
+    catNames = {catNames};
+end
+if ischar(regressionNames),
+    regressionNames = {regressionNames};
+end
+
+% Check covariates and regression variables - they need to be present in
+% the dataset
+checkDataColumnsIQM(data,covNames);
+checkDataColumnsIQM(data,catNames);
+checkDataColumnsIQM(data,regressionNames);
+
+% Keep only dose and readouts in the dataset
+dataNLME = IQMselectDataEvents(data,[DOSENAMES,OBSNAMES]);
+
+% Remove dose records with AMT=0 (needed to allow NONMEM to function)
+% This should have been done previously in the cleaning part but here it
+% needs to be repeated if forgotten - otherwise beautiful NONMEM will crash
+% ... in the year 2015 it is weird that software of that poor quality is
+% accepted.
+dataNLME = IQMcleanRemoveZeroDoses(dataNLME);
+
+% Check if MDV=1 present for observations without a reason in IGNORE column.
+% If yes, then throw an error.
+ix_MDV_IGNORE_test = find(dataNLME.EVID==0 & dataNLME.MDV==1 & strcmp(dataNLME.IGNORE,''));
+if ~isempty(ix_MDV_IGNORE_test),
+    error('MDV=1 observations present that do not have an IGNORE reason.');
+end
+
+% Set all non-empty IGNORE observation records to MDV=1 
+dataNLME.MDV(dataNLME.EVID==0 & ~strcmp(dataNLME.IGNORE,'')) = 1;
+
+% Set for all IGNORE entries for which DV=NaN DV to 0
+dataNLME.DV(dataNLME.EVID==0 & ~strcmp(dataNLME.IGNORE,'') & isnan(dataNLME.DV)) = 0;
+
+
+% Add a YTYPE column - in the order of the OBSNAMES from 1...N
+dataNLME.YTYPE = zeros(height(dataNLME),1);
+for k=1:length(OBSNAMES),
+    dataNLME.YTYPE(strmatchIQM(OBSNAMES{k},dataNLME.NAME,'exact')) = k;
+end
+
+% Check CENS column and inform the user
+if sum(abs(dataNLME.CENS)) ~= 0,
+    disp('CENS column used. For NONMEM you can select the M3 or M4 method for BLOQ in the model generation.');
+    disp('For MONOLIX the standard approach will be used.');
+end
+
+% Define initial structure of NLME dataset
+varNames = {'IXGDF' 'IGNORE' 'ID' 'USUBJID' 'STUDY' 'STUDYN' 'TRT' 'TRTNAME' 'TIME' 'TIMEPOS' 'NT' 'TAD' 'TIMEUNIT' 'YTYPE' 'NAME' 'DV' 'UNIT' 'CENS' 'MDV' 'EVID' 'AMT' 'ADM' 'INTERVAL' 'NRDOSES' 'ROUTE' 'RATE' 'TINF'};
+
+% Check if DOSE is present in the dataset then add it
+if ~isempty(strmatchIQM('DOSE',dataNLME.Properties.VariableNames,'exact')),
+    dataNLME.DOSE(isnan(dataNLME.DOSE)) = 0;
+    varNames{end+1} = 'DOSE';
+else
+    % DOSE not present ... might be due to multiple DOSENAMES ... check
+    for k=1:length(DOSENAMES),
+        doseNameTest = ['DOSE' makeVariableNameIQM(DOSENAMES{k})];
+        if ~isempty(strmatchIQM(doseNameTest,dataNLME.Properties.VariableNames,'exact')),
+            % if only one DOSENAME(S) then rename to DOSE ... otherwise
+            % keep changed name
+            if length(DOSENAMES)==1,
+                dataNLME.DOSE = dataNLME.(doseNameTest);
+                dataNLME.DOSE(isnan(dataNLME.DOSE)) = 0;
+                varNames{end+1} = 'DOSE';
+            else
+                dataNLME.(doseNameTest)(isnan(dataNLME.(doseNameTest))) = 0;
+                varNames{end+1} = doseNameTest;                
+            end
+        end
+    end
+end
+
+% Remove covNames, catNames, regressionNames from varNames
+varNames_clean = {};
+for k=1:length(varNames),
+    ix1 = strmatchIQM(varNames{k},covNames,'exact');
+    ix2 = strmatchIQM(varNames{k},catNames,'exact');
+    ix3 = strmatchIQM(varNames{k},regressionNames,'exact');
+    if isempty([ix1 ix2 ix3]),
+        varNames_clean{end+1} = varNames{k};
+    end
+end
+
+% Add covariates and regression variables
+varNames = [varNames_clean covNames(:)' catNames(:)' regressionNames];
+
+% Create dataset in defined structure - also handles double definitions
+dataTemp = table();
+for k=1:length(varNames),
+    dataTemp.(varNames{k}) = dataNLME.(varNames{k});
+end
+dataNLME = dataTemp;
+
+% % - If single DOSENAME(s) then ensure same ADM settings as in
+% %   IQMconvertGeneral2TaskDataset:
+% %                   ROUTE                 ADM INDEX
+% %                   iv                        2
+% %                   subcut                    1 
+% %                   oral                      1
+% %                   intramuscular             1
+% %                   intraarticular            1
+% %                   inhaled                   1
+% %                   rectal                    1
+% %                   topical                   3
+% if length(DOSENAMES) == 1,
+%     dataNLME.ADM(strcmpi(dataNLME.ROUTE,'iv'))              = 2;
+%     dataNLME.ADM(strcmpi(dataNLME.ROUTE,'subcut'))          = 1;
+%     dataNLME.ADM(strcmpi(dataNLME.ROUTE,'oral'))            = 1;
+%     dataNLME.ADM(strcmpi(dataNLME.ROUTE,'intramuscular'))   = 1;
+%     dataNLME.ADM(strcmpi(dataNLME.ROUTE,'intraarticular'))  = 1;
+%     dataNLME.ADM(strcmpi(dataNLME.ROUTE,'inhaled'))         = 1;
+%     dataNLME.ADM(strcmpi(dataNLME.ROUTE,'rectal'))          = 1;
+%     dataNLME.ADM(strcmpi(dataNLME.ROUTE,'topical'))         = 3;
+% end
+
+% Display some information
+disp('NLME dataset generation: Mapping between ADM and ROUTE for the doses:');
+disp(unique(dataNLME(dataNLME.EVID==1,{'NAME','ROUTE','ADM'})))
+
+disp('NLME dataset generation: Mapping between OBSNAMES and YTYPE:');
+disp(unique(dataNLME(dataNLME.EVID==0,{'NAME','YTYPE'})))
+
+% Exchange all spaces in string variables with ':::' in dataset
+dataNLME = echangeSpacesDataIQM(dataNLME);
+
+% Handle NRDOSES/ADDL and INTERVAL/II
+dataNLME.INTERVAL(isnan(dataNLME.INTERVAL)) = 0;
+dataNLME.NRDOSES(isnan(dataNLME.NRDOSES)) = 0;
+% Check if non-zero values present
+nr_INTERVAL_non0 = length(find(dataNLME.INTERVAL~=0));
+nr_NRDOSES_non0 = length(find(dataNLME.NRDOSES~=0));
+if nr_INTERVAL_non0 ~= nr_NRDOSES_non0,
+    error('Numbers of non zero INTERVAL and NRDOSES entries not matching. Please check!');
+end
+if nr_INTERVAL_non0==0,
+    % Remove the columns
+    dataNLME.INTERVAL = [];
+    dataNLME.NRDOSES = [];
+end
+% Rename columns if still present
+ix = strmatchIQM('INTERVAL',dataNLME.Properties.VariableNames,'exact');
+if ~isempty(ix),
+    dataNLME.Properties.VariableNames{ix} = 'II';
+end
+ix = strmatchIQM('NRDOSES',dataNLME.Properties.VariableNames,'exact');
+if ~isempty(ix),
+    dataNLME.Properties.VariableNames{ix} = 'ADDL';
+end
+
+% Final touch ... IGNORE and ROUTE colum entries are not allowed to stay
+% empty ... this time it is MONOLIX who fucks up. We exchange empty entries
+% in these two columns with '.'. Also UNIT might be missing from the source data
+% (but it should not).
+dataNLME.IGNORE(strcmp(dataNLME.IGNORE,'')) = {'.'};
+dataNLME.ROUTE(strcmp(dataNLME.ROUTE,'')) = {'.'};
+dataNLME.UNIT(strcmp(dataNLME.UNIT,'')) = {'.'};
+
+% Export dataset to CSV if desired
+if ~isempty(filename),
+    IQMexportCSVdataset(dataNLME,filename);
+end
+
+% Check length of original data with final dataNLME. If different than provide a warning or an error.
+% The IQMconvertTask2NLMEdataset does some sanity removals of records for
+% several reasons. For example AMT=0 dose records are removed to allow
+% NONMEM not to crash. However, the user should have taken care of that
+% prior to the call of this function by using the data cleaning functions.
+% The reason is that the data cleaning functions could provide log files of
+% the records that are removed. In a non-regulatory setting, this might not
+% be needed.
+% Therefor if it is detected that records have been removed in this
+% function here then a warning is provided when Compliance mode is off. If
+% Compliance mode is on an error is produced.
+if height(data) ~= height(dataNLME),
+    text = sprintf('The IQMconvertTask2NLMEdataset function removed some rows in the dataset.\n');
+    text = sprintf('%sThis is perfectly normal and it is supposed to do that (see help text for this function).\n',text);
+    text = sprintf('%sBut if you would like to keep track of removed records in clinical projects for compliance\n',text);
+    text = sprintf('%sreasons, then you might want to use the cleaning functions and log the results prior to call\n',text);
+    text = sprintf('%sthe IQMconvertTask2NLMEdataset function, such that no additional entries need to be removed.\n',text);
+    text = sprintf('%sThis text is a warning if compliance mode is off and an error if it is on.\n',text);
+    % Check compliance mode setting
+    SETUP_PATHS_TOOLS_IQMLITE
+    if COMPLIANCE_OUTPUT_MODE == 0,
+        warning(text);
+    else
+        error(text);
+    end
+end
+
+    
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/04-NLMEdataPreparation/03-DataNLMEConversion/IQMgetNLMEdataHeader.m b/IQMtools V1.2.2.2/IQMpro/tools/04-NLMEdataPreparation/03-DataNLMEConversion/IQMgetNLMEdataHeader.m
new file mode 100644
index 0000000000000000000000000000000000000000..2ac286ec202a00d43d1c7378dc67912e0df07aed
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/04-NLMEdataPreparation/03-DataNLMEConversion/IQMgetNLMEdataHeader.m	
@@ -0,0 +1,146 @@
+function [dataNLMEheader] = IQMgetNLMEdataHeader(data,covNames,catNames,regressionNames)
+% This function takes a dataset in an NLME specific format (e.g. generated
+% with the function IQMconvertTask2NLMEdataset). But also user provided NLME
+% datasets can be used. Based on the provided information it will generate
+% a MONOLIX style "dataset header" with column type identifiers as known
+% from MONOLIX. This information is required in IQM Tools for the
+% generation of both MONOLIX and NONMEM projects.
+% 
+% This function requires the presence of a RATE column. Even if all entries
+% need to be zero.
+% 
+% [SYNTAX]
+% [dataNLMEheader] = IQMgetNLMEdataHeader(data)
+% [dataNLMEheader] = IQMgetNLMEdataHeader(data,covNames)
+% [dataNLMEheader] = IQMgetNLMEdataHeader(data,covNames,catNames)
+% [dataNLMEheader] = IQMgetNLMEdataHeader(data,covNames,catNames,regressionNames)
+%
+% [INPUT]
+% data:             NLME specific dataset format (e.g. generated
+%                   with the function IQMconvertTask2NLMEdataset) - containing
+%                   the potentially defined covariates and regression
+%                   variables as columns. Or path to dataset.
+% covNames:         Cell-array with names of continuous covariates
+% catNames:         Cell-array with names of categorical covariates
+% regressionNames:  Cell-array with names of regression variables
+%
+% [OUTPUT]
+% dataNLMEheader:   String with comma separated header info about the type
+%                   of the columns in the dataset.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle data
+if ischar(data),
+    data = IQMloadCSVdataset(data);
+end
+
+% Variable input arguments
+if nargin<2,
+    covNames = {};
+end
+if nargin<3,
+    catNames = {};
+end
+if nargin<4,
+    regressionNames = {};
+end
+
+% Check cov and cat names and regressionNames
+if ischar(covNames),
+    covNames = {covNames};
+end
+if ischar(catNames),
+    catNames = {catNames};
+end
+if ischar(regressionNames),
+    regressionNames = {regressionNames};
+end
+
+% Check covariates and regression variables - they need to be present in
+% the dataset
+checkDataColumnsIQM(data,covNames);
+checkDataColumnsIQM(data,catNames);
+checkDataColumnsIQM(data,regressionNames);
+
+% Define general matches between column names and column types
+% These matches are the same for MONOLIX and NONMEM
+% CMT for NONMEM is not anymore supported and the ADM/YTYPE approach is
+% used instead.
+colName = {'IXGDF'  'USUBJID' 'SS' 'II' 'ADDL' 'STUDYN' 'SUBJECT' 'ID' 'TIME' 'TIMEPOS' 'NT' 'TAD'    'TIMEUNIT' 'DV' 'NAME'   'UNIT'     'MDV' 'EVID' 'CENS' 'AMT'  'ADM' 'ROUTE'  'RATE' 'TINF'    'DOSE'   'TRT' 'YTYPE'};
+colType = {'IGNORE' 'IGNORE'  'SS' 'II' 'ADDL' 'CAT'    'IGNORE'  'ID' 'TIME' 'TIMEPOS' 'IGNORE'       'IGNORE' 'IGNORE'    'DV' 'IGNORE' 'IGNORE'   'MDV' 'EVID' 'CENS' 'AMT'  'ADM' 'IGNORE' 'RATE' 'IGNORE'  'IGNORE' 'CAT' 'YTYPE'};
+
+% Get column names in dataset
+VariableNames = data.Properties.VariableNames;
+
+% Set default header to 'IGNORE'
+headerContent = cell(1,length(VariableNames));
+headerContent(1:end) = {'IGNORE'};
+
+% Apply default matches
+for k=1:length(colName),
+    ix = strmatchIQM(colName{k},VariableNames,'exact');
+    if ~isempty(ix),
+        headerContent{ix} = colType{k};
+    end
+end
+
+% Add continuous covariate information
+for k=1:length(covNames),
+    ix = strmatchIQM(covNames{k},VariableNames,'exact');
+    if ~isempty(ix),
+        headerContent{ix} = 'COV';
+    end
+end
+
+% Add categorical covariate information
+for k=1:length(catNames),
+    ix = strmatchIQM(catNames{k},VariableNames,'exact');
+    if ~isempty(ix),
+        headerContent{ix} = 'CAT';
+    end
+end
+
+% Add regression variable information
+for k=1:length(regressionNames),
+    ix = strmatchIQM(regressionNames{k},VariableNames,'exact');
+    if ~isempty(ix),
+        headerContent{ix} = 'X';
+    end
+end
+
+% Run through all CAT definitions and check if single element value - then
+% warn the user and remove the cat cov by setting to IGNORE, otherwise
+% Monolix error.
+ixCAT = strmatchIQM('CAT',headerContent);
+% Add categorical covariate information
+for k=1:length(ixCAT),
+    catName = VariableNames{ixCAT(k)};
+    if length(unique(data.(catName))) == 1,
+        headerContent{ixCAT(k)} = 'IGNORE';
+        fprintf('\nOnly single cagtegory for candidate categorical covariate "%s". MONOLIX might have problems with that => avoid.\n',catName);    
+    end
+end
+   
+% Create header output string
+dataNLMEheader = sprintf('%s,',headerContent{:});
+dataNLMEheader = dataNLMEheader(1:end-1);
+
+% Check if RATE present in dataset
+ixRATE = strmatchIQM('RATE',headerContent,'exact');
+if isempty(ixRATE),
+    error('The dataset does not contain a RATE column. Please add one even if all entries 0. This allows IQM Tools to work generally across NONMEM and MONOLIX.');
+end
+
+% Print Info
+tableCell = {'<TT>' 'Matching of NLME dataset column names with dataset column types:' ''};
+tableCell(end+1,:) = {'<TH>' 'Column name' 'Inferred Type'};
+for k=1:length(VariableNames),
+    tableCell{k+2,1} = '<TR>';
+    tableCell{k+2,2} = VariableNames{k};
+    tableCell{k+2,3} = headerContent{k};
+end
+disp(IQMconvertCellTable2ReportTable(tableCell,'text'));
+
+
+    
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/04-NLMEdataPreparation/03-DataNLMEConversion/IQMgetRegressionParameters.m b/IQMtools V1.2.2.2/IQMpro/tools/04-NLMEdataPreparation/03-DataNLMEConversion/IQMgetRegressionParameters.m
new file mode 100644
index 0000000000000000000000000000000000000000..7fec6fc501d6ad77d0faa10ffc906e3db5be7a16
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/04-NLMEdataPreparation/03-DataNLMEConversion/IQMgetRegressionParameters.m	
@@ -0,0 +1,38 @@
+function [regressionNames] = IQMgetRegressionParameters(model,dosing)
+% This function takes a model and a dosing scheme and returns the names of
+% the regression parameters that might be in the model+dosing objects.
+% 
+% [SYNTAX]
+% [regressionNames] = IQMgetRegressionParameters(model)
+% [regressionNames] = IQMgetRegressionParameters(model,dosing)
+%
+% [INPUT]
+% model:            IQMmodel object to assess for regression parameters.
+% dosing:           IQMdosing object to assess for regression parameters.
+%
+% [OUTPUT]
+% regressionNames:  Cell-array with regression parameters in the order they
+%                   do appear in the model ... which is the same as in
+%                   which they need to be provided in the NLME fit dataset.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Variable input arguments
+if nargin<2,
+    dosing = [];
+end
+
+% Options
+if isempty(dosing),
+    moddos = model;
+else
+    % Merge model and dosing
+    moddos = mergemoddosIQM(model,dosing);
+end
+
+% Parse the model
+info = basicmodelparsingIQM(moddos);
+
+% Get the regression parameter names
+regressionNames = {info.param_reg.name};
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/04-NLMEdataPreparation/04-DataNLMEInfo/IQMinfoNLMEdata.m b/IQMtools V1.2.2.2/IQMpro/tools/04-NLMEdataPreparation/04-DataNLMEInfo/IQMinfoNLMEdata.m
new file mode 100644
index 0000000000000000000000000000000000000000..7028585c6f0ebfbd3e618af2ad13c7d307496b8f
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/04-NLMEdataPreparation/04-DataNLMEInfo/IQMinfoNLMEdata.m	
@@ -0,0 +1,29 @@
+function [] = IQMinfoNLMEdata(dataNLME)
+% This function provides information about the mapping between doses in the
+% dataset, routes, and their ADM values that need to be matched to the
+% INPUT* values in the model. Additionally information about YTYPE and NAME
+% is provided to support linking to OUTPUT* in the model.
+% 
+% [SYNTAX]
+% [] = IQMinfoNLMEdata(dataNLME)
+%
+% [INPUT]
+% dataNLME:         NLME specific dataset, can also be task specific but
+%                   then no output information is provided.
+%
+% [OUTPUT]
+% Printed table in the command window.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+dataNLME = restoreSpacesDataIQM(dataNLME);
+
+try
+    disp(unique(dataNLME(dataNLME.EVID==1,{'NAME','ROUTE','ADM'})))
+catch
+    disp('Problem showing the link between Dose NAME ROUTE and ADM.');
+end
+
+try
+    disp(unique(dataNLME(dataNLME.EVID==0,{'NAME','YTYPE'})))
+end
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/01-MONOLIX/IQMcreateMLXTRANfile.m b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/01-MONOLIX/IQMcreateMLXTRANfile.m
new file mode 100644
index 0000000000000000000000000000000000000000..2f4ce57625823c8d6c2c7933eef2cc82e08e5b5e
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/01-MONOLIX/IQMcreateMLXTRANfile.m	
@@ -0,0 +1,752 @@
+function [filename, moddosinfo] = IQMcreateMLXTRANfile(model,dosing,varargin)
+% This function creates an MLXTRAN structural model file based on 
+% the IQMmodel and the dosing information. 
+%
+% Regression parameters are taken directly from the model and IT IS IMPORTANT
+% that the regression parameters appear in the model in the same order as they
+% appear in the data file, used for fitting.
+% 
+% [SYNTAX]
+% [filename] = IQMcreateMLXTRANfile(model,dosing)
+% [filename] = IQMcreateMLXTRANfile(model,dosing,filename)
+% [filename] = IQMcreateMLXTRANfile(model,dosing,filename,SILENT,regressionParameters,startTime)
+%
+% [INPUT]
+% model:                IQMmodel (annotated with additional information, see above)
+% dosing:               IQMdosing object (or empty [] if no input defined in model)
+% filename:             Name of the created MLXTRAN file (or '' if undefined)
+% SILENT:               Noutput to command window during run if 1, otherwise 0 (default: 0)
+% regressionParameters: By default regression parameters and their order
+%                       are obtained from the IQMmodel and IQMdosing objects themselves.
+%                       This however has limited usefulness. Normally the
+%                       user is more interested in creating a MONOLIX
+%                       project and in this case the regression parameters
+%                       and their ordering is defined by the dataset and
+%                       user definition. For this case we allow to manually
+%                       provide regression parameters. This is a cell-array
+%                       with the names of the regression parameters and the
+%                       ordering of these parameters needs to be exactly as
+%                       in the dataset. Default: {}. If this input argument
+%                       is given, then the regressor information in the
+%                       IQMmodel and IQMdosing scheme is ignored!!!
+% startTime:            Allows to set the start of the integration to a desired time.
+%                       Default: []: do not set.
+%
+% [OUTPUT]
+% filename: constructed from the model name "modelname_MLXTRAN".
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% SOME CHECKS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isIQMmodel(model),
+    error('First input argument is not an IQMmodel.');
+end
+if isempty(dosing),
+    dosing = IQMdosing();
+end
+if ~isIQMdosing(dosing),
+    error('Second input argument is not an IQMdosing object.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% REPLACE "time" by "t" in the model (MLXTRAN uses t as time variable)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% first check that "t" is not a state, variable, parameter or reaction name
+sn = IQMstates(model);
+pn = IQMparameters(model);
+vn = IQMvariables(model);
+rn = IQMreactions(model);
+allelements = {sn{:} pn{:} vn{:} rn{:}};
+if ~isempty(strmatchIQM('t',allelements,'exact')),
+    error('''t'' defined in the model, but MLXTRAN uses it as the time variable.');
+end
+model = replaceelementIQM(model,'time','t');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% GET STRUCTURES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ms = struct(model);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+filename = [regexprep(ms.name,'\W','') '_MLXTRAN.txt'];
+if nargin >= 3,
+    if ~isempty(varargin{1}),
+        filename = varargin{1};
+        filename = strrep(filename,'.txt','');
+        filename = regexprep(filename,'\W','');
+        filename = [filename '_MLXTRAN.txt'];
+    end
+end
+
+SILENT = 0;
+if nargin >= 4,
+    SILENT = varargin{2};
+end
+
+regressionParameters = {};
+IGNORE_MODELDEFINED_REGRESSORS = 0;
+if nargin >= 5,
+    regressionParameters = varargin{3};
+    IGNORE_MODELDEFINED_REGRESSORS = 1;
+end
+
+startTime = [];
+if nargin>=6,
+    startTime = varargin{4};
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Start conversion protocol with important information
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~SILENT,
+    fprintf('======================================================================\n');
+    fprintf('======================================================================\n');
+    fprintf('Conversion of model to MLXTRAN syntax.\n');
+    fprintf('Please read carefully the information below - it is important to\n');
+    fprintf('ensure correct use of the MLXTRAN model\n');
+    fprintf('==========================================================\n');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% BASIC MODEL PARSING AND MERGE WITH DOSING INFO
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+modelinfo = basicmodelparsingIQM(model);
+moddosinfo = mergemoddosstructsIQM(modelinfo,dosing);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check allowed names ... not all are checked
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+testNames = {modelinfo.param_reg.name modelinfo.param_est.name};
+% DOSE
+if ~isempty(strmatchIQM('DOSE',testNames,'exact')),
+    error('Parameter "DOSE" not allowed in IQMmodels when converting to MONOLIX.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% OPEN FILE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fid = fopen(filename,'w');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INFO
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; MLXTRAN model, created using IQM Tools\r\n');
+fprintf(fid,'; Date: %s\r\n',datestr(now,'yyyy-mmm-DD HH:MM'));
+fprintf(fid,'; By:   %s\r\n',usernameIQM());
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DESCRIPTION (name and notes)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% First line: model name 
+fprintf(fid,'; =============================================\r\n');
+fprintf(fid,'DESCRIPTION: %s\r\n',ms.name);
+fprintf(fid,'; =============================================\r\n');
+% Second (etc.) lines: model notes
+notes = ms.notes;
+% replace "\n" by "\r\n"
+notes = strrep(notes,sprintf('\r'),sprintf('\n'));
+notes = strrep(notes,sprintf('\n'),sprintf('\r\n'));
+% add "\t" in front of each line
+notes = strrep(notes,sprintf('\r\n'),sprintf('\r\n\t'));
+% write out notes
+fprintf(fid,'\t%s\r\n',notes);
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INPUT (parameters etc.)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; =============================================\r\n');
+fprintf(fid,'INPUT:\r\n');
+fprintf(fid,'; =============================================\r\n');
+% Parameters to be estimated are the parameters in the model, marked to be
+% estimated and additional parameters from the dosing scheme also marked for estimation.
+% These parameters are defined in the moddosinfo.param_est structure.
+% Add the parameter names for the parameters to be estimated
+fprintf(fid,'\tparameter = {');
+for k=1:length(moddosinfo.param_est)-1,
+    fprintf(fid,'%s, ',moddosinfo.param_est(k).name);
+end
+fprintf(fid,'%s}',moddosinfo.param_est(end).name);
+fprintf(fid,'\r\n');
+
+% Regression parameters (if defined)
+% If regressionParameters are defined explicitly when calling the function,
+% then these are used. Otherwise the implicitly defined ones in the
+% IQMmodel and IQMdosing scheme are used - if defined.
+if ~IGNORE_MODELDEFINED_REGRESSORS,
+    % USe model defined regressors
+    if ~isempty(moddosinfo.param_reg),
+        fprintf(fid,'\tregressor = {');
+        for k=1:length(moddosinfo.param_reg)-1,
+            fprintf(fid,'%s, ',moddosinfo.param_reg(k).name);
+        end
+        fprintf(fid,'%s}',moddosinfo.param_reg(end).name);
+        fprintf(fid,'\r\n');
+        % Warn the user:
+        if ~SILENT,
+            fprintf('\tRegression parameters present in model:\n');
+            fprintf('\t\tMake sure these parameters appear in the same order in\n');
+            fprintf('\t\tthe dataset as in the model!\n');
+            fprintf('\t=========================================================\n');
+        end       
+    end
+else
+    % Use provided regressors (if not empty)
+    if ~isempty(regressionParameters),
+        fprintf(fid,'\tregressor = {');
+        for k=1:length(regressionParameters)-1,
+            fprintf(fid,'%s, ',regressionParameters{k});
+        end
+        fprintf(fid,'%s}',regressionParameters{end});
+        fprintf(fid,'\r\n');
+        % Check at least that the defined regression parameters are also in the
+        % combined model/dosing scheme
+        moddoscheck = mergemoddosIQM(model,dosing);
+        paramModelsCheck = IQMparameters(moddoscheck);
+        errorMessage = '';
+        for k=1:length(regressionParameters),
+            ix = strmatchIQM(regressionParameters{k},paramModelsCheck,'exact');
+            if isempty(ix),
+                errorMessage = sprintf('%sDefined regression parameter "%s" is not part of the model or dosing scheme.\n',errorMessage,regressionParameters{k});
+            end
+        end
+        if ~isempty(errorMessage),
+            error(errorMessage);
+        end
+        % Warn the user:
+        if ~SILENT,
+            fprintf('\tRegression parameters present in model:\n');
+            fprintf('\t\tMake sure these parameters appear in the same order in\n');
+            fprintf('\t\tthe dataset as in the model!\n');
+            fprintf('\t=========================================================\n');
+        end
+    end
+end  
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PK (input application information)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+warningInfusion = 0;
+if ~isempty(moddosinfo.inputs),
+    % write section identifier
+    fprintf(fid,'; =============================================\r\n');
+    fprintf(fid,'PK:\r\n');
+    fprintf(fid,'; =============================================\r\n');    
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % 1) Define the param_pk parameters that are not estimated, not 
+    %    obtained as regression parameters
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % These parameters are dosing type dependent parameters and model
+    % parameters that appear in the pre-factor of the input definitions
+    % Need to define all but Tinf and Rate parameter (defined in dataset)
+    warningMultipledosings = 0;
+    for k=1:length(moddosinfo.param_pk),
+        if isempty(strfind(moddosinfo.param_pk(k).name,'Rate_')) && isempty(strfind(moddosinfo.param_pk(k).name,'Tinf_')),
+            if length(moddosinfo.param_pk(k).value) > 1 && ~warningMultipledosings,
+                if ~SILENT,
+                    fprintf('\tMultiple dosings present:\n');
+                    fprintf('\t\tIt is assumed that each ka and Tk0 value that might be\n');
+                    fprintf('\t\tdefined in the IQMdosing is equal for all events!\n');
+                    fprintf('\t==========================================================\n');
+                end
+                warningMultipledosings = 1;
+            end
+            if isnumeric(moddosinfo.param_pk(k).value(1)),
+                if ~isempty(moddosinfo.param_pk(k).notes),
+                    fprintf(fid,'\t%s = %g',moddosinfo.param_pk(k).name,moddosinfo.param_pk(k).value(1));
+                    fprintf(fid,'\t; %s\r\n',moddosinfo.param_pk(k).notes);
+                else
+                    fprintf(fid,'\t%s = %g\r\n',moddosinfo.param_pk(k).name,moddosinfo.param_pk(k).value(1));
+                end
+            else
+                if ~isempty(moddosinfo.param_pk(k).notes),
+                    fprintf(fid,'\t%s = %s',moddosinfo.param_pk(k).name,moddosinfo.param_pk(k).value);
+                    fprintf(fid,'\t; %s\r\n',moddosinfo.param_pk(k).notes);
+                else
+                    fprintf(fid,'\t%s = %s\r\n',moddosinfo.param_pk(k).name,moddosinfo.param_pk(k).value);
+                end
+            end
+        end
+    end    
+
+    % Collect information about input fraction definitions etc
+    Xinfo = [];
+    Xinfo.stateindex = [];
+    Xinfo.INPUT_NUMBER = [];
+    Xinfo.factors = {};
+    
+    for k=1:length(moddosinfo.inputs),
+        stateindex = [moddosinfo.inputs(k).stateindex];
+        factors = moddosinfo.inputs(k).factors;
+        % Get input number for comparison with "INPUT" dataset column
+        INPUT_NUMBER = str2double(strrep(moddosinfo.inputs(k).name,'INPUT',''));
+        % Check if partial application into different compartments =>
+        % we do not allow that!
+        if length(stateindex) ~= 1,
+            error('Partial application of a dose into different compartments not supported yet by the MLXTRAN conversion.');
+        end
+        
+        Xinfo.stateindex(end+1) = stateindex(1);
+        Xinfo.INPUT_NUMBER(end+1) = INPUT_NUMBER;
+        Xinfo.factors{end+1} = factors{1};
+    end
+    % Write out one "compartment" statement for each compartment in which doses are administered.
+    % use "amount", since everything else is taken care of by the equations in the model.
+    compstateindices = unique(Xinfo.stateindex);
+    admInfo_compIx = [];
+    admInfo_stateIndex = [];
+    for k=1:length(compstateindices),
+        fprintf(fid,'\tcompartment(cmt=%d, amount=%s)\r\n',k,ms.states(compstateindices(k)).name);
+        admInfo_compIx(end+1) = k;
+        admInfo_stateIndex(end+1) = compstateindices(k);
+    end
+    % Write out dosing type and additional information
+    for k=1:length(moddosinfo.inputs),
+        STATE_NUMBER = moddosinfo.inputs(k).stateindex;
+        % adm: number of input
+        INPUT_NUMBER = eval(strrep(moddosinfo.inputs(k).name,'INPUT',''));
+        % cmt number
+        CMT_NUMBER = admInfo_compIx(admInfo_stateIndex==STATE_NUMBER);
+        % Fraction
+        FRACTION = moddosinfo.inputs(k).factors{1};
+        % Tlag
+        TLAGNAME = '';
+        if ~isempty(moddosinfo.inputs(k).Tlag),
+            TLAGNAME = moddosinfo.inputs(k).TlagName;
+        end
+        
+        % Handle infusion
+        if strcmp(moddosinfo.inputs(k).type,'INFUSION'),
+            fprintf(fid,'\tiv(adm=%d, cmt=%d, p=%s',INPUT_NUMBER,CMT_NUMBER,FRACTION);
+            if isempty(TLAGNAME),
+                fprintf(fid,')\r\n');
+            else
+                fprintf(fid,', Tlag=%s)\r\n',TLAGNAME);
+            end
+            if ~warningInfusion,
+                % Warn the user:
+                if ~SILENT,
+                    fprintf('\tInfusion administration present in model:\n');
+                    fprintf('\t\tMake sure you have a TINF or RATE column in your dataset!\n');
+                    fprintf('\t==========================================================\n');
+                end
+                warningInfusion = 1;
+            end
+        end
+        
+        % Handle 1st order absorption
+        if strcmp(moddosinfo.inputs(k).type,'ABSORPTION1'),
+            KA_PARAMETER = moddosinfo.inputs(k).parameters.name;
+            fprintf(fid,'\tabsorption(adm=%d, cmt=%d, ka=%s, p=%s',INPUT_NUMBER,CMT_NUMBER,KA_PARAMETER,FRACTION);
+            if isempty(TLAGNAME),
+                fprintf(fid,')\r\n');
+            else
+                fprintf(fid,', Tlag=%s)\r\n',TLAGNAME);
+            end
+        end
+        
+        % Handle 0 order absorption
+        if strcmp(moddosinfo.inputs(k).type,'ABSORPTION0'),
+            TK0_PARAMETER = moddosinfo.inputs(k).parameters.name;
+            fprintf(fid,'\tabsorption(adm=%d, cmt=%d, Tk0=%s, p=%s',INPUT_NUMBER,CMT_NUMBER,TK0_PARAMETER,FRACTION);
+            if isempty(TLAGNAME),
+                fprintf(fid,')\r\n');
+            else
+                fprintf(fid,', Tlag=%s)\r\n',TLAGNAME);
+            end
+        end
+        
+        % Handle bolus
+        if strcmp(moddosinfo.inputs(k).type,'BOLUS'),
+            fprintf(fid,'\tiv(adm=%d, cmt=%d, p=%s',INPUT_NUMBER,CMT_NUMBER,FRACTION);
+            if isempty(TLAGNAME),
+                fprintf(fid,')\r\n');
+            else
+                fprintf(fid,', Tlag=%s)\r\n',TLAGNAME);
+            end
+        end
+        
+    end
+    fprintf(fid,'\r\n');
+end
+% Warn the user:
+try
+    if length(unique(Xinfo.INPUT_NUMBER)) > 1,
+        if ~SILENT,
+            fprintf('\tYou have multiple inputs into your model:\n');
+            fprintf('\t\tMake sure you have an "ADM" column in your dataset!\n');
+            fprintf('\t\tFor each dosing record the entry in this column should\n');
+            fprintf('\t\tcorrespond to the number of the input of this dose.\n');
+            fprintf('\t==========================================================\n');
+        end
+    end
+catch
+    % No input available ...
+end
+        
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% EQUATION (define the ODEs, help variables, initial conditions, initial time)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% write section identifier
+fprintf(fid,'; =============================================\r\n');
+fprintf(fid,'EQUATION:\r\n');
+fprintf(fid,'; =============================================\r\n');
+
+if ~isempty(startTime),
+    fprintf(fid,'\r\n\t; Start time of integration');
+    fprintf(fid,'\r\n\t; -------------------------\r\n');
+    fprintf(fid,'\tt0 = %g\r\n\r\n',startTime);
+end
+
+fprintf(fid,'\r\n\t; Always use stiff solver');
+fprintf(fid,'\r\n\t; -----------------------\r\n');
+fprintf(fid,'\todeType = stiff\r\n\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% define the parameters that are not going to be estimated
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% write out all parameter definitions but NEGLECT the following ones:
+%   - parameters to be estimated
+%   - parameters defined as regression parameters
+%   - parameters defined in the PK section (used in input factor terms)
+%   - parameters defining the nominal (0) inputs: INPUT* *=1,2,3,4,...
+%   - consider ONLY model parameters. All dosing specific parameters need
+%     to be handled in the $PK section.
+% All model parameters:
+[pn, pv] = IQMparameters(moddosinfo.model);
+% Remove INPUT*
+removeindex = strmatchIQM('INPUT',pn);
+keepindex = setdiff([1:length(pn)],removeindex);
+pn = pn(keepindex);
+pv = pv(keepindex);
+% Remove the estimated parameters
+removeindex = [];
+pn_est = {moddosinfo.param_est.name};
+for k=1:length(pn_est),
+    removeindex = [removeindex strmatchIQM(pn_est{k},pn,'exact')];
+end
+keepindex = setdiff([1:length(pn)],removeindex);
+pn = pn(keepindex);
+pv = pv(keepindex);
+% Remove the regression parameters
+removeindex = [];
+pn_reg = {moddosinfo.param_reg.name};
+for k=1:length(pn_reg),
+    removeindex = [removeindex strmatchIQM(pn_reg{k},pn,'exact')];
+end
+keepindex = setdiff([1:length(pn)],removeindex);
+pn = pn(keepindex);
+pv = pv(keepindex);
+% Remove the PK parameters
+removeindex = [];
+pn_pk = {moddosinfo.param_pk.name};
+for k=1:length(pn_pk),
+    removeindex = [removeindex strmatchIQM(pn_pk{k},pn,'exact')];
+end
+keepindex = setdiff([1:length(pn)],removeindex);
+pn = pn(keepindex);
+pv = pv(keepindex);
+% Get the parameter notes from the model
+pnotes = {};
+ms = struct(moddosinfo.model);
+for k=1:length(pn),
+    index = strmatchIQM(pn{k},{ms.parameters.name},'exact');
+    pnotes{end+1} = ms.parameters(index).notes;
+end
+% Write out the parameters
+if ~isempty(pn),
+    fprintf(fid,'\t; Model parameters\r\n');
+    fprintf(fid,'\t; ----------------\r\n');
+    for k=1:length(pn),
+        if ~isempty(pnotes{k}),
+            fprintf(fid,'\t%s = %g',pn{k},pv(k));
+            fprintf(fid,'\t; %s\r\n',pnotes{k});
+        else
+            fprintf(fid,'\t%s = %g\r\n',pn{k},pv(k));
+        end
+    end
+    fprintf(fid,'\r\n');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% define the auxiliary variables (model variables)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% write out variables but neglect the following ones:
+%   - output definitions
+%   - regression parameters as variables
+allvarindices = [1:length(ms.variables)];
+% remove output variables
+outputvarindices = [moddosinfo.outputs.varindex];
+varindices = setdiff(allvarindices,outputvarindices);
+% remove regression parameters implemented as variables in the IQMmodel
+if ~isempty(moddosinfo.param_reg),
+    regparvarindices = [moddosinfo.param_reg.varindex];
+    varindices = setdiff(varindices,regparvarindices);
+end
+% Write out the variables
+if ~isempty(varindices),
+    fprintf(fid,'\t; Model variables\r\n');
+    fprintf(fid,'\t; ---------------\r\n');    
+    for k=1:length(varindices),
+        % check if variable contains a piecewise construct
+        if isempty(strfind(ms.variables(varindices(k)).formula,'piecewiseIQM')),
+            % no piecewise contruct present in formula
+            if ~isempty(ms.variables(varindices(k)).notes),
+                fprintf(fid,'\t%s = %s',ms.variables(varindices(k)).name,ms.variables(varindices(k)).formula);
+                fprintf(fid,'; %s\r\n',ms.variables(varindices(k)).notes);
+            else
+                fprintf(fid,'\t%s = %s\r\n',ms.variables(varindices(k)).name,ms.variables(varindices(k)).formula);
+            end
+        else
+            % piecewise contruct present in formula
+            piecewiseText = handlepiecewise4mlxtran(ms.variables(varindices(k)).name,ms.variables(varindices(k)).formula);
+            if ~isempty(ms.variables(varindices(k)).notes),
+                fprintf(fid,'\t%s',piecewiseText);
+                fprintf(fid,'; %s\r\n',ms.variables(varindices(k)).notes);
+            else
+                fprintf(fid,'\t%s\r\n',piecewiseText);
+            end
+        end
+    end
+    fprintf(fid,'\r\n');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Do not define initial time (undefined, means that integrator starts at first event in dataset for each individual)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% initial conditions (only define them if they are non-zero)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% We need to add "_0" to the state names in the assignments
+ictext = '';
+for k=1:length(ms.states),
+    % In IC string if regression variables are used these need "_0" at the end.
+    % If IC defined by a variable that itself is defined by a regression variable then there will be an error --- not caught yet!
+    ICstring = getICstring(ms,k,{moddosinfo.param_reg.name}); % We need to add "_0" to the state names in the assignments
+    ictext = sprintf('%s%s_0 = %s\r\n\t',ictext,ms.states(k).name,ICstring);
+end
+if ~isempty(ictext),
+    fprintf(fid,'\t; Initial conditions\r\n\t;------------------\r\n\t%s',ictext);
+    fprintf(fid,'\r\n');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% define the reactions
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(ms.reactions),
+    fprintf(fid,'\t; Model reactions\r\n');
+    fprintf(fid,'\t; ---------------\r\n');    
+    for k=1:length(ms.reactions),
+        % check if reaction contains a piecewise construct
+        if isempty(strfind(ms.reactions(k).formula,'piecewiseIQM')),
+            % no piecewise contruct present in formula
+            if ~isempty(ms.reactions(k).notes),
+                fprintf(fid,'\t%s = %s',ms.reactions(k).name,ms.reactions(k).formula);
+                fprintf(fid,'\t; %s\r\n',ms.reactions(k).notes);
+            else
+                fprintf(fid,'\t%s = %s\r\n',ms.reactions(k).name,ms.reactions(k).formula);
+            end
+        else
+            % piecewise contruct present in formula
+            piecewiseText = handlepiecewise4mlxtran(ms.reactions(k).name,ms.reactions(k).formula);
+            if ~isempty(ms.reactions(k).notes),
+                fprintf(fid,'\t%s',piecewiseText);
+                fprintf(fid,'\t; %s\r\n',ms.reactions(k).notes);
+            else
+                fprintf(fid,'\t%s\r\n',piecewiseText);
+            end
+        end            
+    end
+    fprintf(fid,'\r\n');    
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% define the differential equations (remove the input terms)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'\t; Differential equations\r\n');
+fprintf(fid,'\t; ----------------------\r\n');
+for k=1:length(ms.states),
+    ODE = ms.states(k).ODE;
+    % remove input terms (do this already general for several inputs)
+    for k2 = 1:length(moddosinfo.inputs),
+        % check if current input exists in current (k-th) ODE:
+        index = find(moddosinfo.inputs(k2).stateindex == k);
+        if ~isempty(index),
+            % the input term to replace is:
+            termreplace = moddosinfo.inputs(k2).terms{index};
+            ODE = strrep(ODE,termreplace,'');
+        end
+    end
+    % write out the ODE
+    fprintf(fid,'\tddt_%s = %s\r\n',ms.states(k).name,ODE);
+end
+% final line break
+fprintf(fid,'\r\n');
+ 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% OUTPUT (all the outputs and expressions, defined in the model
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% write section identifier
+fprintf(fid,'; =============================================\r\n');
+fprintf(fid,'OUTPUT:\r\n');
+fprintf(fid,'; =============================================\r\n');
+fprintf(fid,'\toutput = {');
+for k=1:length(moddosinfo.outputs)-1,
+    fprintf(fid,'%s, ',moddosinfo.outputs(k).formula);
+end
+fprintf(fid,'%s}',moddosinfo.outputs(end).formula);
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CLOSE FILE AND RETURN
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fclose(fid);
+return
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get IC string
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [ICstring] = getICstring(ms,k,regressionvariables)
+IC = ms.states(k).initialCondition;
+% If numeric, then convert to string and return
+if isnumeric(IC),
+    ICstring = num2str(ms.states(k).initialCondition,20);
+    return
+end
+% If not numeric then need to add "_0" to all state names in the equation
+states = {ms.states.name};
+for k2=1:length(states),
+    findstates{k2} = ['\<' states{k2} '\>'];
+    replstates{k2} = [states{k2} '_0'];
+end
+ICstring = regexprep(IC,findstates,replstates);
+% And add "_0" to all regression parameters in the equation
+findregression = {};
+replregression = {};
+for k2=1:length(regressionvariables),
+    findregression{k2} = ['\<' regressionvariables{k2} '\>'];
+    replregression{k2} = [regressionvariables{k2} '_0'];
+end
+ICstring = regexprep(ICstring,findregression,replregression);
+return
+    
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE PIECEWISE EXPRESSIONS => if elseif else end
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [changedformula] = handlepiecewise4mlxtran(name,formula)
+formula = strtrim(formula);
+% 1) Check that only a single piecewise expression 
+index = strfind(formula,'piecewiseIQM');
+if length(index) > 1,
+    error('More than one piecewise expression in formula ''%s''. Only one is allowed.',formula);
+end
+% 2) Get the piecewise expression
+pwformula = strtrim(formula(index:end));
+offset = length('piecewiseIQM(')+1;
+po = 1;
+while po~=0,
+    if pwformula(offset) == '(',
+        po = po+1;
+    end
+    if pwformula(offset) == ')',
+        po = po-1;
+    end
+    offset = offset+1;
+end
+pwformula = pwformula(1:offset-1);
+% 3) Check length pwformula against formula. If not same => error, since
+% then additional terms are present in the formula.
+if length(formula) ~= length(pwformula),
+    error('Formula ''%s'' contains more than a simple piecewise expression.',formula);
+end
+% 4) Get elements of pw expression
+elements = explodePCIQM(pwformula(14:end-1));
+% 5) parse and convert the trigger expressions
+for k=2:2:length(elements),
+    elements{k} = convertlogicalrelationalexpressions(elements{k});
+end
+% 6) check if an else is present
+n = length(elements);
+if n/2 == floor(n/2),
+    elsepresent = 0;
+else
+    elsepresent = 1;
+end
+% 6) construct the if elseif else text
+if elsepresent,
+    elseelement = elements{end};
+    elements = elements(1:end-1);
+end
+% if 
+text = sprintf('if (%s)\r\n\t%s = %s\r\n',elements{2},name,elements{1});
+% elseif
+if length(elements) > 2,
+    for k=4:2:length(elements),
+        text = sprintf('%selseif (%s)\r\n\t%s = %s\r\n',text,elements{k},name,elements{k-1});        
+    end
+end
+% else
+if elsepresent,
+    text = sprintf('%selse\r\n\t%s = %s\r\n',text,name,elseelement);
+end
+% end
+text = sprintf('%send',text);
+% done
+changedformula = text;
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PARSE AND CONVERT LOGICAL AND RELATIONAL OPERATORS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% the syntax of MLXTRAN only allows two elements for each and, or, ...
+% and(gt(time,5),lt(time,10)) => (time.gt.5).and.(time.lt.10)
+function [exp] = convertlogicalrelationalexpressions(exp)
+operatorsfind = {'and','or','andIQM','orIQM','lt','gt','le','ge','eq','ne'};
+operatorsuse  = {' & ',' | ',' & ',' | ',' < ',' > ',' <= ',' >= ',' == ',' != '};
+exp = ['#' exp '#'];
+for k=1:length(operatorsfind),
+    index = regexp(exp,['\W' operatorsfind{k} '\W']);
+    if ~isempty(index),
+        % get pre text
+        exppre = exp(1:index);
+        % get post text and arguments
+        temp = exp(index+1+length(operatorsfind{k})+1:end);
+        po = 1;
+        offset = 1;
+        while po~= 0,
+            if temp(offset) == '(',
+                po = po+1;
+            end
+            if temp(offset) == ')',
+                po = po-1;
+            end
+            offset = offset + 1;
+        end
+        args = explodePCIQM(temp(1:offset-2));
+        if length(args) > 2,
+            error('Only two arguments allowed in an ''andIQM'' or ''orIQM'' when converting piecewiseIQM to MLXTRAN.');
+        end
+        exppost = temp(offset:end);
+        % get args
+        exp = [exppre '(' args{1} ')' operatorsuse{k} '(' args{2} ')'   exppost];
+    end
+end
+exp = exp(2:end-1);
+return
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/01-MONOLIX/IQMcreateMONOLIXproject.m b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/01-MONOLIX/IQMcreateMONOLIXproject.m
new file mode 100644
index 0000000000000000000000000000000000000000..ce128ba061d4e4e8826192eba11bbbbd48f14bc1
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/01-MONOLIX/IQMcreateMONOLIXproject.m	
@@ -0,0 +1,1214 @@
+function IQMcreateMONOLIXproject(model,dosing,data,projectPath,varargin)
+% Creates a Monolix/MLXTRAN project from an IQMmodel and an IQMdosing
+% scheme. 
+%
+% This function will check if underscores are present in parameter and
+% covariatenames. This is not allowed in IQM Tools for Monolix conversion.
+% The reason is that Lixoft is constantly changing the output syntax of the
+% parameter estimates and only by not allowing underscores it is possible
+% to make sense out of the output across Monolix versions.
+%
+% IMPORTANT: continuous covariates are always log-transformed, independent
+% of the distribution of the parameter on which they are added. 
+%
+% [SYNTAX]
+% [] = IQMcreateMONOLIXproject(model,dosing,data,projectPath)
+% [] = IQMcreateMONOLIXproject(model,dosing,data,projectPath,options)
+% [] = IQMcreateMONOLIXproject(model,dosing,data,projectPath,options,parameterOrder)
+%
+% [INPUT]
+% model:            IQMmodel - with additional annotation:
+%                       Variables OUTPUT1-N where 1-N matches the YTYPE definitions in the dataset.
+%                       <estimate> as comment on parameters to be estimated.
+%                       <regression> as comment on parameters to be obtained from dataset.
+% dosing:           IQMdosing object (or empty [] if no INPUT defined in model)
+% data:             Structure with following fields:
+%       data.dataRelPathFromProject:    path to data file - relative to the
+%                                       projectPath folder.
+%       data.dataFileName:              data file filename
+%       data.dataHeaderIdent:           String with datafile header identifiers (example: 'ID,TIME,Y,MDV,EVID,AMT,TINF,ADM,YTYPE,COV,COV,CAT') 
+% projectPath:      String with the path/foldername to which the project files are to be written (example: 'FIT_01' or 'Models/FITS/FIT_01') 
+% parameterOrder:   Used to reorder parameters (used by the popPK workflow, do not use otherwise)
+%
+% options:      Structure with following fields (all optional with default settings):
+%       options.POPestimate:            Vector with 0 and 1 entries. 1 if pop parameter is estimated, 0 if not. Default or []: => all are estimated
+%       options.POPvalues0:             Vector with pop parameter initial values. Default or []: => values stored in model and dosing scheme
+%       options.IIVdistribution:        Cell-array with information about parameter distribution. L (lognormal), N (normal), G (logit)
+%                                       Example: {'L' 'L' 'L' 'L' 'N' 'L' 'L' 'L'}. Default or {}: => use lognormal for all
+%       options.IIVestimate:            Vector with 0 and 1 entries. 1 if random effect is estimated, 0 if not. Default or []: => all are estimated
+%                                       0: IIV not estimated (IIVvalues0 not used) 
+%                                       1: IIV estimated (IIVvalues0 as starting guesses)
+%                                       2: IIV not estimated but fixed on IIVvalues0 value
+%       options.IIVvalues0:             Vector with random effect parameter
+%                                       initial values. Default or []: => all set to 0.5
+%                                       If IIV not estimated then defined initial guess not used but replaced by 0
+%       options.errorModels:            String with definition of residual error models, comma separated for each output.
+%                                       Possible values: const,prop,comb1. Example: 'comb1,prop', Default or '': => const for all outputs
+%       options.errorParam0:            Vector allowing to pass initial guesses for error model parameters. Same order as error models. 
+%                                       'const': a, 'prop': b, 'comb1': a,b
+%       options.covarianceModel:        Definition of covariance model. String with cell-array text inside, grouping the parameters to consider having 
+%                                       correlated random effects. Example: '{CL,Vc},{Q,Vp,KM}'. Default: 'diagonal'
+%       options.covariateModel:         Definition of covariate model. Cell-array. Each element is a sub-cell-array. First element in sub-cell-array is the 
+%                                       parameter to which to add the covariate, all following elements define the covariates as named in the dataset.
+%                                       Example: '{CL,BMI0}, {Fsubcut,WT0}, {Vc,SEX,BMI0}'. Default: '' => no covariates
+%                                       By default (and so far not changeable, the continuous covariates are all weighted by their median, determined from the dataset)
+%                                       >>>Covariates can be added to all parameters for which not both IIVestimate and POPestimate are 0.
+%       options.covariateModelValues:   Definition of covariate coefficients for the selected covariate model. 
+%                                       Syntax is similar to options.covariateModel. It is a cell-array containing vectors instead of cell-arrays.
+%                                       Each vector contains values for the covariate coefficients, matching the covariateModel definition order.
+%                                       Example: if options.covariateModel = '{CL,BMI0,AGE0}, {Fsubcut,WT0}, {Vc,SEX,BMI0}'
+%                                       Then: options.covariateModelValues = {[0.5,0], [0.75], [0,0]}
+%                                       Defines the initial guesses for the covariate coefficients for BMI0 on CL to be 0.5, WT0 on Fsubcut to be 0.75, and the other ones are 0.
+%                                       If not defined, all covariate coefficients start from 0 in the estimation.
+%       options.COVestimate:            Same structure as options.covariateModelValues but with entries 0 or 1. 0 means not estimated, 1 means estimated.
+%                                       By default all are estimated.
+%                                       In the example above options.COVestimate = {[0,1], [1], [1,0]}   will estimate AE0 on CL, WT0 on Fsubcut, SEX on Vc.
+%                                       The other coefficients will be kept fixed.
+%       options.COVcentering.covs:      Cell-array with covariates that should be centered around a custom value. 
+%       options.COVcentering.values:    Vector with centering values. 
+%       options.Ntests:                 Doing robustness analysis - number of models to generate with different initial guesses (randomly generated based on POPvalues0)
+%                                       Default: 1 (no robustness analysis, using initial guesses as provided)
+%       options.std_noise_setting:      Standard deviation to use to add noise to the initial parameter guesses (default=0.5 (50%CV))
+%                                       Normal:         Parameter_guess + std_noise_setting*Parameter_guess*randomNumbers(0-1)
+%                                       Lognormal:      Parameter_guess * exp(std_noise_setting*randomNumbers(0-1))
+%                                       Logitnormal:    Similar and between 0-1
+%       options.algorithm.SEED:         Seed setting. Defualt: 123456
+%       options.algorithm.K1:           First iterations. Default: 500
+%       options.algorithm.K2:           Final iterations. Default: 200
+%       options.algorithm.K1_AUTO:      Automatic first iteration number (0: off, 1: on). Default: 0
+%       options.algorithm.K2_AUTO:      Automatic final iteration number (0: off, 1: on). Default: 0
+%       options.algorithm.NRCHAINS:     Number of parallel chains. Default: 1
+%       options.algorithm.LLsetting:    'linearization' (default) or 'importantsampling'
+%       options.algorithm.FIMsetting:   'linearization' (default) or 'stochasticApproximation'
+%       options.algorithm.INDIVparametersetting: 'conditionalMode' (default) ... others not considered for now. 
+%       options.algorithm.startTime:    start time of integration. default: [] (not set).
+%       options.SILENT:                 =0: do some output in the command window, =1: do no output in command window (default: 0)
+%       options.keepProjectFolder:      =0: remover already existing folder, =1: keep it
+%
+% [OUTPUT]
+% Generated MONOLIX Project at projectPath location
+%
+% [ASSUMPTIONS]
+% - Always log transformed continuous covariates (centered by the median)
+% - Always untransformed categorical covariates
+% - FIM: always by computed by linearization
+% - Individual parameters are always determined by conditional modes, 
+% - Use Monolix default graphics settings
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Define Default Properties (Never changing)
+projectName            = 'project';
+resultsFolder          = 'RESULTS';
+
+% Check input
+if ischar(model),
+    model = IQMmodel(model);
+end
+if ischar(dosing),
+    dosing = IQMdosing(dosing);
+end
+if ~isIQMmodel(model),
+    error('First input argument is not an IQMmodel.');
+end
+if ~isIQMdosing(dosing) && ~isempty(dosing),
+    error('Second input argument is not an IQMdosing scheme.');
+end
+try
+    dataRelPathFromProject = data.dataRelPathFromProject;
+    dataFileName           = data.dataFileName;
+    dataHeaderIdent        = data.dataHeaderIdent;
+catch
+    error('data input argument not defined correctly.');
+end
+
+% Removal of TIMEPOS in dataHeaderIdent: TIMEPOS only needed for NONMEM ...
+dataHeaderIdent         = regexprep(dataHeaderIdent,'\<TIMEPOS\>','IGNORE');
+
+% Handle variable input arguments
+options = [];
+parameterOrder = {};
+if nargin==5,
+    options = varargin{1};
+    parameterOrder = {};
+elseif nargin==6,
+    options = varargin{1};
+    parameterOrder = varargin{2};
+end
+
+% Handle optional arguments
+try POPestimate                     = options.POPestimate;                      catch, POPestimate = [];                             end
+try POPvalues0                      = options.POPvalues0;                       catch, POPvalues0 = [];                              end
+try IIVdistribution                 = options.IIVdistribution;                  catch, IIVdistribution = {};                         end
+try IIVestimate                     = options.IIVestimate;                      catch, IIVestimate = [];                             end
+try IIVvalues0                      = options.IIVvalues0;                       catch, IIVvalues0 = [];                              end
+try errorModels                     = options.errorModels;                      catch, errorModels = '';                             end
+try errorParam0                     = options.errorParam0;                      catch, errorParam0 = [];                             end
+try covarianceModel                 = options.covarianceModel;                  catch, covarianceModel = 'diagonal';                 end
+try covariateModel                  = options.covariateModel;                   catch, covariateModel = '';                          end
+try covariateModelValues            = options.covariateModelValues;             catch, covariateModelValues = {};                    end
+try COVestimate                     = options.COVestimate;                      catch, COVestimate = {};                             end
+try COVcentering_covs               = options.COVcentering.covs;                catch, COVcentering_covs = {};                       end
+try COVcentering_values             = options.COVcentering.values;              catch, COVcentering_values = [];                     end
+try SEED                            = options.algorithm.SEED;                   catch, SEED = 123456;                                end
+try K1                              = options.algorithm.K1;                     catch, K1 = 500;                                     end
+try K2                              = options.algorithm.K2;                     catch, K2 = 200;                                     end
+try K1_AUTO                         = options.algorithm.K1_AUTO;                catch, K1_AUTO = 0;                                  end
+try K2_AUTO                         = options.algorithm.K2_AUTO;                catch, K2_AUTO = 0;                                  end
+try NRCHAINS                        = options.algorithm.NRCHAINS;               catch, NRCHAINS = 1;                                 end
+try SILENT                          = options.SILENT;                           catch, SILENT = 0;                                   end
+try INDIVparametersetting           = options.algorithm.INDIVparametersetting;  catch, INDIVparametersetting = 'conditionalMode';    end
+try LLsetting                       = options.algorithm.LLsetting;              catch, LLsetting = 'linearization';                  end
+try FIMsetting                      = options.algorithm.FIMsetting;             catch, FIMsetting = 'linearization';                 end
+try startTime                       = options.algorithm.startTime;              catch, startTime = [];                               end
+try keepProjectFolder               = options.keepProjectFolder;                catch, keepProjectFolder = 0;                        end   
+try Ntests                          = options.Ntests;                           catch, Ntests = 1;                                   end
+try std_noise_setting               = options.std_noise_setting;                catch, std_noise_setting = 0.5; options.std_noise_setting = 0.5;    end
+
+% Handle cell requirements
+if ~iscell(COVcentering_covs),
+    COVcentering_covs = {COVcentering_covs};
+end
+
+options.covariateModel = covariateModel;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle first the case with robustness analysis
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if Ntests>1,
+    % Check if POPvalues0 and POPestimate defined
+    if isempty(POPestimate) || isempty(POPvalues0),
+        error('When doing robustness analysis, please define options.POPvalues0 and options.POPestimate!');
+    end
+    
+    % Define IIVdistribution if still empty (default: all 'L')
+    if isempty(IIVdistribution),
+        for k=1:length(POPvalues0),
+            IIVdistribution{k} = 'L';
+        end
+    end
+    
+    % Sample Ntests new POPvalues0 for the ones that are estimated using
+    % std_noise_setting as standard deviation
+    
+    % Allocating variable
+    POPvalues0_sampled                              = POPvalues0(ones(1,Ntests),:);
+    
+    % Sampling normally distributed (IIV) parameters - which are also estimated on a population level
+    ix_normal_sampled                               = find(strcmp(IIVdistribution,'N').*POPestimate);
+    POPvalues0_sampled(:,ix_normal_sampled)         = POPvalues0(ones(1,Ntests),ix_normal_sampled) + std_noise_setting*POPvalues0(ones(1,Ntests),ix_normal_sampled).*randn(Ntests,length(ix_normal_sampled));
+
+    % Sampling log normally distributed (IIV) parameters - which are also estimated on a population level
+    ix_lognormal_sampled                            = find(strcmp(IIVdistribution,'L').*POPestimate);
+    MU                                              = log(POPvalues0(ones(1,Ntests),ix_lognormal_sampled));
+    XXX                                             = MU + std_noise_setting.*randn(Ntests,length(ix_lognormal_sampled));
+    POPvalues0_sampled(:,ix_lognormal_sampled)      = exp(XXX);
+    
+    % Sampling logit normally distributed parameters - which are also estimated on a population level
+    ix_logitnormal_sampled                          = find(strcmp(IIVdistribution,'G').*POPestimate);
+    MU                                              = log(POPvalues0(ones(1,Ntests),ix_logitnormal_sampled)./(1-POPvalues0(ones(1,Ntests),ix_logitnormal_sampled)));
+    XXX                                             = MU + std_noise_setting.*randn(Ntests,length(ix_logitnormal_sampled));
+    POPvalues0_sampled(:,ix_logitnormal_sampled)    = exp(XXX)./(1+exp(XXX));
+    
+    % Clean folder
+    try rmdir(projectPath,'s'); catch, end
+    
+    % Create Ntests different models in the projectPath/MODEL_01/02, ... folders
+    for k=1:Ntests,
+        % Setup new project creation stuff
+        modelK                          = model;
+        dosingK                         = dosing;
+        dataK                           = data;
+        dataK.dataRelPathFromProject    = ['../' data.dataRelPathFromProject];
+        projectPathK                    = [projectPath sprintf('/MODEL_%s',preFillCharIQM(k,length(num2str(Ntests)),'0'))];
+        optionsK                        = options;
+        optionsK                        = rmfield(optionsK,'Ntests');
+        optionsK                        = rmfield(optionsK,'std_noise_setting');
+        optionsK.POPvalues0             = POPvalues0_sampled(k,:);
+        IQMcreateMONOLIXproject(modelK,dosingK,dataK,projectPathK,optionsK)
+    end
+    
+    % Ready, return
+    return
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Convert covariate model into different syntax
+% '{CL,BMI0}, {Fsubcut,WT0}, {Vc,SEX,BMI0}'
+% to
+% {{'CL','BMI0'}, {'Fsubcut','WT0'}, {'Vc','SEX','BMI0'}}
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(covariateModel),
+    terms = explodePCIQM(covariateModel,',','{','}');
+    y = {};
+    for k=1:length(terms),
+        x = strrep(strtrim(terms{k}),' ','');
+        x = strrep(x,'{','{''');
+        x = strrep(x,'}','''}');
+        x = strrep(x,',',''',''');
+        y{k} = eval(x);
+    end
+    covariateModel = y;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check covariateModelValues
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(covariateModel) && ~isempty(covariateModelValues),
+    error('If you define covariateModelValues, you also need to define the covariateModel.');
+end
+
+if isempty(covariateModelValues),
+    % Determine default covariateModelValues
+    covariateModelValues = {};
+    for k=1:length(covariateModel),
+        covariateModelValues{k} = zeros(1,length(covariateModel{k})-1);
+    end
+else
+    % Check correct length of covariateModelValues elements
+    if length(covariateModel) ~= length(covariateModelValues),
+        error('Number of elements in covariateModel and covariateModelValues needs to match.');
+    end
+    for k=1:length(covariateModel),
+        if length(covariateModel{k})-1 ~= length(covariateModelValues{k}),
+            error('Length of single elements in covariateModel and covariateModelValues needs to match (covariateModelValues elements being one shorter).');
+        end            
+    end    
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check COVestimate
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(covariateModel) && ~isempty(COVestimate),
+    error('If you define COVestimate, you also need to define the covariateModel.');
+end
+
+if isempty(COVestimate),
+    % Determine default COVestimate - all are estimates
+    COVestimate = {};
+    for k=1:length(covariateModel),
+        COVestimate{k} = ones(1,length(covariateModel{k})-1);
+    end
+else
+    % Check correct length of COVestimate elements
+    if length(covariateModel) ~= length(COVestimate),
+        error('Number of elements in covariateModel and COVestimate needs to match.');
+    end
+    for k=1:length(covariateModel),
+        if length(covariateModel{k})-1 ~= length(COVestimate{k}),
+            error('Length of single elements in covariateModel and COVestimate needs to match (COVestimate elements being one shorter).');
+        end            
+    end    
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Create project and results folder
+% Change into project path
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+warning off
+oldpath = pwd;
+if ~keepProjectFolder,
+    try, rmdir(projectPath,'s'); catch, end
+end
+mkdir(projectPath); cd(projectPath)
+mkdir(resultsFolder);
+warning on
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Load dataset and get column names
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try
+    dataCSV     = IQMloadCSVdataset(fullfile(dataRelPathFromProject,dataFileName));
+catch
+    error('Trouble loading the data file. Please check if data.dataRelPathFromProject has been defined correctly.');
+end
+dataheader  = dataCSV.Properties.VariableNames;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check the NLME dataset for the minimal required columns
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+IQMcheckNLMEdatasetHeader(dataCSV);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Determine medians for covariates
+% Also handle in case custom centering values are defined.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Determine index of COV columns and their names
+terms   = explodePCIQM(dataHeaderIdent);
+ixCOVs  = strmatchIQM('COV',terms,'exact');
+if ~isempty(ixCOVs),
+    covariateMedianNames            = dataheader(ixCOVs);
+
+    % Get median values
+    unique_covs                     = unique(dataCSV(:,{'ID' covariateMedianNames{:}}));
+    covariateMedianValues           = nanmedianIQM(table2array(unique_covs(:,2:end)));
+
+    % Handle custom centering values
+    for k=1:length(COVcentering_covs),
+        ix                          = strmatchIQM(COVcentering_covs{k},covariateMedianNames,'exact');
+        covariateMedianValues(ix)   = COVcentering_values(k);
+    end
+    
+    if ~SILENT, 
+        disp(' ')
+        disp('==================================================================');
+        disp('Analysis of dataset for covariates - determine the centering values  ')
+        disp('These are the median values, if not defined differently by the user.')
+        disp(' Results:');
+        for k=1:length(covariateMedianValues),
+            disp(sprintf('   median(%s) = %g',covariateMedianNames{k},covariateMedianValues(k)));
+        end
+        disp('These values will be used to center the continuous covariates')
+        disp('==================================================================');
+        disp(' ')
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get model structure
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ms = struct(model);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Create MLXTRAN model
+% Provide the correct regression parameter names as ordered in the dataset
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+regressionParametersData = dataCSV.Properties.VariableNames(strmatchIQM('X',explodePCIQM(data.dataHeaderIdent),'exact'));
+[modelFileName, modelInfo] = IQMcreateMLXTRANfile(model,dosing,'model',SILENT,regressionParametersData,startTime);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% If needed, reorder parameters
+% Reordering of parameters happens only for parameters to be estimated and
+% should never be used by a user. Only by the popPK workflow.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(parameterOrder),
+    % First load the MLXTRAN file and change the order of the parameters
+    ptext = sprintf('%s, ',parameterOrder{:});
+    ptext = ptext(1:end-2);
+    parameter_def_new = sprintf('parameter = {%s}\r',ptext);
+    % Read file to be changed
+    content = fileread(modelFileName);
+    % Change
+    content = regexprep(content,'(parameter = {[^\n]+)',parameter_def_new);
+    % Save file again
+    fid = fopen(modelFileName,'w');
+    fprintf(fid,'%s',content);
+    fclose(fid);
+    % Reorder parameters in modelInfo.param_est
+    ix_reorder = [];
+    for k=1:length(parameterOrder),
+        ix_reorder(k) = strmatchIQM(parameterOrder{k},{modelInfo.param_est.name},'exact');
+    end
+    modelInfo.param_est = modelInfo.param_est(ix_reorder);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Info text
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~SILENT,
+    disp(' ')
+    disp('==================================================================');
+    disp('==================================================================');
+    disp('== Start of creation of Monolix project.mlxtran file');
+    disp('==================================================================');
+    disp('==================================================================');
+    disp(' ')
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Write out parameter names and values for information
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~SILENT,
+    disp('Parameters selected to be estimated and their values in the model (this order):');
+    disp('===============================================================================');
+    for k=1:length(modelInfo.param_est),
+        fprintf('\t%d)\t%s%s: %g\n',k,modelInfo.param_est(k).name,char(32*ones(1,15-length(modelInfo.param_est(k).name))),modelInfo.param_est(k).value0(1));
+    end
+    disp('==================================================================');
+    disp(' ');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check if datafile exists and csv file and load some information
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+dataFile = [dataRelPathFromProject '/' dataFileName];
+try
+    dataheader = IQMloadCSVdataset(dataFile,1);
+catch
+    cd(oldpath);
+    error('Please check if the data file "%s" exists.',dataFile)
+end
+% Check if length of header identical to dataHeaderIdent
+if length(explodePCIQM(dataHeaderIdent,',')) ~= length(dataheader),
+    cd(oldpath);
+    error('Please check: The data header identifiers do not have the same length as the number of columns in the dataset.')
+end
+
+% Determine continuous and categorical covariates
+IDs = explodePCIQM(dataHeaderIdent,',');
+covIDs = strmatchIQM('COV',upper(IDs));
+covNames = dataheader(covIDs);
+catIDs = strmatchIQM('CAT',upper(IDs));
+catNames = dataheader(catIDs);
+
+% % Check that regression parameters correctly defined
+% This chcek is not needed anymore, since regression parameters taken from
+% dataset according to user specs. And check that regression parameters are
+% available in the model is done above in the write out of the regression
+% parameters during creation of the MLXTRAN model file.
+% nrREGSmodel = length(modelInfo.param_reg);
+% nrREGSdata  = length(strmatchIQM('X',upper(IDs)));
+% if nrREGSmodel ~= nrREGSdata,
+%     cd(oldpath);
+%     error('Different numbers of regression parameters in model and in dataset.');
+% end
+
+% This printout is not needed anymore, since regression parameters are not
+% taken from the model but from the dataset and the header type information
+% when creating a MONOLIX project.
+% % Print table with regression parameters model and data
+% REGAnamesData  = dataheader(strmatchIQM('X',upper(IDs)));
+% if ~SILENT,
+%     disp(' ');
+%     disp('Please check that the following matches regression parameters in data and model do make sense:');
+%     for k=1:length(REGAnamesData),
+%         fprintf('\t%s%s: %s\n',REGAnamesData{k},char(32*ones(1,8-length(REGAnamesData{k}))),modelInfo.param_reg(k).name)
+%     end
+% end
+% % Print table with header names and identifiers
+% IDs = explodePCIQM(dataHeaderIdent,',');
+
+if ~SILENT,
+    disp(' ');
+    disp('Please check that the following matches between data header and identifiers do make sense:');
+    for k=1:length(dataheader),
+        fprintf('\t%s%s: %s\n',dataheader{k},char(32*ones(1,8-length(dataheader{k}))),IDs{k})
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check parameter and covariate names ... '_' not allowed
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+parNamesCheck = [{modelInfo.param_est.name} covNames catNames];
+text_error = '';
+for k=1:length(parNamesCheck),
+    if ~isempty(strfind(parNamesCheck{k},'_')),
+        text_error = sprintf('%sUnderscores "_" are not allowed in parameter and covariate names: "%s".\n',text_error,parNamesCheck{k});
+    end
+end
+if ~isempty(text_error),
+    error(text_error);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check POPestimate thing
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(POPestimate),
+    POPestimate = ones(1,length(modelInfo.param_est));
+end
+if length(modelInfo.param_est) ~= length(POPestimate),
+    cd(oldpath);
+    error('Please make sure POPestimate is of same length as number of parameters to be estimated.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check POPvalues0 thing
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(POPvalues0),
+    POPvalues0 = [];
+    for k=1:length(modelInfo.param_est),
+        POPvalues0(k) = modelInfo.param_est(k).value0(1);
+    end
+end
+if length(modelInfo.param_est) ~= length(POPvalues0),
+    cd(oldpath);
+    error('Please make sure POPvalues0 is of same length as number of parameters to be estimated.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check IIV distribution things
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(IIVdistribution),
+    IIVdistribution = {};
+    for k=1:length(modelInfo.param_est),
+        IIVdistribution{k} = 'L';
+    end
+end
+
+% Check contents
+test = IIVdistribution;
+for k=1:length(IIVdistribution),
+    if ~ismember(test{k},{'L','N','G'}),
+        cd(oldpath);
+        error('Please make sure that only "N", "L", or "G" appear in the "IIVdistribution" variable.');
+    end
+end
+
+% Check length
+if length(IIVdistribution) ~= length(modelInfo.param_est),
+    cd(oldpath);
+    error('Please make sure that an equal number of IIVdistribution is defined as estimated parameters in the model.');
+end
+
+% Print table parameter names and IIV distributions
+if ~SILENT,
+    disp(' ');
+    disp('Please check that the following matches between parameters and used IIV distributions are correct:');
+    for k=1:length(modelInfo.param_est),
+        if IIVdistribution{k} == 'L', dtext = 'logNormal'; end
+        if IIVdistribution{k} == 'N', dtext = 'Normal'; end
+        if IIVdistribution{k} == 'G', dtext = 'logitNormal'; end
+        fprintf('\t%s%s: %s\n',modelInfo.param_est(k).name,char(32*ones(1,15-length(modelInfo.param_est(k).name))),dtext)
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check IIV estimation things
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(IIVestimate),
+    IIVestimate = ones(1,length(modelInfo.param_est));
+end
+% Check length
+if length(IIVestimate) ~= length(modelInfo.param_est),
+    cd(oldpath);
+    error('Please make sure that an equal number of IIVestimate is defined as estimated parameters in the model.');
+end
+% Print table parameter names and IIV esimations
+if ~SILENT,
+    disp(' ');
+    disp('Please check that the following matches between parameters and used estimated IIVs are correct:');
+    for k=1:length(modelInfo.param_est),
+        if IIVestimate(k) == 0,
+            fprintf('\t%s%s: IIV NOT ESTIMATED (kept on 0)\n',modelInfo.param_est(k).name,char(32*ones(1,15-length(modelInfo.param_est(k).name))));
+        elseif IIVestimate(k) == 1,
+            fprintf('\t%s%s: IIV ESTIMATED\n',modelInfo.param_est(k).name,char(32*ones(1,15-length(modelInfo.param_est(k).name))));
+        elseif IIVestimate(k) == 2,
+            fprintf('\t%s%s: IIV NOT ESTIMATED (kept on initial value)\n',modelInfo.param_est(k).name,char(32*ones(1,15-length(modelInfo.param_est(k).name))));
+        end
+    end
+    disp(' ');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check IIVvalues0 thing
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(IIVvalues0),
+    IIVvalues0 = 0.5*ones(1,length(modelInfo.param_est));
+end
+if length(modelInfo.param_est) ~= length(IIVvalues0),
+    cd(oldpath);
+    error('Please make sure IIVvalues0 is of same length as number of parameters to be estimated.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check residual error things
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(errorModels),
+    errorModels = '';
+    for k=1:length(modelInfo.outputs),
+        errorModels = sprintf('%sconst,',errorModels);
+    end
+    errorModels = errorModels(1:end-1);
+end
+test = errorModels;
+test = strtrim(strrep(strrep(strrep(strrep(strrep(test,'exp',''),'const',''),'prop',''),'comb1',''),',',''));
+if ~isempty(test),
+    cd(oldpath);
+    error('Please make sure that only "const", "prop", "comb1", or "exp" appear in the "errorModels" variable.');
+end
+% Check length
+errors = explodePCIQM(errorModels,',');
+if length(errors) ~= length(modelInfo.outputs),
+    cd(oldpath);
+    error('Please make sure that an equal number of errorModels is defined as outputs in the model.');
+end
+% Print table parameter names and IIV distributions
+if ~SILENT,
+    disp(' ');
+    disp('Please check that the following matches between outputs and used residual error models are correct:');
+    for k=1:length(modelInfo.outputs),
+        fprintf('\t%s%s: %s\n',modelInfo.outputs(k).formula,char(32*ones(1,15-length(modelInfo.outputs(k).formula))),errors{k})
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle empty errorParam0
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(errorParam0),
+    terms = explodePCIQM(errorModels);
+    for k=1:length(terms),
+        if strcmp(lower(terms{k}),'const'),
+            errorParam0(end+1) = 1;
+        elseif strcmp(lower(terms{k}),'prop'),
+            errorParam0(end+1) = 0.3;
+        elseif strcmp(lower(terms{k}),'comb1'),
+            errorParam0(end+1) = 1;
+            errorParam0(end+1) = 0.3;          
+        elseif strcmp(lower(terms{k}),'exp'),
+            errorParam0(end+1) = 1;
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check errorParam0
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+terms = explodePCIQM(errorModels);
+nrneededelements = 0;
+for k=1:length(terms),
+    if strcmpi(terms{k},'const'),
+        nrneededelements = nrneededelements+1;
+    elseif strcmpi(terms{k},'prop'),
+        nrneededelements = nrneededelements+1;
+    elseif strcmpi(terms{k},'comb1'),
+        nrneededelements = nrneededelements+2;
+    elseif strcmpi(terms{k},'exp'),
+        nrneededelements = nrneededelements+1;
+    end
+end
+if length(errorParam0) ~= nrneededelements,
+    error('Incorrect number of elements in options.errorParam0.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check covariance model
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(covarianceModel),
+    covarianceModel = 'diagonal';
+elseif ~strcmp(covarianceModel,'diagonal'),
+    % Need to check that none of the parameters for which no IIV is estimated is used in the covarianceModel
+    param_est_noIIV = {modelInfo.param_est(find(~IIVestimate)).name};
+    for k=1:length(param_est_noIIV),
+        if ~isempty(regexp(covarianceModel,['\<' param_est_noIIV{k} '\>'])),
+            cd(oldpath);
+            error('Please make sure none of the parameters for which no IIV is estimated/fixed to non zero is used in the covarianceModel settings.');
+        end
+    end
+    % Check that all parameters in the covariance model actually are model parameters
+    param = {modelInfo.param_est.name};
+    test  = covarianceModel;
+    for k=1:length(param),
+        test = regexprep(test,['\<' param{k} '\>'],'');
+    end
+    test = strrep(test,'{','');
+    test = strrep(test,'}','');
+    test = strrep(test,',','');
+    test = strtrim(test);
+    if ~isempty(test),
+        cd(oldpath);
+        error('Please make sure that covarianceModel only contains parameter names that are set to <estimate> in the model.');
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check LL setting
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(LLsetting),
+    LLsetting = 'both';
+end
+if isempty(strmatchIQM(LLsetting,{'linearization','importantSampling','both'})),
+    cd(oldpath);
+    error('Please make sure LLsetting has one of the following values: "linearization", "importantSampling", "both"=""');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check FIM setting
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(FIMsetting),
+    FIMsetting = 'linearization';
+end
+if isempty(strmatchIQM(FIMsetting,{'linearization','stochasticApproximation'})),
+    cd(oldpath);
+    error('Please make sure FIMsetting has one of the following values: "linearization" or "stochasticApproximation"');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check covariate model things
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% First check that all first elements are estimated parameters of the model
+param_est = {modelInfo.param_est.name};
+for k=1:length(covariateModel),
+    param = covariateModel{k}{1};
+    if isempty(strmatchIQM(param,param_est,'exact')),
+        cd(oldpath);
+        error('Please make sure that all parameters for which covariates are defined are defined by <estimate> in the model.');
+    end
+end
+% Second check that all defined covariates actually are covariates
+covcatNames = [covNames catNames];
+for k=1:length(covariateModel),
+    for k2=2:length(covariateModel{k}),
+        cov = covariateModel{k}{k2};
+        if isempty(strmatchIQM(cov,covcatNames,'exact')),
+            cd(oldpath);
+            error(sprintf('Please make sure that all covariates, defined in covariateModel, are defined in the dataset\n   This error might be due to a categorical covariate having only single category.'));
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% OPEN File
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fid = fopen([projectName '.mlxtran'],'w');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INFO
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; MLXTRAN PROJECT, created using IQM Tools\r\n');
+fprintf(fid,'; Date: %s\r\n',datestr(now,'yyyy-mmm-DD HH:MM'));
+fprintf(fid,'; By:   %s\r\n',usernameIQM());
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Placeholder for project information
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; ==PROJECT HEADER START===================================================\r\n');
+fprintf(fid,'PROJECT_HEADER_PLACEHOLDER\r\n');
+fprintf(fid,'; ==PROJECT HEADER END=====================================================\r\n');
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DESCRIPTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; =============================================\r\n');
+fprintf(fid,'DESCRIPTION:\r\n');
+fprintf(fid,'; =============================================\r\n');
+fprintf(fid,'\t%s\r\n',ms.name);
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DATA
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; =============================================\r\n');
+fprintf(fid,'DATA:\r\n');
+fprintf(fid,'; =============================================\r\n');
+fprintf(fid,'\tpath = "%%MLXPROJECT%%/%s/",\r\n',dataRelPathFromProject);
+fprintf(fid,'\tfile  ="%s",\r\n',dataFileName);
+fprintf(fid,'\theaders = {%s},\r\n',dataHeaderIdent);
+fprintf(fid,'\tcolumnDelimiter = ","\r\n');
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% VARIABLES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; =============================================\r\n');
+fprintf(fid,'VARIABLES:\r\n');
+fprintf(fid,'; =============================================\r\n');
+% Assume all covariates defined in dataset are used ...
+% Continuous are always log transformed and centered by median
+% Categorical are always kept as they are
+text = '';
+% Write out continuous first
+for k=1:length(covNames),
+    text = sprintf('%s\t%s,\r\n',text,covNames{k});
+    covname = covNames{k};
+    % Scale covariate by median value from dataset
+    ixmedian = strmatchIQM(covname,covariateMedianNames,'exact');
+    covname_weighted = sprintf('%s/%g',covname,covariateMedianValues(ixmedian));
+    text = sprintf('%s\tt_%s = log(%s) [use=cov],\r\n',text,covname,covname_weighted);
+end
+% Write out categorical
+for k=1:length(catNames),
+    text = sprintf('%s\t%s [use=cov, type=cat],\r\n',text,catNames{k});
+end
+% Remove last comma and write text to file
+fprintf(fid,text(1:end-3));
+fprintf(fid,'\r\n');
+fprintf(fid,'\r\n');
+
+% Create BETACOVNAMES and BETACOVTRANS information for header
+BETACOVNAMES = {};
+BETACOVTRANS = {};
+for k=1:length(covariateModel),
+    for k2=2:length(covariateModel{k}),
+        if ~isempty(strmatchIQM(covariateModel{k}{k2},covNames,'exact')),
+            BETACOVNAMES{end+1} = sprintf('beta_%s(%s)',covariateModel{k}{1},covariateModel{k}{k2});
+            ixmedian = strmatchIQM(covariateModel{k}{k2},covariateMedianNames,'exact');
+            BETACOVTRANS{end+1} = sprintf('log(cov/%g)',covariateMedianValues(ixmedian));
+        end
+    end
+end
+
+% Create BETACATNAMES and BETACATREFERENCE information for header
+BETACATNAMES        = {};
+BETACATREFERENCE    = [];
+for k=1:length(covariateModel),
+    for k2=2:length(covariateModel{k}),
+        if ~isempty(strmatchIQM(covariateModel{k}{k2},catNames,'exact')),
+            BETACATNAMES{end+1} = sprintf('beta_%s(%s)',covariateModel{k}{1},covariateModel{k}{k2});
+            BETACATREFERENCE(end+1) = min(unique(dataCSV.(covariateModel{k}{k2})));
+        end
+    end
+end
+
+% Determine all categories for categorical covariates and store them as
+% metadata in the header of the project.mlxtran file
+CAT_CATEGORIES = '';
+for k=1:length(catNames),
+    x = unique(dataCSV.(catNames{k}));
+    x = sprintf('%g,',x);
+    x = ['[' x(1:end-1) ']'];
+    CAT_CATEGORIES{k} = x;
+end
+if ~isempty(CAT_CATEGORIES),
+    CAT_CATEGORIES = sprintf('%s,',CAT_CATEGORIES{:});
+    CAT_CATEGORIES = [CAT_CATEGORIES(1:end-1)];
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INDIVIDUAL
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; =============================================\r\n');
+fprintf(fid,'INDIVIDUAL:\r\n');
+fprintf(fid,'; =============================================\r\n');
+% Write out parameters to estimate. Assume iiv=yes on all of them by default. 
+% If no IIV desired then rather fix omega to 0.01.
+text = '';
+PARAM_TRANSNAME_STRING = {};
+PARAM_INVTRANSNAME_STRING = {};
+
+for k=1:length(modelInfo.param_est),
+    if IIVdistribution{k} == 'L', 
+        dtext = 'logNormal'; 
+        PARAM_INVTRANSNAME_STRING{k} = 'log(psi)';
+        PARAM_TRANSNAME_STRING{k} = 'exp(phi)';        
+    end
+    if IIVdistribution{k} == 'N', 
+        dtext = 'Normal';
+        PARAM_INVTRANSNAME_STRING{k} = '(psi)';
+        PARAM_TRANSNAME_STRING{k} = '(phi)';
+    end
+    if IIVdistribution{k} == 'G', 
+        dtext = 'logitNormal'; 
+        PARAM_INVTRANSNAME_STRING{k} = 'log(psi./(1-psi))';
+        PARAM_TRANSNAME_STRING{k} = 'exp(phi)./(1+exp(phi))';        
+    end
+    % check if IIV 
+    if IIVestimate(k) == 0,
+        iiv='no';
+    else
+        iiv='yes';
+    end
+    % check for covariates to use
+    param = modelInfo.param_est(k).name;
+    covs = {};
+    for k2=1:length(covariateModel),
+        if strcmp(param,covariateModel{k2}{1}),
+            covs = covariateModel{k2}(2:end);
+        end
+    end
+    % Attach "t_" to continuous covariate names, keep categorical covariate names same
+    for k2=1:length(covs),
+        if ~isempty(strmatchIQM(covs{k2},covNames,'exact')),
+            covs{k2} = ['t_' covs{k2}];
+        end
+    end
+    % Write it out
+    if isempty(covs),
+        text = sprintf('%s\t%s = {distribution=%s, iiv=%s},\r\n',text,param,dtext,iiv);
+    else
+        % Create cov text
+        covText = '';
+        for k2=1:length(covs),
+            covText = sprintf('%s%s,',covText,covs{k2});
+        end
+        covText = covText(1:end-1);
+        text = sprintf('%s\t%s = {distribution=%s, covariate={%s}, iiv=%s},\r\n',text,param,dtext,covText,iiv);
+        
+
+    end        
+end
+% Remove last comma and write text to file
+fprintf(fid,text(1:end-3));
+fprintf(fid,'\r\n');
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CORRELATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~strcmp(covarianceModel,'diagonal'),
+    fprintf(fid,'; =============================================\r\n');
+    fprintf(fid,'CORRELATION:\r\n');
+    fprintf(fid,'; =============================================\r\n');
+    fprintf(fid,'\tcorrelationIIV = {%s}\r\n',covarianceModel);
+    fprintf(fid,'\r\n');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% STRUCTURAL_MODEL
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; =============================================\r\n');
+fprintf(fid,'STRUCTURAL_MODEL:\r\n');
+fprintf(fid,'; =============================================\r\n');
+fprintf(fid,'\tfile = "mlxt:%s",\r\n',strrep(modelFileName,'.txt',''));
+fprintf(fid,'\tpath = "%%MLXPROJECT%%",\r\n');
+fprintf(fid,'\toutput = {');
+for k=1:length(modelInfo.outputs)-1,
+    fprintf(fid,'%s, ',modelInfo.outputs(k).formula);
+end
+fprintf(fid,'%s}',modelInfo.outputs(end).formula);
+fprintf(fid,'\r\n');
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% OBSERVATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; =============================================\r\n');
+fprintf(fid,'OBSERVATIONS:\r\n');
+fprintf(fid,'; =============================================\r\n');
+% Only consider "continuous" observations with IQM conversion 
+errors = explodePCIQM(errorModels,',');
+text = '';
+for k=1:length(modelInfo.outputs),
+    if strcmp(errors{k},'const'), errorModel = 'constant'; end
+    if strcmp(errors{k},'prop'), errorModel = 'proportional'; end
+    if strcmp(errors{k},'comb1'), errorModel = 'combined1'; end
+    if strcmp(errors{k},'exp'), errorModel = 'exponential'; end
+    text = sprintf('%s\ty%d = {type=continuous, prediction=%s, error=%s},\r\n',text,k,modelInfo.outputs(k).formula,errorModel);
+end
+% Remove last comma and write text to file
+fprintf(fid,text(1:end-3));
+fprintf(fid,'\r\n');
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% TASKS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; =============================================\r\n');
+fprintf(fid,'TASKS:\r\n');
+fprintf(fid,'; =============================================\r\n');
+fprintf(fid,'\t; settings\r\n');
+fprintf(fid,'\tglobalSettings={\r\n');
+fprintf(fid,'\t\twithVariance=no,\r\n'); % Always estimate standard deviations of IIVs
+% Use default graphics settings
+fprintf(fid,'\t\tsettingsGraphics="%%MLXPROJECT%%/project_graphics.xmlx",\r\n');
+fprintf(fid,'\t\tsettingsAlgorithms="%%MLXPROJECT%%/project_algorithms.xmlx",\r\n');
+fprintf(fid,'\t\tresultFolder="%%MLXPROJECT%%/%s"},\r\n',resultsFolder);
+fprintf(fid,'\t; workflow\r\n');
+fprintf(fid,'\testimatePopulationParameters(\r\n');
+fprintf(fid,'\t\tinitialValues={\r\n');
+% write out population parameter initial values
+for k=1:length(modelInfo.param_est),
+    method = '';
+    if POPestimate(k) == 0,
+        method = '[method=FIXED]';
+    end
+    fprintf(fid,'\t\t\tpop_{%s} = %g %s,\r\n',modelInfo.param_est(k).name,POPvalues0(k),method);
+end
+
+% write out covariate coefficient initial guesses
+for k1=1:length(covariateModel),
+    for k2=2:length(covariateModel{k1}),
+        covarvalue = covariateModelValues{k1}(k2-1);
+        if COVestimate{k1}(k2-1),
+            method = '';
+        else
+            method = '[method=FIXED]';
+        end
+        ix = strmatchIQM(covariateModel{k1}{k2},covNames,'exact');
+        if isempty(ix),
+            fprintf(fid,'\t\t\tbeta_{%s,%s} = %g %s,\r\n',covariateModel{k1}{1},covariateModel{k1}{k2},covarvalue,method);
+        else
+            fprintf(fid,'\t\t\tbeta_{%s,t_%s} = %g %s,\r\n',covariateModel{k1}{1},covariateModel{k1}{k2},covarvalue,method);
+        end
+    end
+end
+
+% write out residual error model
+errors = explodePCIQM(errorModels,',');
+count = 1;
+for k=1:length(errors),
+    if strcmp(errors{k},'const'), 
+        fprintf(fid,'\t\t\ta_y%d = %g,\r\n',k,errorParam0(count));
+        count = count + 1;
+    end
+    if strcmp(errors{k},'prop'), 
+        fprintf(fid,'\t\t\tb_y%d = %g,\r\n',k,errorParam0(count));
+        count = count + 1;
+    end
+    if strcmp(errors{k},'comb1'), 
+        fprintf(fid,'\t\t\ta_y%d = %g,\r\n',k,errorParam0(count));
+        count = count + 1;
+        fprintf(fid,'\t\t\tb_y%d = %g,\r\n',k,errorParam0(count));
+        count = count + 1;
+    end
+    if strcmp(errors{k},'exp'), 
+        fprintf(fid,'\t\t\ta_y%d = %g,\r\n',k,errorParam0(count));
+        count = count + 1;
+    end
+end
+% write out population parameter initial values
+text = '';
+for k=1:length(modelInfo.param_est),
+    if IIVestimate(k)==1,
+        value0 = IIVvalues0(k);
+        text = sprintf('%s\t\t\tomega_{%s} = %g,\r\n',text,modelInfo.param_est(k).name,value0);
+    elseif IIVestimate(k)==2,
+        value0 = IIVvalues0(k);
+        text = sprintf('%s\t\t\tomega_{%s} = %g [method=FIXED],\r\n',text,modelInfo.param_est(k).name,value0);
+    end
+end
+fprintf(fid,text(1:end-3));
+fprintf(fid,'\r\n');
+
+fprintf(fid,'\t\t} ),\r\n');
+if strcmp(FIMsetting,'linearization'),
+    fprintf(fid,'\testimateFisherInformationMatrix( method={linearization} ),\r\n');
+else
+    fprintf(fid,'\testimateFisherInformationMatrix( method={stochasticApproximation} ),\r\n');
+end    
+fprintf(fid,'\testimateIndividualParameters( method={%s} ),\r\n',INDIVparametersetting);
+if strcmp(LLsetting,'linearization'),
+    fprintf(fid,'\testimateLogLikelihood(method={linearization}),\r\n');
+elseif strcmp(LLsetting,'importantSampling'),
+    fprintf(fid,'\testimateLogLikelihood(method={importantSampling}),\r\n');
+elseif strcmp(LLsetting,'both'),
+    fprintf(fid,'\testimateLogLikelihood(method={importantSampling,linearization}),\r\n');
+end
+fprintf(fid,'\tdisplayGraphics()');
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CLOSE File
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fclose(fid);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Create Project Header with Metadata
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+PROJECT_INFO_TEXT = '';
+
+% Data location
+DATA_info = sprintf('; DATA                = ''%s''\r\n',strrep(fullfile(dataRelPathFromProject,dataFileName),'\','/'));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,DATA_info);
+
+% DOSINGTYPES
+ds = struct(dosing);
+DOSINGTYPES = {ds.inputs.type};
+x = sprintf('%s,',DOSINGTYPES{:});
+DOSINGTYPES_info = sprintf('; DOSINGTYPES         = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,DOSINGTYPES_info);
+
+% covNames
+x = sprintf('%s,',covNames{:});
+COVNAMES_info = sprintf('; COVNAMES            = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,COVNAMES_info);
+
+% catNames
+x = sprintf('%s,',catNames{:});
+CATNAMES_info = sprintf('; CATNAMES            = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,CATNAMES_info);
+
+% CATCATEGORIES
+CATCATEGORIES_info = sprintf('; CATCATEGORIES       = ''%s''\r\n',CAT_CATEGORIES);
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,CATCATEGORIES_info);
+
+% Regression parameters
+x = sprintf('%s,',regressionParametersData{:});
+REGRESSNAMES_info = sprintf('; REGRESSIONNAMES     = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,REGRESSNAMES_info);
+
+% Outputs
+x = cell(1,length(modelInfo.outputs));
+for k=1:length(modelInfo.outputs),
+    on = eval(strrep(modelInfo.outputs(k).name,'OUTPUT',''));
+    x{on} = modelInfo.outputs(k).formula;
+end
+y = '';
+for k=1:length(x),
+    y = sprintf('%s%s,',y,x{k});
+end
+y = y(1:end-1);
+OUTPUTS_info = sprintf('; OUTPUTS             = ''%s''\r\n',y);
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,OUTPUTS_info);
+
+% Error models
+ERRORMODELS_info = sprintf('; ERRORMODELS         = ''%s''\r\n',errorModels);
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,ERRORMODELS_info);
+
+% PARAMNAMES
+x = sprintf('%s,',modelInfo.param_est.name);
+PARAMNAMES_info = sprintf('; PARAMNAMES          = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,PARAMNAMES_info);
+
+% PARAMTRANS
+x = sprintf('%s,',PARAM_TRANSNAME_STRING{:});
+PARAMTRANS_info = sprintf('; PARAMTRANS          = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,PARAMTRANS_info);
+
+% PARAMINVTRANS
+x = sprintf('%s,',PARAM_INVTRANSNAME_STRING{:});
+PARAMINVTRANS_info = sprintf('; PARAMINVTRANS       = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,PARAMINVTRANS_info);
+
+% COVARIATENAMES
+COVARIATENAMES = [covNames,catNames];
+x = sprintf('%s,',COVARIATENAMES{:});
+COVARIATENAMES_info = sprintf('; COVARIATENAMES      = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,COVARIATENAMES_info);
+
+% COVARIATESUSED
+COVARIATESUSED = setdiff(explodePCIQM(strrep(strrep(options.covariateModel,'{',''),'}','')),param_est);
+x = sprintf('%s,',COVARIATESUSED{:});
+COVARIATESUSED_info = sprintf('; COVARIATESUSED      = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,COVARIATESUSED_info);
+
+% BETACOVNAMES
+x = sprintf('%s,',BETACOVNAMES{:});
+BETACOVNAMES_info = sprintf('; BETACOVNAMES        = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,BETACOVNAMES_info);
+
+% BETACOVTRANS
+x = sprintf('%s,',BETACOVTRANS{:});
+BETACOVTRANS_info = sprintf('; BETACOVTRANS        = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,BETACOVTRANS_info);
+
+% BETACATNAMES
+x = sprintf('%s,',BETACATNAMES{:});
+BETACATNAMES_info = sprintf('; BETACATNAMES        = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,BETACATNAMES_info);
+
+% BETACATREFERENCE
+x = ''; for k=1:length(BETACATREFERENCE), x=sprintf('%s%g,',x,BETACATREFERENCE(k)); end
+BETACATREFERENCE_info = sprintf('; BETACATREFERENCE    = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,BETACATREFERENCE_info);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Replace PROJECT_HEADER_PLACEHOLDER
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+content = fileread('project.mlxtran');
+content = strrep(content,'PROJECT_HEADER_PLACEHOLDER',strtrim(PROJECT_INFO_TEXT));
+fid = fopen('project.mlxtran','w');
+fprintf(fid,'%s',content);
+fclose(fid);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Do generate the default graphics settings so that 
+% predictions.txt file is generated and included NPDE and meanPWRES
+% Trick is to load project file and to add things and then to save the file
+% again.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+copyfile(which('template_project_graphics.xmlx'),'project_graphics.xmlx')
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Generate project_algorithms.xmlx file
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% only writing out K1, K2, Number of Chains, Seed, and auto settings for K1,K2,Number of chains
+fid = fopen('project_algorithms.xmlx','w');
+fprintf(fid,'<monolix>\n');
+fprintf(fid,'	<algorithms seed="%d">\n',SEED);
+fprintf(fid,'		<populationParameters>\n');
+fprintf(fid,'			<vna value="%d,%d"/>\n',K1,K2);
+fprintf(fid,'			<iop_Kauto value="%d,%d"/>\n',K1_AUTO,K2_AUTO);
+fprintf(fid,'			<nmc value="%d"/>\n',NRCHAINS);
+fprintf(fid,'		</populationParameters>\n');
+fprintf(fid,'	</algorithms>\n');
+fprintf(fid,'</monolix>\n');
+fclose(fid);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Change out of project path
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+cd(oldpath);
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/01-MONOLIX/IQMrunMONOLIXproject.m b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/01-MONOLIX/IQMrunMONOLIXproject.m
new file mode 100644
index 0000000000000000000000000000000000000000..e255478700f3d85167e1c1b3eba03fb9da765158
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/01-MONOLIX/IQMrunMONOLIXproject.m	
@@ -0,0 +1,137 @@
+function [] = IQMrunMONOLIXproject(projectPath,NPROCESSORS,NO_GOF_PLOTS)
+% This function runs a specified Monolix project.
+%
+% [SYNTAX]
+% [] = IQMrunMONOLIXproject(projectPath)
+% [] = IQMrunMONOLIXproject(projectPath,N_PROCESSORS)
+% [] = IQMrunMONOLIXproject(projectPath,N_PROCESSORS,NO_GOF_PLOTS)
+%
+% [INPUT]
+% projectPath:      Path to the .mlxtran Monolix project file
+% NPROCESSORS:      Number of processors if use of parallel (default: 1)
+%                   This argumentis not used yet!
+% NO_GOF_PLOTS:     =0: Create GoF plots for all runs (default), 
+%                   =1: No Gof plots
+%
+% [OUTPUT]
+% Output generated in the RESULTS folder of the Monolix project.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle variable input arguments
+if nargin == 1,
+    NPROCESSORS = 1;
+    NO_GOF_PLOTS = 0;
+elseif nargin == 2,
+    NO_GOF_PLOTS = 0;
+end
+
+% Check if MONOLIX project
+if ~isMONOLIXprojectIQM(projectPath),
+    error('Specified "projectPath" does not point to a MONOLIX project.');
+end
+
+% Run SETUP_PATHS_TOOLS_IQMPRO to get info about paths and ocmmands etc.
+SETUP_PATHS_TOOLS_IQMPRO
+if isunix,
+    PATH_MONOLIX     = PATH_SYSTEM_MONOLIX_UNIX;
+    PATH_MONOLIX_PAR = PATH_SYSTEM_MONOLIX_PARALLEL_UNIX;
+else
+    PATH_MONOLIX     = PATH_SYSTEM_MONOLIX_WINDOWS;
+    PATH_MONOLIX_PAR = PATH_SYSTEM_MONOLIX_PARALLEL_WINDOWS;
+end
+
+% Check things
+if isempty(PATH_MONOLIX),
+    error('Path to MONOLIX standalone version not defined in SETUP_PATHS_TOOLS_IQMPRO.m');
+end
+
+% Change in to project path 
+oldpath = pwd;
+cd(projectPath);
+
+% Run the MONOLIX project
+if isunix,
+	% system([PATH_MONOLIX ' -p ./project.mlxtran -nowin -f run']);
+	% Exchanged previous command with the following to allow compatibility with Monolix 4.3.3 on Mac
+	[exitFlag,exitMessage] = system([PATH_MONOLIX ' -nowin -f run -path . -p project.mlxtran']);
+else
+    fullProjectPath = pwd();
+    PATH_MONOLIX_BAT = fileparts(PATH_MONOLIX);
+    cd(PATH_MONOLIX_BAT);
+    systemcall = sprintf('Monolix.bat -p "%s/project.mlxtran" -nowin -f run',fullProjectPath);
+    system(systemcall);
+    cd(fullProjectPath);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle queuing system - to wait until MONOLIX run is done before
+% continuing processing the results.
+%
+% Only handle under unix ... do not assume queuing under windows
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isunix && ~isempty(PATH_SYSTEM_QUEUE_STATUS_UNIX),
+    
+    % Get jobID from exit message (always assume it is numeric)
+    jobID = regexp(exitMessage,'([0-9]+)','tokens');
+    if length(jobID) == 1,
+        jobID = jobID{1}{1};
+    else
+        error('Something wrong with the queue jobID.');
+    end
+    
+    % Read out users queue
+    [exitFlag,exitMessage] = system([PATH_SYSTEM_QUEUE_STATUS_UNIX]);
+    
+    % Check if jobID still in queue and wait until it is gone
+    while ~isempty(strfind(exitMessage,jobID)),
+        pause(10);
+        [exitFlag,exitMessage] = system([PATH_SYSTEM_QUEUE_STATUS_UNIX]);
+    end
+   
+end
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% End of queue handling
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Convert the results.ps to results.pdf
+try
+    IQMconvert2pdf('RESULTS/results.ps')
+end
+
+% Change back to previous path
+cd(oldpath)
+
+% Generate information for GOF plots
+try
+    PROJECTINFO     = parseMONOLIXprojectHeaderIQM(projectPath);
+    % outputNumber: Defined by metadata "OUTPUTS"
+    outputNumberALL = [1:length(PROJECTINFO.OUTPUTS)];
+    outputNamesALL  = PROJECTINFO.OUTPUTS;
+catch
+    warning('Problem with obtaining information for GOF plots.');
+    disp(lasterr);
+end
+
+% Do GOF plots
+if ~NO_GOF_PLOTS,
+    rehash
+    try
+        % General GOF plots
+        IQMfitanalysisGeneralPlots(projectPath);
+    catch
+        warning('Problem with General GOF plots.');
+        disp(lasterr);
+    end
+    try
+        % Output specific GOF plots
+        IQMfitanalysisOutputPlots(projectPath);
+    catch
+        warning('Problem with Output specific GOF plots.');
+        disp(lasterr);
+    end    
+end
+
+
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/01-MONOLIX/IQMrunMONOLIXprojectFolder.m b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/01-MONOLIX/IQMrunMONOLIXprojectFolder.m
new file mode 100644
index 0000000000000000000000000000000000000000..84ff9fbfb7bb1e2a9b38b6fcf101e30bd9fc5f66
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/01-MONOLIX/IQMrunMONOLIXprojectFolder.m	
@@ -0,0 +1,77 @@
+function [] = IQMrunMONOLIXprojectFolder(modelProjectsFolder,N_PROCESSORS_PAR,N_PROCESSORS_SINGLE,NO_GOF_PLOTS)
+% This functions runs all the Monolix projects in the specified folder.
+% Parallel computation is supported in two different ways. Parallel execution 
+% of models at the same time (par for loop) and also allowing each single model
+% run to be parallelized (if the MONOLIX installation allows for it).
+% The function also generates tables in the modelProjectsFolder allowing to
+% compare individual model results.
+%
+% [SYNTAX]
+% [] = IQMrunMONOLIXprojectFolder(modelProjectsFolder)
+% [] = IQMrunMONOLIXprojectFolder(modelProjectsFolder,N_PROCESSORS_PAR)
+% [] = IQMrunMONOLIXprojectFolder(modelProjectsFolder,N_PROCESSORS_PAR,N_PROCESSORS_SINGLE)
+% [] = IQMrunMONOLIXprojectFolder(modelProjectsFolder,N_PROCESSORS_PAR,N_PROCESSORS_SINGLE,NO_GOF_PLOTS)
+%
+% [INPUT]
+% modelProjectsFolder:      Path to a folder with Monolix project folders
+%                           to be run. Folder names are arbitrary, but a
+%                           project.mlxtran file needs to be present in
+%                           each folder.
+% N_PROCESSORS_PAR:         Number of processors for parallel model evaluation (default: as specified in SETUP_PATHS_TOOLS_IQMPRO)
+% N_PROCESSORS_SINGLE:      Number of processors for parallelization of single model run (default: 1)
+% NO_GOF_PLOTS:             =0: Create GoF plots for all runs (default), =1: No Gof plots
+%
+% If N_PROCESSORS_PAR>1 then parallel nodes are requested via the matlabpool
+% command and N_PROCESSORS_PAR models will be run in parallel.
+%
+% [OUTPUT]
+% No output! The function just runs the Monolix projects. All results are
+% written by Monolix to the relevant output folders ("RESULTS").
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle variable input arguments
+if nargin == 1,
+    N_PROCESSORS_PAR    = getN_PROCESSORS_PARIQM();
+    N_PROCESSORS_SINGLE = 1;
+    NO_GOF_PLOTS = 0;
+elseif nargin == 2,
+    N_PROCESSORS_SINGLE = 1;
+    NO_GOF_PLOTS = 0;
+elseif nargin == 3,
+    NO_GOF_PLOTS = 0;
+end
+    
+% Get the projects to run in the folder
+projects = dir([modelProjectsFolder '/*']);
+% Remove . and ..
+ix_dot = strmatchIQM('.',{projects.name});
+projects(ix_dot) = [];
+% Remove files
+projects(find(~[projects.isdir])) = [];
+
+% Request processors
+% Request min(N_PROCESSORS,length(projects))
+N_PROCESSORS_NEEDED = min(N_PROCESSORS_PAR,length(projects));
+killMATLABpool = startParallelIQM(N_PROCESSORS_NEEDED);
+
+% Run the models
+warning off
+oldpath = pwd();
+parfor k=1:length(projects),
+    fprintf('Running project %d of %d ...\n',k,length(projects));
+    pathfolder = [modelProjectsFolder '/' projects(k).name];
+    if isMONOLIXprojectIQM(pathfolder),
+        IQMrunMONOLIXproject(pathfolder,N_PROCESSORS_SINGLE,NO_GOF_PLOTS);
+    end
+end
+
+% Release processors
+stopParallelIQM(killMATLABpool)
+
+% Prepare tables for model comparison in the folder
+SETUP_PATHS_TOOLS_IQMPRO
+IQMfitsummaryAll(modelProjectsFolder,'',NLME_ORDER_CRITERION);
+
+% Done!
+fprintf('\nEstimations READY!\n\n');
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/01-MONOLIX/IQMsampleMONOLIXparam.m b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/01-MONOLIX/IQMsampleMONOLIXparam.m
new file mode 100644
index 0000000000000000000000000000000000000000..55110ef28f9ef9da8df4c0eca273666d4431713f
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/01-MONOLIX/IQMsampleMONOLIXparam.m	
@@ -0,0 +1,706 @@
+function [output] = IQMsampleMONOLIXparam( projectPath, FLAG_SAMPLE, Nsamples, varargin )
+% This function samples parameters from both uncertainty and variability distributions from a Monolix fit.
+% The result is a structure with sampled population parameters and sampled individual parameters. The desired
+% number of parameter sets can be specified.
+%
+% This function is very useful for trial simulation purposes.
+%
+% Handles automatically different parameter distributions (logNormal, Normal, logitNormal)
+%
+% [SYNTAX]
+% output = IQMsampleMONOLIXparam( projectPath, FLAG_SAMPLE, Nsamples )
+% output = IQMsampleMONOLIXparam( projectPath, FLAG_SAMPLE, Nsamples, covNames, covValues, catNames, catValues )
+%
+% [INPUT]
+% projectPath: path to the Monolix project folder. It is assumed that the results of the estimation
+%                                 (pop_parameters.txt, results.mat) are stored in a "RESULTS" folder within this
+%                                 project folder.
+% FLAG_SAMPLE:                    0=use point estimates of population parameters (do not consider uncertainty) and sample Nsample 
+%                                   individual patients based on these. Covariates considered if defined by user and used in model.
+%                                   Please note: population parameters do not take covariates into account!
+%                                 1=sample single set of population parameters from uncertainty distribution and sample Nsample 
+%                                   individual patient parameters based on these. Covariates considered if defined by user and used in model.
+%                                   Please note: population parameters do not take covariates into account!
+%                                 2=sample Nsample sets of population parameters from uncertainty distribution 
+%                                   Do not sample from variability distribution and do not take into account covariates (even if user specified).
+%                                 3=use point estimates of population parameters (do not consider uncertainty)
+%                                   Return Nsamples sets of population parameters with covariates taken into account.
+%                                 4=sample single set of population parameters from uncertainty distribution 
+%                                   Return Nsamples sets of population parameters with covariates taken into account.
+%                                 5=sample Nsamples sets of population parameters from uncertainty distribution 
+%                                   And take provided covariates into account.
+% 
+% Nsamples:                       Number of individual parameter sets to sample
+%
+% covNames:                       Cell-array with names of continuous covariates to consider in the parameter sampling (only used for FLAG_SAMPLE=0 or 1)
+%                                 Default: {}
+% covValues:                      Matrix with Nsamples rows and as many columns as continuous covariate names in covNames (only used for FLAG_SAMPLE=0 or 1)
+% catNames:                       Cell-array with names of categorical covariates to consider in the parameter sampling (only used for FLAG_SAMPLE=0 or 1)
+%                                 Default: {}
+% catValues:                      Matrix with Nsamples rows and as many columns as categorical covariate names in covNames (only used for FLAG_SAMPLE=0 or 1)
+%
+% [OUTPUT]
+% Structure with the following fields:
+% output.parameterNames:                Cell-array with parameter names
+% output.FLAG_SAMPLE:                   Sampling flag used (see above for definition)
+% output.Nsamples:                      Number of sampled parameter sets (type of parameter sets sampled depends on FLAG_SAMPLE)
+% output.parameterValuesPopulation:     Vector or Matrix with (sampled) population parameters
+% output.parameterValuesIndividual:     Matrix with samples individual parameter sets (one set per row, one parameter per column)
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle variable input arguments for CONTINUOUS covariates 
+if nargin>=5,
+    covNames = varargin{1};
+    covValues = varargin{2};
+    
+    if ~isempty(covNames),
+        % Check correct size (Nsamples)
+        if size(covValues,1) ~= Nsamples,
+            error('Provided values for continuous covariates need to have length of "Nsamples".');
+        end
+    else
+        covNames = {};
+        covValues = [];
+    end
+else
+    % No continuous covariates provided! 
+    covNames = {};
+    covValues = [];
+end
+if ~iscell(covNames),
+    covNames = {covNames};
+end
+
+% Handle variable input arguments for CATEGORICAL covariates 
+if nargin==7,
+    catNames = varargin{3};
+    catValues = varargin{4};
+    
+    if ~isempty(catNames),
+        % Check correct size (Nsamples)
+        if size(catValues,1) ~= Nsamples,
+            error('Provided values for categorical covariates need to have length of "Nsamples".');
+        end
+    else
+        catNames = {};
+        catValues = [];
+    end
+else
+    % No categorical covariates provided! 
+    catNames = {};
+    catValues = [];
+end
+if ~iscell(catNames),
+    catNames = {catNames};
+end
+
+% Parse Monolix results
+x = parseMONOLIXresultsIQM(projectPath);
+
+% Run the sampling function once to get covariate information
+% Parameter values will not be considered here and handled later
+% Check if covariates in model and warn if yes but user has not provided covariate information
+%
+% Do run this part only if FLAG_SAMPLE not equal to 2
+if FLAG_SAMPLE~=2,
+    y = sampleMONOLIXpopulationParametersIQM(x,0,1);
+    covInfo = y.covariates.continuous;
+    catInfo = y.covariates.categorical;
+    % Check if covariates are in the model but not provided
+    if ~isempty(covInfo(1).parameter) && isempty(covNames),
+        disp('Model contains continuous covariates but no covariates are provided by the user.');
+        disp(' ');
+    end
+    if ~isempty(catInfo(1).parameter) && isempty(catNames),
+        disp('Model contains categorical covariates but no covariates are provided by the user.');
+        disp(' ');
+    end
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Prepare CONTINUOUS covariate information (if needed)
+    %
+    % phi = mu + eta + t_cov * beta
+    %
+    % phi:      matrix of transformed individual parameters. one row per individual. (Nsamples x Nparameters)
+    % mu:       matrix of transformed population parameter values (same row repeated Nsamples times). (Nsamples x Nparameters)
+    % t_cov:    matrix of transformed covariates (Nsamples x Ncovariates)
+    %           We will assume that each covariate with the same name has the same transformation. And this will be checked.
+    % beta:     matrix with covariate coefficients beta_ij (Ncovariates x Nparameters)
+    %
+    % Only covariates will be considered that actually are passed by the user.
+    % If other covariates are present in the model then a warning will be made.
+    %
+    % No covariate parameter values are considered here. Just error checking, data transformation, ...
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    allModelCovNames = {};
+    allModelCovFormulas = {};
+    for k1=1:length(covInfo),
+        paramName = covInfo(k1).parameter;
+        for k2=1:length(covInfo(k1).covariates),
+            covname     = covInfo(k1).covariates{k2};
+            betavalue   = covInfo(k1).values(k2);
+            formula     = covInfo(k1).formula{k2};
+            % Check if covname already in allModelCovNames
+            ix = strmatchIQM(covname,allModelCovNames,'exact');
+            if isempty(ix),
+                % add covariate and formula to lists
+                allModelCovNames{end+1} = covname;
+                allModelCovFormulas{end+1} = formula;
+            else
+                % check that formula is the same, otherwise error
+                if ~strcmp(formula,allModelCovFormulas{ix}),
+                    error('Different covariate transformations for same continuous covariate.');
+                end
+            end
+        end
+    end
+    
+    if isempty(covNames),
+        if ~isempty(allModelCovNames),
+            disp('No continuous covariates for sampling have been defined but the model contains the following:');
+            disp(allModelCovNames);
+        end
+    else
+        % Cycle through covariate information and build data and do some error checks
+        % Handle centervalue by replacing "cov" by "cov/centervalue". But only if centervalue not NaN and not 0.
+        
+        % Check model covariates against provided covariates
+        % Remove covariates provided by the user that are not used in the model - warn the user
+        % Warn the user also about covariates that are in the model but not provided by the user
+        [covsUser_notinmodel,ix_notinmodel] = setdiff(covNames,allModelCovNames);
+        [covsModel_notuser,ix_notuser] = setdiff(allModelCovNames,covNames);
+        
+        % Remove user defined covariates that are not used in the model
+        covNames(ix_notinmodel) = [];
+        covValues(:,ix_notinmodel) = [];
+        
+        % Warn the user about what has been found
+        if ~isempty(ix_notinmodel),
+            disp('The following continuous covariates have been defined by the user but they are not present in the model. They will be not considered.');
+            disp(covsUser_notinmodel);
+        end
+        if ~isempty(ix_notuser),
+            disp('The following continuous covariates are defined in the model but have not been provided by the user. They will be not considered.');
+            disp(covsModel_notuser);
+        end
+        
+        % Generate the transformed covariates
+        t_cov = covValues;
+        for k=1:length(covNames),
+            ix = strmatchIQM(covNames{k},allModelCovNames,'exact');
+            formula = allModelCovFormulas{ix};
+            t_cov(:,k) = eval(strrep(formula,'cov','covValues(:,k)'));
+        end
+    end
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Prepare CATEGORICAL covariate information (if needed)
+    %
+    % phi = mu + eta + t_cov * beta + beta_cat
+    %
+    % phi:      matrix of transformed individual parameters. one row per individual. (Nsamples x Nparameters)
+    % mu:       matrix of transformed population parameter values (same row repeated Nsamples times). (Nsamples x Nparameters)
+    % t_cov:    matrix of transformed covariates (Nsamples x Ncovariates)
+    %           We will assume that each covariate with the same name has the same transformation. And this will be checked.
+    % beta:     matrix with covariate coefficients beta_ij (Ncovariates x Nparameters)
+    % beta_cat: matrix with categorical covariate coefficients (Nsamples x Nparameters)
+    %           Does not need to be prepared much but some error checking needs to be done
+    %
+    % Only covariates will be considered that actually are passed by the user.
+    % If other covariates are present in the model then a warning will be made.
+    %
+    % No covariate parameter values are considered here. Just error checking, data transformation, ...
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Cycle through covariate information and get all categorical covariate names used
+    allModelCatNames = {};
+    for k1=1:length(catInfo),
+        paramName = catInfo(k1).parameter;
+        for k2=1:length(catInfo(k1).covariates),
+            catname     = catInfo(k1).covariates{k2};
+            % Check if catname already in allModelCatNames
+            ix = strmatchIQM(catname,allModelCatNames,'exact');
+            if isempty(ix),
+                % add covariate and formula to lists
+                allModelCatNames{end+1} = catname;
+            end
+        end
+    end
+    
+    if isempty(catNames), 
+        if ~isempty(allModelCatNames),
+            disp('No categorical covariates for sampling have been defined but the model contains the following:');
+            disp(allModelCatNames);
+        end
+    else
+        % Check model covariates against provided covariates
+        % Remove covariates provided by the user that are not used in the model - warn the user
+        % Warn the user also about covariates that are in the model but not provided by the user
+        [catsUser_notinmodel,ix_notinmodel] = setdiff(catNames,allModelCatNames);
+        [catsModel_notuser,ix_notuser] = setdiff(allModelCatNames,catNames);
+        
+        % Remove user defined covariates that are not used in the model
+        catNames(ix_notinmodel) = [];
+        catValues(:,ix_notinmodel) = [];
+        
+        % Warn the user about what has been found
+        if ~isempty(ix_notinmodel),
+            disp('The following categorical covariates have been defined by the user but they are not present in the model. They will be not considered.');
+            disp(catsUser_notinmodel);
+        end
+        if ~isempty(ix_notuser),
+            disp('The following categorical covariates are defined in the model but have not been provided by the user. They will be not considered.');
+            disp(catsModel_notuser);
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle case of FLAG_SAMPLE=0 and 1
+% Sampling individual parameters with (1) or without (0) uncertainty 
+% Taking covariates into account if provided.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if FLAG_SAMPLE == 0 || FLAG_SAMPLE ==1,
+    % Need to sample until reasonable values (no imaginary parts in parameters)
+    while 1,
+        
+        % Parse and sample monolix results
+        y = sampleMONOLIXpopulationParametersIQM(x,FLAG_SAMPLE);
+        
+        % Get covariance matrix
+        cov = y.randomEffects.covariancematrix;
+        
+        % Check if positive semidefinite
+        [~,Lambda]  = eig(cov);
+        if min(diag(Lambda))<0,
+            % Attempt to make covariancematrix positive semidefinite
+            % Might still not work due to numerics ... so the outer while
+            % loop is important to sample until the resulting parameters
+            % are non-complex.
+            cov     = makePosSemiDefIQM(cov);
+        end
+        
+        % Sample individual random effects (etas)
+        ETA = mvnrndIQM(zeros(1,size(cov,1)),cov,Nsamples);
+        
+        % Transform population estimates to normal distribution (mu) (allowing for transformations: lognormal, logitnormal, normal)
+        mu = [];
+        for k=1:length(y.randomEffects.inv_transformation),
+            mu(k) = eval(strrep(y.randomEffects.inv_transformation{k},'psi',sprintf('%g',y.fixedEffects.values(k))));
+        end
+        
+        % Determine normally distributed phi - without covariate contributions: phi = mu + eta  (+ beta*t_cov + beta_cat)
+        phi = mu(ones(1,Nsamples),:) + ETA;
+        
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        % Determine and add effect of continuous covariates to phi: phi = mu + eta + t_cov*beta  (+ beta_cat)
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        if ~isempty(covNames),
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            % Determine the beta matrix
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            % Get parameter names of estimates
+            paramNames = y.fixedEffects.names;
+            % Initialize the beta matrix
+            beta = zeros(length(covNames),length(paramNames));
+            % Fill the beta matrix
+            for k1=1:length(covInfo),
+                paramName = covInfo(k1).parameter;
+                ix_j = strmatchIQM(paramName,paramNames,'exact');
+                for k2=1:length(covInfo(k1).covariates),
+                    covname     = covInfo(k1).covariates{k2};
+                    beta_ij     = covInfo(k1).values(k2);
+                    ix_i        = strmatchIQM(covname,covNames,'exact');
+                    % Fill beta_ij value into beta matrix
+                    beta(ix_i,ix_j) = beta_ij;
+                end
+            end
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            % Add t_cov*beta to phi
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            phi = phi + t_cov*beta;
+        end
+        
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        % Determine and add effect of categorical covariates to phi: phi = mu + eta + beta*t_cov + beta_cat
+        % One beta_cat matrix for each parameter/covariate combination!
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        if ~isempty(catNames),
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            % Determine the beta_cat matrix
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            % Get parameter names of estimates
+            paramNames = y.fixedEffects.names;
+            % Initialize the beta_cat matrix (Nsamples x Nparameters)
+            beta_cat = {};
+            % Determine the beta_cat matrices
+            for k1=1:length(catInfo),
+                paramName = catInfo(k1).parameter;
+                ix_j = strmatchIQM(paramName,paramNames,'exact');
+                for k2=1:length(catInfo(k1).covariates),
+                    % Initialize parameter/covariate dependent beta_cat matrix
+                    beta_cat_cov = zeros(Nsamples,length(paramNames));
+                    % Get categorical cov name and index
+                    catname     = catInfo(k1).covariates{k2};
+                    ix_i        = strmatchIQM(catname,catNames,'exact');
+                    if ~isempty(ix_i),
+                        % Fill the beta_cat_cov matrix
+                        categories_user = catValues(:,ix_i);
+                        categories_model = catInfo(k1).information(k2).categories;
+                        categories_values = catInfo(k1).information(k2).values;
+                        % Initialize values
+                        values = NaN(size(categories_user));
+                        for kkk=1:length(categories_model),
+                            ix = categories_user==categories_model(kkk);
+                            values(ix) = categories_values(kkk);
+                        end
+                        % Check if values contains NaN, then error and inform the user
+                        if ~isempty(find(isnan(values), 1)),
+                            error('Categorical covariate "%s" contains user provided category that has not been used for model building.',catname);
+                        end
+                        % Assign values
+                        beta_cat_cov(:,ix_j) = values;
+                    end
+                    beta_cat{end+1} = beta_cat_cov;
+                end
+            end
+            
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            % Add beta_cat to phi
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            for k1=1:length(beta_cat),
+                phi = phi + beta_cat{k1};
+            end
+        end
+        
+        % Back transform individual parameters (each column one parameter)
+        psi = [];
+        for k=1:size(phi,2),
+            transform_string = strrep(y.randomEffects.transformation{k},'phi',sprintf('phi(:,%d)',k));
+            psi(:,k) = eval(transform_string);
+            % Handle the case when phi=Inf and logit transformation => manually set to 1
+            if strcmp(y.randomEffects.transformation{k},'exp(phi)./(1+exp(phi))'),
+                psi(isnan(psi)) = 1;
+            end
+        end
+        
+        % Check if some issues with the sampled parameters (should not lead to complex values)
+        if isempty(find(imag(psi) ~=0)),
+            break;
+        else
+            % Rerun sampling since problem with population parameter sampling
+        end
+    end
+    % Define output variable
+    output                              = [];
+    output.parameterNames               = y.fixedEffects.names;
+    output.FLAG_SAMPLE                  = FLAG_SAMPLE;
+    output.Nsamples                     = Nsamples;
+    output.parameterValuesPopulation    = y.fixedEffects.values;
+    output.parameterValuesIndividual    = psi;
+
+elseif FLAG_SAMPLE == 2,
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Handle special case of FLAG_SAMPLE=2 (sampling population parameters only)
+    % Not taking covariates into account
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    FLAG_SAMPLE_POPULATIONPARAM = 1;
+    
+    % Run sampling function once just to get the number of parameters to sample
+    y = sampleMONOLIXpopulationParametersIQM(x,0,1);
+
+    % Initialize the matrix with the parameter values (number of parameters needed for that)
+    popvalues = zeros(Nsamples,length(y.fixedEffects.names));
+    
+    % Get Nsamples sets of population parameters from uncertainty distribution
+    for k=1:Nsamples,
+        y = sampleMONOLIXpopulationParametersIQM(x,FLAG_SAMPLE_POPULATIONPARAM,1);
+        popvalues(k,:) = y.fixedEffects.values;
+    end
+    
+    % Define output variable
+    output                              = [];
+    output.parameterNames               = y.fixedEffects.names;
+    output.FLAG_SAMPLE                  = FLAG_SAMPLE;
+    output.Nsamples                     = Nsamples;
+    output.parameterValuesPopulation    = popvalues;
+    output.parameterValuesIndividual    = [];
+    
+elseif FLAG_SAMPLE == 3 || FLAG_SAMPLE == 4,
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Handle special case of FLAG_SAMPLE=3 || 4
+    % - Sampling population parameters once only from uncertainty distributions (if FLAG_SAMPLE=4)
+    % - Including covariate effect on sampled population parameters
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%    
+    if FLAG_SAMPLE==3,
+        FLAG_SAMPLE_POPULATIONPARAM = 0;
+    else
+        FLAG_SAMPLE_POPULATIONPARAM = 1;
+    end
+    
+    % Need to sample until reasonable values (no imaginary parts in parameters)
+    while 1,
+        % Parse and sample monolix results to get base population parameters without covariate effects
+        y = sampleMONOLIXpopulationParametersIQM(x,FLAG_SAMPLE_POPULATIONPARAM);
+        
+        % Transform population parameters to normal distribution (mu) (allowing for transformations: lognormal, logitnormal, normal)
+        mu = [];
+        for k=1:length(y.randomEffects.inv_transformation),
+            mu(k) = eval(strrep(y.randomEffects.inv_transformation{k},'psi',sprintf('%g',y.fixedEffects.values(k))));
+        end
+        
+        % Determine normally distributed phi - without eta and covariate contribution: phi = mu (+ eta)  (+ beta*t_cov + beta_cat)
+        phi = mu(ones(1,Nsamples),:);
+        
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        % Determine and add effect of continuous covariates to phi: phi = mu (+ eta) + t_cov*beta  (+ beta_cat)
+        % Without eta contribution
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        if ~isempty(covNames),
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            % Determine the beta matrix
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            % Get parameter names of estimates
+            paramNames = y.fixedEffects.names;
+            % Initialize the beta matrix
+            beta = zeros(length(covNames),length(paramNames));
+            % Fill the beta matrix
+            for k1=1:length(covInfo),
+                paramName = covInfo(k1).parameter;
+                ix_j = strmatchIQM(paramName,paramNames,'exact');
+                for k2=1:length(covInfo(k1).covariates),
+                    covname     = covInfo(k1).covariates{k2};
+                    beta_ij     = covInfo(k1).values(k2);
+                    ix_i        = strmatchIQM(covname,covNames,'exact');
+                    % Fill beta_ij value into beta matrix
+                    beta(ix_i,ix_j) = beta_ij;
+                end
+            end
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            % Add t_cov*beta to phi
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            phi = phi + t_cov*beta;
+        end
+        
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        % Determine and add effect of categorical covariates to phi: phi = mu + eta + beta*t_cov + beta_cat
+        % One beta_cat matrix for each parameter/covariate combination!
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        if ~isempty(catNames),
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            % Determine the beta_cat matrix
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            % Get parameter names of estimates
+            paramNames = y.fixedEffects.names;
+            % Initialize the beta_cat matrix (Nsamples x Nparameters)
+            beta_cat = {};
+            % Determine the beta_cat matrices
+            for k1=1:length(catInfo),
+                paramName = catInfo(k1).parameter;
+                ix_j = strmatchIQM(paramName,paramNames,'exact');
+                for k2=1:length(catInfo(k1).covariates),
+                    % Initialize parameter/covariate dependent beta_cat matrix
+                    beta_cat_cov = zeros(Nsamples,length(paramNames));
+                    % Get categorical cov name and index
+                    catname     = catInfo(k1).covariates{k2};
+                    ix_i        = strmatchIQM(catname,catNames,'exact');
+                    if ~isempty(ix_i),
+                        % Fill the beta_cat_cov matrix
+                        categories_user = catValues(:,ix_i);
+                        categories_model = catInfo(k1).information(k2).categories;
+                        categories_values = catInfo(k1).information(k2).values;
+                        % Initialize values
+                        values = NaN(size(categories_user));
+                        for kkk=1:length(categories_model),
+                            ix = categories_user==categories_model(kkk);
+                            values(ix) = categories_values(kkk);
+                        end
+                        % Check if values contains NaN, then error and inform the user
+                        if ~isempty(find(isnan(values), 1)),
+                            error('Categorical covariate "%s" contains user provided category that has not been used for model building.',catname);
+                        end
+                        % Assign values
+                        beta_cat_cov(:,ix_j) = values;
+                    end
+                    beta_cat{end+1} = beta_cat_cov;
+                end
+            end
+            
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            % Add beta_cat to phi
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            for k1=1:length(beta_cat),
+                phi = phi + beta_cat{k1};
+            end
+        end
+        
+        % Back transform individual parameters (each column one parameter)
+        psi = [];
+        for k=1:size(phi,2),
+            transform_string = strrep(y.randomEffects.transformation{k},'phi',sprintf('phi(:,%d)',k));
+            psi(:,k) = eval(transform_string);
+            % Handle the case when phi=Inf and logit transformation => manually set to 1
+            if strcmp(y.randomEffects.transformation{k},'exp(phi)./(1+exp(phi))'),
+                psi(isnan(psi)) = 1;
+            end
+        end
+        
+        % Check if some issues with the sampled parameters (should not lead to complex values)
+        if isempty(find(imag(psi) ~=0)),
+            break;
+        else
+            % Rerun sampling since problem with population parameter sampling
+        end
+    end
+    % Define output variable
+    output                              = [];
+    output.parameterNames               = y.fixedEffects.names;
+    output.FLAG_SAMPLE                  = FLAG_SAMPLE;
+    output.Nsamples                     = Nsamples;
+    output.parameterValuesPopulation    = psi;    
+    output.parameterValuesIndividual    = [];
+    
+elseif FLAG_SAMPLE == 5,
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Handle special case of FLAG_SAMPLE=5
+    % - Sampling Nsamples population parameters from uncertainty distribution
+    % - Including covariate effect on sampled population parameters
+    %   Need to provide Nsamples number of covariate values
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%    
+    FLAG_SAMPLE_POPULATIONPARAM = 1;
+    
+    % Run sampling function once just to get the number of parameters to sample
+    y = sampleMONOLIXpopulationParametersIQM(x,0,1);
+
+    % Initialize the matrix with the parameter values (number of parameters needed for that)
+    mu = zeros(Nsamples,length(y.fixedEffects.names));
+
+    % Need to sample until reasonable values (no imaginary parts in parameters)
+    while 1,
+
+        % Get Nsamples sets of population parameters from uncertainty distribution
+        for k0=1:Nsamples,
+            % Sample
+            y = sampleMONOLIXpopulationParametersIQM(x,FLAG_SAMPLE_POPULATIONPARAM,1);
+            mu(k0,:) = y.fixedEffects.values;
+        end
+
+        % Transform
+        for k=1:length(y.randomEffects.inv_transformation),
+            mu(:,k) = eval(strrep(y.randomEffects.inv_transformation{k},'psi',sprintf('mu(:,%d)',k)));
+        end
+        
+        % Determine normally distributed phi - without eta and covariate contribution: phi = mu (+ eta)  (+ beta*t_cov + beta_cat)
+        phi = mu;
+        
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        % Determine and add effect of continuous covariates to phi: phi = mu (+ eta) + t_cov*beta  (+ beta_cat)
+        % Without eta contribution
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        if ~isempty(covNames),
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            % Determine the beta matrix
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            % Get parameter names of estimates
+            paramNames = y.fixedEffects.names;
+            % Initialize the beta matrix
+            beta = zeros(length(covNames),length(paramNames));
+            % Fill the beta matrix
+            for k1=1:length(covInfo),
+                paramName = covInfo(k1).parameter;
+                ix_j = strmatchIQM(paramName,paramNames,'exact');
+                for k2=1:length(covInfo(k1).covariates),
+                    covname     = covInfo(k1).covariates{k2};
+                    beta_ij     = covInfo(k1).values(k2);
+                    ix_i        = strmatchIQM(covname,covNames,'exact');
+                    % Fill beta_ij value into beta matrix
+                    beta(ix_i,ix_j) = beta_ij;
+                end
+            end
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            % Add t_cov*beta to phi
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            phi = phi + t_cov*beta;
+        end
+        
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        % Determine and add effect of categorical covariates to phi: phi = mu + eta + beta*t_cov + beta_cat
+        % One beta_cat matrix for each parameter/covariate combination!
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        if ~isempty(catNames),
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            % Determine the beta_cat matrix
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            % Get parameter names of estimates
+            paramNames = y.fixedEffects.names;
+            % Initialize the beta_cat matrix (Nsamples x Nparameters)
+            beta_cat = {};
+            % Determine the beta_cat matrices
+            for k1=1:length(catInfo),
+                paramName = catInfo(k1).parameter;
+                ix_j = strmatchIQM(paramName,paramNames,'exact');
+                for k2=1:length(catInfo(k1).covariates),
+                    % Initialize parameter/covariate dependent beta_cat matrix
+                    beta_cat_cov = zeros(Nsamples,length(paramNames));
+                    % Get categorical cov name and index
+                    catname     = catInfo(k1).covariates{k2};
+                    ix_i        = strmatchIQM(catname,catNames,'exact');
+                    if ~isempty(ix_i),
+                        % Fill the beta_cat_cov matrix
+                        categories_user = catValues(:,ix_i);
+                        categories_model = catInfo(k1).information(k2).categories;
+                        categories_values = catInfo(k1).information(k2).values;
+                        % Initialize values
+                        values = NaN(size(categories_user));
+                        for kkk=1:length(categories_model),
+                            ix = categories_user==categories_model(kkk);
+                            values(ix) = categories_values(kkk);
+                        end
+                        % Check if values contains NaN, then error and inform the user
+                        if ~isempty(find(isnan(values), 1)),
+                            error('Categorical covariate "%s" contains user provided category that has not been used for model building.',catname);
+                        end
+                        % Assign values
+                        beta_cat_cov(:,ix_j) = values;
+                    end
+                    beta_cat{end+1} = beta_cat_cov;
+                end
+            end
+            
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            % Add beta_cat to phi
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            for k1=1:length(beta_cat),
+                phi = phi + beta_cat{k1};
+            end
+        end
+        
+        % Back transform individual parameters (each column one parameter)
+        psi = [];
+        for k=1:size(phi,2),
+            transform_string = strrep(y.randomEffects.transformation{k},'phi',sprintf('phi(:,%d)',k));
+            psi(:,k) = eval(transform_string);
+            % Handle the case when phi=Inf and logit transformation => manually set to 1
+            if strcmp(y.randomEffects.transformation{k},'exp(phi)./(1+exp(phi))'),
+                psi(isnan(psi)) = 1;
+            end
+        end
+        
+        % Check if some issues with the sampled parameters (should not lead to complex values)
+        if isempty(find(imag(psi) ~=0)),
+            break;
+        else
+            % Rerun sampling since problem with population parameter sampling
+        end
+    end
+    % Define output variable
+    output                              = [];
+    output.parameterNames               = y.fixedEffects.names;
+    output.FLAG_SAMPLE                  = FLAG_SAMPLE;
+    output.Nsamples                     = Nsamples;
+    output.parameterValuesPopulation    = psi;    
+    output.parameterValuesIndividual    = [];
+    
+end
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/01-MONOLIX/auxiliary/fitanalysisETAvsCOVmonolixIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/01-MONOLIX/auxiliary/fitanalysisETAvsCOVmonolixIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..315c93e0d47262ac8bbe5fd9b031120efb349ed7
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/01-MONOLIX/auxiliary/fitanalysisETAvsCOVmonolixIQM.m	
@@ -0,0 +1,242 @@
+function [] = fitanalysisETAvsCOVmonolixIQM(projectPath,filename,options)    
+% Called by IQMfitanalysisETAvsCOV - same calling syntax and handling Monolix.
+% 
+% [SYNTAX]
+% See IQMfitanalysisETAvsCOV 
+%
+% [INPUT]
+% See IQMfitanalysisETAvsCOV
+%
+% [OUTPUT]
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle variable input arguments
+if nargin<2,
+    filename    = '';
+end
+if nargin<3,
+    options = [];
+end
+
+% Get additional information from header
+headerinfo  = parseMONOLIXprojectHeaderIQM(projectPath);
+covNames    = headerinfo.COVNAMES;
+catNames    = headerinfo.CATNAMES;
+dataPath    = headerinfo.DATA{1};
+
+% Handle empty covariate definitions
+if length(covNames) == 1,
+    if isempty(covNames{1}),
+        covNames = {};
+    end
+end
+% Handle empty covariate definitions
+if length(catNames) == 1,
+    if isempty(catNames{1}),
+        catNames = {};
+    end
+end
+
+% Load the data
+data        = IQMloadCSVdataset([projectPath '/' dataPath]);
+
+% Handle options
+try corrcoeffThreshold = options.corrcoeffThreshold; catch, corrcoeffThreshold = 0.3; end
+try withlabels = options.labels; catch, withlabels = 1; end
+
+% Check cov and catnames
+datanames = data.Properties.VariableNames;
+for k=1:length(covNames),
+    if isempty(strmatchIQM(covNames{k},datanames,'exact')), error('The dataset does not contain the covariate ''%s''.',covNames{k}); end    
+end
+for k=1:length(catNames),
+    if isempty(strmatchIQM(catNames{k},datanames,'exact')), error('The dataset does not contain the covariate ''%s''.',catNames{k}); end    
+end
+
+% Construct RESULTS path
+resultsPath = [projectPath '/RESULTS'];
+    
+% Check the projectPath
+if ~exist(resultsPath),
+    error(sprintf('The provided project path "%s" does not point to a valid Monolix project.\nPlease make sure a "RESULTS" folder is in the provided path.',projectPath));
+end
+
+% Check that indiv_eta.txt is present in the RESULTS folder
+indiv_eta_file = [resultsPath '/indiv_eta.txt'];
+if ~exist(indiv_eta_file)
+    error('The "indiv_eta.txt" file does not exist in the RESULTS folder.');
+end
+
+% Load eta file
+indiv_eta   = IQMloadNONCSVdataset([resultsPath '/indiv_eta.txt']);
+
+% Determine random effect estimates for shrinkage determination
+x = parseMONOLIXresultsIQM(projectPath);
+y = sampleMONOLIXpopulationParametersIQM(x,0,1);
+OMEGA       = y.randomEffects.values;
+OMEGAnames  = y.randomEffects.names;
+
+% Get eta modes
+dataeta = table();
+dataeta.ID = indiv_eta.ID;
+for k=1:length(OMEGAnames),
+    dataeta.(OMEGAnames{k}) = indiv_eta.(['eta_' OMEGAnames{k} '_mode']);
+end
+
+% Remove the non estimated omegas/etas
+ix =  find(sum(abs(table2array(dataeta(:,2:end)))) ~= 0);
+dataeta_est                 = dataeta(:,[1 ix+1]);
+OMEGAnames_est              = OMEGAnames(ix);
+
+% Get the continuous covariates - transformed or not from indiv_eta
+datacovs = table();
+datacovs.ID = indiv_eta.ID;
+varnames = indiv_eta.Properties.VariableNames;
+for k=1:length(covNames),
+    ix = strmatchIQM(covNames{k},varnames,'exact');
+    covname = covNames{k};
+    if isempty(ix),
+        ix = strmatchIQM(['t_' covNames{k}],varnames,'exact');
+        covname = ['t_' covNames{k}];
+    end
+    if isempty(ix),
+        error('Trouble finding the right covariate - check!');
+    end
+    datacovs.(covname) = indiv_eta.(covname);
+end
+
+% Get the categorical covariates for same IDs as in the dataeta_est
+% This only works correclty if no transformation has been done in Monolix
+allIDeta = unique(dataeta_est.ID);
+datacats = table();
+dataeta_cats = table(); % eta dataset in case when there is iov and each occasion has a repeated entry in dataeta_est
+for k=1:length(allIDeta),
+    datak = data(data.ID==allIDeta(k),:);
+    datacatsk = table();
+    datacatsk.ID = allIDeta(k);
+    datak_etas = dataeta_est(dataeta_est.ID == allIDeta(k),:);
+    for k2=1:length(catNames),
+        datacatsk.(catNames{k2}) = datak.(catNames{k2})(1);
+    end
+    datacats = [datacats; datacatsk];
+    dataeta_cats = [dataeta_cats; datak_etas(1,:)]; % this avoids duplicate lines when iov
+end
+dataeta_cats.ID = []; % we don't need the id column
+
+% Interface to old code ;-)
+etas = dataeta_est(:,2:end);
+covs = datacovs(:,2:end);
+cats = datacats(:,2:end);
+nretas = size(etas,1);
+nrcovs = size(covs,1);
+nrcats = size(cats,1);
+etaNames = etas.Properties.VariableNames;
+covNames = covs.Properties.VariableNames;
+catNames = cats.Properties.VariableNames;
+ids = datacovs.ID;
+
+% Determine subplot organization
+Neta = length(etaNames);
+nrow = ceil(sqrt(Neta));
+ncol = ceil(Neta/nrow);
+
+% If filename then remove old file
+IQMstartNewPrintFigure(filename);
+
+% First handle continuous covariates
+% Cycle through covariates and produce on figure per covariate
+% The etas in subplots
+for k=1:size(covs,2),
+    cov = table2array(covs(:,k));
+    % New figure
+    h = figure;
+    set(h,'Name',['Covariate: ' covNames{k}])
+    for k2=1:size(etas,2),
+        name = etaNames{k2};
+        eta = table2array(etas(:,k2));
+        subplot(nrow,ncol,k2);
+        [cc,pp] = corrcoef([cov,eta]);
+        cc = cc(1,2);
+        pp = pp(1,2);
+        if abs(cc) > corrcoeffThreshold,            
+            if ~withlabels,
+                plot(cov,eta,'.r','MarkerSize',20); hold on
+            else
+                plot(cov,eta,'.w','MarkerSize',20); hold on
+                labels1 = cellstr( num2str(ids, '%d') );
+                text(cov, eta, labels1, 'VerticalAlignment','middle', 'HorizontalAlignment','center', 'FontSize', 8,'Color','r'); hold on
+            end
+        else
+            if ~withlabels,
+                plot(cov,eta,'.b','MarkerSize',20); hold on
+            else
+                plot(cov,eta,'.w','MarkerSize',1); hold on
+                labels1 = cellstr( num2str(ids, '%d') );
+                text(cov, eta, labels1, 'VerticalAlignment','middle', 'HorizontalAlignment','center', 'FontSize', 8,'Color','b'); hold on
+            end
+        end
+
+        % Remove the potential NaN things
+        covreg          = cov;
+        ixNaN           = find(isnan(covreg));
+        covreg(ixNaN)   = [];
+        etareg          = eta;
+        etareg(ixNaN)   = [];
+        % Add linear regression result
+        X = [ones(size(covreg)) covreg];
+        
+        try
+            b = regressIQM(etareg,X); % Removes NaN data
+            x = get(gca,'XLim');        
+            plot(x, b(1)+b(2)*x,'k--','LineWidth',2)
+            % Title etc.
+            title(['Corr. coeff.: ' sprintf('%1.2g (p=%1.2g)',cc,pp)],'Interpreter','None');
+        catch
+        end
+        
+        xlabel(covNames{k},'Interpreter','None')
+        ylabel(['eta' etaNames{k2}],'Interpreter','None')
+    end
+    IQMprintFigure(gcf,filename);
+    if ~isempty(filename),
+        close(gcf);
+    end    
+end
+
+% Second handle categorical covariates
+% Cycle through covariates and produce on figure per covariate
+% The etas in subplots
+for k=1:size(cats,2),  
+    cat = table2array(cats(:,k));
+    catunique = unique(cat);
+    % New figure
+    h = figure;
+    set(h,'Name',['Covariate: ' catNames{k}]);
+    for k2=1:size(etas,2),
+        name = etaNames{k2};
+        eta = table2array(dataeta_cats(:,k2));
+        subplot(nrow,ncol,k2);
+        
+        optionsBoxplot                      = [];
+        optionsBoxplot.verticalFlag         = 0;
+        optionsBoxplot.outliers             = 0;
+        optionsBoxplot.whiskerPercentiles   = [5 95];
+        boxplotIQM(eta,cat,optionsBoxplot);
+        
+        plotZeroLim = get(gca,'YLim');
+        hold on;
+        plot([0 0],plotZeroLim,'--k','LineWidth',2)
+        xlabel(['eta' etaNames{k2}],'Interpreter','None')
+        ylabel(catNames{k},'Interpreter','None')
+        grid on
+    end
+    IQMprintFigure(gcf,filename);
+    if ~isempty(filename),
+        close(gcf);
+    end    
+end
+
+% PS2PDF
+IQMconvert2pdf(filename);
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/01-MONOLIX/auxiliary/parseMONOLIXetasIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/01-MONOLIX/auxiliary/parseMONOLIXetasIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..90f3688777c0df08fe9039e6a1ab24dd30ff9698
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/01-MONOLIX/auxiliary/parseMONOLIXetasIQM.m	
@@ -0,0 +1,42 @@
+function [ dataeta, OMEGA, OMEGAnames ] = parseMONOLIXetasIQM( projectPath )
+% Parses a MONOLIX project and returns the ETAs.
+% 
+% [SYNTAX]
+% [ dataeta, OMEGA, OMEGAnames ] = parseMONOLIXetasIQM( projectPath )
+%
+% [INPUT]
+% projectPath: Project from which to return the etas.
+%
+% [OUTPUT]
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Construct RESULTS path
+resultsPath = [projectPath '/RESULTS'];
+    
+% Check the projectPath
+if ~exist(resultsPath),
+    error(sprintf('The provided project path "%s" does not point to a valid Monolix project.\nPlease make sure a "RESULTS" folder is in the provided path.',projectPath));
+end
+
+% Check that indiv_eta.txt is present in the RESULTS folder
+indiv_eta_file = [resultsPath '/indiv_eta.txt'];
+if ~exist(indiv_eta_file)
+    error('The "indiv_eta.txt" file does not exist in the RESULTS folder.');
+end
+
+% Determine random effect estimates for shrinkage determination
+x = parseMONOLIXresultsIQM(projectPath);
+y = sampleMONOLIXpopulationParametersIQM(x,0,1);
+OMEGA       = y.randomEffects.values;
+OMEGAnames  = y.randomEffects.names;
+
+% Load eta file
+indiv_eta   = IQMloadNONCSVdataset([resultsPath '/indiv_eta.txt']);
+
+% Get eta modes
+dataeta = table();
+for k=1:length(OMEGAnames),
+    dataeta.(OMEGAnames{k}) = indiv_eta.(['eta_' OMEGAnames{k} '_mode']);
+end
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/01-MONOLIX/auxiliary/parseMONOLIXindivparamIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/01-MONOLIX/auxiliary/parseMONOLIXindivparamIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..1247cbf6034fd275729a0eef7763f55a347d7f34
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/01-MONOLIX/auxiliary/parseMONOLIXindivparamIQM.m	
@@ -0,0 +1,21 @@
+function [ indiv_param ] = parseMONOLIXindivparamIQM( projectPath,numberParameters )
+% Returns the individual parameters from a MONOLIX fit. numberParameters
+% needs to be provided to know how many they are, since this can change 
+% depending on the settings.
+% 
+% [SYNTAX]
+% [ indiv_param ] = parseMONOLIXindivparamIQM( projectPath,numberParameters )
+%
+% [INPUT]
+% projectPath:      Project to return the individual parameters
+% numberParameters: Number of parameters
+%
+% [OUTPUT]
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+indiv_param             = IQMloadNONCSVdataset([projectPath '/RESULTS/indiv_parameters.txt']);
+indiv_param             = indiv_param(:,1:numberParameters+1);
+
+% Remove the _mode thing
+indiv_param.Properties.VariableNames = strrep(indiv_param.Properties.VariableNames,'_mode','');
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/01-MONOLIX/auxiliary/parseMONOLIXparameterEstimatesIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/01-MONOLIX/auxiliary/parseMONOLIXparameterEstimatesIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..6263f2620d7b563d39f3d31183718739946fddd8
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/01-MONOLIX/auxiliary/parseMONOLIXparameterEstimatesIQM.m	
@@ -0,0 +1,204 @@
+function [parameters] = parseMONOLIXparameterEstimatesIQM(projectPath)
+% Parses a MONOLIX project and returns parameters estimates information.
+% It requires the presence of the estimates.txt and fim_lin.txt or 
+% fim_sa.txt files. If SA was done then these values are returned. Otherwise
+% the results from the linearization (for FIM and standard errors).
+%
+% This function also changes naming conventions of results to allow easier 
+% parsing and get more independent of the ever changing ideas on how to 
+% format the output of Monolix.
+% 
+% [SYNTAX]
+% [parameters] = parseMONOLIXparameterEstimatesIQM(projectPath)
+%
+% [INPUT]
+% projectPath:  Project to return the individual parameters
+%
+% [OUTPUT]
+% parameters:   MATLAB structure with the following fields:
+%   parameters.names                           
+%   parameters.values                          
+%   parameters.stderrors                       
+%   parameters.correlationmatrix               
+%   parameters.FLAGestimated                   
+%   parameters.covariancematrix                
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Load information
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Load estimates.txt from Monolix run
+try
+    warning off;
+    estimates = readtable([projectPath '/RESULTS/estimates.txt'],'Delimiter',';');
+    warning on;
+catch
+    error('Problem loading the estimates.txt file.');
+end
+
+% Load fisher information matrix from Monolix - SA FIM overwrites LIN FIM
+fim = [];
+try
+	fim = readtable([projectPath '/RESULTS/fim_lin.txt'],'Delimiter',';','ReadVariableNames',0);
+end
+try
+    fim = readtable([projectPath '/RESULTS/fim_sa.txt'],'Delimiter',';','ReadVariableNames',0);
+end
+% In MONOLIX 2016R1 Lixoft decided to change the name of the fim files ... NICE!
+% They also decided to change the content (only reporting FIM for estimated
+% parameter ... YEAH). So we need to do other manipulations to get MONOLIX
+% 2016R1 integrated.
+% 
+R2016_FLAG = 0;
+try
+    fim = readtable([projectPath '/RESULTS/fimTransPop_lin.txt'],'Delimiter',';','ReadVariableNames',0);
+	R2016_FLAG = 1;
+end
+try
+    fim = readtable([projectPath '/RESULTS/fimTransPop_sa.txt'],'Delimiter',';','ReadVariableNames',0);
+	R2016_FLAG = 1;
+end
+if R2016_FLAG,
+    error('MONOLIX 2016R1 not yet supported by IQM Tools.');
+end
+
+% Check if fim file was loaded
+if isempty(fim),
+    error('Problem loading the fim.txt file.');
+end
+
+% Load the header information
+MLX_project_header = parseMONOLIXprojectHeaderIQM(projectPath);
+
+% Load pop_parameters.txt file
+content = fileread([projectPath '/RESULTS/pop_parameters.txt']);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get version of Monolix
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+mlxversion = regexp(content,'Monolix version:[\s]+([0-9.]+)','tokens');
+try
+    MONOLIXversion = mlxversion{1}{1};
+catch
+    MONOLIXversion = 'unknown';
+end    
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Process covariate information
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Find ix of parameters that relate to betas for categorical covariates 
+names = table2cell(estimates(:,1));
+ix_cats = [];
+for k=1:length(MLX_project_header.CATNAMES),
+    for k2=1:length(names),
+        if ~isempty(strfind(names{k2},MLX_project_header.CATNAMES{k})),
+            ix_cats(end+1) = k2;
+        end
+    end
+end
+ix_cats = unique(ix_cats);
+
+% Check which of these has parameters value 0 (Exact)
+ix_cats_reference = ix_cats(find(estimates.parameter(ix_cats) == 0));
+
+% Remove rows defined by ix_cats_reference from estimates and fim
+estimates(ix_cats_reference,:) = [];
+fim(ix_cats_reference,:) = [];
+fim(:,ix_cats_reference+1) = [];
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get the parameters information
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Postprocess the FIM
+FIM                                         = table2array(fim(:,2:end));
+
+% Get correlation matrix
+correlationMatrix                           = FIM;
+correlationMatrix(isnan(correlationMatrix)) = 0;
+correlationMatrix                           = correlationMatrix-diag(diag(correlationMatrix)) + eye(size(correlationMatrix));
+
+% Initialize output - SA results overwrite LIN results
+parameters                                  = [];
+parameters.MONOLIXversion                   = MONOLIXversion;
+parameters.names                            = table2cell(estimates(:,1))';
+parameters.values                           = estimates.parameter';
+parameters.stderrors                        = estimates.s_e__lin';
+% RSE needed only to test if values very close to zero estimates or not.
+rse                                         = estimates.r_s_e__lin'; 
+try
+    parameters.stderrors                    = estimates.s_e__sa';
+    rse                                     = estimates.r_s_e__sa';
+end
+
+% Find estimated parameters. Rules:
+% - Parameters with 0 as stderr have not been estimated
+% - Parameters with NaN as stderr have not been estimated if their value is 0
+FLAGestimated                                                           = ones(1,size(FIM,1));
+FLAGestimated(parameters.stderrors==0 & rse==0)                         = 0;
+FLAGestimated(isnan(parameters.stderrors==0) & (parameters.values==0))  = 0;
+
+% Get correlation matrix
+parameters.correlationmatrix                = correlationMatrix;
+parameters.FLAGestimated                    = FLAGestimated;
+parameters.covariancematrix                 = correlationMatrix.*(parameters.stderrors'*parameters.stderrors);
+   
+% Need to make covariancematrix positive semidefinite
+parameters.covariancematrix = makePosSemiDefIQM(parameters.covariancematrix);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Change names to match some "standard" with parentheses
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Remove "_pop" from the parameters names
+parameters.names = strrep(parameters.names,'_pop','');
+
+% Remove "t_" from the parameters names (better: "replace _t_ with _"!!!
+% Since t_ can come from other things ...
+parameters.names = strrep(parameters.names,'_t_','_');
+
+% Change beta_ and corr_ and omega_ to beta( corr( and omega(
+parameters.names = strrep(parameters.names,'beta_','beta(');
+parameters.names = strrep(parameters.names,'corr_','corr(');
+parameters.names = strrep(parameters.names,'omega_','omega(');
+parameters.names = strrep(parameters.names,'omega2_','omega2(');
+
+% If beta or corr or omega in name then add ")" at end
+% Also in this case exchange first occurence of '_' to ','
+for k=1:length(parameters.names),
+   if ~isempty(strfind(parameters.names{k},'beta(')) && isempty(strfind(parameters.names{k},')')),
+       parameters.names{k} = [parameters.names{k} ')'];
+   end
+   if ~isempty(strfind(parameters.names{k},'corr(')) && isempty(strfind(parameters.names{k},')')),
+       parameters.names{k} = [parameters.names{k} ')'];
+   end
+   if ~isempty(strfind(parameters.names{k},'omega(')) && isempty(strfind(parameters.names{k},')')),
+       parameters.names{k} = [parameters.names{k} ')'];
+   end
+   if ~isempty(strfind(parameters.names{k},'omega2(')) && isempty(strfind(parameters.names{k},')')),
+       parameters.names{k} = [parameters.names{k} ')'];
+   end
+   % Find '_'
+   ix = strfind(parameters.names{k},'_');
+   if ~isempty(ix),
+       parameters.names{k}(ix(1)) = ',';
+   end
+end
+
+% Additional change of beta ... from beta(par,cov) => beta_par(cov)
+for k=1:length(parameters.names),
+    if ~isempty(strfind(parameters.names{k},'beta(')),
+        parameters.names{k} = strrep(parameters.names{k},'(','_');
+        parameters.names{k} = strrep(parameters.names{k},',','(');
+    end
+end
+
+% Change error parameter names ("a,1"=>"error_ADD1", ...) 
+parameters.names = regexprep(parameters.names,'\<a,','error_ADD');
+parameters.names = regexprep(parameters.names,'\<b,','error_PROP');
+parameters.names = regexprep(parameters.names,'\<a\>','error_ADD1');
+parameters.names = regexprep(parameters.names,'\<b\>','error_PROP1');
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/01-MONOLIX/auxiliary/parseMONOLIXpredictionsIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/01-MONOLIX/auxiliary/parseMONOLIXpredictionsIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..8e5bb143b351a847e26f7c54f4fe33afc198e22e
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/01-MONOLIX/auxiliary/parseMONOLIXpredictionsIQM.m	
@@ -0,0 +1,43 @@
+function [ predictions ] = parseMONOLIXpredictionsIQM( projectPath,outputNumber )
+% Returns the predictions of a MONOLIX project for a given output number.
+% 
+% [SYNTAX]
+% [ predictions ] = parseMONOLIXpredictionsIQM( projectPath,outputNumber )
+%
+% [INPUT]
+% projectPath:      Project to return the predictions
+% outputNumber:     Number of the output to return the predictions for
+%
+% [OUTPUT]
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Construct RESULTS path
+resultsPath = [projectPath '/RESULTS'];
+    
+% Check the projectPath
+if ~exist(resultsPath),
+    error(sprintf('The provided project path "%s" does not point to a valid Monolix project.\nPlease make sure a "RESULTS" folder is in the provided path.',projectPath));
+end
+
+% Check that predictions.txt or predictions<outputNumber>.txt is present in the RESULTS folder
+predictions_file = [resultsPath '/predictions' num2str(outputNumber) '.txt'];
+if ~exist(predictions_file)
+    if outputNumber == 1,
+        % Check if predictions.txt is present
+        if ~exist([resultsPath '/predictions.txt']),
+            error('The "%s" or "predictions.txt" file for output "%d" does not exist in the RESULTS folder.',predictions_file,outputNumber);
+        else
+            % It does exist - rename predictions_file
+            predictions_file = [resultsPath '/predictions.txt'];
+        end
+    else
+        error('The "%s" file for output "%d" does not exist in the RESULTS folder.',predictions_file,outputNumber);
+    end
+end
+
+% Load predictions file
+predictions = IQMloadNONCSVdataset(predictions_file);
+
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/01-MONOLIX/auxiliary/parseMONOLIXprojectHeaderIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/01-MONOLIX/auxiliary/parseMONOLIXprojectHeaderIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..c261211d34bdc282e30f9a740cc3f6d3b39cc72d
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/01-MONOLIX/auxiliary/parseMONOLIXprojectHeaderIQM.m	
@@ -0,0 +1,40 @@
+function [projectinfo] = parseMONOLIXprojectHeaderIQM(projectPath)
+% Parses the project header information from the MONOLIX project and returns it.
+% 
+% [SYNTAX]
+% [projectinfo] = parseMONOLIXprojectHeaderIQM(projectPath)
+%
+% [INPUT]
+% projectPath:      Project to return the project header
+%
+% [OUTPUT]
+% projectinfo:      Structure with information
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Check if project.mlxtran in project folder
+if exist([projectPath '/project.mlxtran']),
+    project = fileread([projectPath '/project.mlxtran']);
+else
+    error('project.mlxtran file could not be found.');
+end
+
+% Get the header
+ixstart = strfind(project,'; ==PROJECT HEADER START===================================================');
+ixend = strfind(project,  '; ==PROJECT HEADER END=====================================================');
+if isempty(ixstart) || isempty(ixend),
+    error('Project header could not be found in project.nmctl file.');
+end
+headertext = strtrim(project(ixstart+75:ixend-1));
+headerterms = explodePCIQM(headertext,char(10));
+
+% Construct output
+projectinfo = [];
+for k=1:length(headerterms),
+    eval(['projectinfo.' strrep(strtrim(headerterms{k}(2:end)),'=','=explodePCIQM(') ','','',''['','']'');']);
+end
+
+% Add project.mlxtran to header
+projectinfo.projectFile = 'project.mlxtran';
+projectinfo.TOOL        = 'MONOLIX';
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/01-MONOLIX/auxiliary/parseMONOLIXresultsIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/01-MONOLIX/auxiliary/parseMONOLIXresultsIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..4782d4e8b23596f15f1776b6a57745134de6bc7b
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/01-MONOLIX/auxiliary/parseMONOLIXresultsIQM.m	
@@ -0,0 +1,306 @@
+function [ output ] = parseMONOLIXresultsIQM( projectPath )
+% This function parses the output of Monolix and returns all information in a structure
+%
+% [SYNTAX]
+% output = parseMONOLIXresultsIQM( projectPath )
+%
+% [INPUT]
+% projectPath: path to the Monolix project folder. It is assumed that the results of the estimation
+%                                 (pop_parameters.txt, results.mat) are stored in a "RESULTS" folder within this
+%                                 project folder.
+%
+% [OUTPUT]
+% Structure with the following fields:
+%
+% output.path                         : path from which the results are read (project folder+RESULTS)
+% output.parameters                   : a structure with all parameter information
+% output.parameters.names             : cell-array with the parameter names
+% output.parameters.values            : vector with estimated values
+% output.parameters.stderrors         : vector with standard errors of estimation
+% output.parameters.correlationmatrix : full correlation matrix for estimates
+% output.parameters.FLAGestimated     : vector with flags 1 if estimated, 0 if not estimated
+% output.parameters.covariancematrix  : full covariance matrix for parameter estimates, determined
+%                                       from correlationmatrix and standard errors
+% output.objectivefunction            : structure with the values for the log-likelihood, AIC and BIC for
+%                                       both linearization and importance sampling. NaN if not determined
+% output.residualerrormodels          : cell-array with the aliases of the residual error models in the order 
+%                                       of the outputs, as defined in the MLXTRAN models
+% output.trans_randeffects            : a cell-array with the transformation of the random effects 
+% output.inv_trans_randeffects        : a cell-array with the inverse transformation of the random effects
+%
+% output.covariates.covNames          : cell-array with names of continuous covariates
+% output.covariates.covTransformation : cell-array with transformations of continuous covariates 
+% output.covariates.catNames          : cell-array with names of categorical covariates 
+% output.covariates.catCategories     : cell-array with categories of categorical covariates  
+% output.covariates.catReference      : cell-array with reference values of categorical covariates 
+
+% output.rawParameterInfo             : Info about fixed, random effects, covariates, correlations, error model etc.
+%
+% [ASSUMPTIONS]
+% String assumptions about the structure and syntax of the pop_parameters.txt file were made.
+% Need to reassess when new functions of Monolix arrive.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Check if folder exists and that RESULTS folder exists within
+if exist(projectPath) ~= 7,
+    error('The specified Monolix project folder "%s" does not exist.',projectPath);
+end
+projectPathRESULTS = [projectPath '/RESULTS'];
+if exist(projectPathRESULTS) ~= 7,
+    error('The "RESULTS" folder within the project folder "%s" does not exist.',projectPathRESULTS);
+end
+
+% Check availability of required files in specified folder
+if exist(fullfile(projectPathRESULTS, 'pop_parameters.txt')) ~= 2, 
+    error('Please check if the "%s" folder contains the ''pop_parameters.txt'' file.',projectPathRESULTS);
+end
+if exist(fullfile(projectPathRESULTS, 'results.mat')) ~= 2, 
+    error('Please check if the "%s" folder contains the ''results.mat'' file.',projectPathRESULTS);
+end
+
+% Define output structure
+output = [];
+output.type = 'MONOLIX';
+output.path = projectPathRESULTS;
+output.parameters.names = {};
+output.parameters.values = [];
+output.parameters.stderrors = [];
+output.parameters.correlationmatrix = [];
+output.parameters.FLAGestimated = [];
+output.objectivefunction.OBJ = [];
+output.objectivefunction.AIC = [];
+output.objectivefunction.BIC = [];
+output.residualerrormodels = {};
+output.trans_randeffects = {};
+output.inv_trans_randeffects = {};
+output.covariates.covNames = {};
+output.covariates.covTransformation = {};
+output.covariates.catNames = {};
+output.covariates.catCategories = {};
+output.covariates.catReference = [];
+output.rawParameterInfo = [];
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Parse parameter information  (names, values, stderr, estimated, correlation, covariance)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+output.parameters = parseMONOLIXparameterEstimatesIQM(projectPath);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Parse objective function from pop_parameters.txt
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+content = fileread([projectPath '/RESULTS/pop_parameters.txt']);
+LL      = regexp(content,'-2 x log-likelihood:[\s]+([-0-9.]+)','tokens');
+AIC     = regexp(content,'Akaike Information Criteria   \(AIC\):[\s]+([-0-9.]+)','tokens');
+BIC     = regexp(content,'Bayesian Information Criteria \(BIC\):[\s]+([-0-9.]+)','tokens');
+output.objectivefunction.OBJ = NaN;
+output.objectivefunction.AIC = NaN;
+output.objectivefunction.BIC = NaN;
+try output.objectivefunction.OBJ = eval(LL{end}{1}); end
+try output.objectivefunction.AIC = eval(AIC{end}{1}); end
+try output.objectivefunction.BIC = eval(BIC{end}{1}); end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Load monolix project header to get error model, random effect, and
+% covariate information
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+MLX_project_header = parseMONOLIXprojectHeaderIQM(projectPath);
+
+% Read the results.mat file to obtain information about error model
+output.residualerrormodels = MLX_project_header.ERRORMODELS;
+
+% Add information about the transformation of the random effects 
+output.trans_randeffects = MLX_project_header.PARAMTRANS;
+output.inv_trans_randeffects = MLX_project_header.PARAMINVTRANS;
+
+% Get covariate names - continuous and categorical
+output.covariates.covNames = MLX_project_header.COVNAMES;
+output.covariates.catNames = MLX_project_header.CATNAMES;
+x = MLX_project_header.CATCATEGORIES;
+y = {};
+for k=1:length(x),
+    if ~isempty(x{k}),
+        y{k} = eval(x{k});
+    end
+end
+output.covariates.catCategories = y;
+
+% Get covariate transformations for continuous ones
+% IQM Tools always log transforms the continuous covariates and always uses
+% t_ as the name. 
+projectTEXT         = fileread([projectPath '/project.mlxtran']);
+for k=1:length(MLX_project_header.COVNAMES),
+    x = regexp(projectTEXT,['t_' MLX_project_header.COVNAMES{k} ' = ([^\[])+\['],'tokens');
+    if ~isempty(x),
+        output.covariates.covTransformation{k} = strrep(strtrim(x{1}{1}),MLX_project_header.COVNAMES{k},'cov');
+    else
+        output.covariates.covTransformation{k} = 'unknown';
+    end
+end
+ 
+% Get reference values for categorical covariates from the
+% pop_parameters.txt file
+parametersTEXT         = fileread([projectPath '/RESULTS/pop_parameters.txt']);
+for k=1:length(output.covariates.catNames),
+    x = regexp(parametersTEXT,[output.covariates.catNames{k} '[\s]+Reference group: ([^\n]+)\n'],'tokens');
+    if ~isempty(x),
+        output.covariates.catReference(k) = eval(x{1}{1});
+    else
+        output.covariates.catReference(k) = NaN;
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Determine additional information
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Fixed effect parameter values, standard errors, rel std errors
+% Random effect parameter values, standard errors, rel std errors
+% Correlation parameter values, standard errors, rel std errors
+% Covariate parameter values, standard errors, rel std errors
+paramnames  = output.parameters.names;
+paramvalues = output.parameters.values;
+paramstderr = output.parameters.stderrors;
+FLAGestimated = output.parameters.FLAGestimated;
+
+% Determine indices of omegas
+ix_omega = strmatchIQM('omega(',paramnames);
+% Determine indices of correlations
+ix_corr  = strmatchIQM('corr(',paramnames);
+% Determine indices of covariates
+ix_cov   = strmatchIQM('beta_',paramnames);
+
+% Get random effect names, values, standard errors
+omega_names  = paramnames(ix_omega);
+omega_values = paramvalues(ix_omega);
+omega_stderr = paramstderr(ix_omega);
+omega_rse    = abs(100*(omega_stderr./omega_values));
+omega_rse(omega_stderr==0) = 0;
+omega_estimated = FLAGestimated(ix_omega);
+
+% Get correlation coefficient names, values, standard errors
+corr_names  = paramnames(ix_corr);
+corr_values = paramvalues(ix_corr);
+corr_stderr = paramstderr(ix_corr);
+corr_rse    = abs(100*(corr_stderr./corr_values));
+corr_rse(corr_stderr==0) = 0;
+corr_estimated = FLAGestimated(ix_corr);
+
+% Get covariate coefficient names, values, standard errors
+cov_names  = paramnames(ix_cov);
+cov_values = paramvalues(ix_cov);
+cov_stderr = paramstderr(ix_cov);
+cov_rse    = abs(100*(cov_stderr./cov_values));
+cov_rse(cov_stderr==0) = 0;
+cov_estimated = FLAGestimated(ix_cov);
+
+% Remove handled elements from all results to take care of rest
+paramnames([ix_omega(:);ix_corr(:);ix_cov(:)]) = [];
+paramvalues([ix_omega(:);ix_corr(:);ix_cov(:)]) = [];
+paramstderr([ix_omega(:);ix_corr(:);ix_cov(:)]) = [];
+FLAGestimated([ix_omega(:);ix_corr(:);ix_cov(:)]) = [];
+
+% Get fixed effect results
+ix_fixed = 1:length(omega_names);
+fixed_names  = paramnames(ix_fixed);
+fixed_values = paramvalues(ix_fixed);
+fixed_stderr = paramstderr(ix_fixed);
+fixed_rse    = abs(100*(fixed_stderr./fixed_values));
+fixed_rse(fixed_stderr==0) = 0;
+fixed_estimated = FLAGestimated(ix_fixed);
+
+% Add to output
+output.rawParameterInfo.fixedEffects.names      = fixed_names;
+output.rawParameterInfo.fixedEffects.values     = fixed_values;
+output.rawParameterInfo.fixedEffects.stderr     = fixed_stderr;
+output.rawParameterInfo.fixedEffects.rse        = fixed_rse;
+output.rawParameterInfo.fixedEffects.estimated  = fixed_estimated;
+output.rawParameterInfo.fixedEffects.distribution_info  = output.inv_trans_randeffects;
+
+output.rawParameterInfo.randomEffects.names     = omega_names;
+output.rawParameterInfo.randomEffects.values    = omega_values;
+output.rawParameterInfo.randomEffects.stderr    = omega_stderr;
+output.rawParameterInfo.randomEffects.rse       = omega_rse;
+output.rawParameterInfo.randomEffects.estimated = omega_estimated;
+
+output.rawParameterInfo.correlation.names       = corr_names;
+output.rawParameterInfo.correlation.values      = corr_values;
+output.rawParameterInfo.correlation.stderr      = corr_stderr;
+output.rawParameterInfo.correlation.rse         = corr_rse;
+output.rawParameterInfo.correlation.estimated   = corr_estimated;
+
+output.rawParameterInfo.covariate.names         = cov_names;
+output.rawParameterInfo.covariate.values        = cov_values;
+output.rawParameterInfo.covariate.stderr        = cov_stderr;
+output.rawParameterInfo.covariate.rse           = cov_rse;
+output.rawParameterInfo.covariate.estimated     = cov_estimated;
+
+% Finally parse the error model parameters
+names                                           = output.parameters.names;
+residual_error_names                            = paramnames(length(omega_names)+1:end);
+residual_error_values                           = [];
+residual_error_stderr                           = [];
+residual_error_rse                              = [];
+residual_error_estimated                        = [];
+for k=1:length(residual_error_names),
+    ix = strmatchIQM(residual_error_names{k},names,'exact');
+    residual_error_values(end+1)                = output.parameters.values(ix);
+    residual_error_stderr(end+1)                = output.parameters.stderrors(ix);
+    residual_error_estimated(end+1)             = output.parameters.FLAGestimated(ix);
+end
+residual_error_rse                              = 100*residual_error_stderr./residual_error_values;
+
+output.rawParameterInfo.errorParameter.names     = residual_error_names;
+output.rawParameterInfo.errorParameter.values    = residual_error_values;
+output.rawParameterInfo.errorParameter.stderr    = residual_error_stderr;
+output.rawParameterInfo.errorParameter.rse       = residual_error_rse;
+output.rawParameterInfo.errorParameter.estimated = residual_error_estimated;
+
+%% Handle different MONOLIX versions (currently only 4.3.2 and 4.3.3)
+% 4.3.2 is default ... only need to handle 4.3.3
+
+% Check version of MONOLIX
+MLXversion = getMONOLIXversionIQM();
+
+% Error if version can not be determined
+if strcmpi(MLXversion,'unknown'),
+    error(sprintf('MONOLIX version can not be determined. Please ensure version number appears in installation path.\nCurrently supported versions are 4.3.2 and 4.3.3.'));
+end
+
+% Handle 4.3.3 differences
+if strcmpi(MLXversion,'433'),
+    % Main differences to 4.3.2:
+    % Categorical covariate parameter names in 4.3.3 have no additional
+    % underscore. Example:
+    %  4.3.2: beta_PLbase_IND_3 :     5.47          0.52            10   < 1e-010 
+    %  4.3.3: beta_PLbase_IND3  :     5.47          0.52            10   < 1e-010
+
+    % Two things need to be done:
+    % 1) The output.parameters.names field needs to be assessed for cat
+    % covs and an underscore needs to be added between catname and
+    % catcategory
+    % 2) The output.rawParameterInfo.covariate.names field needs to be assessed
+    % and the same thing needs to be done (underscore between catname and
+    % catcategory)
+    
+
+    
+    % 1) The output.parameters.names field needs to be assessed for cat
+    % covs and an underscore needs to be added between catname and
+    % catcategory
+    CATNAMES = MLX_project_header.CATNAMES;
+    names    = output.parameters.names;
+    for k=1:length(CATNAMES),
+        names = regexprep(names,sprintf('\\(%s([0-9]+)',CATNAMES{k}),sprintf('(%s_$1',CATNAMES{k}));
+    end
+    output.parameters.names = names;
+    
+    % 2) The output.rawParameterInfo.covariate.names field needs to be assessed
+    % and the same thing needs to be done (underscore between catname and
+    % catcategory)
+    CATNAMES = MLX_project_header.CATNAMES;
+    names    = output.rawParameterInfo.covariate.names;
+    for k=1:length(CATNAMES),
+        names = regexprep(names,sprintf('\\(%s([0-9]+)',CATNAMES{k}),sprintf('(%s_$1',CATNAMES{k}));
+    end
+    output.rawParameterInfo.covariate.names = names;
+end
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/01-MONOLIX/auxiliary/sampleMONOLIXpopulationParametersIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/01-MONOLIX/auxiliary/sampleMONOLIXpopulationParametersIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..8cdc03c5a9e637362687ba534ce4d8077aa05025
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/01-MONOLIX/auxiliary/sampleMONOLIXpopulationParametersIQM.m	
@@ -0,0 +1,425 @@
+function [ output ] = sampleMONOLIXpopulationParametersIQM( input, varargin )
+% This function uses the output of the parseMONOLIXresultsIQM function.
+% It samples once the distributions to obtain population parameters.
+% Then it splits these up into fixed effects, random effects, residual 
+% error models, covariates, IOV.
+%
+% Not everything is handled, but if things are found that can not be handled, 
+% then an error message is shown.
+%
+% Covariate information is parsed. 
+%   Continuous covariates:  no limitation
+%   Categorical covariates: parsed but at the moment identification problems when grouping is 
+%                           used with groups of more than one category (then the names of these 
+%                           categories are unclear). No issue in this function and handled in the
+%                           IQMsampleMONOLIXparam function by warning the user.
+%
+% [SYNTAX]
+% output = sampleMONOLIXpopulationParametersIQM( input )
+% output = sampleMONOLIXpopulationParametersIQM( input, FLAG_SAMPLE )
+% output = sampleMONOLIXpopulationParametersIQM( input, FLAG_SAMPLE, FLAG_SILENT )
+%
+% [INPUT]
+% input        : output structure from the parseMONOLIXresultsIQM function
+% FLAG_SAMPLE  : 1=sample population parameters from uncertainty distribution (default case)
+%                0=use estimated population parameters and do not consider uncertainty
+% FLAG_SILENT  : 1=do not output any warnings and messages, only errors 
+%                0=do output any warnings and messages, only errors (default)
+%
+% [OUTPUT]
+% Structure with the following fields:
+%
+% output.path                               : the path provided by the user from which Monolix results have been read
+%
+% output.fixedEffects.names                 : cell-array with names of fixed effect parameters
+% output.fixedEffects.values                : vector with sampled values of fixed effect parameters
+%
+% output.randomEffects.names                : cell-array with names of random effect parameters (same as fixed effect param names)
+% output.randomEffects.values               : vector with sampled values of random effect parameters
+% output.randomEffects.covariancematrix     : covariance matrix of random effects
+% output.randomEffects.transformation       : formula of the transformation
+% output.randomEffects.inv_transformation   : inverse of the formula
+% output.randomEffects.correlationmatrix    : correlation matrix of random effects
+% 
+% output.residualErrorModel.alias           : for each output/residual error model one substructure in the order of the outpt numbering. "alias" is a string with the name of the error model
+% output.residualErrorModel.ab              : vector with 2 elements for the a,b parameters. If undefined then NaN
+% output.residualErrorModel.formula         : formula of the transformation
+% 
+% output.covariates.continuous.parameter               : one substructure per parameter. "parameter" is a string with the parameter name
+% output.covariates.continuous.covariates              : cell-array with the covariates on this parameter
+% output.covariates.continuous.information             : cell-array with covariate transformation in formation (categorical:reference group, continuous:transformation formula and centering value)
+% output.covariates.continuous.information.categories  : vector with numerical categories (only numerical ones are accepted)
+% output.covariates.continuous.information.values      : vector with estimated covariate coefficients for each category (same order). Reference group has 0 value
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle variable input arguments
+FLAG_SAMPLE = 1;
+FLAG_SILENT = 0;
+if nargin == 2,
+    FLAG_SAMPLE = varargin{1};
+elseif nargin == 3,
+    FLAG_SAMPLE = varargin{1};
+    FLAG_SILENT = varargin{2};
+end    
+
+% Define output structure
+output = [];
+output.type                                 = 'MONOLIX';
+output.path                                 = '';
+
+output.fixedEffects.names                   = {};
+output.fixedEffects.values                  = [];   % Vector
+
+output.randomEffects.names                  = {};
+output.randomEffects.values                 = [];   % Vector
+output.randomEffects.covariancematrix       = [];   % Matrix 
+output.randomEffects.transformation          = {};   % cell-array defining the transformation (normal, lognormal, etc.)
+output.randomEffects.inv_transformation      = {};   % cell-array defining the inverse transformation
+
+output.residualErrorModel.alias             = '';   % One substructure per output alias=string
+output.residualErrorModel.ab                = [];   % Vector with 4 elements (a,b,c,d - parameters in error model)
+output.residualErrorModel.formula           = [];   % Error model formula
+
+output.covariates.continuous.parameter                 = [];   % One substructure per parameter
+output.covariates.continuous.covariates                = {};   % cell array with all covariates
+output.covariates.continuous.values                    = [];   % vector with corresponding values
+output.covariates.continuous.transformation            = {};   % cell-array with covariate transformation: formula and centering value
+
+output.covariates.categorical.parameter                = [];   % One substructure per parameter
+output.covariates.categorical.covariates               = {};   % cell array with all covariates
+output.covariates.categorical.information              = {};   % cell-array with covariate transformation: 
+                                     
+% Write the path of the folder with all the results
+output.path = input.path;
+
+% Sample ALL parameters from the distribution 
+names      = input.parameters.names;
+values     = input.parameters.values;
+covariance = input.parameters.covariancematrix;
+
+% Handle the sampling flag and sample if desired and possible from the
+% uncertainty distribution to obtain a new set of population
+% parameters
+if FLAG_SAMPLE,
+    if ~isempty(covariance),
+        covariance  = makePosSemiDefIQM(covariance);
+        samples     = mvnrndIQM(values,covariance);
+    else
+        if ~FLAG_SILENT,
+            disp('The FIM was not estimated => No sampling of population parameters from uncertainty distributions.');
+        end
+        samples = values;
+    end
+else
+    samples = values;
+    if ~FLAG_SILENT,
+        disp('No sampling of population parameters from uncertainty distributions.');
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle Random Effects 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Determine the random effects (names and values as std)
+% Both std deviation and variance estimates for random effects are
+% handled, defined by "omega(" or "omega2(".
+ixo = strmatchIQM('omega(',names);
+if ~isempty(ixo),
+    % if they are the standard errors we just stored the values
+    output.randomEffects.names = strrep(strrep(names(ixo),'omega(',''),')','');
+    output.randomEffects.values = samples(ixo);
+else
+    ixo = strmatchIQM('omega2(',names);
+    output.randomEffects.names = strrep(strrep(names(ixo),'omega2(',''),')','');
+    % convert variance to standard deviation
+    output.randomEffects.values = sqrt(samples(ixo));
+end
+    
+% Determine the correlation matrix for the random effects based on the "corr(" parameters
+correlationmatrix           = eye(length(output.randomEffects.names));
+ixc                         = strmatchIQM('corr(',names);
+recorrelationnames          = strrep(strrep(names(ixc),'corr(',''),')','');
+recorrelationvalues         = samples(ixc);
+if ~isempty(recorrelationnames)
+    for k=1:length(recorrelationnames),
+        % Find the two correlated things
+        terms = explodePCIQM(recorrelationnames{k},',');
+        ix1 = strmatchIQM(terms{1},output.randomEffects.names,'exact');
+        ix2 = strmatchIQM(terms{2},output.randomEffects.names,'exact');
+        % Update matrix
+        correlationmatrix(ix1,ix2) = recorrelationvalues(k);
+        correlationmatrix(ix2,ix1) = recorrelationvalues(k);
+    end
+end
+output.randomEffects.correlationmatrix = correlationmatrix;
+
+% Determine the covariance matrix based on random effect std and
+% correlation matrix
+output.randomEffects.covariancematrix = correlationmatrix.*(output.randomEffects.values'*output.randomEffects.values);
+% Make sampled covariance matrix pos semidefinite
+output.randomEffects.covariancematrix = makePosSemiDefIQM(output.randomEffects.covariancematrix);
+
+% Add the distribution of the random effects to the output
+output.randomEffects.transformation = input.trans_randeffects;
+output.randomEffects.inv_transformation = input.inv_trans_randeffects;
+
+% Remove omega(... and corr(... from samples and names
+ix          = [ixo' ixc'];
+samples(ix) = [];
+names(ix)   = [];
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle Fixed Effects 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% In the input structure it has been made sure that all names that appear as fixed effects also appear in random effects
+output.fixedEffects.names = output.randomEffects.names;
+
+% Get the values or the fixed effects
+ixfe = [];
+for k=1:length(output.fixedEffects.names),
+    ix = strmatchIQM(output.fixedEffects.names{k},names,'exact');
+    output.fixedEffects.values(k) = samples(ix);
+    ixfe = [ixfe ix];
+end
+
+% Remove fixed effects from samples and names
+samples(ixfe)   = [];
+names(ixfe)     = [];
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle Residual Error
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+removeIX = [];
+for k=1:length(input.residualerrormodels),
+    output.residualErrorModel(k).alias = input.residualerrormodels{k};
+    output.residualErrorModel(k).ab = NaN(1,2);
+    ix = strmatchIQM(['error_ADD' num2str(k)],names,'exact'); if ~isempty(ix), output.residualErrorModel(k).ab(1) = samples(ix); removeIX = [removeIX ix]; end
+    ix = strmatchIQM(['error_PROP' num2str(k)],names,'exact'); if ~isempty(ix), output.residualErrorModel(k).ab(2) = samples(ix); removeIX = [removeIX ix]; end
+end
+
+% Save the formula of the function of the residual error.
+for k = 1:length(input.residualerrormodels)
+    ix = strmatchIQM(output.residualErrorModel(k).alias,'const','exact'); if ~isempty(ix), output.residualErrorModel(k).formula = 'ab(1).*ones(size(f))'; end
+    ix = strmatchIQM(output.residualErrorModel(k).alias,'prop','exact'); if ~isempty(ix), output.residualErrorModel(k).formula = 'ab(2).*f'; end
+    ix = strmatchIQM(output.residualErrorModel(k).alias,'comb1','exact'); if ~isempty(ix), output.residualErrorModel(k).formula = 'ab(1) + ab(2).*f'; end
+end
+
+% Remove the handled elements
+samples(removeIX) = [];
+names(removeIX) = [];
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Prepare Covariates
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Get covariates names and values
+ix              = strmatchIQM('beta_',names);
+covariates      = strrep(strrep(strrep(names(ix),'beta_',''),')',''),'(',',');
+covariatevalues = samples(ix);
+
+% Remove the handled elements
+samples(ix)     = [];
+names(ix)       = [];
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle continuous covariates
+% 
+% Creating output structure as follows:
+%
+% output.covariates.continuous(1)
+%          parameter: 'CLp'
+%         covariates: {'WT0'  'PNA0'}
+%             values: [2.3074 0.44059]
+%            formula: {'log(cov/2.8)'  'log(cov/6)'}    
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+COVparameters = {};
+COVcovNames   = {};
+COVvalues     = [];
+COVformulas   = {};
+
+ix_remove = [];
+for k=1:length(covariates),
+    % Get parameter and covariate
+    terms   = explodePCIQM(covariates{k});
+    name    = terms{1};
+    cov     = terms{2};
+    % Check if continuous
+    ix = strmatchIQM(cov,input.covariates.covNames,'exact');
+    if ~isempty(ix),
+        ix_remove(end+1) = k;
+        formula = input.covariates.covTransformation{ix};
+        COVparameters{end+1} = name;
+        COVcovNames{end+1}   = cov;
+        COVvalues(end+1)     = covariatevalues(k);
+        COVformulas{end+1}   = formula;
+    end
+end
+
+% Create desired output structure for continuous covariates
+covariateSTRUCT.continuous = [];
+covariateSTRUCT.continuous.parameter = [];
+covariateSTRUCT.continuous.covariates = [];
+covariateSTRUCT.continuous.values = [];
+covariateSTRUCT.continuous.formula = [];
+for k=1:length(COVparameters),
+    if k==1,
+        covariateSTRUCT.continuous.parameter        = COVparameters{k};
+        covariateSTRUCT.continuous.covariates{1}    = COVcovNames{k};
+        covariateSTRUCT.continuous.values(1)        = COVvalues(k);
+        covariateSTRUCT.continuous.formula{1}       = COVformulas{k};
+    else
+        ix = strmatchIQM(COVparameters{k},{covariateSTRUCT.continuous.parameter},'exact');
+        if isempty(ix),
+            ix = length(covariateSTRUCT.continuous)+1;
+        end
+        covariateSTRUCT.continuous(ix).parameter            = COVparameters{k};
+        covariateSTRUCT.continuous(ix).covariates{end+1}    = COVcovNames{k};
+        covariateSTRUCT.continuous(ix).values(end+1)        = COVvalues(k);
+        covariateSTRUCT.continuous(ix).formula{end+1}       = COVformulas{k};
+    end
+end
+
+output.covariates.continuous = covariateSTRUCT.continuous;
+
+% Remove handled continuous covariates
+covariates(ix_remove) = [];
+covariatevalues(ix_remove) = [];
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle categorical covariates
+% 
+% Creating output structure as follows:
+%
+% output.covariates.categorical(1)
+%          parameter: 'Vp'
+%         covariates: {'GA28'  'SEX'}
+%        information: structure with ionformation
+%
+%      information(1):
+%           categories: [0 1]
+%               values: [0 -0.64859]
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Parse categorical covariate information
+COVparameters   = {};
+COVcovNames     = {};
+COVcategory     = [];
+COVvalues       = [];
+
+ix_remove = [];
+for k=1:length(covariates),
+    % Get parameter and covariate
+    terms       = explodePCIQM(covariates{k});
+    name        = terms{1};
+    cov         = terms{2};
+    terms       = explodePCIQM(cov,'_');
+    if length(terms)==2,
+        cov         = terms{1};
+        category    = eval(terms{2});
+        % Check if categorical
+        ix = strmatchIQM(cov,input.covariates.catNames,'exact');
+        if ~isempty(ix),
+            ix_remove(end+1) = k;
+            COVparameters{end+1} = name;
+            COVcovNames{end+1}   = cov;
+            COVvalues(end+1)     = covariatevalues(k);
+            COVcategory(end+1)   = category;
+        end
+    end
+end
+
+covariates(ix_remove) = [];
+covariatevalues(ix_remove) = [];
+
+% Construct a structure with combined categories
+COV2parameters   = {};
+COV2covNames     = {};
+COV2informationCategories  = {};
+COV2informationValues  = {};
+
+for k=1:length(COVparameters),
+    if k==1,
+        COV2parameters{k}               = COVparameters{k};
+        COV2covNames{k}                 = COVcovNames{k};
+        % Determine reference value
+        reference                       = input.covariates.catReference(strmatchIQM(COVcovNames{k},input.covariates.catNames,'exact'));
+        COV2informationCategories{k}    = [reference COVcategory(k)];
+        COV2informationValues{k}        = [0 COVvalues(k)];
+    elseif isempty(strmatchIQM(COVparameters{k},COV2parameters,'exact')),
+        COV2parameters{end+1}               = COVparameters{k};
+        COV2covNames{end+1}                 = COVcovNames{k};
+        % Determine reference value
+        reference                       = input.covariates.catReference(strmatchIQM(COVcovNames{k},input.covariates.catNames,'exact'));
+        COV2informationCategories{end+1}    = [reference COVcategory(k)];
+        COV2informationValues{end+1}        = [0 COVvalues(k)];
+    else
+        % No all parameter names are present ... need to check if covariate
+        % name already present in this parameter
+        name = COVparameters{k};
+        cov = COVcovNames{k};
+        ix_param = strmatchIQM(name,COV2parameters,'exact');
+        ix_cov   = strmatchIQM(cov,COV2covNames,'exact');
+        ix_add = intersect(ix_param,ix_cov);
+        if isempty(ix_add),
+            % add as new covariate
+            COV2parameters{k}               = COVparameters{k};
+            COV2covNames{k}                 = COVcovNames{k};
+            % Determine reference value
+            reference                       = input.covariates.catReference(strmatchIQM(COVcovNames{k},input.covariates.catNames,'exact'));
+            COV2informationCategories{k}    = [reference COVcategory(k)];
+            COV2informationValues{k}        = [0 COVvalues(k)];
+        else
+            % Add new category
+            COV2informationCategories{ix_add}(end+1) = COVcategory(k);
+            COV2informationValues{ix_add}(end+1)     = COVvalues(k);
+        end
+    end
+end
+
+% Create desired output structure for categorical covariates
+covariateSTRUCT.categorical = [];
+covariateSTRUCT.categorical.parameter = [];
+covariateSTRUCT.categorical.covariates = [];
+covariateSTRUCT.categorical.information = [];
+covariateSTRUCT.categorical.information.categories = [];
+covariateSTRUCT.categorical.information.values = [];
+for k=1:length(COV2parameters),
+    if k==1,
+        covariateSTRUCT.categorical.parameter                   = COV2parameters{k};
+        covariateSTRUCT.categorical.covariates{1}               = COV2covNames{k};
+        covariateSTRUCT.categorical.information(1).categories   = COV2informationCategories{k};
+        covariateSTRUCT.categorical.information(1).values       = COV2informationValues{k};
+    else
+        ix = strmatchIQM(COV2parameters{k},{covariateSTRUCT.categorical.parameter},'exact');
+        if isempty(ix),
+            ix = length(covariateSTRUCT.categorical)+1;
+        end
+        covariateSTRUCT.categorical(ix).parameter                       = COV2parameters{k};
+        covariateSTRUCT.categorical(ix).covariates{end+1}               = COV2covNames{k};
+        covariateSTRUCT.categorical(ix).information(end+1).categories   = COV2informationCategories{k};
+        covariateSTRUCT.categorical(ix).information(end).values         = COV2informationValues{k};
+    end
+end
+
+output.covariates.categorical = covariateSTRUCT.categorical;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check if everything was handled
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(names),
+    if ~FLAG_SILENT,
+        disp('Warning: The Monolix output contained information that are currently not handled.');
+        disp('This could be IOV or other things. Please have a look at the following unhandled names:');
+        for k=1:length(names),
+            fprintf('\t%s\n',names{k})
+        end
+    end
+end
+
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/01-MONOLIX/isMONOLIXprojectIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/01-MONOLIX/isMONOLIXprojectIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..e9c57e4d4ece944274185314e3bca4ea63d9e4b5
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/01-MONOLIX/isMONOLIXprojectIQM.m	
@@ -0,0 +1,24 @@
+function [ output ] = isMONOLIXprojectIQM( projectPath )
+% Checks if given project path is a Monolix project. This is checked by 
+% requiring a project.mlxtran file in this folder.
+% 
+% [SYNTAX]
+% [output] = isMONOLIXprojectIQM( projectPath )
+%
+% [INPUT]
+% projectPath:  PAth to check if Monolix project
+%
+% [OUTPUT]
+% output = 0: No MONOLIX project
+% output = 1: MONOLIX project
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+testfile = fullfile(projectPath,'project.mlxtran');
+if ~exist(testfile),
+    output = 0;
+else
+    output = 1;
+end
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/01-MONOLIX/templates/template_project_graphics.xmlx b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/01-MONOLIX/templates/template_project_graphics.xmlx
new file mode 100644
index 0000000000000000000000000000000000000000..c6bc74f358d13e8605f4d55a6efc6885f5167940
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/01-MONOLIX/templates/template_project_graphics.xmlx	
@@ -0,0 +1,75 @@
+<monolix>
+	<graphics>
+		<version value="420"/>
+		<graphicList>
+			<graphic name="residuals" out="1">
+				<K value="10"/>
+				<Kmax value="30"/>
+				<Kmin value="5"/>
+				<alpha value="0.0005"/>
+				<beta value="0.4"/>
+				<beta_reg value="0.75"/>
+				<continous value="1"/>
+				<gamma value="0"/>
+				<iop_blqres value="2"/>
+				<iop_censcalc value="1"/>
+				<iop_colorcens value="1"/>
+				<iop_colorobs value="1"/>
+				<iop_displaybins value="0"/>
+				<iop_displaycens value="1"/>
+				<iop_displayciout value="0"/>
+				<iop_displayciprct value="0"/>
+				<iop_displayemdens value="1"/>
+				<iop_displayemprct value="0"/>
+				<iop_displayhisto value="0"/>
+				<iop_displayobs value="1"/>
+				<iop_displayoutprct value="0"/>
+				<iop_displayspline value="0"/>
+				<iop_displaythdens value="1"/>
+				<iop_displaythprct value="0"/>
+				<iop_gfind value="1"/>
+				<iop_gfobs value="1"/>
+				<iop_gs value="1"/>
+				<iop_legend value="0"/>
+				<level value="90"/>
+				<lmin value="10"/>
+				<nmax value="200"/>
+				<obin value="3"/>
+				<prctile value="3" vector="10,50,90"/>
+				<selectK value="1"/>
+				<select_graphics value="4" vector="1,1,1,0"/>
+				<select_residual value="6" vector="0,1,0,1,1,0"/>
+			</graphic>
+			<graphic name="cvSAEM" out="0">
+				<nbParam value="100"/>
+				<firstIndividual value="1"/>
+			</graphic>
+		</graphicList>
+		<graphicsToPrint>
+			<projectSummary value="0"/>
+			<spaghetti value="0"/>
+			<individualFits value="0"/>
+			<predVsObs value="0"/>
+			<residuals value="0"/>
+			<covariates value="0"/>
+			<VPC value="0"/>
+			<NPC value="0"/>
+			<BLQ value="0"/>
+			<categorizedData value="0"/>
+			<vpcPredDist value="0"/>
+			<distPsi value="0"/>
+			<boxplot value="0"/>
+			<jointDist value="0"/>
+			<kaplanMeier value="0"/>
+			<transProba value="0"/>
+			<bayesian value="0"/>
+			<individualContribution value="0"/>
+			<cvSAEM value="1"/>
+			<obsTimes value="1"/>
+			<intTimes value="0"/>
+			<fullTimes value="0"/>
+			<indContTable value="0"/>
+			<covTable value="0"/>
+		</graphicsToPrint>
+	</graphics>
+</monolix>
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/IQMcreateNONMEMproject.m b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/IQMcreateNONMEMproject.m
new file mode 100644
index 0000000000000000000000000000000000000000..726b5d28578a7a8446a87f44dfc6312a720b60cd
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/IQMcreateNONMEMproject.m	
@@ -0,0 +1,1951 @@
+function IQMcreateNONMEMproject(model,dosing,data,projectPath,varargin)
+% Creates a NONMEM project from an IQMmodel and an IQMdosing scheme. 
+%
+% Handling the BLOQ Methods M3 and M4:  
+%   M3 or M4 method of BLOQ handling can be used. This requires a CENS
+%   column in the dataset (CENS=0 for >=LLOQ values, CENS=1 for <LLOQ
+%   values and DV=LLOQ in case of CENS=1 (just as in MONOLIX). Since M3 and
+%   M4 requires the use of "LAPLACIAN NUMERICAL SLOW" in the $EST
+%   statements with INTERACTION, the code for M3 or M4 is only added to the
+%   model if the CENS column has non-zero entries - meaning that the model
+%   in this case needs to be generated for each dataset to be run. M3 is
+%   the default method. M4 can be selected in the options by setting
+%   options.algorithm.M4 = 1.
+%
+% ASSUMPTIONS:
+% ============
+% - MU Referencing always used. 
+% - Continuous covariates are always log-transformed, independent
+%   of the distribution of the parameter on which they are added. Centering
+%   by the median (or user defined values) for the covariates. 
+% - Always untransformed categorical covariates. Several categories per
+%   covariate possible but all need to be numeric and integers.
+% - IIV correlation parameters always 0.1 at the initial guess.
+% - Selection of PRED,RES,WRES outputs dependent on the method that is used
+%   for estimation (in the tables renamed to: XPRED, XRES, XWRES):
+%       - PREDI RESI WRESI if FO
+%       - CPREDI, CRESI, CWRESI if FOCE
+%       - EPRED, ERES, EWRES if SAEM
+% - Default values for add and prop errors: 1 and 0.3
+% - Dataset can contain CMT or (ADM+YTYPE) columns. The output on the
+%   screen of this function will guide the user as to the needed values in
+%   these columns.
+%       - ADM+YTYPE but not CMT 
+%           - YTYPE defines number of output
+%           - ADM used as CMT column (states reordered to accomodate)
+%
+%       - ADM+CMT but not YTYPE
+%           - YTYPE is inferred based on CMT for observation records (in $ERROR)
+%             But this means that CMT needs to follow the OUTPUTn numbering! 
+%           - CMT will be used as defined for selecting the dosing compartments
+%           - ADM is used to inform potential switchings for NONMEM parameters in the PK section
+%
+% [SYNTAX]
+% [] = IQMcreateNONMEMproject(model,dosing,data,projectPath)
+% [] = IQMcreateNONMEMproject(model,dosing,data,projectPath,options)
+% [] = IQMcreateNONMEMproject(model,dosing,data,projectPath,options,parameterOrder)
+%
+% [INPUT]
+% model:            IQMmodel - with additional annotation:
+%                       Variables OUTPUT1-N where 1-N matches the YTYPE definitions in the dataset.
+%                       <estimate> as comment on parameters to be estimated.
+%                       <regression> as comment on parameters to be obtained from dataset.
+% dosing:           IQMdosing object (or empty [] if no INPUT defined in model)
+% data:             Structure with following fields:
+%       data.dataRelPathFromProject:    path to data file - relative to the
+%                                       projectPath folder.
+%       data.dataFileName:              data file filename
+%       data.dataHeaderIdent:           String with datafile header identifiers (example: 'ID,TIME,Y,MDV,EVID,AMT,TINF,ADM,YTYPE,COV,COV,CAT') 
+% projectPath:      String with the path/foldername to which the project files are to be written (example: 'FIT_01' or 'Models/FITS/FIT_01') 
+% parameterOrder:   Used to reorder parameters (used by the popPK workflow, do not use otherwise)
+%
+% options:      Structure with following fields (all optional with default settings):
+%       options.POPestimate:            Vector with 0 and 1 entries. 1 if pop parameter is estimated, 0 if not. Default or []: => all are estimated
+%       options.POPvalues0:             Vector with pop parameter initial values. Default or []: => values stored in model and dosing scheme
+%       options.IIVdistribution:        Cell-array with information about parameter distribution. L (lognormal), N (normal), G (logit)
+%                                       Example: {'L' 'L' 'L' 'L' 'N' 'L' 'L' 'L'}. Default or {}: => use lognormal for all
+%       options.IIVestimate:            Vector with 0 and 1 entries. 1 if random effect is estimated, 0 if not. Default or []: => all are estimated
+%                                       0: IIV not estimated (IIVvalues0 not used) 
+%                                       1: IIV estimated (IIVvalues0 as starting guesses)
+%                                       2: IIV not estimated but fixed on IIVvalues0 value
+%       options.IIVvalues0:             Vector with random effect parameter
+%                                       initial values. Default or []: => all set to 0.5
+%                                       If IIV not estimated then defined initial guess not used but replaced by 0
+%       options.errorModels:            String with definition of residual error models, comma separated for each output.
+%                                       Possible values: const,prop,comb1. Example: 'comb1,prop', Default or '': => const for all outputs
+%       options.errorParam0:            Vector allowing to pass initial guesses for error model parameters. Same order as error models. 
+%                                       'const': a, 'prop': b, 'comb1': a,b
+%       options.covarianceModel:        Definition of covariance model. String with cell-array text inside, grouping the parameters to consider having 
+%                                       correlated random effects. Example: '{CL,Vc},{Q,Vp,KM}'. Default: 'diagonal'
+%       options.covariateModel:         Definition of covariate model. Cell-array. Each element is a sub-cell-array. First element in sub-cell-array is the 
+%                                       parameter to which to add the covariate, all following elements define the covariates as named in the dataset.
+%                                       Example: '{CL,BMI0}, {Fsubcut,WT0}, {Vc,SEX,BMI0}'. Default: '' => no covariates
+%                                       By default (and so far not changeable, the continuous covariates are all weighted by their median, determined from the dataset)
+%                                       >>>Covariates can be added to all parameters for which not both IIVestimate and POPestimate are 0.
+%       options.covariateModelValues:   Definition of covariate coefficients for the selected covariate model. 
+%                                       Syntax is similar to options.covariateModel. It is a cell-array containing vectors instead of cell-arrays.
+%                                       Each vector contains values for the covariate coefficients, matching the covariateModel definition order.
+%                                       Example: if options.covariateModel = '{CL,BMI0,AGE0}, {Fsubcut,WT0}, {Vc,SEX,BMI0}'
+%                                       Then: options.covariateModelValues = {[0.5,0], [0.75], [0,0]}
+%                                       Defines the initial guesses for the covariate coefficients for BMI0 on CL to be 0.5, WT0 on Fsubcut to be 0.75, and the other ones are 0.
+%                                       If not defined, all covariate coefficients start from 0 in the estimation.
+%       options.COVestimate:            Same structure as options.covariateModelValues but with entries 0 or 1. 0 means not estimated, 1 means estimated.
+%                                       By default all are estimated.
+%                                       In the example above options.COVestimate = {[0,1], [1], [1,0]}   will estimate AE0 on CL, WT0 on Fsubcut, SEX on Vc.
+%                                       The other coefficients will be kept fixed.
+%       options.COVcentering.covs:      Cell-array with covariates that should be centered around a custom value. 
+%       options.COVcentering.values:    Vector with centering values. 
+%       options.Ntests:                 Doing robustness analysis - number of models to generate with different initial guesses (randomly generated based on POPvalues0)
+%                                       Default: 1 (no robustness analysis, using initial guesses as provided)
+%       options.std_noise_setting:      Standard deviation to use to add noise to the initial parameter guesses (default=0.5 (50%CV))
+%                                       Normal:         Parameter_guess + std_noise_setting*Parameter_guess*randomNumbers(0-1)
+%                                       Lognormal:      Parameter_guess * exp(std_noise_setting*randomNumbers(0-1))
+%                                       Logitnormal:    Similar and between 0-1
+%       options.keepProjectFolder:      =0: remover already existing folder, =1: keep it
+%
+% ALGORITHM SETTINGS:
+% ===================
+%
+%       options.algorithm.METHOD:       'FO','FOCE','FOCEI','SAEM' (default: SAEM)
+%       options.algorithm.MAXEVAL:      Default: 9999
+%       options.algorithm.SIGDIGITS:    Default: 3
+%       options.algorithm.PRINT:        Default: 1
+%
+%       options.algorithm.M4:           Default: 0 (default: M3 method if dataset formated with CENS column and non-zero entries in it.)
+%
+%       options.algorithm.ITS:                  Allow to run an ITS method as first method befor all other methods (METHOD)
+%                                               ITS = 0 or 1 (default: 0 if not FO) - ITS=1 only accepted if not FO!
+%       options.algorithm.ITS_ITERATIONS:       Number of iterations for ITS (default: 10)
+%
+%       options.algorithm.IMPORTANCESAMPLING:   Allow determination of the OFV - only accepted after SAEM
+%                                               Default: 0, If 1 then do the importance sampling
+%       options.algorithm.IMP_ITERATIONS:       Number of iterations for importance sampling (default: 5)
+% 
+%       options.algorithm.SEED:         Seed setting. Defualt: 123456
+%       options.algorithm.K1:           First iterations. Default: 500
+%       options.algorithm.K2:           Final iterations. Default: 200
+%       options.algorithm.NRCHAINS:     Number of parallel chains. Default: 1
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Define Default Properties (Never changing)
+projectName            = 'project';
+resultsFolder          = 'RESULTS';
+
+% Check input
+if ischar(model),
+    model = IQMmodel(model);
+end
+if ischar(dosing),
+    dosing = IQMdosing(dosing);
+end
+if ~isIQMmodel(model),
+    error('First input argument is not an IQMmodel.');
+end
+if ~isIQMdosing(dosing) && ~isempty(dosing),
+    error('Second input argument is not an IQMdosing scheme.');
+end
+try
+    dataRelPathFromProject = data.dataRelPathFromProject;
+    dataFileName           = data.dataFileName;
+    dataHeaderIdent        = data.dataHeaderIdent;
+catch
+    error('data input argument not defined correctly.');
+end
+
+try
+    dataRelPathFromProject = data.dataRelPathFromProject;
+    dataFileName           = data.dataFileName;
+    dataHeaderIdent        = data.dataHeaderIdent;
+catch
+    error('data input argument not defined correctly.');
+end
+
+% Need to change the data header
+% TIME => TIME2 (Since it can contain negative times)
+% TIMEPOS => TIME (The normal NONMEM time ... since it is only positive)
+dataHeaderIdent         = regexprep(dataHeaderIdent,'\<TIME\>','TIME2');
+dataHeaderIdent         = regexprep(dataHeaderIdent,'\<TIMEPOS\>','TIME');
+
+% Handle variable input arguments
+options = [];
+parameterOrder = {};
+if nargin==5,
+    options = varargin{1};
+    parameterOrder = {};
+elseif nargin==6,
+    options = varargin{1};
+    parameterOrder = varargin{2};
+end
+
+% Handle optional arguments
+try POPestimate                     = options.POPestimate;                      catch, POPestimate = [];                             end
+try POPvalues0                      = options.POPvalues0;                       catch, POPvalues0 = [];                              end
+try IIVdistribution                 = options.IIVdistribution;                  catch, IIVdistribution = {};                         end
+try IIVestimate                     = options.IIVestimate;                      catch, IIVestimate = [];                             end
+try IIVvalues0                      = options.IIVvalues0;                       catch, IIVvalues0 = [];                              end
+try errorModels                     = options.errorModels;                      catch, errorModels = '';                             end
+try errorParam0                     = options.errorParam0;                      catch, errorParam0 = [];                             end
+try covarianceModel                 = options.covarianceModel;                  catch, covarianceModel = 'diagonal';                 end
+try covariateModel                  = options.covariateModel;                   catch, covariateModel = '';                          end
+try covariateModelValues            = options.covariateModelValues;             catch, covariateModelValues = {};                    end
+try COVestimate                     = options.COVestimate;                      catch, COVestimate = {};                             end
+
+try COVcentering_covs               = options.COVcentering.covs;                catch, COVcentering_covs = {};                       end
+try COVcentering_values             = options.COVcentering.values;              catch, COVcentering_values = [];                     end
+
+try METHOD                          = options.algorithm.METHOD;                 catch, METHOD = 'SAEM';                              end
+try MAXEVAL                         = options.algorithm.MAXEVAL;                catch, MAXEVAL = 9999;                               end
+try SIGDIGITS                       = options.algorithm.SIGDIGITS;              catch, SIGDIGITS = 3;                                end
+try PRINT                           = options.algorithm.PRINT;                  catch, PRINT = 1;                                    end
+try M4                              = options.algorithm.M4;                     catch, M4 = 0;                                       end
+try SEED                            = options.algorithm.SEED;                   catch, SEED = 123456;                                end
+try K1                              = options.algorithm.K1;                     catch, K1 = 500;                                     end
+try K2                              = options.algorithm.K2;                     catch, K2 = 200;                                     end
+try NRCHAINS                        = options.algorithm.NRCHAINS;               catch, NRCHAINS = 1;                                 end
+try IMPORTANCESAMPLING              = options.algorithm.IMPORTANCESAMPLING;     catch, IMPORTANCESAMPLING = 0;                       end
+try ITS                             = options.algorithm.ITS;                    catch, ITS = 0;                                      end
+try ITS_ITERATIONS                  = options.algorithm.ITS_ITERATIONS;         catch, ITS_ITERATIONS = 10;                          end
+try IMP_ITERATIONS                  = options.algorithm.IMP_ITERATIONS;         catch, IMP_ITERATIONS = 5;                           end
+
+try SILENT                          = options.SILENT;                           catch, SILENT = 0;                                   end
+try keepProjectFolder               = options.keepProjectFolder;                catch, keepProjectFolder = 0;                        end   
+
+try Ntests                          = options.Ntests;                           catch, Ntests = 1;                                   end
+try std_noise_setting               = options.std_noise_setting;                catch, std_noise_setting = 0.5; options.std_noise_setting = 0.5;    end
+
+% Allow bioavailability term in special cases (only for popPK workflow)
+try FLAG_NONMEM__RATE_BIOAVAILABILITY_ISSUE__OK = options.FLAG_NONMEM__RATE_BIOAVAILABILITY_ISSUE__OK; catch, FLAG_NONMEM__RATE_BIOAVAILABILITY_ISSUE__OK = 0; end
+
+% Again - and final special case for good old NONMEM software
+% FLAG_IV_POPPK = NaN: not called from popPK workflow
+% FLAG_IV_POPPK=0 or 1: called from popPK workflow ... need to handle dosing section differently.
+% absorptionModel_POPPK: passed from popPK workflow ... need to handle dosing section differently.
+try FLAG_IV_POPPK                   = options.FLAG_IV_POPPK;                    catch, FLAG_IV_POPPK = NaN;                          end
+try absorptionModel_POPPK           = options.absorptionModel_POPPK;            catch, absorptionModel_POPPK = NaN;                  end
+
+% Handle cell requirements
+if ~iscell(COVcentering_covs),
+    COVcentering_covs = {COVcentering_covs};
+end
+
+options.covariateModel = covariateModel;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle first the case with robustness analysis
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if Ntests>1,
+    % Robustness analysis desired
+    % Check if POPvalues0 and POPestimate defined
+    if isempty(POPestimate) || isempty(POPvalues0),
+        error('When doing robustness analysis, please define options.POPvalues0 and options.POPestimate!');
+    end
+    
+    % Define IIVdistribution if still empty (default: all 'L')
+    if isempty(IIVdistribution),
+        for k=1:length(POPvalues0),
+            IIVdistribution{k} = 'L';
+        end
+    end
+    
+    % Sample Ntests new POPvalues0 for the ones that are estimated using
+    % std_noise_setting as standard deviation
+    
+    % Allocating variable
+    POPvalues0_sampled                          = POPvalues0(ones(1,Ntests),:);
+    
+    % Sampling normally distributed (IIV) parameters - which are also estimated on a population level
+    ix_normal_sampled                           = find(strcmp(IIVdistribution,'N').*POPestimate);
+    POPvalues0_sampled(:,ix_normal_sampled)     = POPvalues0(ones(1,Ntests),ix_normal_sampled) + std_noise_setting*POPvalues0(ones(1,Ntests),ix_normal_sampled).*randn(Ntests,length(ix_normal_sampled));
+
+    % Sampling log normally distributed (IIV) parameters - which are also estimated on a population level
+    ix_lognormal_sampled                        = find(strcmp(IIVdistribution,'L').*POPestimate);
+    MU                                          = log(POPvalues0(ones(1,Ntests),ix_lognormal_sampled));
+    XXX                                         = MU + std_noise_setting.*randn(Ntests,length(ix_lognormal_sampled));
+    POPvalues0_sampled(:,ix_lognormal_sampled)  = exp(XXX);
+    
+    % Sampling logit normally distributed parameters - which are also estimated on a population level
+    ix_logitnormal_sampled                          = find(strcmp(IIVdistribution,'G').*POPestimate);
+    MU                                              = log(POPvalues0(ones(1,Ntests),ix_logitnormal_sampled)./(1-POPvalues0(ones(1,Ntests),ix_logitnormal_sampled)));
+    XXX                                             = MU + std_noise_setting.*randn(Ntests,length(ix_logitnormal_sampled));
+    POPvalues0_sampled(:,ix_logitnormal_sampled)    = exp(XXX)./(1+exp(XXX));
+      
+    % Clean folder
+    try rmdir(projectPath,'s'); catch, end
+    
+    % Create Ntests different models in the projectPath/MODEL_01/02, ... folders
+    for k=1:Ntests,
+        % Setup new project creation stuff
+        modelK                          = model;
+        dosingK                         = dosing;
+        dataK                           = data;
+        dataK.dataRelPathFromProject    = ['../' data.dataRelPathFromProject];
+        projectPathK                    = [projectPath sprintf('/MODEL_%s',preFillCharIQM(k,length(num2str(Ntests)),'0'))];
+        optionsK                        = options;
+        optionsK                        = rmfield(optionsK,'Ntests');
+        optionsK                        = rmfield(optionsK,'std_noise_setting');
+        optionsK.POPvalues0             = POPvalues0_sampled(k,:);
+        IQMcreateNONMEMproject(modelK,dosingK,dataK,projectPathK,optionsK)
+    end
+    
+    % Ready, return
+    return
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle methods - some IQM Tools limitations
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if strcmp(METHOD,'FO') && ITS==1,
+    ITS = 0;
+end
+
+if ~strcmp(METHOD,'SAEM') && IMPORTANCESAMPLING==1,
+    warning('The importance sampling (IMPORTANCESAMPLING=1) is disabled for all but the SAEM method.');
+    IMPORTANCESAMPLING = 0;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Info text
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~SILENT,
+    disp(' ')
+    disp('==================================================================');
+    [xdummyx,projectFolderName] = fileparts(projectPath);
+    disp(sprintf('== Start of creation of %s/project.nmctl file',projectFolderName));
+    disp('==================================================================');
+    disp(' ')
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Create project and results folder
+% Change into project path
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+warning off
+oldpath = pwd;
+if ~keepProjectFolder,
+    try, rmdir(projectPath,'s'); catch, end
+end
+mkdir(projectPath); cd(projectPath)
+mkdir(resultsFolder);
+warning on
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Load data and get info about data
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try
+    dataModeling = IQMloadCSVdataset([data.dataRelPathFromProject '/' data.dataFileName]);
+catch
+    error('Trouble loading the data file. Please check if data.dataRelPathFromProject has been defined correctly.');
+end
+
+% Determine maximum number of data records per ID
+maxDATARECORDS_ID = -Inf;
+allID = unique(dataModeling.ID);
+for k=1:length(allID),
+    datak = dataModeling(dataModeling.ID==allID(k),:);
+    maxDATARECORDS_ID = max(maxDATARECORDS_ID,height(datak));
+end
+maxDATARECORDS = height(dataModeling);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Process data to get the dataheader and the median values for the covariates
+% and the categorical covariate names and their unique values.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[covariateMedianNames,covariateMedianValues,covariateCATNames,covariateCATValues,dataheader,dataCSV] = processDataAndGetMedianValuesIQM(oldpath,dataRelPathFromProject,dataFileName,dataHeaderIdent,SILENT,COVcentering_covs,COVcentering_values);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check data regarding the CMT/ADM/YTYPE thing
+% Allowed combinations:
+%
+%  - ADM+YTYPE but not CMT 
+%       - YTYPE defines number of output
+%       - ADM used as CMT column but rearrange states to fit the input/state numbers
+%
+%  - ADM+CMT but not YTYPE
+%       - YTYPE is inferred based on CMT for observation records (in $ERROR)
+%         But this means that CMT needs to follow the OUTPUTn numbering! 
+%       - CMT will be used as defined for selecting the dosing compartments
+%       - ADM is used to inform potential switchings for NONMEM parameters in the PK section
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+dataHeaderIdentAll = explodePCIQM(dataHeaderIdent);
+
+ix_CMT   = strmatchIQM('CMT',dataHeaderIdentAll,'exact');
+ix_ADM   = strmatchIQM('ADM',dataHeaderIdentAll,'exact');
+ix_YTYPE = strmatchIQM('YTYPE',dataHeaderIdentAll,'exact');
+
+if isempty(ix_CMT) && ~isempty(ix_ADM) && ~isempty(ix_YTYPE),
+    FLAG_CMT = 0;
+elseif ~isempty(ix_CMT) && ~isempty(ix_ADM) && isempty(ix_YTYPE),
+    FLAG_CMT = 1;
+else
+    error('Not allowed ADM/YTYPE/CMT combinations. Allowed: ADM+YTYPE or ADM+CMT (CMT defines dosing compartments and output numbers).');
+end
+
+if ~isempty(ix_CMT),
+    FLAG_CMT = 1;       % Defines that the CMT column is present
+    % Also means that ADM is present and can be accessed in the NONMEM code
+else
+    FLAG_CMT = 0;       % Defines that the CMT column is not present and that ADM and YTYPE are present instead
+    % Need to rename ADM to CMT in dataHeaderIdentAll, dataHeaderIdent, dataheader
+    dataHeaderIdent = regexprep(dataHeaderIdent,'\<ADM\>','CMT');
+    dataheader{strmatchIQM('ADM',dataheader,'exact')} = 'CMT';
+    dataHeaderIdentAll{strmatchIQM('ADM',dataHeaderIdentAll,'exact')} = 'CMT';
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check and update model syntax to be fit(ter) for NONMEM
+% Also check dosing object ...
+%
+% Also, based on the FLAG_CMT (if 0) flag do a re-ordering of the states to
+% match the ADM values to the state order. Check if this is possible - if
+% more than one INPUT on the same state then this is not possible and the
+% CMT version should be used! Print an error if this happens!
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+model = checkAndChangeModelSyntax4NONMEMconversionIQM(model,dosing,FLAG_CMT);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get model information
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+modelInfo           = mergemoddosstructsIQM(basicmodelparsingIQM(model),dosing);
+ms                  = struct(model);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% If needed, reorder parameters
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(parameterOrder),
+    ix_reorder = [];
+    for k=1:length(parameterOrder),
+        ix_reorder(k) = strmatchIQM(parameterOrder{k},{modelInfo.param_est.name},'exact');
+    end
+    modelInfo.param_est = modelInfo.param_est(ix_reorder);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Copy param_est information for reordering for covariance
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+param_est           = modelInfo.param_est;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check and update default input arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[ POPestimate,POPvalues0,IIVestimate,IIVvalues0,IIVdistribution,...
+    covariateModel,covariateModelValues, COVestimate ] = ...
+    checkHandleDefaultInputArguments4NONMEMconversionIQM( oldpath,param_est,...
+    POPestimate,POPvalues0,IIVestimate,IIVvalues0,IIVdistribution,...
+    covariateModel,covariateModelValues,COVestimate );
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Reorder estimation parameters to allow for block-diagonal covariance
+% matrix
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[param_est,POPestimate,POPvalues0,IIVestimate,IIVvalues0,IIVdistribution] = reorderParameters4NONMEMcovIQM(covarianceModel,param_est,POPestimate,POPvalues0,IIVestimate,IIVvalues0,IIVdistribution);
+
+if ~SILENT,
+    writeOutConversionNONMEMinformationIQM( param_est, IIVdistribution, IIVestimate )
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Do additional checks and write out information
+% Definition of param_est and IIVestimation + reordering needed to be ready
+% before running these checks.
+% Additionally, the names of the covariates are determined and the
+% errorModels default setting is handled here.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[covNames,catNames,errorModels,errorParam0] = additionalChecks4NONMEMconversionIQM( oldpath,param_est, dataHeaderIdent,dataheader,modelInfo,IIVestimate,errorModels,errorParam0,covarianceModel,covariateModel,SILENT);
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check for absorption0 presence
+% The user will be warned that RATE needs to be set to -2 for these doses
+% Additionally, the dataset might be updated if RATE column present and 0 order
+% doses present in dataset and RATE not set to -2. The updated dataset then is 
+% saved in the NLME project folder and the dataset name and relative path are 
+% changed accordingly.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ismember('ABSORPTION0',{modelInfo.inputs.type}),
+    % Warn the user about the presence of ABSORPTION0 doses:
+    if ~SILENT,
+        disp(' ');
+        fprintf('==========================================================\n');
+        fprintf('0 order administration present in model:\n');
+        fprintf('If no RATE column present an error will appear!\n');
+        fprintf('If RATE column present but values not -2 for entries of\n');
+        fprintf('0 order absorption doses, then a new dataset will be\n');
+        fprintf('generated with RATE=-2 and saved in the NLME project folder.\n');
+        fprintf('The generated model will then use this updated dataset!\n');      
+        fprintf('==========================================================\n');
+        disp(' ');
+    end
+    
+    % Check if RATE=-2 for the 0 order absorption dose events
+    FIX_dataset_0order_absorption = 0;
+    ix_inputs_0order = strmatchIQM('ABSORPTION0',{modelInfo.inputs.type});
+    for k=1:length(ix_inputs_0order),
+        input_number = eval(strrep(modelInfo.inputs(ix_inputs_0order(k)).name,'INPUT',''));
+        datak = dataModeling(dataModeling.ADM==input_number,:);
+        
+        % Only check further if datak is not empty (if empty then model might contain 0th order absorption input(s), 
+        % but data does not contain doses for this/these input(s)
+        fixRATEminus2 = 0;
+        if ~isempty(datak),
+            try
+                RATE = unique(datak.RATE);
+            catch
+                error('Please check if a RATE column is present and that the entries for 0 order absorption doses are set to -2');
+            end
+            if length(RATE)~=1,
+                fixRATEminus2 = 1;
+            else
+                if RATE~=-2,
+                    fixRATEminus2 = 1;
+                end
+            end
+        end
+        
+        % If RATE for 0 order absorption not defined adequately (-2) then fix that and save the fixed dataset in the NLME project folder.
+        if fixRATEminus2,
+            dataModeling.RATE(dataModeling.ADM==input_number) = -2;
+            FIX_dataset_0order_absorption = 1;
+        end
+    end
+    
+    if FIX_dataset_0order_absorption,
+        % Need to save the fixed dataset in the NLME project folder
+        % Define new name
+        [p,f,e] = fileparts(data.dataFileName);
+        FIX_dataset_0order_absorption_NewName = [f '_0orderABS_fix.csv'];
+        IQMexportCSVdataset(dataModeling,FIX_dataset_0order_absorption_NewName);
+        % Update data file information
+        dataRelPathFromProject = '.'; % data file in project folder
+        dataFileName = FIX_dataset_0order_absorption_NewName; % New name
+    end
+end
+
+
+
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% OPEN File
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fid = fopen([projectName '.nmctl'],'w');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INFO
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; NONMEM PROJECT, created using IQM Tools\r\n');
+fprintf(fid,'; Date: %s\r\n',datestr(now,'yyyy-mmm-DD HH:MM'));
+fprintf(fid,'; By:   %s\r\n',usernameIQM());
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Placeholder for project information
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; ==PROJECT HEADER START===================================================\r\n');
+fprintf(fid,'PROJECT_HEADER_PLACEHOLDER\r\n');
+fprintf(fid,'; ==PROJECT HEADER END=====================================================\r\n');
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Define $SIZES
+% Set all LIM1,2,6 to TOTDREC=maxDATARECORDS!
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'$SIZES LIM1=%d\r\n',maxDATARECORDS);
+fprintf(fid,'$SIZES LIM2=%d\r\n',maxDATARECORDS);
+fprintf(fid,'$SIZES LIM6=%d\r\n',maxDATARECORDS);
+fprintf(fid,'$SIZES LTH=XXX\r\n');
+% Define PD as number of columns that are not skipped
+PD = length(explodePCIQM(data.dataHeaderIdent))-length(strfind(data.dataHeaderIdent,'IGNORE'))+5;
+fprintf(fid,'$SIZES PD=%d\r\n',PD);
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $PROBLEM
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[xdummyx,problemName]     = fileparts(projectPath);
+fprintf(fid,'$PROBLEM %s\r\n',problemName);
+% Convert model notes to commented nonmem string
+if ~isempty(strtrim(ms.notes)),
+    fprintf(fid,'\r\n; %s\r\n',strrep(ms.notes,sprintf('\n'),sprintf('\n; ')));
+end
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $DATA
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'$DATA %s\r\n',strrep(fullfile(dataRelPathFromProject,dataFileName),'\','/'));
+fprintf(fid,'    IGNORE=@\r\n');
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $INPUT
+% Assumption: names for INPUT are used as in the dataset for CAT,COV,X
+% for all others as in dataHeaderIdent. This means that the ordering of
+% regression parameters is done as in the dataset!
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+dataHeaderIdentAll = explodePCIQM(dataHeaderIdent);
+
+text = '$INPUT';
+for k=1:length(dataheader),
+    col     = dataheader{k};
+    coltype = dataHeaderIdentAll{k};
+    
+    % Check if CAT, COV or X
+    if ismember(coltype,{'CAT','COV','X'}),
+        % Use name as in dataset header
+        text = sprintf('%s %s',text,col);
+    elseif strcmp(coltype,'IGNORE'),
+        % If column set to IGNORE then use SKIP in the $INPUT definition
+        text = sprintf('%s SKIP',text);
+    else
+        % Use name as in dataset ident
+        text = sprintf('%s %s',text,coltype);
+    end
+end
+fprintf(fid,'%s\r\n',wrapRowTextIQM(text,80,7));
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $SUBROUTINE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'$SUBROUTINE ADVAN13 TOL=6\r\n\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $MODEL
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'$MODEL\r\n');
+
+textAll = {};
+maxLength = 0;
+for k=1:length(ms.states),
+    textAll{k} = sprintf('    COMP = (%s)',ms.states(k).name);
+    maxLength = max(maxLength,length(textAll{k}));
+end
+text = '';
+for k=1:length(ms.states),
+    notes = ms.states(k).notes;
+    if isempty(notes),
+        notes = ['Compartment ' num2str(k)];
+    end
+    text = sprintf('%s%s%s; %s\r\n',text,textAll{k},char(32*ones(1,4+maxLength-length(textAll{k}))),notes);
+end
+fprintf(fid,'%s\r\n',text);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $PK - Start
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'$PK\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $PK - PK parameters
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; Parameters\r\n');
+% 1) Define the param_pk parameters that are not estimated, not
+%    obtained as regression parameters
+% These parameters are dosing type dependent parameters and model
+% parameters that appear in the pre-factor of the input definitions
+% Need to define all but Tinf and Rate parameter (defined in dataset)
+for k=1:length(modelInfo.param_pk),
+    if isempty(strfind(modelInfo.param_pk(k).name,'Rate_')) && isempty(strfind(modelInfo.param_pk(k).name,'Tinf_')),
+        if ~isempty(modelInfo.param_pk(k).notes),
+            fprintf(fid,'    %s = %g',modelInfo.param_pk(k).name,modelInfo.param_pk(k).value(1));
+            fprintf(fid,'\t; %s\r\n',modelInfo.param_pk(k).notes);
+        else
+            fprintf(fid,'    %s = %g\r\n',modelInfo.param_pk(k).name,modelInfo.param_pk(k).value(1));
+        end
+    end
+end
+fprintf(fid,'\r\n');
+
+% Write out all other parameters also
+model_element_prefix = '';
+time_variable_replacement = 'TIME2';
+[StatesText, ParametersText, VariablesText, ODEsText] = getmodelPartTextInfo4NONMEMconversion(model,model_element_prefix,param_est,modelInfo,time_variable_replacement);
+if ~isempty(ParametersText),
+    fprintf(fid,'; Parameters\r\n');
+    fprintf(fid,'%s',ParametersText);
+    fprintf(fid,'\r\n');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $PK - Start by THETAs
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+MU_param_text = {};
+for k=1:length(param_est)
+    MU_param_text{k} = sprintf('    MU_%d%s = THETA(%d)%sX#X#X    ; %s\r\n',k,char(32*ones(1,2-length(num2str(k)))),k,char(32*ones(1,2-length(num2str(k)))),param_est(k).name);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $PK - Introduce covariates
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+[MU_param_text,THETA_INDEX_BETA,beta_parameters,text_defining_cat_auxiliaries,cov_type_continuous,covparam,covcov,beta_parameters_cov_project_info,beta_parameters_cat_project_info,COV_transformation_info,CAT_reference_info,CAT_categories_info,COVCATestimate_info] = handleCovariateDefinitionsIQM(MU_param_text,covariateModel,param_est,covariateMedianValues,covariateMedianNames,covariateCATNames,covariateCATValues,IIVdistribution,COVestimate);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $PK - Write out the auxiliaries if needed
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(text_defining_cat_auxiliaries),
+    fprintf(fid,'; Auxiliary definitions for handling categorical covariates\r\n');
+    fprintf(fid,'%s\r\n',text_defining_cat_auxiliaries);
+end
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $PK - MU Referencing
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; MU Referencing\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle MU_param_text to wrap lines
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+MAXLENGTHLINE = 80;
+for k=1:length(MU_param_text),
+    if length(MU_param_text{k}) > MAXLENGTHLINE,
+        xxx = MU_param_text{k};
+        % Get first additive element
+        ix = strfind(xxx,' + ');
+        ix = ix(1);
+        text_start = xxx(1:ix(1));
+        text_wrap = xxx(ix(1)+3:end);
+        pieces_wrap = {};
+        while length(text_wrap)>MAXLENGTHLINE,
+            ix = strfind(text_wrap,' + ');
+            ixx = ix(find(ix>MAXLENGTHLINE)-1);
+            if ~isempty(ixx),
+                ix = ixx(1);
+            else
+                ix = ix(end);
+            end
+            pieces_wrap{end+1} = text_wrap(1:ix);
+            text_wrap = text_wrap(ix+3:end);
+        end        
+        pieces_wrap{end+1} = text_wrap;
+        for k2=1:length(pieces_wrap),
+            if k2==1,
+                pieces_wrap{k2} = sprintf('    MU%dWRAP_%d = %s',k,k2,strtrim(pieces_wrap{k2}));
+            else
+                pieces_wrap{k2} = sprintf('    MU%dWRAP_%d = MU%dWRAP_%d + %s',k,k2,k,k2-1,strtrim(pieces_wrap{k2}));
+            end
+        end
+        pieces_wrap{end+1} = sprintf('%s + MU%dWRAP_%d',text_start,k,k2);
+        
+        % Put together
+        xxx = '';
+        for k2=1:length(pieces_wrap),
+            xxx = sprintf('%s%s\r\n',xxx,pieces_wrap{k2});
+        end
+        
+        MU_param_text{k} = xxx;
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $PK - Write out the MU parameter definitions with covariates
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for k=1:length(MU_param_text),
+    fprintf(fid,'%s',MU_param_text{k});
+end
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $PK - Parameter transformations
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; MU+ETA\r\n');
+for k=1:length(param_est),
+    fprintf(fid,'    T_%s%s = MU_%d + ETA(%d)\r\n',param_est(k).name,char(32*ones(1,cellmaxlengthIQM({param_est.name})-length(param_est(k).name)+1)),k,k);
+end
+fprintf(fid,'\r\n');
+
+fprintf(fid,'; Parameter transformations\r\n');
+for k=1:length(param_est),
+    if IIVdistribution{k} == 'N',
+        fprintf(fid,'    %s%s = T_%s\r\n',param_est(k).name,char(32*ones(1,cellmaxlengthIQM({param_est.name})-length(param_est(k).name)+1)),param_est(k).name);
+    elseif  IIVdistribution{k} == 'L',
+        fprintf(fid,'    %s%s = EXP(T_%s)\r\n',param_est(k).name,char(32*ones(1,cellmaxlengthIQM({param_est.name})-length(param_est(k).name)+1)),param_est(k).name);
+    elseif  IIVdistribution{k} == 'G',
+        fprintf(fid,'    %s%s = EXP(T_%s)/(1+EXP(T_%s))\r\n',param_est(k).name,char(32*ones(1,cellmaxlengthIQM({param_est.name})-length(param_est(k).name)+1)),param_est(k).name,param_est(k).name);
+    else
+        error('Unknown distribution.');
+    end
+end
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $PK - Compartment assignment, etc.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; Dosing compartments info\r\n');
+if isnan(FLAG_IV_POPPK),
+    % Not run from within the popPK workflow ... handle normally
+    warningInfusion = 0;
+    % Collect information about input fraction definitions etc
+    Xinfo = [];
+    Xinfo.stateindex = [];
+    Xinfo.INPUT_NUMBER = [];
+    Xinfo.factors = {};
+    
+    for k=1:length(modelInfo.inputs),
+        stateindex = [modelInfo.inputs(k).stateindex];
+        factors = modelInfo.inputs(k).factors;
+        % Get input number for comparison with "INPUT" dataset column
+        INPUT_NUMBER = str2double(strrep(modelInfo.inputs(k).name,'INPUT',''));
+        % Check if partial application into different compartments =>
+        % we do not allow that!
+        if length(stateindex) ~= 1,
+            error('Partial application of a dose into different compartments not supported yet by the NONMEM conversion.');
+        end
+        
+        Xinfo.stateindex(end+1) = stateindex(1);
+        Xinfo.INPUT_NUMBER(end+1) = INPUT_NUMBER;
+        Xinfo.factors{end+1} = factors{1};
+    end
+    
+    uniqueStateindex = unique(Xinfo.stateindex);
+    for k=1:length(uniqueStateindex),
+        if ~FLAG_CMT,
+            % If normal ADM/YTYPE then standard stuff ... no state can have more than one input
+            fprintf(fid,'    F%d = %s%s; %s\r\n',Xinfo.stateindex(k),Xinfo.factors{k},char(32*ones(1,cellmaxlengthIQM(Xinfo.factors)-length(Xinfo.factors{k})+1)),ms.states(Xinfo.stateindex(k)).name );
+        else
+            % If CMT then a state can have more than one input. Input number then defined by
+            % ADM ... potentially different bioavailabilities and etc. need to be handled in this case
+            ix = find(Xinfo.stateindex==uniqueStateindex(k));
+            if length(ix)==1,
+                fprintf(fid,'    F%d = %s%s; %s\r\n',Xinfo.stateindex(ix),Xinfo.factors{ix},char(32*ones(1,cellmaxlengthIQM(Xinfo.factors)-length(Xinfo.factors{ix})+1)),ms.states(Xinfo.stateindex(ix)).name );
+            elseif length(ix)==2,
+                fprintf(fid,'    IF (ADM.EQ.%d) THEN\r\n',Xinfo.INPUT_NUMBER(ix(1)));
+                fprintf(fid,'        F%d = %s%s; %s\r\n',Xinfo.stateindex(ix(1)),Xinfo.factors{ix(1)},char(32*ones(1,cellmaxlengthIQM(Xinfo.factors)-length(Xinfo.factors{ix(1)})+1)),ms.states(Xinfo.stateindex(ix(1))).name );
+                fprintf(fid,'    ELSE ; (if ADM=%d)\r\n',Xinfo.INPUT_NUMBER(ix(2)));
+                fprintf(fid,'        F%d = %s%s; %s\r\n',Xinfo.stateindex(ix(2)),Xinfo.factors{ix(2)},char(32*ones(1,cellmaxlengthIQM(Xinfo.factors)-length(Xinfo.factors{ix(2)})+1)),ms.states(Xinfo.stateindex(ix(2))).name );
+                fprintf(fid,'    ENDIF\r\n');
+            else
+                error(sprintf('Due to nesting limitations in IF THEN ELSE statements not more\nthan 2 inputs can be added automatically on the same compartment\nwith the CMT column. If you want more ... use MONOLIX ... easy,\nstraight forward, etc.'));
+            end
+        end
+    end
+    fprintf(fid,'\r\n');
+    
+    % Only check the following if not running from the popPK workflow. The
+    % popPK workflow checks itself if it is ok or not.
+    if ~FLAG_NONMEM__RATE_BIOAVAILABILITY_ISSUE__OK,
+        % Infusion with bioavailability terms ... or conversion to other unit terms
+        % is not allowed in NONMEM conversion. The bioavailability part is not
+        % applied to the RATE ... really really really stupid.
+        for k=1:length(Xinfo.stateindex),
+            % Get dosing data with input number
+            datak = dataModeling(dataModeling.YTYPE==0 & dataModeling.ADM==Xinfo.INPUT_NUMBER(k),:);
+            % Check if RATE>0 for these doses (at least one rate)
+            if max(datak.RATE)>0,
+                % Check if bioavailability term present
+                factor = Xinfo.factors{k};
+                if ~strcmp(factor,'1'),
+                    error(sprintf('NONMEM does not apply bioavailability factors (or unit conversions) to RATE.\nPlease consider changing the unit of your input to not need a pre-factor - or use MONOLIX!'));
+                end
+            end
+        end
+    end
+    fprintf(fid,'\r\n');
+    
+    if ~FLAG_CMT,
+        % If normal ADM/YTYPE then standard stuff ... no state can have more than one input
+        for k=1:length(modelInfo.inputs),
+            % Get state/compartment number for input
+            STATE_NUMBER = modelInfo.inputs(k).stateindex;
+            % Write out the ALAGn statement if Tlag defined
+            if ~isempty(modelInfo.inputs(k).Tlag),
+                fprintf(fid,'    ALAG%d = %s\r\n',STATE_NUMBER,modelInfo.inputs(k).TlagName);
+            end
+        end
+    else
+        % If CMT then a state can have more than one input. Input number then defined by
+        % ADM ... potentially different lag times and etc. need to be handled in this case
+        %
+        % Find all inputs with lag time and check if numeric or non-numeric
+        LAGinputs = [];
+        for k=1:length(modelInfo.inputs),
+            if ~isempty(modelInfo.inputs(k).Tlag),
+                LAGinputs(end+1) = k;
+            end
+        end
+        LAGinputInfo = modelInfo.inputs(LAGinputs);
+        % Update TlagName if non-numerical Tlag definition
+        for k=1:length(LAGinputInfo),
+            if ~isnumeric(LAGinputInfo(k).Tlag),
+                LAGinputInfo(k).TlagName = LAGinputInfo(k).Tlag;
+            end
+        end
+        
+        % Get states on which LAG inputs are
+        LAGinputStates = [LAGinputInfo.stateindex];
+        uniqueLAGinputStates = unique(LAGinputStates);
+        for k=1:length(uniqueLAGinputStates),
+            ix = find(LAGinputStates==uniqueLAGinputStates(k));
+            if length(ix)==1,
+                fprintf(fid,'    ALAG%d = %s\r\n',uniqueLAGinputStates(ix),LAGinputInfo(ix).TlagName);
+            elseif length(ix)==2,
+                fprintf(fid,'    IF (ADM.EQ.%s) THEN\r\n',strrep(LAGinputInfo(ix(1)).name,'INPUT',''));
+                fprintf(fid,'        ALAG%d = %s\r\n',LAGinputStates(ix(1)),LAGinputInfo(ix(1)).TlagName);
+                fprintf(fid,'    ELSE ; (if ADM=%s)\r\n',strrep(LAGinputInfo(ix(2)).name,'INPUT',''));
+                fprintf(fid,'        ALAG%d = %s\r\n',LAGinputStates(ix(2)),LAGinputInfo(ix(2)).TlagName);
+                fprintf(fid,'    ENDIF\r\n');
+            end
+        end
+    end
+    fprintf(fid,'\r\n');
+    
+    % Define the Dn parameters in case that zero order absorption is chosen as input
+    if ~FLAG_CMT,
+        % If normal ADM/YTYPE then standard stuff ... no state can have more than one input
+        for k=1:length(modelInfo.inputs),
+            % Get state/compartment number for input
+            STATE_NUMBER = modelInfo.inputs(k).stateindex;
+            % Write out the Dn statement if input is zero order absorption ...
+            if strcmp(modelInfo.inputs(k).type,'ABSORPTION0'),
+                fprintf(fid,'    D%d = %s\r\n',STATE_NUMBER,strrep(modelInfo.inputs(k).name,'INPUT','Tk0input'));
+            end
+        end
+    else
+        % If CMT then a state can have more than one input. Input number then defined by
+        % ADM ... potentially different zero order rates to estimate and etc. need to be handled in this case
+        %
+        % Find all inputs with zero order absorption
+        ZOinputs = strmatchIQM('ABSORPTION0',{modelInfo.inputs.type},'exact');
+        ZOinputInfo = modelInfo.inputs(ZOinputs);
+        % Get states on which ZO inputs are
+        ZOinputStates = [ZOinputInfo.stateindex];
+        uniqueZOinputStates = unique(ZOinputStates);
+        for k=1:length(uniqueZOinputStates),
+            ix = find(ZOinputStates==uniqueZOinputStates(k));
+            if length(ix)==1,
+                fprintf(fid,'    D%d = %s\r\n',uniqueZOinputStates(ix),strrep(ZOinputInfo(ix).name,'INPUT','Tk0input'));
+            elseif length(ix)==2,
+                fprintf(fid,'    IF (ADM.EQ.%s) THEN\r\n',strrep(ZOinputInfo(ix(1)).name,'INPUT',''));
+                fprintf(fid,'        D%d = %s\r\n',ZOinputStates(ix(1)),strrep(ZOinputInfo(ix(1)).name,'INPUT','Tk0input'));
+                fprintf(fid,'    ELSE ; (if ADM=%s)\r\n',strrep(ZOinputInfo(ix(2)).name,'INPUT',''));
+                fprintf(fid,'        D%d = %s\r\n',ZOinputStates(ix(2)),strrep(ZOinputInfo(ix(1)).name,'INPUT','Tk0input'));
+                fprintf(fid,'    ENDIF\r\n');
+            end
+        end
+    end
+    fprintf(fid,'\r\n');
+    
+else
+    % Run from within the popPK workflow - handle specially - since we know
+    % exactly what is possible and what is needed in terms of the dosing
+    % definitions.
+    if absorptionModel_POPPK == 0,
+        % Zero order absorption into central compartment
+        % Additional IV administration not allowed
+        if FLAG_IV_POPPK == 1,
+            error('IV dosing and zero order absorption into central compartment with NONMEM not handled automatically.');
+        end
+        fprintf(fid,'    F2 = FACTOR_UNITS*Fabs0*Frel0     ; Ac\r\n');
+        fprintf(fid,'    \r\n');
+        fprintf(fid,'    ALAG2 = Tlaginput3\r\n');
+        fprintf(fid,'    \r\n');
+        fprintf(fid,'    D2 = Tk0input3\r\n');
+        fprintf(fid,'\r\n');
+    elseif absorptionModel_POPPK == 1,
+        if FLAG_IV_POPPK==1,
+            % Mixed 1st order and IV
+            fprintf(fid,'    F1 = FACTOR_UNITS*Fabs1           ; Ad\r\n');
+            fprintf(fid,'    F2 = FACTOR_UNITS*Fiv             ; Ac\r\n');
+            fprintf(fid,'    \r\n');
+            fprintf(fid,'    ALAG1 = Tlaginput1\r\n');
+            fprintf(fid,'\r\n');
+        else
+            % Only 1st order absorption
+            fprintf(fid,'    F1 = FACTOR_UNITS*Fabs1           ; Ad\r\n');
+            fprintf(fid,'    \r\n');
+            fprintf(fid,'    ALAG1 = Tlaginput1\r\n');
+            fprintf(fid,'\r\n');
+        end
+    elseif absorptionModel_POPPK == 2,
+        % No IV allowed. Parallel zero and first order absorption
+        if FLAG_IV_POPPK == 1,
+            error('IV dosing and zero order absorption into central compartment with NONMEM not handled automatically.');
+        end
+        % CMT=2 dose is 0 order absorption
+        fprintf(fid,'    F1 = FACTOR_UNITS*Fabs1*(1-Frel0) ; Ad\r\n');
+        fprintf(fid,'    F2 = FACTOR_UNITS*Fabs0*Frel0     ; Ac\r\n');
+        fprintf(fid,'    \r\n');
+        fprintf(fid,'    ALAG1 = Tlaginput1\r\n');
+        fprintf(fid,'    ALAG2 = Tlaginput3\r\n');
+        fprintf(fid,'    \r\n');
+        fprintf(fid,'    D2 = Tk0input3\r\n');
+        fprintf(fid,'\r\n');
+    elseif absorptionModel_POPPK == 3,
+        % Sequential 0/1 order absorption
+        % Set ALAG1 to Tk0input3
+        % Additional IV administration not allowed
+        if FLAG_IV_POPPK == 1,
+            error('IV dosing and zero order absorption into central compartment with NONMEM not handled automatically.');
+        end
+        fprintf(fid,'    F1 = FACTOR_UNITS*Fabs1*(1-Frel0) ; Ad\r\n');
+        fprintf(fid,'    F2 = FACTOR_UNITS*Fabs0*Frel0     ; Ac\r\n');
+        fprintf(fid,'    \r\n');
+        fprintf(fid,'    ALAG1 = Tk0input3\r\n');
+        fprintf(fid,'    ALAG2 = Tlaginput3\r\n');
+        fprintf(fid,'    \r\n');
+        fprintf(fid,'    D2 = Tk0input3\r\n');
+        fprintf(fid,'\r\n');
+    else
+        error('Unknown absorption model.');
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check for infusion presence
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ismember('INFUSION',{modelInfo.inputs.type}),
+    % Warn the user:
+    if ~SILENT,
+        disp(' ');
+        fprintf('==========================================================\n');
+        fprintf('Infusion administration present in model:\n');
+        fprintf('Make sure you have a RATE column in your dataset!\n');
+        fprintf('==========================================================\n');
+        disp(' ');
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Tell the user how to map INPUTn and OUTPUTn with the CMT column or 
+% with the optional ADM and YTYPE columns.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+if ~SILENT,
+    if FLAG_CMT,
+        disp('===============================================================================');
+        disp('IMPORTANT:');
+        disp('The dataset contains the "CMT" column. In order to correctly map dosing inputs');
+        disp('and observations with the CMT column, please make sure you used the following');
+        disp('entries in the CMT column (keep the ADM column):');
+        disp(' ');
+        disp('Mapping of the INPUTn in the model and the CMT column in the dataset:');
+        for k=1:length(modelInfo.inputs),
+            % Get state/compartment number for input
+            STATE_NUMBER = modelInfo.inputs(k).stateindex;
+            INPUT_NUMBER = eval(strrep(modelInfo.inputs(k).name,'INPUT',''));
+            fprintf('INPUT%d => CMT column value: %d\n',INPUT_NUMBER,STATE_NUMBER);
+        end
+        disp(' ');
+        disp('Mapping of the OUTPUTn in the model and the CMT column in the dataset:');
+        for k=1:length(modelInfo.outputs),
+            OUTPUT_NUMBER = eval(strrep(modelInfo.outputs(k).name,'OUTPUT',''));        
+            fprintf('OUTPUT%d => CMT column value: %d\n',OUTPUT_NUMBER,OUTPUT_NUMBER);
+        end
+        disp('===============================================================================');
+    else
+        disp('===============================================================================');
+        disp('IMPORTANT:');
+        disp('The dataset contains the "ADM" and "YTYPE" columns. In order to correctly map');
+        disp('dosing inputs and observations with the these columns, please make sure you');
+        disp('used the following entries in the "ADM" and "YTYPE" columns:');
+        disp(' ');
+        disp('Mapping of the INPUTn in the model and the ADM column in the dataset:');
+        for k=1:length(modelInfo.inputs),
+            % Get state/compartment number for input
+            STATE_NUMBER = modelInfo.inputs(k).stateindex;
+            INPUT_NUMBER = eval(strrep(modelInfo.inputs(k).name,'INPUT',''));
+            fprintf('INPUT%d => ADM column value: %d\n',INPUT_NUMBER,STATE_NUMBER);
+        end
+        disp(' ');
+        disp('Mapping of the OUTPUTn in the model and the YTYPE column in the dataset:');
+        for k=1:length(modelInfo.outputs),
+            OUTPUT_NUMBER = eval(strrep(modelInfo.outputs(k).name,'OUTPUT',''));        
+            fprintf('OUTPUT%d => YTYPE column value: %d\n',OUTPUT_NUMBER,OUTPUT_NUMBER);
+        end
+        disp('===============================================================================');        
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $PK - Initial conditions
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; Initial conditions\r\n');
+for k=1:length(ms.states),
+    ic = ms.states(k).initialCondition;
+    if isnumeric(ic),
+        fprintf(fid,'    A_0(%d) = %g\r\n',k,ic);
+    else
+        fprintf(fid,'    A_0(%d) = %s\r\n',k,ic);
+    end        
+end
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $PK - Define TIMEOFFSET
+% For NONMEM this is the difference between TIME and TIME2
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; Define TIMEOFFSET\r\n');
+fprintf(fid,'    TIMEOFFSET = TIME-TIME2\r\n');
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $DES - Start
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'$DES\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get model information 
+% Use "DES_" as prefix and (T-TIMEOFFSET) as time variable T
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+model_element_prefix = 'DES_';
+time_variable_replacement = '(T-TIMEOFFSET)';
+[StatesText, ParametersText, VariablesText, ODEsText] = getmodelPartTextInfo4NONMEMconversion(model,model_element_prefix,param_est,modelInfo,time_variable_replacement);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $DES Write out the components
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; States\r\n');
+fprintf(fid,'%s',StatesText);
+fprintf(fid,'\r\n');
+
+if ~isempty(ParametersText),
+    fprintf(fid,'; Parameters\r\n');
+    fprintf(fid,'%s',ParametersText);
+    fprintf(fid,'\r\n');
+end
+
+if ~isempty(VariablesText),
+    fprintf(fid,'; Variables\r\n');
+    fprintf(fid,'%s',VariablesText);
+    fprintf(fid,'\r\n');
+end
+
+fprintf(fid,'; ODEs\r\n');
+fprintf(fid,'%s',ODEsText);
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $ERROR
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'$ERROR\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get model information 
+% Use empty prefix and (TIME2) as time variable T
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+model_element_prefix = '';
+time_variable_replacement = 'TIME2';
+[StatesText, ParametersText, VariablesText, ODEsText] = getmodelPartTextInfo4NONMEMconversion(model,model_element_prefix,param_est,modelInfo,time_variable_replacement);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $ERROR Write out the components
+% Dont write out parameters here - do that in $PK
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; States\r\n');
+fprintf(fid,'%s',StatesText);
+fprintf(fid,'\r\n');
+
+if ~isempty(VariablesText),
+    fprintf(fid,'; Variables\r\n');
+    fprintf(fid,'%s',VariablesText);
+    fprintf(fid,'\r\n');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $ERROR - error models
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Define next index for THETA parameters
+if isempty(THETA_INDEX_BETA),
+    THETA_INDEX_NEXT = length(param_est)+1;
+else
+    THETA_INDEX_NEXT = max(THETA_INDEX_BETA)+1;
+end
+THETA_ERROR_MODELS_IX = [];
+THETA_ERROR_MODELS_NAME = {};
+THETA_ERROR_MODELS_VALUE = [];
+error_model = explodePCIQM(errorModels);
+
+if FLAG_CMT,
+    fprintf(fid,'; Use CMT as YTYPE information\r\n');
+    fprintf(fid,'    IF(EVID.EQ.1) THEN\r\n');
+    fprintf(fid,'        YTYPE = 0\r\n');
+    fprintf(fid,'    ELSE\r\n');
+    fprintf(fid,'       YTYPE = CMT\r\n');
+    fprintf(fid,'    ENDIF\r\n');
+    fprintf(fid,'\r\n');
+end
+
+% Check if BLOQ data is to be handled in the MODEL (M3 and M4 methods)
+CENS_tobehandled = 0;
+if ~isempty(strfind(data.dataHeaderIdent,',CENS')),
+    if ~isempty(find(dataCSV.CENS==1)),
+        CENS_tobehandled = 1;
+        if ~SILENT,
+            disp(' ');
+            disp('BLOQ - Handling in the NONMEM code:');
+            disp('===================================');
+            if M4,
+                disp('Using the M4 method.');
+            else
+                disp('Using the M3 method.');
+            end
+            disp(' ');
+        end
+    end
+end
+
+fprintf(fid,'; just to avoid a NONMEM warning\r\n');
+if CENS_tobehandled,
+    fprintf(fid,'    CUMD  = 0 ; only needed for M4 method\r\n');
+    fprintf(fid,'    CUMDZ = 0 ; only needed for M4 method\r\n');
+end
+fprintf(fid,'    Y     = 0.1\r\n\r\n');
+
+output_parameters_project_info = {};
+count = 1;
+for k=1:length(ms.outputs),
+    fprintf(fid,'; Error model %s / %s\r\n',ms.outputs(k).name,ms.outputs(k).formula);
+    outputNumber = eval(strrep(ms.outputs(k).name,'OUTPUT',''));
+    
+    textError = '';
+    textError = sprintf('%s        IPRED  = %s\r\n',textError,ms.outputs(k).formula);
+    textError = sprintf('%s        IRES   = DV - IPRED\r\n',textError);
+    
+    if strcmpi(error_model{k},'const'),
+        textError = sprintf('%s        W      = THETA(%d)\r\n',textError,THETA_INDEX_NEXT); 
+        THETA_ERROR_MODELS_IX(end+1) = THETA_INDEX_NEXT;
+        THETA_ERROR_MODELS_NAME{end+1} = sprintf('Additive error %s',ms.outputs(k).name);
+        THETA_ERROR_MODELS_VALUE(end+1) = errorParam0(count);
+        count = count + 1;
+        THETA_INDEX_NEXT = THETA_INDEX_NEXT+1;
+        output_parameters_project_info{end+1} = sprintf('error_ADD%d',outputNumber);
+    elseif strcmpi(error_model{k},'prop'),
+        textError = sprintf('%s        W      = THETA(%d)*IPRED\r\n',textError,THETA_INDEX_NEXT); 
+        THETA_ERROR_MODELS_IX(end+1) = THETA_INDEX_NEXT;
+        THETA_ERROR_MODELS_NAME{end+1} = sprintf('Proportional error %s',ms.outputs(k).name);
+        THETA_ERROR_MODELS_VALUE(end+1) = errorParam0(count);
+        count = count + 1;
+        THETA_INDEX_NEXT = THETA_INDEX_NEXT+1;
+        output_parameters_project_info{end+1} = sprintf('error_PROP%d',outputNumber);
+    elseif strcmpi(error_model{k},'comb1'),
+        textError = sprintf('%s        W      = SQRT(THETA(%d)**2 + (THETA(%d)*IPRED)**2)\r\n',textError,THETA_INDEX_NEXT,THETA_INDEX_NEXT+1); 
+        THETA_ERROR_MODELS_IX(end+1) = THETA_INDEX_NEXT;
+        THETA_ERROR_MODELS_IX(end+1) = THETA_INDEX_NEXT+1;
+        THETA_ERROR_MODELS_NAME{end+1} = sprintf('Additive error %s',ms.outputs(k).name);
+        THETA_ERROR_MODELS_NAME{end+1} = sprintf('Proportional error %s',ms.outputs(k).name);
+        THETA_ERROR_MODELS_VALUE(end+1) = errorParam0(count);
+        count = count + 1;
+        THETA_ERROR_MODELS_VALUE(end+1) = errorParam0(count);
+        count = count + 1;
+        THETA_INDEX_NEXT = THETA_INDEX_NEXT+2;
+        output_parameters_project_info{end+1} = sprintf('error_ADD%d',outputNumber);
+        output_parameters_project_info{end+1} = sprintf('error_PROP%d',outputNumber);
+    else
+        error('Unknown error model definition.');
+    end
+    textError = sprintf('%s        IWRES  = IRES/W\r\n',textError);
+
+    % Handle different BLOQ methods if CENS column in dataset - only
+    % handled if non zero elements present in CENS column
+    % Reason: handling CENS=1 in M3 and M4 requires LAPLACIAN in the $EST
+    % statement. To be avoided if not needed.
+    
+    if ~CENS_tobehandled,
+        % NO CENS column in the dataset (or no 1 entries in CENS) => just use standard
+        fprintf(fid,'    IF(YTYPE.EQ.%d) THEN\r\n',outputNumber);
+        fprintf(fid,'%s',textError);
+        fprintf(fid,'        Y      = IPRED + W*ERR(%d)\r\n',k);
+        fprintf(fid,'    ENDIF\r\n');
+    else
+        % CENS column in the dataset 
+        
+        % Handle uncensored values (CENS==0)
+        fprintf(fid,'    IF(YTYPE.EQ.%d.AND.CENS.EQ.0) THEN\r\n',outputNumber);
+        fprintf(fid,'        ; Handle data above LLOQ\r\n');
+        fprintf(fid,'%s',textError);
+        fprintf(fid,'        F_FLAG = 0\r\n');
+        fprintf(fid,'        Y      = IPRED + W*ERR(%d)\r\n',k);
+        fprintf(fid,'    ENDIF\r\n');
+
+        % Handle censored BLOQ values (CENS==1) - assumption that LLOQ in DV
+        
+        if ~M4,
+            % M3 method
+            fprintf(fid,'    IF(YTYPE.EQ.%d.AND.CENS.EQ.1) THEN\r\n',outputNumber);
+            fprintf(fid,'        ; Handle data below LLOQ (M3 method - assuming LLOQ in DV and CENS=1)\r\n');
+            fprintf(fid,'%s',textError);
+            fprintf(fid,'        F_FLAG = 1\r\n');
+            fprintf(fid,'        Y      = PHI((DV-IPRED)/W)\r\n');
+            fprintf(fid,'    ENDIF\r\n');
+        else
+            % M4 method
+            fprintf(fid,'    IF(YTYPE.EQ.%d.AND.CENS.EQ.1) THEN\r\n',outputNumber);
+            fprintf(fid,'        ; Handle data below LLOQ (M4 method - assuming LLOQ in DV and CENS=1)\r\n');
+            fprintf(fid,'%s',textError);
+            fprintf(fid,'        F_FLAG = 1\r\n');
+            fprintf(fid,'        CUMD   = PHI((DV-IPRED)/W)\r\n');
+            fprintf(fid,'        CUMDZ  = PHI(-IPRED/W)\r\n');
+            fprintf(fid,'        Y      = (CUMD-CUMDZ)/(1-CUMDZ)\r\n');
+            fprintf(fid,'    ENDIF\r\n');
+        end
+    end
+    fprintf(fid,'\r\n');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Assign variables to report in tables
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% ETAs:
+fprintf(fid,'; Assign variables to report in tables\r\n');
+for k=1:length(param_est),
+    fprintf(fid,'    ETA_%s%s = ETA(%d)\r\n',param_est(k).name,char(32*ones(1,cellmaxlengthIQM({param_est(k).name})-length(param_est(k).name)+1)),k);
+end
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $THETA for model parameters
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'$THETA\r\n');
+
+fprintf(fid,'; Model parameters\r\n');
+
+THETA_GUESS0_STRING = {};
+PARAM_TRANSNAME_STRING = {};
+PARAM_INVTRANSNAME_STRING = {};
+initialGuess_noTrans = [];
+for k=1:length(param_est),
+    initialGuess = POPvalues0(k);
+    initialGuess_noTrans(k) = POPvalues0(k);
+    if IIVdistribution{k} == 'N',
+        initialGuess = initialGuess;
+        if POPestimate(k),
+            if initialGuess == 0,
+                initialGuess = 0.01;
+            end
+        end
+        PARAM_INVTRANSNAME_STRING{k} = '(psi)';
+        PARAM_TRANSNAME_STRING{k} = '(phi)';
+    elseif IIVdistribution{k} == 'L';
+        initialGuess = log(initialGuess);
+        if POPestimate(k),
+            if initialGuess == 0,
+                initialGuess = 0.01;
+            end
+        end
+        PARAM_INVTRANSNAME_STRING{k} = 'log(psi)';
+        PARAM_TRANSNAME_STRING{k} = 'exp(phi)';
+    elseif IIVdistribution{k} == 'G',
+        initialGuess = log(initialGuess/(1-initialGuess));
+        if POPestimate(k),
+            if initialGuess == 0,
+                initialGuess = 0.01;
+            end
+        end
+        PARAM_INVTRANSNAME_STRING{k} = 'log(psi./(1-psi))';
+        PARAM_TRANSNAME_STRING{k} = 'exp(phi)./(1+exp(phi))';
+    else
+        error('Unknown parameter transformation.');
+    end
+    THETA_GUESS0_STRING{k} = sprintf('%1.3g',initialGuess);
+    % Check if parameter fixed or not
+    if POPestimate(k) == 0,
+        THETA_GUESS0_STRING{k} = [THETA_GUESS0_STRING{k} '  FIX'];
+    end
+end    
+
+for k=1:length(param_est),
+    texttext = strrep(PARAM_INVTRANSNAME_STRING{k},'psi',param_est(k).name);
+    fprintf(fid,'    %s%s ; %d %s (%1.3g)\r\n',THETA_GUESS0_STRING{k},char(32*ones(1,cellmaxlengthIQM(THETA_GUESS0_STRING)-length(THETA_GUESS0_STRING{k})+1)),k,texttext,initialGuess_noTrans(k));
+end
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $THETA for continuous covariate parameters
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+THETA_INDEX_BETA_cov = THETA_INDEX_BETA(cov_type_continuous==1);
+beta_parameters_cov  = beta_parameters(cov_type_continuous==1);
+
+if ~isempty(COVestimate) && ~isempty(THETA_INDEX_BETA_cov),
+    fprintf(fid,'; Continuous covariate model parameters\r\n');
+    count = 1;
+    for kparam=1:length(COVestimate),
+        for kcov=1:length(COVestimate{kparam}),
+            estimate = COVestimate{kparam}(kcov);
+            value    = covariateModelValues{kparam}(kcov);
+            cov      = covariateModel{kparam}{kcov+1};
+            if ismember(cov,covNames),
+                % Only handle if covariate member iof continuous covariates
+                index    = THETA_INDEX_BETA_cov(count);
+                param    = beta_parameters_cov{count};
+                count    = count+1;
+                if estimate,
+                    if value==0,
+                        value = 0.01;
+                    end
+                    fprintf(fid,'    %g ; %d %s\r\n',value,index,param);
+                else
+                    fprintf(fid,'    %g FIX ; %d %s\r\n',value,index,param);
+                end
+            end
+        end
+    end
+    fprintf(fid,'\r\n');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $THETA for categorical covariate parameters
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+THETA_INDEX_BETA_cat = THETA_INDEX_BETA(cov_type_continuous==0);
+beta_parameters_cat  = beta_parameters(cov_type_continuous==0);
+covcov_cat           = covcov(cov_type_continuous==0);
+covparam_cat         = covparam(cov_type_continuous==0);
+
+if ~isempty(COVestimate) &&  ~isempty(THETA_INDEX_BETA_cat),
+    fprintf(fid,'; Categorical covariate model parameters\r\n');
+    for k=1:length(THETA_INDEX_BETA_cat),
+        % Get parameter name
+        param = covparam_cat{k};
+        % Get covariate name
+        cov = covcov_cat{k};
+        
+        % Find index of parameter in covariateModel
+        covModelAllParam = {};
+        for k2=1:length(covariateModel),
+            covModelAllParam{end+1} = covariateModel{k2}{1};
+        end
+        ixparam = strmatchIQM(param,covModelAllParam,'exact');
+        
+        % Find index of cov in covariateModel{ixparam}
+        ixcov = strmatchIQM(cov,covariateModel{ixparam},'exact');
+        
+        % Is this covariate estimated?
+        estimate = COVestimate{ixparam}(ixcov-1);
+        
+        % Which is the value
+        value = covariateModelValues{ixparam}(ixcov-1);
+        
+        % Write out
+        if estimate,
+            if value == 0,
+                value = 0.01;
+            end
+            fprintf(fid,'    %g ; %d %s\r\n',value,THETA_INDEX_BETA_cat(k),beta_parameters_cat{k});
+        else
+            fprintf(fid,'    %g FIX ; %d %s\r\n',value,THETA_INDEX_BETA_cat(k),beta_parameters_cat{k});
+        end
+    end
+    fprintf(fid,'\r\n');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $THETA for error model parameters
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; Error model parameters\r\n');
+for k=1:length(THETA_ERROR_MODELS_IX),
+    fprintf(fid,'    %g%s ; %d %s\r\n',THETA_ERROR_MODELS_VALUE(k),char(32*ones(1,cellmaxlengthIQM(THETA_GUESS0_STRING)-length('1')+1)),THETA_ERROR_MODELS_IX(k),THETA_ERROR_MODELS_NAME{k});
+end
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $OMEGA
+% Using standard deviations and correlations
+%
+% $OMEGA STANDARD CORRELATION BLOCK(2)
+% 0.8
+% -0.394 0.762
+%
+% or:
+% $OMEGA
+% 0.8 STANDARD
+% 0.5 STANDARD
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+	
+if strcmp(lower(covarianceModel),'diagonal') || isempty(covarianceModel),
+    fprintf(fid,'$OMEGA\r\n');
+    OMEGA_GUESS0_STRING = {};
+    for k=1:length(param_est),
+        if IIVestimate(k) == 0,
+            % Set IIV value to 0 and FIX
+            OMEGA_GUESS0_STRING{k} = sprintf('0 STANDARD FIX');
+        elseif IIVestimate(k) == 1,
+            value = IIVvalues0(k);
+            if value == 0,
+                value = 0.1;
+            end
+            % Set IIV value
+%             OMEGA_GUESS0_STRING{k} = sprintf('%1.2g',(value)^2); % Convert IIV values from STD to VAR
+            OMEGA_GUESS0_STRING{k} = sprintf('%1.2g STANDARD',value); % USE STD
+        elseif IIVestimate(k) == 2,
+            % Set IIV value and FIX
+%             OMEGA_GUESS0_STRING{k} = sprintf('%1.2g  FIX',(IIVvalues0(k))^2); % Convert IIV values from STD to VAR
+            OMEGA_GUESS0_STRING{k} = sprintf('%1.2g STANDARD FIX',IIVvalues0(k)); % Convert IIV values from STD to VAR
+        end
+    end
+    for k=1:length(param_est),
+        fprintf(fid,'    %s%s ; %d %s\r\n',OMEGA_GUESS0_STRING{k},char(32*ones(1,cellmaxlengthIQM(OMEGA_GUESS0_STRING)-length(OMEGA_GUESS0_STRING{k})+1)),k,param_est(k).name);
+    end
+else
+    % Handle the covariances ... block by block
+    terms = explodePCIQM(covarianceModel,',','{','}');
+    for k=1:length(terms),
+        block = terms{k};
+        block = strrep(block,'{','');
+        block = strrep(block,'}','');
+        block = explodePCIQM(block);
+        ix_parameters = [];
+        for k2=1:length(block),
+            ix_parameters(end+1) = strmatchIQM(block{k2},{param_est.name},'exact');
+        end
+        % Need to reorder each block to match the order of the parameters
+        % in param_est.name. It already has been made sure that they are
+        % sequential.
+        ix_parameters_ordered = sort(ix_parameters,'ascend');
+        % Construct the block text
+        blockText = sprintf('$OMEGA STANDARD CORRELATION BLOCK(%d)\r\n',length(block));
+        blockMatrix = 0.1*ones(length(ix_parameters_ordered));
+        for k=1:length(ix_parameters_ordered),
+            value = IIVvalues0(ix_parameters_ordered(k));
+            if value == 0,
+                value = 0.1;
+            end
+            blockMatrix(k,k) = value; % No need to convert, since in STD
+        end
+        for krow=1:length(block),
+            for kcol=1:krow,
+                if kcol ~= krow,
+                    blockText = sprintf('%s    %1.2g',blockText,blockMatrix(krow,kcol));
+                else
+                    if IIVestimate(ix_parameters_ordered(krow)) == 2,
+                        blockText = sprintf('%s    %1.2g FIX',blockText,blockMatrix(krow,kcol));
+                    else
+                        blockText = sprintf('%s    %1.2g',blockText,blockMatrix(krow,kcol));
+                    end
+                end
+            end
+            blockText = sprintf('%s    ; %d %s',blockText,ix_parameters_ordered(krow),param_est(ix_parameters_ordered(krow)).name);
+            blockText = sprintf('%s\r\n',blockText);
+        end
+        fprintf(fid,'%s\r\n',blockText);
+    end
+    
+    % Finally find the parameters that have not been handled yet by the
+    % block things ...
+    x = strrep(covarianceModel,'{','');
+    x = strrep(x,'}','');
+    terms = explodePCIQM(x);
+    missingParam = setdiff({param_est.name},terms);
+    % These are not in the right order ...
+    ix_parameters = [];
+    for k2=1:length(missingParam),
+        ix_parameters(end+1) = strmatchIQM(missingParam{k2},{param_est.name},'exact');
+    end
+    % Need to reorder according to their appearance in the model
+    % It already has been made sure that they are sequential.
+    ix_parameters_ordered = sort(ix_parameters,'ascend');
+    
+    if ~isempty(missingParam),
+        fprintf(fid,'$OMEGA\r\n');
+    end
+    OMEGA_GUESS0_STRING = {};
+    for k=1:length(missingParam),
+        if IIVestimate(ix_parameters_ordered(k)) == 0,
+            % Set IIV value to 0 and FIX
+            OMEGA_GUESS0_STRING{k} = sprintf('0 STANDARD FIX');
+        elseif IIVestimate(ix_parameters_ordered(k)) == 1,
+            value = IIVvalues0(ix_parameters_ordered(k));
+            if value == 0,
+                value = 0.1;
+            end
+            % Set IIV value
+            OMEGA_GUESS0_STRING{k} = sprintf('%1.2g STANDARD',value); % Need to convert from STD to VAR
+        elseif IIVestimate(ix_parameters_ordered(k)) == 2,
+            % Set IIV value and FIX
+            OMEGA_GUESS0_STRING{k} = sprintf('%1.2g STANDARD FIX',IIVvalues0(ix_parameters_ordered(k))); % Need to convert from STD to VAR
+        end
+    end    
+    for k=1:length(missingParam),
+        fprintf(fid,'    %s%s ; %d %s\r\n',OMEGA_GUESS0_STRING{k},char(32*ones(1,cellmaxlengthIQM(OMEGA_GUESS0_STRING)-length(OMEGA_GUESS0_STRING{k})+1)),ix_parameters_ordered(k),param_est(ix_parameters_ordered(k)).name);
+    end
+end
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $SIGMA
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'$SIGMA\r\n');
+for k=1:length(ms.outputs),
+    fprintf(fid,'    1 FIX\r\n');
+end   
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $ESTIMATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Need to add 'LAPLACIAN NUMERICAL SLOW' as arguments for $EST definitions
+% with INTERACTION if M3 or M4 method handled (CENS_tobehandled=1).
+if CENS_tobehandled==1,
+    addTEXT_INTERACTION = 'LAPLACIAN NUMERICAL SLOW';
+else
+    addTEXT_INTERACTION = '';
+end
+
+if ~isempty(addTEXT_INTERACTION) && strcmp(upper(METHOD),'FO'),
+    error('LLOQ data present and M3 or M4 method used. Please use FOCE, FOCEI, or SAEM but not FO.');
+end
+
+% Check if ITS done as first method
+if ITS,
+    % ITS
+    if strcmp(upper(METHOD),'FO') || strcmp(upper(METHOD),'FOCE'),
+        text = sprintf('$ESTIMATION METHOD=ITS NOINTERACTION %s NOABORT NITER=%d SIGDIGITS=%d PRINT=%d\r\n',addTEXT_INTERACTION,ITS_ITERATIONS,SIGDIGITS,PRINT);
+    else
+        text = sprintf('$ESTIMATION METHOD=ITS INTERACTION %s NOABORT NITER=%d SIGDIGITS=%d PRINT=%d\r\n',addTEXT_INTERACTION,ITS_ITERATIONS,SIGDIGITS,PRINT);
+    end
+    fprintf(fid,'%s\r\n',wrapRowTextIQM(text,80,12));
+end    
+
+% Then the "Main" Method
+if strcmp(upper(METHOD),'FO'),
+    % FO
+    text = sprintf('$ESTIMATION METHOD=ZERO NOINTERACTION NOABORT MAXEVAL=%d CTYPE=4 POSTHOC SIGDIGITS=%d PRINT=%d\r\n',MAXEVAL,SIGDIGITS,PRINT);
+    fprintf(fid,'%s\r\n',wrapRowTextIQM(text,80,12));
+elseif strcmp(upper(METHOD),'FOCE'),
+    % FOCE
+    text = sprintf('$ESTIMATION METHOD=CONDITIONAL NOINTERACTION %s NOABORT MAXEVAL=%d CTYPE=4 POSTHOC SIGDIGITS=%d PRINT=%d\r\n',addTEXT_INTERACTION,MAXEVAL,SIGDIGITS,PRINT);
+    fprintf(fid,'%s\r\n',wrapRowTextIQM(text,80,12));
+elseif strcmp(upper(METHOD),'FOCEI'),
+    % FOCEI
+    text = sprintf('$ESTIMATION METHOD=CONDITIONAL INTERACTION %s NOABORT MAXEVAL=%d CTYPE=4 POSTHOC SIGDIGITS=%d PRINT=%d\r\n',addTEXT_INTERACTION,MAXEVAL,SIGDIGITS,PRINT);
+    fprintf(fid,'%s\r\n',wrapRowTextIQM(text,80,12));
+elseif strcmp(upper(METHOD),'SAEM'),
+    % SAEM
+    text = sprintf('$ESTIMATION METHOD=SAEM INTERACTION %s NOABORT NBURN=%d NITER=%d ISAMPLE=%d CONSTRAIN=1 CTYPE=0 SEED=%d POSTHOC SIGDIGITS=%d PRINT=%d\r\n',addTEXT_INTERACTION,K1,K2,NRCHAINS,SEED,SIGDIGITS,PRINT);
+    fprintf(fid,'%s\r\n',wrapRowTextIQM(text,80,12));
+else
+    error('Unknown estimation method.');
+end
+
+% Then check if importance sampling to be done for objective function evaluation
+if IMPORTANCESAMPLING,
+    text = sprintf('$ESTIMATION METHOD=IMP INTERACTION %s NOABORT EONLY=1 ISAMPLE=1000 NITER=%d MAPITER=0 SIGDIGITS=%d PRINT=%d',addTEXT_INTERACTION,IMP_ITERATIONS,SIGDIGITS,PRINT);
+    fprintf(fid,'%s\r\n',wrapRowTextIQM(text,80,12));
+end
+
+fprintf(fid,'\r\n');
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $COVARIANCE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'$COVARIANCE UNCONDITIONAL MATRIX=S\r\n');
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Define FORMAT for all TABLEs
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORMAT = 's1PG15.6';
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $TABLE similar to predictions.txt in MONOLIX 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if strcmp(METHOD,'FO'),
+    text = sprintf('$TABLE ID TIME TIME2 YTYPE MDV EVID CENS DV IPRED IRES IWRES NPDE NPRED=XPRED  NRES=XRES  NWRES=XWRES  NOPRINT ONEHEADER NOAPPEND FILE=project.pred FORMAT=%s',FORMAT);
+elseif strcmp(METHOD,'FOCE'), 
+    text = sprintf('$TABLE ID TIME TIME2 YTYPE MDV EVID CENS DV IPRED IRES IWRES NPDE NPRED=XPRED  CRES=XRES  CWRES=XWRES  NOPRINT ONEHEADER NOAPPEND FILE=project.pred FORMAT=%s',FORMAT);
+elseif strcmp(METHOD,'FOCEI'),
+    text = sprintf('$TABLE ID TIME TIME2 YTYPE MDV EVID CENS DV IPRED IRES IWRES NPDE CPREDI=XPRED CRESI=XRES CWRESI=XWRES NOPRINT ONEHEADER NOAPPEND FILE=project.pred FORMAT=%s',FORMAT);
+elseif strcmp(METHOD,'SAEM'),
+    text = sprintf('$TABLE ID TIME TIME2 YTYPE MDV EVID CENS DV IPRED IRES IWRES NPDE EPRED=XPRED  ERES=XRES  EWRES=XWRES  NOPRINT ONEHEADER NOAPPEND FILE=project.pred FORMAT=%s ESAMPLE=1000 SEED=%d',FORMAT,SEED);
+else
+    error('Unknown method');
+end
+text = wrapRowTextIQM(text,80,7);
+% Print out table command
+fprintf(fid,'%s\r\n',text);
+fprintf(fid,'\r\n');
+  
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $TABLE similar to indiv_eta.txt in MONOLIX - include all covariates
+% in the dataset
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+text = 'ID';
+for k=1:length(param_est),
+    text = sprintf('%s ETA_%s',text,param_est(k).name);
+end
+% Add covariates
+for k=1:length(covNames),
+    text = sprintf('%s %s',text,covNames{k});
+end
+for k=1:length(catNames),
+    text = sprintf('%s %s',text,catNames{k});
+end
+% Create the full table command
+text = sprintf('$TABLE %s NOPRINT ONEHEADER FIRSTONLY NOAPPEND FILE=project.eta FORMAT=%s',text,FORMAT);
+text = wrapRowTextIQM(text,80,7);
+% Print out table command
+fprintf(fid,'%s\r\n',text);
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $TABLE similar to indiv_parameters.txt in MONOLIX - include all covariates
+% in the dataset - also include the regression parameters
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+text = 'ID';
+for k=1:length(param_est),
+    text = sprintf('%s %s',text,param_est(k).name);
+end
+% Add regression parameters
+for k=1:length(modelInfo.param_reg),
+    text = sprintf('%s %s',text,modelInfo.param_reg(k).name);
+end
+% Add covariates
+for k=1:length(covNames),
+    text = sprintf('%s %s',text,covNames{k});
+end
+for k=1:length(catNames),
+    text = sprintf('%s %s',text,catNames{k});
+end
+% Create the full table command
+text = sprintf('$TABLE %s NOPRINT ONEHEADER FIRSTONLY NOAPPEND FILE=project.indiv FORMAT=%s',text,FORMAT);
+text = wrapRowTextIQM(text,80,7);
+% Print out table command
+fprintf(fid,'%s\r\n',text);
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Close file and change out of project path
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fclose(fid);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Construct PROJECT_HEADER_PLACEHOLDER information
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+PROJECT_INFO_TEXT = '';
+
+% Method
+METHOD_ALL = METHOD;
+if ITS,
+    METHOD_ALL = ['ITS,' METHOD_ALL];
+end
+if IMPORTANCESAMPLING,
+    METHOD_ALL = [METHOD_ALL ',IMP'];
+end
+METHOD_info = sprintf('; METHOD              = ''%s''\r\n',METHOD_ALL);
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,METHOD_info);
+
+% Data location
+DATA_info = sprintf('; DATA                = ''%s''\r\n',strrep(fullfile(dataRelPathFromProject,dataFileName),'\','/'));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,DATA_info);
+
+% DOSINGTYPES
+ds = struct(dosing);
+DOSINGTYPES = {ds.inputs.type};
+x = sprintf('%s,',DOSINGTYPES{:});
+DOSINGTYPES_info = sprintf('; DOSINGTYPES         = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,DOSINGTYPES_info);
+
+% covNames
+x = sprintf('%s,',covNames{:});
+COVNAMES_info = sprintf('; COVNAMES            = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,COVNAMES_info);
+
+% catNames
+x = sprintf('%s,',catNames{:});
+CATNAMES_info = sprintf('; CATNAMES            = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,CATNAMES_info);
+
+% Regression parameters
+x = sprintf('%s,',modelInfo.param_reg.name);
+REGRESSNAMES_info = sprintf('; REGRESSIONNAMES     = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,REGRESSNAMES_info);
+
+% Outputs
+x = cell(1,length(modelInfo.outputs));
+for k=1:length(modelInfo.outputs),
+    on = eval(strrep(modelInfo.outputs(k).name,'OUTPUT',''));
+    x{on} = modelInfo.outputs(k).formula;
+end
+y = '';
+for k=1:length(x),
+    y = sprintf('%s%s,',y,x{k});
+end
+y = y(1:end-1);
+OUTPUTS_info = sprintf('; OUTPUTS             = ''%s''\r\n',y);
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,OUTPUTS_info);
+
+% Error models
+ERRORMODELS_info = sprintf('; ERRORMODELS         = ''%s''\r\n',errorModels);
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,ERRORMODELS_info);
+
+% ERRORNAMES
+x = sprintf('%s,',output_parameters_project_info{:});
+ERRORNAMES_info = sprintf('; ERRORNAMES          = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,ERRORNAMES_info);
+
+% PARAMNAMES
+x = sprintf('%s,',param_est.name);
+PARAMNAMES_info = sprintf('; PARAMNAMES          = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,PARAMNAMES_info);
+
+% PARAMTRANS
+x = sprintf('%s,',PARAM_TRANSNAME_STRING{:});
+PARAMTRANS_info = sprintf('; PARAMTRANS          = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,PARAMTRANS_info);
+
+% PARAMINVTRANS
+x = sprintf('%s,',PARAM_INVTRANSNAME_STRING{:});
+PARAMINVTRANS_info = sprintf('; PARAMINVTRANS       = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,PARAMINVTRANS_info);
+
+% COVARIATENAMES
+COVARIATENAMES = [covariateMedianNames,covariateCATNames];
+x = sprintf('%s,',COVARIATENAMES{:});
+COVARIATENAMES_info = sprintf('; COVARIATENAMES      = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,COVARIATENAMES_info);
+
+% COVARIATESUSED
+COVARIATESUSED = setdiff(explodePCIQM(strrep(strrep(options.covariateModel,'{',''),'}','')),{param_est.name});
+x = sprintf('%s,',COVARIATESUSED{:});
+COVARIATESUSED_info = sprintf('; COVARIATESUSED      = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,COVARIATESUSED_info);
+
+% BETACOVNAMES
+x = sprintf('%s,',beta_parameters_cov_project_info{:});
+BETACOVNAMES_info = sprintf('; BETACOVNAMES        = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,BETACOVNAMES_info);
+
+% BETACOVTRANS
+x = sprintf('%s,',COV_transformation_info{:});
+BETACOVTRANS_info = sprintf('; BETACOVTRANS        = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,BETACOVTRANS_info);
+
+% BETACATNAMES
+x = sprintf('%s,',beta_parameters_cat_project_info{:});
+BETACATNAMES_info = sprintf('; BETACATNAMES        = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,BETACATNAMES_info);
+
+% BETACATREFERENCE
+x = ''; for k=1:length(CAT_reference_info), x=sprintf('%s%g,',x,CAT_reference_info{k}); end
+BETACATREFERENCE_info = sprintf('; BETACATREFERENCE    = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,BETACATREFERENCE_info);
+
+% BETACATCATEGORIES
+x = ''; 
+for k=1:length(CAT_categories_info), 
+    x = [x '['];
+    x2 = '';
+    x2 = sprintf('%d ',CAT_categories_info{k});
+    x = [x x2(1:end-1) '],'];
+end
+BETACATCATEGORIES_info = sprintf('; BETACATCATEGORIES   = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,BETACATCATEGORIES_info);
+
+% ALL THETANAMES
+x = [{param_est.name} beta_parameters output_parameters_project_info];
+y = sprintf('%s,',x{:});
+THETANAMES_info = sprintf('; THETANAMES          = ''%s''\r\n',y(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,THETANAMES_info);
+
+% THETAESTIMATE
+% Add theta for parameters
+PARAM_info = sprintf('%d,',POPestimate);
+% Add theta for covariates
+COVCAT_info = sprintf('%d,',COVCATestimate_info);
+if isempty(COVCATestimate_info),
+    COVCAT_info = [];
+end
+% Add theta for error models
+x = ones(1,length(output_parameters_project_info));
+ERROR_info = sprintf('%d,',x);
+% Combine
+ESTIMATE_info = strtrim([PARAM_info COVCAT_info ERROR_info]);
+% Create text
+THETAESTIMATE_info = sprintf('; THETAESTIMATE       = ''%s''\r\n',ESTIMATE_info(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,THETAESTIMATE_info);
+
+% ALL ETANAMES (should be same as PARAMNAMES)
+x = sprintf('omega(%s),',param_est.name);
+ETANAMES_info = sprintf('; ETANAMES            = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,ETANAMES_info);
+
+% ETAESTIMATE
+ETAESTIMATE = sprintf('%d,',IIVestimate); 
+ETAESTIMATE_info = sprintf('; ETAESTIMATE         = ''%s''\r\n',ETAESTIMATE(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,ETAESTIMATE_info);
+
+% ALL CORRNAMES 
+cov = explodePCIQM(covarianceModel,',','{','}');
+text = '';
+for k=1:length(cov),
+    covk = strrep(strrep(cov{k},'{',''),'}','');
+    covk = explodePCIQM(covk);
+    for k1=1:length(covk),
+        for k2=1:k1,
+            if k1~=k2,
+                text = sprintf('%scorr(%s,%s),',text,covk{k2},covk{k1});
+            end
+        end
+    end
+end
+CORR_info = sprintf('; CORRELATIONNAMES    = ''%s''\r\n',text(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,CORR_info);
+
+% CORRESTIMATE
+if ~isempty(text),
+    CORRestimate = ones(1,length(explodePCIQM(text(1:end-1))));
+    x = sprintf('%d,',CORRestimate); 
+    CORRESTIMATE_info = sprintf('; CORRESTIMATE        = ''%s''\r\n',x(1:end-1));
+else
+    CORRestimate = 0;
+    CORRESTIMATE_info = sprintf('; CORRESTIMATE        = ''''\r\n');
+end
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,CORRESTIMATE_info);
+
+% Get and store number of observations in the data
+% Remove MDV=1 records
+x = dataCSV(dataCSV.MDV==0,:);
+% Remove CMT>nrOUTPUTS or YTYPE>nrOUTPUT
+nrOUTPUTS = length(length(modelInfo.outputs));
+if FLAG_CMT,
+    x(x.CMT > nrOUTPUTS,:) = [];
+else
+    x(x.YTYPE > nrOUTPUTS,:) = [];
+end
+% Write out number of observations
+nOBS = height(x);
+NROBS_info = sprintf('; NROBSERVATIONS      = ''%d''\r\n',nOBS);
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,NROBS_info);
+
+% Determine the number of estimated parameters (THETA and ETA)
+NRPARAMETERS_ESTIMATED = sum(eval(['[' ESTIMATE_info(1:end-1) ']']))+sum(eval(['[' ETAESTIMATE(1:end-1) ']'])==1)+sum(CORRestimate);
+NRPARAMETERS_ESTIMATED_info = sprintf('; NRPARAM_ESTIMATED   = ''%d''\r\n',NRPARAMETERS_ESTIMATED);
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,NRPARAMETERS_ESTIMATED_info);
+
+% Info about residual names depending on the selected method
+RESIDUAL_NAMES_USED = sprintf('; RESIDUAL_NAMES_USED = ''XPRED,XRES,XWRES''\r\n');
+if strcmp(METHOD,'FO'),
+    RESIDUAL_NAMES_ORIG = sprintf('; RESIDUAL_NAMES_ORIG = ''NPRED,NRES,NWRES''\r\n');
+elseif strcmp(METHOD,'FOCE'), 
+    RESIDUAL_NAMES_ORIG = sprintf('; RESIDUAL_NAMES_ORIG = ''NPRED,CRES,CWRES''\r\n');
+elseif strcmp(METHOD,'FOCEI'),
+    RESIDUAL_NAMES_ORIG = sprintf('; RESIDUAL_NAMES_ORIG = ''CPREDI,CRESI,CWRESI''\r\n');
+elseif strcmp(METHOD,'SAEM'),
+    RESIDUAL_NAMES_ORIG = sprintf('; RESIDUAL_NAMES_ORIG = ''EPRED,ERES,EWRES''\r\n');
+end
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,RESIDUAL_NAMES_USED);
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,RESIDUAL_NAMES_ORIG);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Replace PROJECT_HEADER_PLACEHOLDER and 
+% "$SIZES LTH=XXX"
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+content = fileread('project.nmctl');
+content = strrep(content,'PROJECT_HEADER_PLACEHOLDER',strtrim(PROJECT_INFO_TEXT));
+x = [{param_est.name} beta_parameters output_parameters_project_info]; % get theta names
+content = strrep(content,'$SIZES LTH=XXX',sprintf('$SIZES LTH=%d',length(x)));
+fid = fopen('project.nmctl','w');
+fprintf(fid,'%s',content);
+fclose(fid);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Go back to old path
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+cd(oldpath);
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/IQMcreateNONMEMresultsTable.m b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/IQMcreateNONMEMresultsTable.m
new file mode 100644
index 0000000000000000000000000000000000000000..c610f0975d0edb814134d7a734ba45718277359e
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/IQMcreateNONMEMresultsTable.m	
@@ -0,0 +1,389 @@
+function [] = IQMcreateNONMEMresultsTable(projectPath)
+% Parses the results of a NONMEM run and reports
+% them in a similar manner as in the MONOLIX pop_parameters.txt file.
+%
+% The function saves a text file version in the projectPath/RESULTS
+% folder. Additionally, the result is shown in the command window.
+%
+% [SYNTAX]
+% [] = IQMcreateNONMEMresultsTable(projectPath)
+%
+% [INPUT]
+% projectPath:      Path to the project.nmctl NONMEM project file
+%
+% [OUTPUT]
+% project_results.txt file in the RESULTS folder.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% parse the results
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+x = parseNONMEMresultsIQM(projectPath);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Start output text
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+OUTPUT = '';
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Print the header
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+OUTPUT  = sprintf('%s========================================================================================================\n',OUTPUT);
+OUTPUT  = sprintf('%s    Summary results\n',OUTPUT);
+[xdummyx,project] = fileparts(x.path);
+OUTPUT  = sprintf('%s    Project: %s\n',OUTPUT,project);
+OUTPUT  = sprintf('%s========================================================================================================\n',OUTPUT);
+OUTPUT  = sprintf('%s\n',OUTPUT);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Print termination information
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(x.termination_info),
+    OUTPUT = sprintf('%s--------------------------------------------------------------------------------------------------------\n',OUTPUT);
+    method = sprintf('%s,',x.PROJECTINFO.METHOD{:});
+    OUTPUT = sprintf('%sTermination information (Method(s): %s)\n',OUTPUT,method(1:end-1));
+    OUTPUT = sprintf('%s--------------------------------------------------------------------------------------------------------\n',OUTPUT);
+    for k=1:length(x.termination_info),
+        OUTPUT = sprintf('%s%s\n',OUTPUT,x.termination_info{k});
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check if major problems with the fit
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isnan(x.objectivefunction.OBJ),
+    OUTPUT = sprintf('%sMajor problems with the project results. Please check!\n',OUTPUT);
+    % Save the text
+    filename = sprintf('%s/RESULTS/project_results.txt',projectPath);
+    IQMwriteText2File(OUTPUT,filename);
+    % Print out in command window
+    disp(OUTPUT)    
+    return
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Print the fixed effects (still transformed)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+OUTPUT = sprintf('%s--------------------------------------------------------------------------------------------------------\n',OUTPUT);
+OUTPUT  = sprintf('%sName                           Value          stderr         RSE (%%)          95%%CI\n',OUTPUT);
+OUTPUT = sprintf('%s--------------------------------------------------------------------------------------------------------\n',OUTPUT);
+fe = x.rawParameterInfo.fixedEffects;
+names = {};
+values = {};
+stderrs = {};
+RSEs = {};
+for k=1:length(fe.names)
+    % Names
+    if strcmp(fe.trans{k},'(phi)'),
+        names{k} = fe.names{k};
+    elseif strcmp(fe.trans{k},'exp(phi)'),
+        names{k} = ['log(' fe.names{k} ')'];
+    elseif strcmp(fe.trans{k},'exp(phi)./(1+exp(phi))'),
+        names{k} = ['logit(' fe.names{k} ')'];
+    else
+        error('Unknown transformation');
+    end
+    % Values
+    if fe.estimated(k)==1,
+        values{k} = sprintf('%1.4g',fe.values(k));
+        stderrs{k} = sprintf('%1.4g',fe.stderr(k));
+        RSEs{k} = sprintf('%1.4g',fe.rse(k));
+    else
+        values{k} = sprintf('%1.4g (FIX)',fe.values(k));
+        stderrs{k} = '-';
+        RSEs{k} = '-';
+    end
+end
+for k=1:length(names),
+    text = sprintf('%s%s%s%s\n',postFillCharIQM(names{k},20,' '),...
+        preFillCharIQM(values{k},16,' '), ...
+        preFillCharIQM(stderrs{k},16,' '), ...
+        preFillCharIQM(RSEs{k},16,' '));
+    OUTPUT = sprintf('%s%s',OUTPUT,text);
+end
+OUTPUT  = sprintf('%s\n',OUTPUT);
+    
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Print the fixed effects (back transformed)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fe = x.rawParameterInfo.fixedEffects;
+names = {};
+values = {};
+stderrs = {};
+RSEs = {};
+for k=1:length(fe.names)
+    % Names
+    names{k} = fe.names{k};
+    % Value
+    phi = fe.values(k);
+    value = eval(fe.trans{k});
+    % sample standard error
+    if fe.stderr(k)==0,
+        stderr = 0;
+    else
+        phi = fe.values(k)+fe.stderr(k)*randn(1,100000);
+        stderr = std(eval(fe.trans{k}));
+    end
+    
+    % Values
+    if fe.estimated(k)==1,
+        values{k} = sprintf('%1.4g',value);
+        rse = sprintf('%1.4g*',100*stderr/value);
+        stderr = sprintf('%1.4g*',stderr);
+    else
+        values{k} = sprintf('%1.4g (FIX)',value);
+        stderr = '-';
+        rse = '-';
+    end        
+    
+    % Stderrs
+    stderrs{k} = stderr;
+    % RSEs
+    RSEs{k} = rse;
+end
+for k=1:length(names),
+    text = sprintf('%s%s%s%s\n',postFillCharIQM(names{k},20,' '),...
+        preFillCharIQM(values{k},16,' '), ...
+        preFillCharIQM(stderrs{k},16,' '), ...
+        preFillCharIQM(RSEs{k},16,' '));
+    OUTPUT = sprintf('%s%s',OUTPUT,text);
+end
+OUTPUT  = sprintf('%s                                    (*approximation by sampling)\n',OUTPUT);
+OUTPUT  = sprintf('%s\n',OUTPUT);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Print the covariates
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fe = x.rawParameterInfo.covariate;
+names = {};
+values = {};
+stderrs = {};
+RSEs = {};
+CI = {};
+for k=1:length(fe.names)
+    names{k} = fe.names{k};
+    if fe.estimated(k) 
+        values{k} = sprintf('%1.4g',fe.values(k));
+        stderrs{k} = sprintf('%1.4g',fe.stderr(k));
+        RSEs{k} = sprintf('%1.4g',fe.rse(k));
+        CI{k} = sprintf('[%1.2f %1.2f]',fe.values(k)-1.96*fe.stderr(k),fe.values(k)+1.96*fe.stderr(k));
+    else
+        % Not estimated
+        values{k} = sprintf('%1.4g (FIX)',fe.values(k));
+        stderrs{k} = '-';
+        RSEs{k} = '-';
+        CI{k} = '-';
+    end
+end
+for k=1:length(names),
+    text = sprintf('%s%s%s%s%s\n',postFillCharIQM(names{k},20,' '),...
+        preFillCharIQM(values{k},16,' '), ...
+        preFillCharIQM(stderrs{k},16,' '), ...
+        preFillCharIQM(RSEs{k},16,' '), ...
+        preFillCharIQM(CI{k},30,' '));
+    OUTPUT = sprintf('%s%s',OUTPUT,text);
+end
+if length(fe.names) > 0,
+    OUTPUT  = sprintf('%s\n',OUTPUT);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Print the random effects
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fe = x.rawParameterInfo.randomEffects;
+names = {};
+values = {};
+stderrs = {};
+RSEs = {};
+for k=1:length(fe.names)
+    names{k} = fe.names{k};
+    if fe.estimated(k) == 1,
+        % Really estimated
+        values{k} = sprintf('%1.4g',fe.values(k));
+        stderrs{k} = sprintf('%1.4g',fe.stderr(k));
+        RSEs{k} = sprintf('%1.4g',fe.rse(k));
+    else
+        values{k} = sprintf('%1.4g (FIX)',fe.values(k));
+        stderrs{k} = '-';
+        RSEs{k} = '-';
+    end
+end
+for k=1:length(names),
+    text = sprintf('%s%s%s%s\n',postFillCharIQM(names{k},20,' '),...
+        preFillCharIQM(values{k},16,' '), ...
+        preFillCharIQM(stderrs{k},16,' '), ...
+        preFillCharIQM(RSEs{k},16,' '));
+    OUTPUT = sprintf('%s%s',OUTPUT,text);
+end
+if length(fe.names) > 0,
+    OUTPUT  = sprintf('%s\n',OUTPUT);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Print the correlations
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(x.rawParameterInfo.correlation.names),
+    fe = x.rawParameterInfo.correlation;
+    names = {};
+    values = {};
+    stderrs = {};
+    RSEs = {};
+    CI = {};
+    for k=1:length(fe.names)
+        names{k} = fe.names{k};
+        % Always estimated
+        values{k} = sprintf('%1.4g',fe.values(k));
+        stderrs{k} = sprintf('%1.4g',fe.stderr(k));
+        RSEs{k} = sprintf('%1.4g',fe.rse(k));
+        CI{k} = sprintf('[%1.2f %1.2f]',fe.values(k)-1.96*fe.stderr(k),fe.values(k)+1.96*fe.stderr(k));
+    end
+    for k=1:length(names),
+        text = sprintf('%s%s%s%s%s\n',postFillCharIQM(names{k},20,' '),...
+            preFillCharIQM(values{k},16,' '), ...
+            preFillCharIQM(stderrs{k},16,' '), ...
+            preFillCharIQM(RSEs{k},16,' '), ...
+            preFillCharIQM(CI{k},30,' '));
+        OUTPUT = sprintf('%s%s',OUTPUT,text);
+    end
+    OUTPUT  = sprintf('%s\n',OUTPUT);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Print the errors
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fe = x.rawParameterInfo.errorParameter;
+names = {};
+values = {};
+stderrs = {};
+RSEs = {};
+for k=1:length(fe.names)
+    names{k} = fe.names{k};
+    if fe.estimated(k) == 1,
+        values{k} = sprintf('%1.4g',fe.values(k));
+        stderrs{k} = sprintf('%1.4g',fe.stderr(k));
+        RSEs{k} = sprintf('%1.4g',fe.rse(k));
+    else
+        values{k} = sprintf('%1.4g (FIX)',fe.values(k));
+        stderrs{k} = '-';
+        RSEs{k} = '-';
+    end
+end
+for k=1:length(names),
+    text = sprintf('%s%s%s%s\n',postFillCharIQM(names{k},20,' '),...
+        preFillCharIQM(values{k},16,' '), ...
+        preFillCharIQM(stderrs{k},16,' '), ...
+        preFillCharIQM(RSEs{k},16,' '));
+    OUTPUT = sprintf('%s%s',OUTPUT,text);
+end
+OUTPUT  = sprintf('%s\n',OUTPUT);
+
+
+if ~isempty(x.parameters.correlationmatrix),
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Correlation fE and beta
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    OUTPUT = sprintf('%s--------------------------------------------------------------------------------------------------------\n',OUTPUT);
+    OUTPUT = sprintf('%sCorrelation of fixed effects and covariate coefficients\n',OUTPUT);
+    OUTPUT = sprintf('%s--------------------------------------------------------------------------------------------------------\n',OUTPUT);
+    names = [x.rawParameterInfo.fixedEffects.names x.rawParameterInfo.covariate.names];
+    ix_all = [];
+    for k=1:length(names),
+        ix_all(k) = strmatchIQM(names{k},x.parameters.names,'exact');
+    end
+    cor = x.parameters.correlationmatrix(ix_all,ix_all);
+    for row=1:length(cor),
+        rowtext = postFillCharIQM(names{row},18,' ');
+        for col=1:row,
+            rowtext = sprintf('%s%s',rowtext,preFillCharIQM(sprintf('%1.2g',0.01*round(100*cor(row,col))),7,' '));
+        end
+        OUTPUT = sprintf('%s%s\n',OUTPUT,rowtext);
+    end
+    OUTPUT  = sprintf('%s\n',OUTPUT);
+    eigM    = eig(cor);
+    eigMmin = min(eigM);
+    eigMmax = max(eigM);
+    OUTPUT  = sprintf('%sEigenvalues (min, max, max/min): %1.2f  %1.2f  %1.2f\n',OUTPUT,eigMmin,eigMmax,eigMmax/eigMmin);
+    OUTPUT  = sprintf('%s\n',OUTPUT);
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Correlation of omegas and error parameters
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    OUTPUT = sprintf('%s--------------------------------------------------------------------------------------------------------\n',OUTPUT);
+    OUTPUT = sprintf('%sCorrelation of random effects (variances) and error parameters\n',OUTPUT);
+    OUTPUT = sprintf('%s--------------------------------------------------------------------------------------------------------\n',OUTPUT);
+    names = [strrep(x.rawParameterInfo.randomEffects.names,'omega','omega2') x.rawParameterInfo.errorParameter.names];
+    ix_all = [];
+    for k=1:length(names),
+        ix_all(k) = strmatchIQM(names{k},x.parameters.names,'exact');
+    end
+    cor = x.parameters.correlationmatrix(ix_all,ix_all);
+    for row=1:length(cor),
+        rowtext = postFillCharIQM(names{row},18,' ');
+        for col=1:row,
+            rowtext = sprintf('%s%s',rowtext,preFillCharIQM(sprintf('%1.2g',0.01*round(100*cor(row,col))),7,' '));
+        end
+        OUTPUT = sprintf('%s%s\n',OUTPUT,rowtext);
+    end
+    OUTPUT  = sprintf('%s\n',OUTPUT);
+    eigM    = eig(cor);
+    eigMmin = min(eigM);
+    eigMmax = max(eigM);
+    OUTPUT  = sprintf('%sEigenvalues (min, max, max/min): %1.2f  %1.2f  %1.2f\n',OUTPUT,eigMmin,eigMmax,eigMmax/eigMmin);
+    OUTPUT  = sprintf('%s\n',OUTPUT);
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Correlation of correlations
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    names = [strrep(x.rawParameterInfo.correlation.names,'corr(','omega2(')];
+    if length(names) > 1,
+        OUTPUT = sprintf('%s--------------------------------------------------------------------------------------------------------\n',OUTPUT);
+        OUTPUT = sprintf('%sCorrelation of random effect covariances\n',OUTPUT);
+        OUTPUT = sprintf('%s--------------------------------------------------------------------------------------------------------\n',OUTPUT);
+        ix_all = [];
+        for k=1:length(names),
+            ix_all(k) = strmatchIQM(names{k},x.parameters.names);
+        end
+        cor = x.parameters.correlationmatrix(ix_all,ix_all);
+        for row=1:length(cor),
+            rowtext = postFillCharIQM(names{row},18,' ');
+            for col=1:row,
+                rowtext = sprintf('%s%s',rowtext,preFillCharIQM(sprintf('%1.2g',0.01*round(100*cor(row,col))),7,' '));
+            end
+            OUTPUT = sprintf('%s%s\n',OUTPUT,rowtext);
+        end
+        OUTPUT  = sprintf('%s\n',OUTPUT);
+        eigM    = eig(cor);
+        eigMmin = min(eigM);
+        eigMmax = max(eigM);
+        OUTPUT  = sprintf('%sEigenvalues (min, max, max/min): %1.2f  %1.2f  %1.2f\n',OUTPUT,eigMmin,eigMmax,eigMmax/eigMmin);
+        OUTPUT  = sprintf('%s\n',OUTPUT);
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Print the OFV / AIC / BIC
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+OUTPUT = sprintf('%s--------------------------------------------------------------------------------------------------------\n',OUTPUT);
+METHOD = x.PROJECTINFO.METHOD{end};
+OUTPUT = sprintf('%sObjective function (%s)\n',OUTPUT,METHOD);
+if strcmp(METHOD,'SAEM'),
+    OUTPUT = sprintf('%sThe SAEM objective function should not be used for statistical testing.\n',OUTPUT);
+    OUTPUT = sprintf('%sPlease consider the use of the IMPORTANCESAMPLING option!\n',OUTPUT);
+end
+OUTPUT = sprintf('%s--------------------------------------------------------------------------------------------------------\n',OUTPUT);
+OUTPUT = sprintf('%sOFV:    %g\n',OUTPUT,x.objectivefunction.OBJ);
+OUTPUT = sprintf('%sAIC:    %g\n',OUTPUT,x.objectivefunction.AIC);
+OUTPUT = sprintf('%sBIC:    %g\n',OUTPUT,x.objectivefunction.BIC);
+OUTPUT  = sprintf('%s\n',OUTPUT);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Save the text
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+filename = sprintf('%s/RESULTS/project_results.txt',projectPath);
+IQMwriteText2File(OUTPUT,filename);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Print out in command window
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+disp(OUTPUT)
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/IQMplotConvergenceNONMEM.m b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/IQMplotConvergenceNONMEM.m
new file mode 100644
index 0000000000000000000000000000000000000000..1abb4e1b73a5110a82d206b0a56839b0fe1f6b0a
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/IQMplotConvergenceNONMEM.m	
@@ -0,0 +1,328 @@
+function [] = IQMplotConvergenceNONMEM(projectPath)
+% Plots the convergence plots for NONMEM
+% Assumes that NONMEM >=7.2 has been used - might be same for later
+% versions. Function can be used when run is still executed or afterwards
+% when cleanup is done and result files have been moved to the RESULTS
+% folder. If several estimation methods where concatenated, then for each
+% method a plot wil be done.
+%
+% The function also saves the convergence plots in the projectPath/RESULTS
+% folder. If several methods present, then for each a figure will be saved.
+% Figures will only be printed if project.ext file in the RESULTS folder! 
+%
+% [SYNTAX]
+% [] = IQMplotConvergenceNONMEM(projectPath)
+%
+% [INPUT]
+% projectPath:      Path to the project.nmctl NONMEM project file
+%
+% [OUTPUT]
+% Saving the plot in the project/RESULTS folder.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Load the project information to get parameter names etc.
+projectinfo = parseNONMEMprojectHeaderIQM(projectPath);
+
+THETANAMES      = strrep(strrep(strrep(projectinfo.THETANAMES,'(','_'),')','_'),',','_');
+ETANAMES        = strrep(strrep(strrep(projectinfo.ETANAMES,'(','_'),')','_'),',','_');
+BETACATNAMES    = strrep(strrep(strrep(projectinfo.BETACATNAMES,'(','_'),')','_'),',','_');
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check if METHOD more than one ...
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for nrTable=1:length(projectinfo.METHOD),
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Check if project.ext in project or in RESULTS folder
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    PRINT = 0;
+    if exist([projectPath '/project.ext']),
+        x = getTableNnonmemOutputIQM([projectPath '/project.ext'],nrTable);
+    elseif exist([projectPath '/RESULTS/project.ext']),
+        x = getTableNnonmemOutputIQM([projectPath '/RESULTS/project.ext'],nrTable);
+        PRINT = 1;
+    else
+        error('project.ext file could not be found.');
+    end
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Remove the negative ITERATIONs at the end
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    x(x.ITERATION<-100000000,:) = [];
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Remove all 0 elements
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    x(:,find(sum(abs(table2array(x))) == 0)) = [];
+
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Remove all elements which are not changing
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    x(:,find(var(table2array(x)) < 100*eps)) = [];
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Split data into ITERATION, THETA, OBJ, OMEGA
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    header          = x.Properties.VariableNames;
+    % Get ITERATIONs
+    xITERATION      = x(:,strmatch('ITERATION',header));
+    % Get THETAs
+    xTHETA          = x(:,strmatchIQM('THETA',header));
+    % Get OMEGAs
+    xOMEGA          = x(:,strmatchIQM('OMEGA',header));
+    % Get OBJs
+    xOBJ            = x(:,end);
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Calculate standard deviation and correlation from OMEGAs
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    xSTDCORR = table();
+    h = strrep(strrep(xOMEGA.Properties.VariableNames,'OMEGA',''),'_',',');
+    h2 = xOMEGA.Properties.VariableNames;
+    % Convert first the variances
+    for k=1:length(h),
+        rc = explodePCIQM(h{k}(2:end-1));
+        r = eval(rc{1});
+        c = eval(rc{2});
+        if r==c,
+            xSTDCORR.(sprintf('%s',ETANAMES{r})) = sqrt(table2array(xOMEGA(:,k)));
+        end
+    end
+    % Then do the correlations
+    for k=1:length(h),
+        rc = explodePCIQM(h{k}(2:end-1));
+        r = eval(rc{1});
+        c = eval(rc{2});
+        if r~=c,
+            covariance = xOMEGA(:,k);
+            variance1  = xOMEGA.(sprintf('OMEGA_%d_%d_',r,r));
+            variance2  = xOMEGA.(sprintf('OMEGA_%d_%d_',c,c));
+            correlation = table2array(xOMEGA(:,k))./sqrt(variance1.*variance2);
+            xSTDCORR.(sprintf('corr_%s_%s',ETANAMES{c},ETANAMES{r})) = correlation;
+        end
+    end
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Split xSTDCORR into diagonal and off-diagonal
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    h = xSTDCORR.Properties.VariableNames;
+    ixSTD = strmatchIQM('omega',h);
+    ixCORR = strmatchIQM('corr',h);
+    xSTANDARD = xSTDCORR(:,ixSTD);
+    xCORR = xSTDCORR(:,ixCORR);
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Rename THETAs
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    header = xTHETA.Properties.VariableNames;
+    theta_name_indices = [];
+    for k=1:length(header),
+        theta_name_indices(end+1) = eval(strrep(header{k},'THETA',''));
+    end
+    xTHETA.Properties.VariableNames = THETANAMES(theta_name_indices);
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Split of beta and betacat from theta
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    header = xTHETA.Properties.VariableNames;
+    ixbeta = strmatchIQM('beta_',header);
+    xBETA = xTHETA(:,ixbeta);
+    xTHETA(:,ixbeta) = [];
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Split of beta cont and cat
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    xBETA_cat = {};
+    xBETA_cov = xBETA;
+    header = xBETA.Properties.VariableNames;
+    ixcovremove = [];
+    for k=1:length(BETACATNAMES),
+        if ~isempty(BETACATNAMES{k}),
+            ix = strmatch(BETACATNAMES{k},header);
+            xBETA_cat{end+1} = xBETA(:,ix);
+            ixcovremove = [ixcovremove; ix(:)];
+        end
+    end
+    xBETA_cov(:,ixcovremove) = [];
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Split of ERROR from theta
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    header = xTHETA.Properties.VariableNames;
+    ixerror = strmatchIQM('error_',header);
+    xERROR = xTHETA(:,ixerror);
+    xTHETA(:,ixerror) = [];
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Determine needed subplots
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    nTHETA      = size(xTHETA,2);
+    nBETAcov    = size(xBETA_cov,2);
+    nBETAcat    = length(BETACATNAMES);
+    if isempty(BETACATNAMES{1}),
+        nBETAcat = 0;
+    end
+    nSTD        = size(xSTANDARD,2);
+    nCORR       = double(~isempty(xCORR));
+    nERROR      = size(xERROR,2);
+    nOBJ        = 1;
+    nTotal      = nTHETA+nBETAcov+nBETAcat+nSTD+nCORR+nERROR+nOBJ;
+    nrows       = ceil(sqrt(nTotal));
+    ncols       = ceil(nTotal/nrows);
+    
+    % If method is IMP then only OFV is determined, so set nrows and ncols to 1
+    if strcmp(projectinfo.METHOD{nrTable},'IMP'),
+        nrows = 1;
+        ncols = 1;
+        nCORR = 0;
+        nTHETA = 0;
+        nBETAcov = 0;
+        nBETAcat = 0;
+        nTotal = 1;
+    end
+    
+    figure(nrTable); clf
+    colors      = IQMgetcolors();
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Plot THETAs
+    % And first backtransform them
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    h = xTHETA.Properties.VariableNames;
+    for k=1:size(xTHETA,2),
+        phi = table2array(xTHETA(:,k));
+        param = h{k};
+        ixparam = strmatchIQM(param,projectinfo.PARAMNAMES,'exact');
+        % do inverse trans
+        value = eval(projectinfo.PARAMTRANS{ixparam});
+        % plot
+        subplot(nrows,ncols,k);
+        plot(table2array(xITERATION),value,'-','Color',colors(1,:),'LineWidth',2);
+        grid on;
+        title([h{k} ' (' projectinfo.METHOD{nrTable} ')'],'Interpreter','None','FontWeight','bold','FontSize',8)
+        hold on;
+        set(gca,'YLim',get(gca,'YLim'))
+        set(gca,'XLim',[min(xITERATION.ITERATION) max(xITERATION.ITERATION)])
+%         set(gca,'XTick',[]);
+        YLim = get(gca,'YLim');
+        set(gca,'YTick',linspace(YLim(1),YLim(2),5));
+        plot([0 0],get(gca,'YLim'),'k-')
+    end
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Plot BETAcovs
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    h = xBETA_cov.Properties.VariableNames;
+    for k=1:size(xBETA_cov,2),
+        subplot(nrows,ncols,k+nTHETA);
+        plot(table2array(xITERATION),table2array(xBETA_cov(:,k)),'-','Color',colors(2,:),'LineWidth',2);
+        grid on;
+        title([h{k} ' (' projectinfo.METHOD{nrTable} ')'],'Interpreter','None','FontWeight','bold','FontSize',8)
+        hold on;
+        set(gca,'YLim',get(gca,'YLim'))
+        set(gca,'XLim',[min(xITERATION.ITERATION) max(xITERATION.ITERATION)])
+%         set(gca,'XTick',[]);
+        YLim = get(gca,'YLim');
+        set(gca,'YTick',linspace(YLim(1),YLim(2),5));
+        plot([0 0],get(gca,'YLim'),'k-')
+    end
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Plot BETAcats
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    for k=1:length(xBETA_cat),
+        if ~isempty(xBETA_cat{k}),
+            subplot(nrows,ncols,k+nTHETA+nBETAcov);
+            plot(table2array(xITERATION),table2array(xBETA_cat{k}),'-','LineWidth',2);
+            grid on;
+            title([BETACATNAMES{k} ' (' projectinfo.METHOD{nrTable} ')'],'Interpreter','None','FontWeight','bold','FontSize',8)
+            hold on;
+            set(gca,'YLim',get(gca,'YLim'))
+            set(gca,'XLim',[min(xITERATION.ITERATION) max(xITERATION.ITERATION)])
+%             set(gca,'XTick',[]);
+            YLim = get(gca,'YLim');
+            set(gca,'YTick',linspace(YLim(1),YLim(2),5));
+            plot([0 0],get(gca,'YLim'),'k-')
+        end
+    end
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Plot OMEGAs (STDs)
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    h = xSTANDARD.Properties.VariableNames;
+    for k=1:size(xSTANDARD,2),
+        subplot(nrows,ncols,k+nTHETA+nBETAcov+nBETAcat);
+        plot(table2array(xITERATION),table2array(xSTANDARD(:,k)),'-','Color',colors(4,:),'LineWidth',2);
+        grid on;
+        title([h{k} ' (' projectinfo.METHOD{nrTable} ')'],'Interpreter','None','FontWeight','bold','FontSize',8)
+        hold on;
+        set(gca,'YLim',get(gca,'YLim'))
+        set(gca,'XLim',[min(xITERATION.ITERATION) max(xITERATION.ITERATION)])
+%         set(gca,'XTick',[]);
+        YLim = get(gca,'YLim');
+        set(gca,'YTick',linspace(YLim(1),YLim(2),5));
+        plot([0 0],get(gca,'YLim'),'k-')
+    end
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Plot CORRs
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    if ~isempty(xCORR)
+        subplot(nrows,ncols,nCORR+nTHETA+nBETAcov+nBETAcat+nSTD);
+        plot(table2array(xITERATION),table2array(xCORR),'-','LineWidth',2);
+        grid on;
+        title('IIV Correlations','Interpreter','None','FontWeight','bold','FontSize',8)
+        hold on;
+        set(gca,'YLim',get(gca,'YLim'))
+        plot([0 0],get(gca,'YLim'),'k-')
+        set(gca,'XLim',[min(xITERATION.ITERATION) max(xITERATION.ITERATION)])
+%         set(gca,'XTick',[]);
+        YLim = get(gca,'YLim');
+        set(gca,'YTick',linspace(YLim(1),YLim(2),5));
+    end
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Plot ERRORs
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    h = xERROR.Properties.VariableNames;
+    for k=1:size(xERROR,2),
+        subplot(nrows,ncols,k+nCORR+nTHETA+nBETAcov+nBETAcat+nSTD);
+        plot(table2array(xITERATION),table2array(xERROR(:,k)),'-','Color',colors(5,:),'LineWidth',2);
+        grid on;
+        title([h{k} ' (' projectinfo.METHOD{nrTable} ')'],'Interpreter','None','FontWeight','bold','FontSize',8)
+        hold on;
+        set(gca,'YLim',get(gca,'YLim'))
+        set(gca,'XLim',[min(xITERATION.ITERATION) max(xITERATION.ITERATION)])
+%         set(gca,'XTick',[]);
+        YLim = get(gca,'YLim');
+        set(gca,'YTick',linspace(YLim(1),YLim(2),5));
+        plot([0 0],get(gca,'YLim'),'k-')
+    end
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Plot OBJ
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    h = xOBJ.Properties.VariableNames;
+    subplot(nrows,ncols,nTotal);
+    plot(table2array(xITERATION),table2array(xOBJ),'r-','LineWidth',2);
+    grid on;
+    title([h{1} ' (' projectinfo.METHOD{nrTable} ')'],'Interpreter','None','FontWeight','bold','FontSize',8)
+    set(gca,'XTickLabel',[]);
+    hold on;
+    set(gca,'YLim',get(gca,'YLim'))
+    plot([0 0],get(gca,'YLim'),'k-')
+    set(gca,'XLim',[min(xITERATION.ITERATION) max(xITERATION.ITERATION)])
+%     set(gca,'XTick',[]);
+    YLim = get(gca,'YLim');
+    set(gca,'YTick',linspace(YLim(1),YLim(2),5));
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Print figure
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    if PRINT,
+        filename = sprintf('%s/RESULTS/CONVERGENCE_PLOT__%d_%s',projectPath,nrTable,projectinfo.METHOD{nrTable});
+        IQMprintFigure(gcf,filename,'png');
+    end
+end
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/IQMrunNONMEMproject.m b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/IQMrunNONMEMproject.m
new file mode 100644
index 0000000000000000000000000000000000000000..c91a25cd77dc52d6c530d562a68de3fdf2354b41
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/IQMrunNONMEMproject.m	
@@ -0,0 +1,186 @@
+function [] = IQMrunNONMEMproject(projectPath,NPROCESSORS,NO_GOF_PLOTS)
+% This function runs a specified NONMEM project.
+%
+% [SYNTAX]
+% [] = IQMrunNONMEMproject(projectPath)
+% [] = IQMrunNONMEMproject(projectPath,N_PROCESSORS)
+% [] = IQMrunNONMEMproject(projectPath,N_PROCESSORS,NO_GOF_PLOTS)
+%
+% [INPUT]
+% projectPath:      Path to the project.nmctl NONMEM project file
+% NPROCESSORS:      Number of processors if use of parallel (default: 1)
+% NO_GOF_PLOTS:     =0: Create GoF plots for all runs (default), 
+%                   =1: No Gof plots
+%
+% [OUTPUT]
+% Output generated in the RESULTS folder of the NONMEM project.
+%
+% Control NONMEM run from commandline:
+% ====================================
+% CTRL-J: Console iteration printing on/off 
+% CTRL-K: Exit analysis at any time, which completes its output, and goes
+%         on to next mode or estimation method
+% CTRL-E: Exit program gracefully at any time
+% CTRL-T: Monitor the progress of each individual during an estimation by
+%         toggling ctrl-T. Wait 15 seconds or more to observe a subject’s
+%         ID, and individual objective function value. It is also good to
+%         test that the problem did not hang if a console output had not
+%         been observed for a long while
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle variable input arguments
+if nargin == 1,
+    NPROCESSORS = 1;
+    NO_GOF_PLOTS = 0;
+elseif nargin == 2,
+    NO_GOF_PLOTS = 0;
+end
+
+% Check if NONMEM project
+if ~isNONMEMprojectIQM(projectPath),
+    error('Specified "projectPath" does not point to a NONMEM project.');
+end
+
+% Run SETUP_PATHS_TOOLS_IQMPRO to get info about paths and ocmmands etc.
+SETUP_PATHS_TOOLS_IQMPRO
+if isunix,
+    PATH_NONMEM     = PATH_SYSTEM_NONMEM_UNIX;
+    PATH_NONMEM_PAR = PATH_SYSTEM_NONMEM_PARALLEL_UNIX;
+else
+    PATH_NONMEM     = PATH_SYSTEM_NONMEM_WINDOWS;
+    PATH_NONMEM_PAR = PATH_SYSTEM_NONMEM_PARALLEL_WINDOWS;
+end
+
+% Check things
+if isempty(PATH_NONMEM) && NPROCESSORS==1,
+    error('Path to NONMEM executable not defined in SETUP_PATHS_TOOLS_IQMPRO.m');
+end
+if isempty(PATH_NONMEM_PAR) && NPROCESSORS>1,
+    error('Path to NONMEM parallel executable not defined in SETUP_PATHS_TOOLS_IQMPRO.m');
+end
+
+% Change in to project path
+oldpath = pwd;
+cd(projectPath);
+
+% Run NONMEM
+if NPROCESSORS == 1,
+    eval(sprintf('[exitFlag,exitMessage] = system(''%s project.nmctl project.nmlog'');',PATH_NONMEM));
+else
+    eval(sprintf('[exitFlag,exitMessage] = system(''%s %d project.nmctl project.nmlog'');',PATH_NONMEM_PAR,NPROCESSORS));
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle queuing system - to wait until NONMEM run is done before
+% continuing processing the results.
+%
+% Only handle under unix ... do not assume queuing under windows
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isunix && ~isempty(PATH_SYSTEM_QUEUE_STATUS_UNIX),
+    
+    % Get jobID from exit message (always assume it is numeric)
+    jobID = regexp(exitMessage,'([0-9]+)','tokens');
+    if length(jobID) == 1,
+        jobID = jobID{1}{1};
+    else
+        error('Something wrong with the queue jobID.');
+    end
+    
+    % Read out users queue
+    [exitFlag,exitMessage] = system([PATH_SYSTEM_QUEUE_STATUS_UNIX]);
+    
+    % Check if jobID still in queue and wait until it is gone
+    while ~isempty(strfind(exitMessage,jobID)),
+        pause(10);
+        [exitFlag,exitMessage] = system([PATH_SYSTEM_QUEUE_STATUS_UNIX]);
+    end
+   
+end
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% End of queue handling
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handling stupid NONMEM
+% For some reason NONMEM on some systems can not generate the
+% controlfile.xml file if the path to the model is to long.
+%
+% However, it can create the temporaryfile.xml, which is identical (at
+% least in all the cases I tested. 
+% 
+% So to circumvent an issue, if the project.xml file is not present but the
+% temporaryfile.xml file is present this one will be renamed!
+%
+% ICON: please get your software in order and fit for a decent way of
+% working that is consistent with the year 2016 and not with 1980! Thanks!
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isunix,
+    % Check if project.xml file present
+    x = dir('project.xml');
+    y = dir('temporaryfile.xml');
+    if isempty(x) && isempty(y),
+        error('Problem with NONMEM and creation of output XML file - the path name is too long (OLD software).');
+    end
+    if isempty(x) && ~isempty(y),
+        copyfile('temporaryfile.xml','project.xml');
+    end
+end
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% End of handling stupid NONMEM
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Change back to old path
+cd(oldpath);
+
+% Cleanup
+try
+    cleanNONMEMprojectFolderIQM(projectPath);
+catch
+    error('NONMEM run created a problem. Please check.');
+end
+
+% Postprocess ...
+try
+    IQMplotConvergenceNONMEM(projectPath);
+	close all
+catch
+    disp('Problem with plotting');
+    disp(lasterr);    
+end
+try
+    IQMcreateNONMEMresultsTable(projectPath);
+catch
+    disp('Problem with reporting');
+    disp(lasterr);    
+end
+
+% Generate information for GOF plots
+try
+    PROJECTINFO     = parseNONMEMprojectHeaderIQM(projectPath);
+    % outputNumber: Defined by metadata "OUTPUTS"
+    outputNumberALL = [1:length(PROJECTINFO.OUTPUTS)];
+    outputNamesALL  = PROJECTINFO.OUTPUTS;
+catch
+    warning('Problem with obtaining information for GOF plots.');
+    disp(lasterr);    
+end
+
+% Do GOF plots
+if ~NO_GOF_PLOTS,
+    try
+        % General GOF plots
+        IQMfitanalysisGeneralPlots(projectPath);
+    catch
+        warning('Problem with General GOF plots.');
+        disp(lasterr);
+    end
+    try
+        % Output specific GOF plots
+        IQMfitanalysisOutputPlots(projectPath);
+    catch
+        warning('Problem with Output specific GOF plots.');
+        disp(lasterr);
+    end    
+end
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/IQMrunNONMEMprojectFolder.m b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/IQMrunNONMEMprojectFolder.m
new file mode 100644
index 0000000000000000000000000000000000000000..777c211e897bea18c5573e6f03e246347498bc2e
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/IQMrunNONMEMprojectFolder.m	
@@ -0,0 +1,77 @@
+function [] = IQMrunNONMEMprojectFolder(modelProjectsFolder,N_PROCESSORS_PAR,N_PROCESSORS_SINGLE,NO_GOF_PLOTS)
+% This functions runs all the NONMEM projects in the specified folder.
+% Parallel computation is supported in two different ways. Parallel execution 
+% of models at the same time (par for loop) and also allowing each single model
+% run to be parallelized (if the NONMEM installation allows for it).
+% The function also generates tables in the modelProjectsFolder allowing to
+% compare individual model results.
+%
+% [SYNTAX]
+% [] = IQMrunNONMEMprojectFolder(modelProjectsFolder)
+% [] = IQMrunNONMEMprojectFolder(modelProjectsFolder,N_PROCESSORS_PAR)
+% [] = IQMrunNONMEMprojectFolder(modelProjectsFolder,N_PROCESSORS_PAR,N_PROCESSORS_SINGLE)
+% [] = IQMrunNONMEMprojectFolder(modelProjectsFolder,N_PROCESSORS_PAR,N_PROCESSORS_SINGLE,NO_GOF_PLOTS)
+%
+% [INPUT]
+% modelProjectsFolder:      Path to a folder with NONMEM project folders
+%                           to be run. Folder names are arbitrary, but a
+%                           project.nmctl file needs to be present in
+%                           each folder.
+% N_PROCESSORS_PAR:         Number of processors for parallel model evaluation (default: as specified in SETUP_PATHS_TOOLS_IQMPRO)
+% N_PROCESSORS_SINGLE:      Number of processors for parallelization of single model run (default: 1)
+% NO_GOF_PLOTS:             =0: Create GoF plots for all runs (default), =1: No Gof plots
+%
+% If N_PROCESSORS_PAR>1 then parallel nodes are requested via the matlabpool
+% command and N_PROCESSORS_PAR models will be run in parallel.
+%
+% [OUTPUT]
+% No output! The function just runs the NONMEM projects. All results are
+% written to the relevant output folders ("RESULTS").
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle variable input arguments
+if nargin == 1,
+    N_PROCESSORS_PAR    = getN_PROCESSORS_PARIQM();
+    N_PROCESSORS_SINGLE = 1;
+    NO_GOF_PLOTS = 0;
+elseif nargin == 2,
+    N_PROCESSORS_SINGLE = 1;
+    NO_GOF_PLOTS = 0;
+elseif nargin == 3,
+    NO_GOF_PLOTS = 0;
+end
+    
+% Get the projects to run in the folder
+projects = dir([modelProjectsFolder '/*']);
+% Remove . and ..
+ix_dot = strmatchIQM('.',{projects.name});
+projects(ix_dot) = [];
+% Remove files
+projects(find(~[projects.isdir])) = [];
+
+% Request processors
+% Request min(N_PROCESSORS,length(projects))
+N_PROCESSORS_NEEDED = min(N_PROCESSORS_PAR,length(projects));
+killMATLABpool = startParallelIQM(N_PROCESSORS_NEEDED);
+
+% Run the models
+warning off
+oldpath = pwd();
+parfor k=1:length(projects),
+    fprintf('Running project %d of %d ...\n',k,length(projects));
+    pathfolder = [modelProjectsFolder '/' projects(k).name];
+    if isNONMEMprojectIQM(pathfolder),
+        IQMrunNONMEMproject(pathfolder,N_PROCESSORS_SINGLE,NO_GOF_PLOTS);
+    end
+end
+    
+% Release processors
+stopParallelIQM(killMATLABpool);
+
+% Prepare tables for model comparison in the folder
+SETUP_PATHS_TOOLS_IQMPRO
+IQMfitsummaryAll(modelProjectsFolder,'',NLME_ORDER_CRITERION);
+
+% Done!
+fprintf('\nEstimations READY!\n\n');
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/IQMsampleNONMEMparam.m b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/IQMsampleNONMEMparam.m
new file mode 100644
index 0000000000000000000000000000000000000000..29a4d37f552e884b3d650448c2158a0927ea00e9
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/IQMsampleNONMEMparam.m	
@@ -0,0 +1,705 @@
+function [output] = IQMsampleNONMEMparam( projectPath, FLAG_SAMPLE, Nsamples, varargin )
+% This function samples parameters from both uncertainty and variability distributions from a NONMEM fit.
+% The result is a structure with sampled population parameters and sampled individual parameters. The desired
+% number of parameter sets can be specified.
+%
+% This function is very useful for trial simulation purposes.
+%
+% Handles automatically different parameter distributions (logNormal, Normal, logitNormal)
+%
+% [SYNTAX]
+% output = IQMsampleNONMEMparam( projectPath, FLAG_SAMPLE, Nsamples )
+% output = IQMsampleNONMEMparam( projectPath, FLAG_SAMPLE, Nsamples, covNames, covValues, catNames, catValues )
+%
+% [INPUT]
+% projectPath: path to the NONMEM project folder (created by IQM Tools)
+% FLAG_SAMPLE:                    0=use point estimates of population parameters (do not consider uncertainty) and sample Nsample 
+%                                   individual patients based on these. Covariates considered if defined by user and used in model.
+%                                   Please note: population parameters do not take covariates into account!
+%                                 1=sample single set of population parameters from uncertainty distribution and sample Nsample 
+%                                   individual patient parameters based on these. Covariates considered if defined by user and used in model.
+%                                   Please note: population parameters do not take covariates into account!
+%                                 2=sample Nsample sets of population parameters from uncertainty distribution 
+%                                   Do not sample from variability distribution and do not take into account covariates (even if user specified).
+%                                 3=use point estimates of population parameters (do not consider uncertainty)
+%                                   Return Nsamples sets of population parameters with covariates taken into account.
+%                                 4=sample single set of population parameters from uncertainty distribution 
+%                                   Return Nsamples sets of population parameters with covariates taken into account.
+%                                 5=sample Nsamples sets of population parameters from uncertainty distribution 
+%                                   And take provided covariates into account.
+% 
+% Nsamples:                       Number of individual parameter sets to sample
+%
+% covNames:                       Cell-array with names of continuous covariates to consider in the parameter sampling (only used for FLAG_SAMPLE=0 or 1)
+%                                 Default: {}
+% covValues:                      Matrix with Nsamples rows and as many columns as continuous covariate names in covNames (only used for FLAG_SAMPLE=0 or 1)
+% catNames:                       Cell-array with names of categorical covariates to consider in the parameter sampling (only used for FLAG_SAMPLE=0 or 1)
+%                                 Default: {}
+% catValues:                      Matrix with Nsamples rows and as many columns as categorical covariate names in covNames (only used for FLAG_SAMPLE=0 or 1)
+%
+% [OUTPUT]
+% Structure with the following fields:
+% output.parameterNames:                Cell-array with parameter names
+% output.FLAG_SAMPLE:                   Sampling flag used (see above for definition)
+% output.Nsamples:                      Number of sampled parameter sets (type of parameter sets sampled depends on FLAG_SAMPLE)
+% output.parameterValuesPopulation:     Vector or Matrix with (sampled) population parameters
+% output.parameterValuesIndividual:     Matrix with samples individual parameter sets (one set per row, one parameter per column)
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Need to handle variable input arguments for CONTINUOUS covariates 
+if nargin>=5,
+    covNames = varargin{1};
+    covValues = varargin{2};
+    
+    if ~isempty(covNames),
+        % Check correct size (Nsamples)
+        if size(covValues,1) ~= Nsamples,
+            error('Provided values for continuous covariates need to have length of "Nsamples".');
+        end
+    else
+        covNames = {};
+        covValues = [];
+    end
+else
+    % No covariates provided! 
+    covNames = {};
+    covValues = [];
+end
+if ~iscell(covNames),
+    covNames = {covNames};
+end
+
+% Need to handle variable input arguments for CATEGORICAL covariates 
+if nargin==7,
+    catNames = varargin{3};
+    catValues = varargin{4};
+    
+    if ~isempty(catNames),
+        % Check correct size (Nsamples)
+        if size(catValues,1) ~= Nsamples,
+            error('Provided values for categorical covariates need to have length of "Nsamples".');
+        end
+    else
+        catNames = {};
+        catValues = [];
+    end
+else
+    % No covariates provided! 
+    catNames = {};
+    catValues = [];
+end
+if ~iscell(catNames),
+    catNames = {catNames};
+end
+
+% Parse NONMEM results
+x = parseNONMEMresultsIQM(projectPath);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Run the sampling function once to get covariate information
+% Parameter values will not be considered here and handled later
+% Check if covariates in model and warn if yes but user has not provided covariate information
+%
+% Do run this part only if FLAG_SAMPLE not equal to 2
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if FLAG_SAMPLE~=2,
+    y = sampleNONMEMpopulationParametersIQM(x,0,1);
+    covInfo = y.covariates.continuous;
+    catInfo = y.covariates.categorical;
+    % Check if covariates are in the model but not provided
+    if ~isempty(covInfo(1).parameter) && isempty(covNames),
+        disp('Model contains continuous covariates but no covariates are provided by the user.');
+        disp(' ');
+    end
+    if ~isempty(catInfo(1).parameter) && isempty(catNames),
+        disp('Model contains categorical covariates but no covariates are provided by the user.');
+        disp(' ');
+    end
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Prepare CONTINUOUS covariate information (if needed)
+    %
+    % phi = mu + eta + t_cov * beta
+    %
+    % phi:      matrix of transformed individual parameters. one row per individual. (Nsamples x Nparameters)
+    % mu:       matrix of transformed population parameter values (same row repeated Nsamples times). (Nsamples x Nparameters)
+    % t_cov:    matrix of transformed covariates (Nsamples x Ncovariates)
+    %           We will assume that each covariate with the same name has the same transformation. And this will be checked.
+    % beta:     matrix with covariate coefficients beta_ij (Ncovariates x Nparameters)
+    %
+    % Only covariates will be considered that actually are passed by the user.
+    % If other covariates are present in the model then a warning will be made.
+    %
+    % No covariate parameter values are considered here. Just error checking, data transformation, ...
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Cycle through covariate information and build data and do some error checks
+    allModelCovNames = {};
+    allModelCovFormulas = {};
+    for k1=1:length(covInfo),
+        paramName = covInfo(k1).parameter;
+        for k2=1:length(covInfo(k1).covariates),
+            covname     = covInfo(k1).covariates{k2};
+            betavalue   = covInfo(k1).values(k2);
+            formula     = covInfo(k1).formula{k2};
+            % Check if covname already in allModelCovNames
+            ix = strmatchIQM(covname,allModelCovNames,'exact');
+            if isempty(ix),
+                % add covariate and formula to lists
+                allModelCovNames{end+1} = covname;
+                allModelCovFormulas{end+1} = formula;
+            else
+                % check that formula is the same, otherwise error
+                if ~strcmp(formula,allModelCovFormulas{ix}),
+                    error('Different covariate transformations for same continuous covariate.');
+                end
+            end
+        end
+    end
+    
+    if isempty(covNames),
+        if ~isempty(allModelCovNames),
+            disp('No continuous covariates for sampling have been defined but the model contains the following:');
+            disp(allModelCovNames);
+        end
+    else
+        % Check model covariates against provided covariates
+        % Remove covariates provided by the user that are not used in the model - warn the user
+        % Warn the user also about covariates that are in the model but not provided by the user
+        [covsUser_notinmodel,ix_notinmodel] = setdiff(covNames,allModelCovNames);
+        [covsModel_notuser,ix_notuser] = setdiff(allModelCovNames,covNames);
+        
+        % Remove user defined covariates that are not used in the model
+        covNames(ix_notinmodel) = [];
+        covValues(:,ix_notinmodel) = [];
+        
+        % Warn the user about what has been found
+        if ~isempty(ix_notinmodel),
+            disp('The following continuous covariates have been defined by the user but they are not present in the model. They will be not considered.');
+            covsUser_notinmodel
+        end
+        if ~isempty(ix_notuser),
+            disp('The following continuous covariates are defined in the model but have not been provided by the user. They will be not considered.');
+            covsModel_notuser
+        end
+        
+        % Generate the transformed covariates
+        t_cov = covValues;
+        for k=1:length(covNames),
+            ix = strmatchIQM(covNames{k},allModelCovNames,'exact');
+            formula = allModelCovFormulas{ix};
+            t_cov(:,k) = eval(strrep(formula,'cov','covValues(:,k)'));
+        end
+    end
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Prepare CATEGORICAL covariate information (if needed)
+    %
+    % phi = mu + eta + t_cov * beta + beta_cat
+    %
+    % phi:      matrix of transformed individual parameters. one row per individual. (Nsamples x Nparameters)
+    % mu:       matrix of transformed population parameter values (same row repeated Nsamples times). (Nsamples x Nparameters)
+    % t_cov:    matrix of transformed covariates (Nsamples x Ncovariates)
+    %           We will assume that each covariate with the same name has the same transformation. And this will be checked.
+    % beta:     matrix with covariate coefficients beta_ij (Ncovariates x Nparameters)
+    % beta_cat: matrix with categorical covariate coefficients (Nsamples x Nparameters)
+    %           Does not need to be prepared much but some error checking needs to be done
+    %
+    % Only covariates will be considered that actually are passed by the user.
+    % If other covariates are present in the model then a warning will be made.
+    %
+    % No covariate parameter values are considered here. Just error checking, data transformation, ...
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Cycle through covariate information and get all categorical covariate names used
+    allModelCatNames = {};
+    for k1=1:length(catInfo),
+        paramName = catInfo(k1).parameter;
+        for k2=1:length(catInfo(k1).covariates),
+            catname     = catInfo(k1).covariates{k2};
+            % Check if catname already in allModelCatNames
+            ix = strmatchIQM(catname,allModelCatNames,'exact');
+            if isempty(ix),
+                % add covariate and formula to lists
+                allModelCatNames{end+1} = catname;
+            end
+        end
+    end
+    
+    if isempty(catNames),
+        if ~isempty(allModelCatNames),
+            disp('No categorical covariates for sampling have been defined but the model contains the following:');
+            disp(allModelCatNames);
+        end
+    else
+        
+        % Check model covariates against provided covariates
+        % Remove covariates provided by the user that are not used in the model - warn the user
+        % Warn the user also about covariates that are in the model but not provided by the user
+        [catsUser_notinmodel,ix_notinmodel] = setdiff(catNames,allModelCatNames);
+        [catsModel_notuser,ix_notuser] = setdiff(allModelCatNames,catNames);
+        
+        % Remove user defined covariates that are not used in the model
+        catNames(ix_notinmodel) = [];
+        catValues(:,ix_notinmodel) = [];
+        
+        % Warn the user about what has been found
+        if ~isempty(ix_notinmodel),
+            disp('The following categorical covariates have been defined by the user but they are not present in the model. They will be not considered.');
+            disp(catsUser_notinmodel)
+        end
+        if ~isempty(ix_notuser),
+            disp('The following categorical covariates are defined in the model but have not been provided by the user. They will be not considered.');
+            disp(catsModel_notuser)
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle case of FLAG_SAMPLE=0 and 1
+% Sampling individual parameters with (1) or without (0) uncertainty
+% Taking covariates into account if provided.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if FLAG_SAMPLE == 0 || FLAG_SAMPLE ==1,
+    % Need to sample until reasonable values (no imaginary parts in parameters)
+    while 1,
+        
+        % Parse and sample NONMEM results
+        y = sampleNONMEMpopulationParametersIQM(x,FLAG_SAMPLE);
+        
+        % Get covariance matrix
+        cov = y.randomEffects.covariancematrix;
+        
+        % Check if positive semidefinite
+        [~,Lambda]  = eig(cov);
+        if min(diag(Lambda))<0,
+            % Attempt to make covariancematrix positive semidefinite
+            % Might still not work due to numerics ... so the outer while
+            % loop is important to sample until the resulting parameters
+            % are non-complex.
+            cov     = makePosSemiDefIQM(cov);
+        end
+        
+        % Sample individual random effects (etas)
+        ETA = mvnrndIQM(zeros(1,size(cov,1)),cov,Nsamples);
+        
+        % Transform population estimates to normal distribution (mu) (allowing for transformations: lognormal, logitnormal, normal)
+        mu = [];
+        for k=1:length(y.randomEffects.inv_transformation),
+            mu(k) = eval(strrep(y.randomEffects.inv_transformation{k},'psi',sprintf('%g',y.fixedEffects.values(k))));
+        end
+        
+        % Determine normally distributed phi - without covariate contributions: phi = mu + eta  (+ beta*t_cov + beta_cat)
+        phi = mu(ones(1,Nsamples),:) + ETA;
+        
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        % Determine and add effect of continuous covariates to phi: phi = mu + eta + t_cov*beta  (+ beta_cat)
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        if ~isempty(covNames),
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            % Determine the beta matrix
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            % Get parameter names of estimates
+            paramNames = y.fixedEffects.names;
+            % Initialize the beta matrix
+            beta = zeros(length(covNames),length(paramNames));
+            % Fill the beta matrix
+            for k1=1:length(covInfo),
+                paramName = covInfo(k1).parameter;
+                ix_j = strmatchIQM(paramName,paramNames,'exact');
+                for k2=1:length(covInfo(k1).covariates),
+                    covname     = covInfo(k1).covariates{k2};
+                    beta_ij     = covInfo(k1).values(k2);
+                    ix_i        = strmatchIQM(covname,covNames,'exact');
+                    % Fill beta_ij value into beta matrix
+                    beta(ix_i,ix_j) = beta_ij;
+                end
+            end
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            % Add t_cov*beta to phi
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            phi = phi + t_cov*beta;
+        end
+        
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        % Determine and add effect of categorical covariates to phi: phi = mu + eta + beta*t_cov + beta_cat
+        % One beta_cat matrix for each parameter/covariate combination!
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        if ~isempty(catNames),
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            % Determine the beta_cat matrix
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            % Get parameter names of estimates
+            paramNames = y.fixedEffects.names;
+            % Initialize the beta_cat matrix (Nsamples x Nparameters)
+            beta_cat = {};
+            % Determine the beta_cat matrices
+            for k1=1:length(catInfo),
+                paramName = catInfo(k1).parameter;
+                ix_j = strmatchIQM(paramName,paramNames,'exact');
+                for k2=1:length(catInfo(k1).covariates),
+                    % Initialize parameter/covariate dependent beta_cat matrix
+                    beta_cat_cov = zeros(Nsamples,length(paramNames));
+                    % Get categorical cov name and index
+                    catname     = catInfo(k1).covariates{k2};
+                    ix_i        = strmatchIQM(catname,catNames,'exact');
+                    if ~isempty(ix_i),
+                        % Fill the beta_cat_cov matrix
+                        categories_user = catValues(:,ix_i);
+                        categories_model = catInfo(k1).information(k2).categories;
+                        categories_values = catInfo(k1).information(k2).values;
+                        % Initialize values
+                        values = NaN(size(categories_user));
+                        for kkk=1:length(categories_model),
+                            ix = categories_user==categories_model(kkk);
+                            values(ix) = categories_values(kkk);
+                        end
+                        % Check if values contains NaN, then error and inform the user
+                        if ~isempty(find(isnan(values), 1)),
+                            error('Categorical covariate "%s" contains user provided category that has not been used for model building.',catname);
+                        end
+                        % Assign values
+                        beta_cat_cov(:,ix_j) = values;
+                    end
+                    beta_cat{end+1} = beta_cat_cov;
+                end
+            end
+            
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            % Add beta_cat to phi
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            for k1=1:length(beta_cat),
+                phi = phi + beta_cat{k1};
+            end
+        end
+        
+        % Back transform individual parameters (each column one parameter)
+        psi = [];
+        for k=1:size(phi,2),
+            transform_string = strrep(y.randomEffects.transformation{k},'phi',sprintf('phi(:,%d)',k));
+            psi(:,k) = eval(transform_string);
+            % Handle the case when phi=Inf and logit transformation => manually set to 1
+            if strcmp(y.randomEffects.transformation{k},'exp(phi)./(1+exp(phi))'),
+                psi(isnan(psi)) = 1;
+            end
+        end
+        
+        % Check if some issues with the sampled parameters (should not lead to complex values)
+        if isempty(find(imag(psi) ~=0)),
+            break;
+        else
+            % Rerun sampling since problem with population parameter sampling
+        end
+    end
+    % Define output variable
+    output                              = [];
+    output.parameterNames               = y.fixedEffects.names;
+    output.FLAG_SAMPLE                  = FLAG_SAMPLE;
+    output.Nsamples                     = Nsamples;
+    output.parameterValuesPopulation    = y.fixedEffects.values;
+    output.parameterValuesIndividual    = psi;
+
+elseif FLAG_SAMPLE == 2,
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Handle special case of FLAG_SAMPLE=2 (sampling population parameters only)
+    % Not taking covariates into account
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    FLAG_SAMPLE_POPULATIONPARAM = 1;
+    
+    % Run sampling function once just to get the number of parameters to sample
+    y = sampleNONMEMpopulationParametersIQM(x,0,1);
+
+    % Initialize the matrix with the parameter values (number of parameters needed for that)
+    popvalues = zeros(Nsamples,length(y.fixedEffects.names));
+    
+    % Get Nsamples sets of population parameters from uncertainty distribution
+    for k=1:Nsamples,
+        y = sampleNONMEMpopulationParametersIQM(x,FLAG_SAMPLE_POPULATIONPARAM,1);
+        popvalues(k,:) = y.fixedEffects.values;
+    end
+    
+    % Define output variable
+    output                              = [];
+    output.parameterNames               = y.fixedEffects.names;
+    output.FLAG_SAMPLE                  = FLAG_SAMPLE;
+    output.Nsamples                     = Nsamples;
+    output.parameterValuesPopulation    = popvalues;
+    output.parameterValuesIndividual    = [];
+    
+elseif FLAG_SAMPLE == 3 || FLAG_SAMPLE == 4,
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Handle special case of FLAG_SAMPLE=3 || 4
+    % - Sampling population parameters once only from uncertainty distributions (if FLAG_SAMPLE=4)
+    % - Including covariate effect on sampled population parameters
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%    
+    if FLAG_SAMPLE==3,
+        FLAG_SAMPLE_POPULATIONPARAM = 0;
+    else
+        FLAG_SAMPLE_POPULATIONPARAM = 1;
+    end
+    
+    % Need to sample until reasonable values (no imaginary parts in parameters)
+    while 1,
+        % Parse and sample NONMEM results to get base population parameters without covariate effects
+        y = sampleNONMEMpopulationParametersIQM(x,FLAG_SAMPLE_POPULATIONPARAM);
+        
+        % Transform population parameters to normal distribution (mu) (allowing for transformations: lognormal, logitnormal, normal)
+        mu = [];
+        for k=1:length(y.randomEffects.inv_transformation),
+            mu(k) = eval(strrep(y.randomEffects.inv_transformation{k},'psi',sprintf('%g',y.fixedEffects.values(k))));
+        end
+        
+        % Determine normally distributed phi - without eta and covariate contribution: phi = mu (+ eta)  (+ beta*t_cov + beta_cat)
+        phi = mu(ones(1,Nsamples),:);
+        
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        % Determine and add effect of continuous covariates to phi: phi = mu (+ eta) + t_cov*beta  (+ beta_cat)
+        % Without eta contribution
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        if ~isempty(covNames),
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            % Determine the beta matrix
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            % Get parameter names of estimates
+            paramNames = y.fixedEffects.names;
+            % Initialize the beta matrix
+            beta = zeros(length(covNames),length(paramNames));
+            % Fill the beta matrix
+            for k1=1:length(covInfo),
+                paramName = covInfo(k1).parameter;
+                ix_j = strmatchIQM(paramName,paramNames,'exact');
+                for k2=1:length(covInfo(k1).covariates),
+                    covname     = covInfo(k1).covariates{k2};
+                    beta_ij     = covInfo(k1).values(k2);
+                    ix_i        = strmatchIQM(covname,covNames,'exact');
+                    % Fill beta_ij value into beta matrix
+                    beta(ix_i,ix_j) = beta_ij;
+                end
+            end
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            % Add t_cov*beta to phi
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            phi = phi + t_cov*beta;
+        end
+        
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        % Determine and add effect of categorical covariates to phi: phi = mu + eta + beta*t_cov + beta_cat
+        % One beta_cat matrix for each parameter/covariate combination!
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        if ~isempty(catNames),
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            % Determine the beta_cat matrix
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            % Get parameter names of estimates
+            paramNames = y.fixedEffects.names;
+            % Initialize the beta_cat matrix (Nsamples x Nparameters)
+            beta_cat = {};
+            % Determine the beta_cat matrices
+            for k1=1:length(catInfo),
+                paramName = catInfo(k1).parameter;
+                ix_j = strmatchIQM(paramName,paramNames,'exact');
+                for k2=1:length(catInfo(k1).covariates),
+                    % Initialize parameter/covariate dependent beta_cat matrix
+                    beta_cat_cov = zeros(Nsamples,length(paramNames));
+                    % Get categorical cov name and index
+                    catname     = catInfo(k1).covariates{k2};
+                    ix_i        = strmatchIQM(catname,catNames,'exact');
+                    if ~isempty(ix_i),
+                        % Fill the beta_cat_cov matrix
+                        categories_user = catValues(:,ix_i);
+                        categories_model = catInfo(k1).information(k2).categories;
+                        categories_values = catInfo(k1).information(k2).values;
+                        % Initialize values
+                        values = NaN(size(categories_user));
+                        for kkk=1:length(categories_model),
+                            ix = categories_user==categories_model(kkk);
+                            values(ix) = categories_values(kkk);
+                        end
+                        % Check if values contains NaN, then error and inform the user
+                        if ~isempty(find(isnan(values), 1)),
+                            error('Categorical covariate "%s" contains user provided category that has not been used for model building.',catname);
+                        end
+                        % Assign values
+                        beta_cat_cov(:,ix_j) = values;
+                    end
+                    beta_cat{end+1} = beta_cat_cov;
+                end
+            end
+            
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            % Add beta_cat to phi
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            for k1=1:length(beta_cat),
+                phi = phi + beta_cat{k1};
+            end
+        end
+        
+        % Back transform individual parameters (each column one parameter)
+        psi = [];
+        for k=1:size(phi,2),
+            transform_string = strrep(y.randomEffects.transformation{k},'phi',sprintf('phi(:,%d)',k));
+            psi(:,k) = eval(transform_string);
+            % Handle the case when phi=Inf and logit transformation => manually set to 1
+            if strcmp(y.randomEffects.transformation{k},'exp(phi)./(1+exp(phi))'),
+                psi(isnan(psi)) = 1;
+            end
+        end
+        
+        % Check if some issues with the sampled parameters (should not lead to complex values)
+        if isempty(find(imag(psi) ~=0)),
+            break;
+        else
+            % Rerun sampling since problem with population parameter sampling
+        end
+    end
+    % Define output variable
+    output                              = [];
+    output.parameterNames               = y.fixedEffects.names;
+    output.FLAG_SAMPLE                  = FLAG_SAMPLE;
+    output.Nsamples                     = Nsamples;
+    output.parameterValuesPopulation    = psi;    
+    output.parameterValuesIndividual    = [];
+    
+elseif FLAG_SAMPLE == 5,
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Handle special case of FLAG_SAMPLE=5
+    % - Sampling Nsamples population parameters from uncertainty distribution
+    % - Including covariate effect on sampled population parameters
+    %   Need to provide Nsamples number of covariate values
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%    
+    FLAG_SAMPLE_POPULATIONPARAM = 1;
+    
+    % Run sampling function once just to get the number of parameters to sample
+    y = sampleNONMEMpopulationParametersIQM(x,0,1);
+
+    % Initialize the matrix with the parameter values (number of parameters needed for that)
+    mu = zeros(Nsamples,length(y.fixedEffects.names));
+
+    % Need to sample until reasonable values (no imaginary parts in parameters)
+    while 1,
+
+        % Get Nsamples sets of population parameters from uncertainty distribution
+        for k0=1:Nsamples,
+            % Sample
+            y = sampleNONMEMpopulationParametersIQM(x,FLAG_SAMPLE_POPULATIONPARAM,1);
+            mu(k0,:) = y.fixedEffects.values;
+        end
+
+        % Transform
+        for k=1:length(y.randomEffects.inv_transformation),
+            mu(:,k) = eval(strrep(y.randomEffects.inv_transformation{k},'psi',sprintf('mu(:,%d)',k)));
+        end
+        
+        % Determine normally distributed phi - without eta and covariate contribution: phi = mu (+ eta)  (+ beta*t_cov + beta_cat)
+        phi = mu;
+        
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        % Determine and add effect of continuous covariates to phi: phi = mu (+ eta) + t_cov*beta  (+ beta_cat)
+        % Without eta contribution
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        if ~isempty(covNames),
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            % Determine the beta matrix
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            % Get parameter names of estimates
+            paramNames = y.fixedEffects.names;
+            % Initialize the beta matrix
+            beta = zeros(length(covNames),length(paramNames));
+            % Fill the beta matrix
+            for k1=1:length(covInfo),
+                paramName = covInfo(k1).parameter;
+                ix_j = strmatchIQM(paramName,paramNames,'exact');
+                for k2=1:length(covInfo(k1).covariates),
+                    covname     = covInfo(k1).covariates{k2};
+                    beta_ij     = covInfo(k1).values(k2);
+                    ix_i        = strmatchIQM(covname,covNames,'exact');
+                    % Fill beta_ij value into beta matrix
+                    beta(ix_i,ix_j) = beta_ij;
+                end
+            end
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            % Add t_cov*beta to phi
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            phi = phi + t_cov*beta;
+        end
+        
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        % Determine and add effect of categorical covariates to phi: phi = mu + eta + beta*t_cov + beta_cat
+        % One beta_cat matrix for each parameter/covariate combination!
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        if ~isempty(catNames),
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            % Determine the beta_cat matrix
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            % Get parameter names of estimates
+            paramNames = y.fixedEffects.names;
+            % Initialize the beta_cat matrix (Nsamples x Nparameters)
+            beta_cat = {};
+            % Determine the beta_cat matrices
+            for k1=1:length(catInfo),
+                paramName = catInfo(k1).parameter;
+                ix_j = strmatchIQM(paramName,paramNames,'exact');
+                for k2=1:length(catInfo(k1).covariates),
+                    % Initialize parameter/covariate dependent beta_cat matrix
+                    beta_cat_cov = zeros(Nsamples,length(paramNames));
+                    % Get categorical cov name and index
+                    catname     = catInfo(k1).covariates{k2};
+                    ix_i        = strmatchIQM(catname,catNames,'exact');
+                    if ~isempty(ix_i),
+                        % Fill the beta_cat_cov matrix
+                        categories_user = catValues(:,ix_i);
+                        categories_model = catInfo(k1).information(k2).categories;
+                        categories_values = catInfo(k1).information(k2).values;
+                        % Initialize values
+                        values = NaN(size(categories_user));
+                        for kkk=1:length(categories_model),
+                            ix = categories_user==categories_model(kkk);
+                            values(ix) = categories_values(kkk);
+                        end
+                        % Check if values contains NaN, then error and inform the user
+                        if ~isempty(find(isnan(values), 1)),
+                            error('Categorical covariate "%s" contains user provided category that has not been used for model building.',catname);
+                        end
+                        % Assign values
+                        beta_cat_cov(:,ix_j) = values;
+                    end
+                    beta_cat{end+1} = beta_cat_cov;
+                end
+            end
+            
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            % Add beta_cat to phi
+            %%%%%%%%%%%%%%%%%%%%%%%%%%%
+            for k1=1:length(beta_cat),
+                phi = phi + beta_cat{k1};
+            end
+        end
+        
+        % Back transform individual parameters (each column one parameter)
+        psi = [];
+        for k=1:size(phi,2),
+            transform_string = strrep(y.randomEffects.transformation{k},'phi',sprintf('phi(:,%d)',k));
+            psi(:,k) = eval(transform_string);
+            % Handle the case when phi=Inf and logit transformation => manually set to 1
+            if strcmp(y.randomEffects.transformation{k},'exp(phi)./(1+exp(phi))'),
+                psi(isnan(psi)) = 1;
+            end
+        end
+        
+        % Check if some issues with the sampled parameters (should not lead to complex values)
+        if isempty(find(imag(psi) ~=0)),
+            break;
+        else
+            % Rerun sampling since problem with population parameter sampling
+        end
+    end
+    % Define output variable
+    output                              = [];
+    output.parameterNames               = y.fixedEffects.names;
+    output.FLAG_SAMPLE                  = FLAG_SAMPLE;
+    output.Nsamples                     = Nsamples;
+    output.parameterValuesPopulation    = psi;    
+    output.parameterValuesIndividual    = [];
+    
+end
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/cleanNONMEMprojectFolderIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/cleanNONMEMprojectFolderIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..b3dfc64ddb0dc263ecea2bc6ea4a79f44884c640
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/cleanNONMEMprojectFolderIQM.m	
@@ -0,0 +1,52 @@
+function [] = cleanNONMEMprojectFolderIQM(projectPath)
+% Moves all files into the RESULTS folder and removes all additional
+% folders. Does not move the project.nmctl file 
+%
+% [SYNTAX]
+% [] = cleanNONMEMprojectFolderIQM(projectPath)
+%
+% [INPUT]
+% projectPath:      Path to the project.nmctl NONMEM project file
+%
+% [OUTPUT]
+% No output
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Change in to project path and load Monolix project
+oldpath = pwd;
+cd(projectPath);
+
+% Delete all folder except RESULTS
+warning off
+x = dir();
+for k=1:length(x),
+    if x(k).isdir,
+        if ~strcmp(x(k).name,'.') && ~strcmp(x(k).name,'..') && ~strcmp(x(k).name,'RESULTS'),
+            rmdir(x(k).name,'s');
+        end
+    end
+end
+
+% Move all project.* files into RESULTS (except project.nmctl)
+x = dir('project.*');
+for k=1:length(x),
+    if ~strcmp(x(k).name,'project.nmctl'),
+        movefile(x(k).name,'RESULTS');
+    end
+end
+
+% Delete all other files (except project.nmctl) - also do not delete any potential *.csv files, since these might be datasets
+% that have been generated for this particular NLME model (e.g. 0 order absorption fix or bootstrap).
+x = dir('*');
+for k=1:length(x),
+    [p,f,e] = fileparts(x(k).name);
+    if ~strcmp(x(k).name,'project.nmctl') && ~strcmp(e,'.csv') && ~strcmp(e,'.txtbc') && ~strcmp(e,'.dos'),
+        delete(x(k).name);
+    end
+end
+
+warning on
+
+% Change back to old path
+cd(oldpath);
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/fitanalysisETAvsCOVnonmemIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/fitanalysisETAvsCOVnonmemIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..3bf498e5ada14c65656e8e76da9fecdf2a8b8627
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/fitanalysisETAvsCOVnonmemIQM.m	
@@ -0,0 +1,197 @@
+function [] = fitanalysisETAvsCOVnonmemIQM(projectPath,filename,options)    
+% Called by IQMfitanalysisETAvsCOV - same calling syntax and handling NONMEM.
+% 
+% [SYNTAX]
+% See IQMfitanalysisETAvsCOV 
+%
+% [INPUT]
+% See IQMfitanalysisETAvsCOV
+%
+% [OUTPUT]
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle variable input arguments
+if nargin<2,
+    filename    = '';
+end
+if nargin<3,
+    options = [];
+end
+
+% Get additional information from header
+headerinfo  = parseNONMEMprojectHeaderIQM(projectPath);
+covNames    = headerinfo.COVNAMES;
+catNames    = headerinfo.CATNAMES;
+
+% Handle empty covariate definitions
+if length(covNames) == 1,
+    if isempty(covNames{1}),
+        covNames = {};
+    end
+end
+% Handle empty covariate definitions
+if length(catNames) == 1,
+    if isempty(catNames{1}),
+        catNames = {};
+    end
+end
+
+% Handle varargins
+try corrcoeffThreshold = options.corrcoeffThreshold; catch, corrcoeffThreshold = 0.3; end
+try withlabels = options.labels; catch, withlabels = 1; end
+
+% Load the etas and covariates
+etaCovs = IQMloadNONCSVdataset([projectPath '/RESULTS/project.eta'],1); 
+
+% Check cov and catnames to be present in the etaCovs
+datanames = etaCovs.Properties.VariableNames;
+
+ixRemoveCovNames = [];
+for k=1:length(covNames),
+    if isempty(strmatchIQM(covNames{k},datanames,'exact')), 
+        warning('The project.eta file does not contain the covariate ''%s''.\nNot considered in analysis.',covNames{k}); 
+        ixRemoveCovNames(end+1) = k;
+    end    
+end
+covNames(ixRemoveCovNames) = [];
+
+ixRemoveCovNames = [];
+for k=1:length(catNames),
+    if isempty(strmatchIQM(catNames{k},datanames,'exact')), 
+        warning('The project.eta file does not contain the covariate ''%s''\nNot considered in analysis.',catNames{k}); 
+        ixRemoveCovNames(end+1) = k;
+    end    
+end
+catNames(ixRemoveCovNames) = [];
+
+% Get the ETAs
+ixETA = strmatchIQM('ETA_',etaCovs.Properties.VariableNames);
+dataeta = etaCovs(:,[1 ixETA(:)']);
+dataeta.Properties.VariableNames = strrep(dataeta.Properties.VariableNames,'ETA_','');
+
+% Get covs
+ixCOVs = [];
+for k=1:length(covNames),
+    ixCOVs(end+1) = strmatchIQM(covNames{k},etaCovs.Properties.VariableNames,'exact');
+end
+datacovs = etaCovs(:,[1 ixCOVs(:)']);
+
+% Get cats
+ixCATs = [];
+for k=1:length(catNames),
+    ixCATs(end+1) = strmatchIQM(catNames{k},etaCovs.Properties.VariableNames,'exact');
+end
+datacats = etaCovs(:,[1 ixCATs(:)']);
+
+% Remove the non estimated omegas/etas
+ix =  find(sum(abs(table2array(dataeta(:,2:end)))) ~= 0);
+dataeta_est                 = dataeta(:,[1 ix+1]);
+
+% Interface to old code ;-)
+etas = dataeta_est(:,2:end);
+covs = datacovs(:,2:end);
+cats = datacats(:,2:end);
+nretas = size(etas,1);
+nrcovs = size(covs,1);
+nrcats = size(cats,1);
+etaNames = etas.Properties.VariableNames;
+covNames = covs.Properties.VariableNames;
+catNames = cats.Properties.VariableNames;
+ids = datacovs.ID;
+
+% Determine subplot organization
+Neta = length(etaNames);
+nrow = ceil(sqrt(Neta));
+ncol = ceil(Neta/nrow);
+
+% If filename then remove old file
+IQMstartNewPrintFigure(filename);
+
+% First handle continuous covariates
+% Cycle through covariates and produce one figure per covariate
+% The etas in subplots
+for k=1:size(covs,2),
+    cov = table2array(covs(:,k));
+    % New figure
+    h = figure;
+    set(h,'Name',['Covariate: ' covNames{k}])
+    for k2=1:size(etas,2),
+        name = etaNames{k2};
+        eta = table2array(etas(:,k2));
+        subplot(nrow,ncol,k2);
+        [cc,pp] = corrcoef([cov,eta]);
+        cc = cc(1,2);
+        pp = pp(1,2);
+        if abs(cc) > corrcoeffThreshold,            
+            if ~withlabels,
+                plot(cov,eta,'.r','MarkerSize',20); hold on
+            else
+                plot(cov,eta,'.w','MarkerSize',20); hold on
+                labels1 = cellstr( num2str(ids, '%d') );
+                text(cov, eta, labels1, 'VerticalAlignment','middle', 'HorizontalAlignment','center', 'FontSize', 8,'Color','r'); hold on
+            end
+        else
+            if ~withlabels,
+                plot(cov,eta,'.b','MarkerSize',20); hold on
+            else
+                plot(cov,eta,'.w','MarkerSize',1); hold on
+                labels1 = cellstr( num2str(ids, '%d') );
+                text(cov, eta, labels1, 'VerticalAlignment','middle', 'HorizontalAlignment','center', 'FontSize', 8,'Color','b'); hold on
+            end
+        end
+        % Add linear regression result
+        X = [ones(size(cov)) cov];
+        warning off
+        b = regressIQM(eta,X); % Removes NaN data
+        warning on
+        x = get(gca,'XLim');        
+        plot(x, b(1)+b(2)*x,'k--','LineWidth',2)
+        % Title etc.
+        title(['Corr. coeff.: ' sprintf('%1.2g (p=%1.2g)',cc,pp)],'Interpreter','None');
+        xlabel(covNames{k},'Interpreter','None')
+        ylabel(['eta' etaNames{k2}],'Interpreter','None')
+    end
+    set(h,'Color',[1 1 1]);
+    IQMprintFigure(gcf,filename);
+    if ~isempty(filename),
+        close(gcf);
+    end    
+end
+
+% Second handle categorical covariates
+% Cycle through covariates and produce one figure per covariate
+% The etas in subplots
+for k=1:size(cats,2),
+    cat = table2array(cats(:,k));
+    catunique = unique(cat);
+    % New figure
+    h = figure;
+    set(h,'Name',['Covariate: ' catNames{k}]);
+    for k2=1:size(etas,2),
+        name = etaNames{k2};
+        eta = table2array(etas(:,k2));
+        x = [eta cat];
+        subplot(nrow,ncol,k2);
+
+        optionsBoxplot                      = [];
+        optionsBoxplot.verticalFlag         = 0;
+        optionsBoxplot.outliers             = 0;
+        optionsBoxplot.whiskerPercentiles   = [5 95];
+        boxplotIQM(eta,cat,optionsBoxplot);
+        
+        plotZeroLim = get(gca,'YLim');
+        hold on;
+        plot([0 0],plotZeroLim,'--k')
+        xlabel(['eta' etaNames{k2}],'Interpreter','None')
+        ylabel(catNames{k},'Interpreter','None')
+    end
+    set(h,'Color',[1 1 1]);    
+    IQMprintFigure(gcf,filename);
+    if ~isempty(filename),
+        close(gcf);
+    end    
+end
+
+% PS2PDF
+IQMconvert2pdf(filename);
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/getTableNnonmemOutputIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/getTableNnonmemOutputIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..7161d4e54e0445543e7766432da6d5aa1a5a2152
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/getTableNnonmemOutputIQM.m	
@@ -0,0 +1,46 @@
+function [ data ] = getTableNnonmemOutputIQM(filename,nrTable)
+% Basically doing a IQMloadNONCSVdataset for
+% NONMEM outputs where more than one table might be present, due to
+% concatenated estimation methods.
+% 
+% [SYNTAX]
+% [data] = getTableNnonmemOutputIQM(filename,nrTable)
+%
+% [INPUT]
+% filename:     Name and path of the NONMEM output file to read
+% nrTable:      Number of the table to load as MATLAB table
+%
+% [OUTPUT]
+% data:         NONMEM output table in MATLAB table format.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Load file
+content = fileread(filename);
+
+% Get start index of table
+ix = strfind(content,sprintf('TABLE NO.     %d',nrTable));
+if isempty(ix),
+    error('Table %d could not be found.',nrTable);
+end
+
+% Get text until end
+table = content(ix:end);
+
+% find next table
+ix = strfind(table,sprintf('TABLE NO.'));
+if length(ix)>1,
+    table = table(1:ix(2)-1);
+end
+
+% save as temporary
+[xdummyx,tempfile] = fileparts(tempnameIQM);
+fid = fopen(tempfile,'w');
+fprintf(fid,'%s',table);
+fclose(fid);
+
+% Load as dataset
+data = IQMloadNONCSVdataset(tempfile,1);
+
+% Delete tempfile
+delete(tempfile)
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/modelconversion/additionalChecks4NONMEMconversionIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/modelconversion/additionalChecks4NONMEMconversionIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..aba91a4eb74ad24e34e03d29aa29d5ed974aa234
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/modelconversion/additionalChecks4NONMEMconversionIQM.m	
@@ -0,0 +1,166 @@
+function [ covNames,catNames,errorModels,errorParam0 ] = additionalChecks4NONMEMconversionIQM( oldpath,param_est, dataHeaderIdent,dataheader,modelInfo,IIVestimate,errorModels,errorParam0,covarianceModel,covariateModel,SILENT)
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Determine continuous and categorical covariates
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+dataHeaderIDs   = explodePCIQM(dataHeaderIdent,',');
+covIDs          = strmatchIQM('COV',upper(dataHeaderIDs));
+covNames        = dataheader(covIDs);
+catIDs          = strmatchIQM('CAT',upper(dataHeaderIDs));
+catNames        = dataheader(catIDs);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check that regression parameters correctly defined
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+nrREGSmodel     = length(modelInfo.param_reg);
+nrREGSdata      = length(strmatchIQM('X',upper(dataHeaderIDs)));
+if nrREGSmodel ~= nrREGSdata,
+    cd(oldpath);
+    error('Different numbers of regression parameters in model and in dataset.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Print table with regression parameters model and data
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+REGSnamesData   = dataheader(strmatchIQM('X',upper(dataHeaderIDs)));
+if ~SILENT,
+    if ~isempty(REGSnamesData),
+        disp(' ');
+        disp('Please check that the following matches regression parameters in data and model do make sense:');
+        disp('    DATA    : MODEL');
+        disp('--------------------------');
+        for k=1:length(REGSnamesData),
+            fprintf('\t%s%s: %s\n',REGSnamesData{k},char(32*ones(1,8-length(REGSnamesData{k}))),modelInfo.param_reg(k).name)
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check all headers
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~SILENT,
+    disp(' ');
+    disp('Please check that the following matches between data header and identifiers do make sense:');
+    for k=1:length(dataheader),
+        fprintf('\t%s%s: %s\n',dataheader{k},char(32*ones(1,8-length(dataheader{k}))),dataHeaderIDs{k})
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check residual error things
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(errorModels),
+    errorModels = '';
+    for k=1:length(modelInfo.outputs),
+        errorModels = sprintf('%sconst,',errorModels);
+    end
+    errorModels = errorModels(1:end-1);
+end
+test = errorModels;
+test = strtrim(strrep(strrep(strrep(strrep(test,'const',''),'prop',''),'comb1',''),',',''));
+if ~isempty(test),
+    cd(oldpath);
+    error('Please make sure that only "const", "prop", or "comb1" appear in the "errorModels" variable.');
+end
+% Check length
+errors = explodePCIQM(errorModels,',');
+if length(errors) ~= length(modelInfo.outputs),
+    cd(oldpath);
+    error('Please make sure that an equal number of errorModels is defined as outputs in the model.');
+end
+% Print table parameter names and IIV distributions
+if ~SILENT,
+    disp(' ');
+    disp('Please check that the following matches between outputs and used residual error models are correct:');
+    for k=1:length(modelInfo.outputs),
+        fprintf('\t%s%s: %s\n',modelInfo.outputs(k).formula,char(32*ones(1,15-length(modelInfo.outputs(k).formula))),errors{k})
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle empty errorParam0
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(errorParam0),
+    terms = explodePCIQM(errorModels);
+    for k=1:length(terms),
+        if strcmp(lower(terms{k}),'const'),
+            errorParam0(end+1) = 1;
+        elseif strcmp(lower(terms{k}),'prop'),
+            errorParam0(end+1) = 0.3;
+        elseif strcmp(lower(terms{k}),'comb1'),
+            errorParam0(end+1) = 1;
+            errorParam0(end+1) = 0.3;          
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check errorParam0
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+terms = explodePCIQM(errorModels);
+nrneededelements = 0;
+for k=1:length(terms),
+    if strcmp(lower(terms{k}),'const'),
+        nrneededelements = nrneededelements+1;
+    elseif strcmp(lower(terms{k}),'prop'),
+        nrneededelements = nrneededelements+1;
+    elseif strcmp(lower(terms{k}),'comb1'),
+        nrneededelements = nrneededelements+2;
+    end
+end
+if length(errorParam0) ~= nrneededelements,
+    error('Incorrect number of elements in options.errorParam0.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check covariance model
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(covarianceModel),
+    covarianceModel = 'diagonal';
+elseif ~strcmp(covarianceModel,'diagonal'),
+    % Need to check that none of the parameters for which no IIV is estimated is used in the covarianceModel
+    param_est_noIIV = {param_est(IIVestimate==0).name};
+    for k=1:length(param_est_noIIV),
+        if ~isempty(regexp(covarianceModel,['\<' param_est_noIIV{k} '\>'])),
+            cd(oldpath);
+            error('Please make sure none of the parameters for which NO IIV is estimated (IIVestimate=0) is used in the covarianceModel settings.');
+        end
+    end
+    % Check that all parameters in the covariance model actually are model parameters
+    param = {param_est.name};
+    test  = covarianceModel;
+    for k=1:length(param),
+        test = regexprep(test,['\<' param{k} '\>'],'');
+    end
+    test = strrep(test,'{','');
+    test = strrep(test,'}','');
+    test = strrep(test,',','');
+    test = strtrim(test);
+    if ~isempty(test),
+        cd(oldpath);
+        error('Please make sure that covarianceModel only contains parameter names that are set to <estimate> in the model.');
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check covariate model things
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% First check that all first elements are estimated parameters of the model
+for k=1:length(covariateModel),
+    param = covariateModel{k}{1};
+    if isempty(strmatchIQM(param,{param_est.name},'exact')),
+        cd(oldpath);
+        error('Please make sure that all parameters for which covariates are defined are defined by <estimate> in the model.');
+    end
+end
+% Second check that all defined covariates actually are covariates
+covcatNames = [covNames catNames];
+for k=1:length(covariateModel),
+    for k2=2:length(covariateModel{k}),
+        cov = covariateModel{k}{k2};
+        if isempty(strmatchIQM(cov,covcatNames,'exact')),
+            error(sprintf('Please make sure that all covariates, defined in covariateModel, are defined in the dataset\n   This error might be due to a categorical covariate having only single category.'));
+        end
+    end
+end
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/modelconversion/checkAndChangeModelSyntax4NONMEMconversionIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/modelconversion/checkAndChangeModelSyntax4NONMEMconversionIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..6b8008f47386b5d983a11801aa8adee255f799d7
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/modelconversion/checkAndChangeModelSyntax4NONMEMconversionIQM.m	
@@ -0,0 +1,117 @@
+function [ model ] = checkAndChangeModelSyntax4NONMEMconversionIQM( model,dosing,FLAG_CMT )
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check reactions - for now we do not allow reactions in the IQMmodel
+% for NONMEM conversion
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if length(IQMreactions(model)) > 0,
+    error('Model not allowed to contain reactions.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check dosing for other than BOLUS and INFUSION
+% We will only allow BOLUS and INFUSION for NONMEM conversion ... not a
+% limitation but simpler and cleaner
+% Change 06.01.2016: we also allow zero order absorption.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ds = struct(dosing);
+allTypes = {ds.inputs.type};
+if ismember('ABSORPTION1',allTypes),
+    error('ABSORPTION1 dosing not allowed for NONMEM conversion - please code an absorption compartment and use a BOLUS input.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check if "T" is used in the model 
+% and check other things
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% first check that "T" is not a state, variable, parameter or reaction name
+sn = IQMstates(model);
+pn = IQMparameters(model);
+vn = IQMvariables(model);
+rn = IQMreactions(model);
+allelements = {sn{:} pn{:} vn{:} rn{:}};
+if ~isempty(strmatchIQM('T',allelements,'exact')),
+    error('''T'' defined in the model, but NONMEM uses it as the time variable.');
+end
+if ~isempty(strmatchIQM('F',allelements,'exact')),
+    error('''F'' defined in the model, but NONMEM uses it as reserved word - please change it in the model.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% REPLACE some functions wth fortran equivalents accepted by NONMEM 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+nonmemfct = {'LOG','LOG10','EXP','SQRT','SIN','COS','ABS','TAN','ASIN','ACOS','ATAN','ABS'};
+iqmmodelfct = lower({'LOG','LOG10','EXP','SQRT','SIN','COS','ABS','TAN','ASIN','ACOS','ATAN','ABS'});
+for k=1:length(nonmemfct),
+    model = replaceelementIQM(model,iqmmodelfct{k},nonmemfct{k});
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% REPLACE ^ by **
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+modelTextStructure = convertModelToTextIQM(model);
+modelText = setPartsToCompleteTextIQM(modelTextStructure);
+modelText = strrep(modelText,'^','**');
+[IQMstructure,errorMsg] = convertTextToModelIQM(modelText);
+model = IQMmodel(IQMstructure);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle the FLAG_CMT thingy - but only if FLAG_CMT=0
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+if FLAG_CMT==1,
+    return
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check if multiple inputs on same state - if yes => error
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ms = struct(model);
+for k=1:length(ms.inputs),
+    if length(ms.inputs(k).stateindex)>1,
+        error(sprintf('An INPUTn definition is used on more than one state. This can not be handled.'))
+    end
+end
+if length(ms.inputs) ~= length(unique([ms.inputs.stateindex])),
+    error(sprintf('Multiple INPUTn definitions on the same state.\n\tThe ADM/YTYPE version can not be used.\n\tPlease use the CMT version.'))
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Now reorder the states according to the INPUTn numbers
+% INPUT1 => state 1
+% INPUT2 => state 2
+% ...
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ms = struct(model);
+input_numbers = [];
+state_numbers = [];
+for k=1:length(ms.inputs),
+    input_numbers(end+1) = eval(strrep(ms.inputs(k).name,'INPUT',''));
+    state_numbers(end+1) = ms.inputs(k).stateindex;
+end
+if length(ms.states)<max(input_numbers),
+    error('Model can not be handled by NONMEM due to INPUT* number larger than state numbers - consider changing INPUT* number.');
+end
+% Reorder inputs and states in input order
+% First create a table linking input and state numbers
+input_states = [NaN(length(ms.states),1) [1:length(ms.states)]'];
+for k=1:length(state_numbers),
+    input_states(state_numbers(k)) = input_numbers(k);
+end
+% These non input states still need to be assigned new numbers
+% determine which state numbers are still available
+available_state_numbers = setdiff(1:length(ms.states),input_numbers);
+% Distribute the available_state_numbers to the NaN input values
+input_states(isnan(input_states(:,1)),1) = available_state_numbers;
+
+
+% Column one in input_states defines the new state numbers and second column the old ones
+% Now switch the ODEs
+sort_ix = sortrows(input_states,1);
+ms.states = ms.states(sort_ix(:,2));
+% Need to reassign stateindex in ms.states.input
+for k=1:length(ms.inputs),
+    ms.inputs(k).stateindex = input_numbers(k);
+end
+% Create again a model and return
+model = IQMmodel(ms);
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/modelconversion/checkHandleDefaultInputArguments4NONMEMconversionIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/modelconversion/checkHandleDefaultInputArguments4NONMEMconversionIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..1a56fd34da14c3aceb03245ee7435311ca6a0b9c
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/modelconversion/checkHandleDefaultInputArguments4NONMEMconversionIQM.m	
@@ -0,0 +1,149 @@
+function [ POPestimate,POPvalues0,IIVestimate,IIVvalues0,IIVdistribution,covariateModel, covariateModelValues, COVestimate ] = checkHandleDefaultInputArguments4NONMEMconversionIQM( oldpath,param_est,POPestimate,POPvalues0,IIVestimate,IIVvalues0,IIVdistribution,covariateModel, covariateModelValues, COVestimate )
+% Do some checks on the input arguments and assign default values if
+% needed.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check POPestimate thing
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(POPestimate),
+    POPestimate = ones(1,length(param_est));
+end
+if length(param_est) ~= length(POPestimate),
+    error('Please make sure POPestimate is of same length as number of parameters to be estimated.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check POPvalues0 thing
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(POPvalues0),
+    POPvalues0 = [];
+    for k=1:length(param_est),
+        POPvalues0(k) = param_est(k).value0(1);
+    end
+end
+if length(param_est) ~= length(POPvalues0),
+    cd(oldpath);
+    error('Please make sure POPvalues0 is of same length as number of parameters to be estimated.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check IIV distribution things
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(IIVdistribution),
+    IIVdistribution = {};
+    for k=1:length(param_est),
+        IIVdistribution{k} = 'L';
+    end
+end
+
+% Check contents
+test = IIVdistribution;
+for k=1:length(IIVdistribution),
+    if ~ismember(test{k},{'L','N','G'}),
+        cd(oldpath);
+        error('Please make sure that only "N", "L", or "G" appear in the "IIVdistribution" variable.');
+    end
+end
+
+% Check length
+if length(IIVdistribution) ~= length(param_est),
+    cd(oldpath);
+    error('Please make sure that an equal number of IIVdistribution is defined as estimated parameters in the model.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check IIV estimation things
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(IIVestimate),
+    IIVestimate = ones(1,length(param_est));
+end
+% Check length
+if length(IIVestimate) ~= length(param_est),
+    cd(oldpath);
+    error('Please make sure that an equal number of IIVestimate is defined as estimated parameters in the model.');
+end
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check IIVvalues0 thing
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(IIVvalues0),
+    IIVvalues0 = 0.5*ones(1,length(param_est));
+end
+if length(param_est) ~= length(IIVvalues0),
+    cd(oldpath);
+    error('Please make sure IIVvalues0 is of same length as number of parameters to be estimated.');
+end
+
+% Convert covariate model into different syntax
+% '{CL,BMI0}, {Fsubcut,WT0}, {Vc,SEX,BMI0}'
+% to
+% {{'CL','BMI0'}, {'Fsubcut','WT0'}, {'Vc','SEX','BMI0'}}
+if ~isempty(covariateModel),
+    terms = explodePCIQM(covariateModel,',','{','}');
+    y = {};
+    for k=1:length(terms),
+        x = strrep(strtrim(terms{k}),' ','');
+        x = strrep(x,'{','{''');
+        x = strrep(x,'}','''}');
+        x = strrep(x,',',''',''');
+        y{k} = eval(x);
+    end
+    covariateModel = y;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check covariateModelValues
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(covariateModel) && ~isempty(covariateModelValues),
+    error('If you define covariateModelValues, you also need to define the covariateModel.');
+end
+
+if isempty(covariateModelValues),
+    % Determine default covariateModelValues
+    covariateModelValues = {};
+    for k=1:length(covariateModel),
+        covariateModelValues{k} = 0.1*ones(1,length(covariateModel{k})-1);
+    end
+else
+    % Check correct length of covariateModelValues elements
+    if length(covariateModel) ~= length(covariateModelValues),
+        error('Number of elements in covariateModel and covariateModelValues needs to match.');
+    end
+    for k=1:length(covariateModel),
+        if length(covariateModel{k})-1 ~= length(covariateModelValues{k}),
+            error('Length of single elements in covariateModel and covariateModelValues needs to match (covariateModelValues elements being one shorter).');
+        end
+    end
+    % Check if one of the covariateModelValues is 0 (not allowed in NONMEM)
+    for k=1:length(covariateModel),
+        if sum(covariateModelValues{k} == 0) > 0,
+            error('Initial guess for at least one covariate coefficient is 0. Not allowed for NONMEM!');
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check COVestimate
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(covariateModel) && ~isempty(COVestimate),
+    error('If you define COVestimate, you also need to define the covariateModel.');
+end
+
+if isempty(COVestimate),
+    % Determine default COVestimate - all are estimates
+    COVestimate = {};
+    for k=1:length(covariateModel),
+        COVestimate{k} = ones(1,length(covariateModel{k})-1);
+    end
+else
+    % Check correct length of COVestimate elements
+    if length(covariateModel) ~= length(COVestimate),
+        error('Number of elements in covariateModel and COVestimate needs to match.');
+    end
+    for k=1:length(covariateModel),
+        if length(covariateModel{k})-1 ~= length(COVestimate{k}),
+            error('Length of single elements in covariateModel and COVestimate needs to match (COVestimate elements being one shorter).');
+        end
+    end
+end
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/modelconversion/getmodelPartTextInfo4NONMEMconversion.m b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/modelconversion/getmodelPartTextInfo4NONMEMconversion.m
new file mode 100644
index 0000000000000000000000000000000000000000..0b2b5d40d7341434f295d4e1b8e75e9bb2e7629e
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/modelconversion/getmodelPartTextInfo4NONMEMconversion.m	
@@ -0,0 +1,144 @@
+function [StatesText, ParametersText, VariablesText, ODEsText] = getmodelPartTextInfo4NONMEMconversion(model,model_element_prefix,param_est,modelInfo,time_variable_replacement)
+% Add prefix to model elements that need it and return formatted
+% strings for states, parameters, variables and ODEs ... to be used for
+% NONMEM conversion.
+% Also the time variable is handled appropriately
+
+% Start by handling the time variable
+model = replaceelementIQM(model,'time',time_variable_replacement);
+ 
+% Determine elements that might need prefix
+sn = IQMstates(model);
+rn = IQMreactions(model);
+% For variables do not consider OUTPUTx
+vn = IQMvariables(model);
+ix = strmatchIQM('OUTPUT',vn);
+vn(ix) = [];
+% For parameters we need to NOT consider the ones which are handled already and the
+% ones which are related to the INPUTs
+pn = IQMparameters(model);
+pn = setdiff(setdiff(setdiff(pn,{param_est.name}),{modelInfo.param_pk.name}),{modelInfo.param_reg.name});
+ix = strmatchIQM('INPUT',pn);
+pn(ix) = [];
+
+% Implement the prefix
+allelements = {sn{:} pn{:} vn{:} rn{:}};
+for k=1:length(allelements),
+    model = replaceelementIQM(model,allelements{k},[model_element_prefix allelements{k}]);
+end
+
+% Get new element names
+for k=1:length(sn),
+    sn{k} = [model_element_prefix sn{k}];
+end
+
+for k=1:length(pn),
+    pn{k} = [model_element_prefix pn{k}];
+end
+
+for k=1:length(vn),
+    vn{k} = [model_element_prefix vn{k}];
+end
+
+for k=1:length(rn),
+    rn{k} = [model_element_prefix rn{k}];
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get model structure
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ms = struct(model);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get States text
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+StatesText = '';
+for k=1:length(ms.states),
+    StatesText = sprintf('%s    %s%s = A(%d)\r\n',StatesText,ms.states(k).name,char(32*ones(1,cellmaxlengthIQM({ms.states.name})-length(ms.states(k).name)+1)),k);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get Parameters text
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ParametersText = '';
+for k=1:length(pn),
+    pv = IQMparameters(model,pn{k});
+    ParametersText = sprintf('%s    %s%s = %g\r\n',ParametersText,pn{k},char(32*ones(1,cellmaxlengthIQM(pn)-length(pn{k})+1)),pv);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get Variables text
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+VariablesText = '';
+% write out variables but neglect the following ones:
+%   - output definitions
+%   - regression parameters as variables
+allvarindices = [1:length(ms.variables)];
+% remove output variables
+outputvarindices = [modelInfo.outputs.varindex];
+varindices = setdiff(allvarindices,outputvarindices);
+% remove regression parameters implemented as variables in the IQMmodel
+if ~isempty(modelInfo.param_reg),
+    regparvarindices = [modelInfo.param_reg.varindex];
+    varindices = setdiff(varindices,regparvarindices);
+end
+% Write out the variables
+if ~isempty(varindices),
+    for k=1:length(varindices),
+        % check if variable contains a construct that needs special
+        % handling - at the moment this is only piecewiseIQM, min, max
+        formula = ms.variables(varindices(k)).formula;
+        flag_piecewise = ~isempty(strfind(formula,'piecewiseIQM'));
+        flag_min       = ~isempty(strfind(formula,'min('));
+        flag_max       = ~isempty(strfind(formula,'max('));
+        if flag_piecewise+flag_min+flag_max > 1,
+            error('Model contains more than one MAX, MIN or PIECEWISEIQM expression in a variable assignment. Only one is allowed.');
+        end
+        
+        if flag_piecewise+flag_min+flag_max == 0,
+            % Neither piecewiseIQM, nor min, nor max expressions present
+            VariablesText = sprintf('%s    %s%s = %s\r\n',VariablesText,ms.variables(varindices(k)).name,char(32*ones(1,cellmaxlengthIQM({ms.variables.name})-length(ms.variables(varindices(k)).name)+1)),ms.variables(varindices(k)).formula);
+        elseif flag_piecewise,
+            % piecewise contruct present in formula
+            newText = handleNONMEMpiecewiseIQM(ms.variables(varindices(k)).name,ms.variables(varindices(k)).formula);
+            VariablesText = sprintf('%s\r\n    %s\r\n\r\n',VariablesText,newText);
+        elseif flag_min,
+            % min expression present
+            newText = handleNONMEMminmaxIQM(ms.variables(varindices(k)).name,ms.variables(varindices(k)).formula,'min');
+            VariablesText = sprintf('%s\r\n    %s\r\n\r\n',VariablesText,newText);
+        elseif flag_max
+            % max expression present
+            newText = handleNONMEMminmaxIQM(ms.variables(varindices(k)).name,ms.variables(varindices(k)).formula,'max');
+            VariablesText = sprintf('%s\r\n    %s\r\n\r\n',VariablesText,newText);
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get ODEs text
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ODEsText = '';
+ODEs = {};
+for k=1:length(ms.states),
+    ODE = ms.states(k).ODE;
+    % remove input terms (do this already general for several inputs)
+    for k2 = 1:length(modelInfo.inputs),
+        % check if current input exists in current (k-th) ODE:
+        index = find(modelInfo.inputs(k2).stateindex == k);
+        if ~isempty(index),
+            % the input term to replace is:
+            termreplace = modelInfo.inputs(k2).terms{index};
+            ODE = strrep(ODE,termreplace,'');
+        end
+    end
+    % Remove prefix "+"
+    ODE = strtrim(ODE);
+    if ODE(1)=='+',
+        ODE = ODE(2:end);
+    end
+    ODEs{k} = ODE;
+end
+for k=1:length(ms.states),
+    % write out the ODE
+    ODEsText = sprintf('%s    DADT(%d) = %s%s ; %s\r\n',ODEsText,k,ODEs{k},char(32*ones(1,cellmaxlengthIQM(ODEs)-length(ODEs{k})+1)),strrep(ms.states(k).name,model_element_prefix,''));
+end
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/modelconversion/handleCovariateDefinitionsIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/modelconversion/handleCovariateDefinitionsIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..00dbb63adc1cc2a64d9c2a8f37afff189b0ae194
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/modelconversion/handleCovariateDefinitionsIQM.m	
@@ -0,0 +1,164 @@
+function [ MU_param_text,THETA_INDEX_BETA,beta_parameters,text_defining_cat_auxiliaries,cov_type_continuous,covparam,covcov,beta_parameters_cov_project_info,beta_parameters_cat_project_info,COV_transformation_info,CAT_reference_info,CAT_categories_info,COVCATestimate_info ] = handleCovariateDefinitionsIQM( MU_param_text,covariateModel,param_est,covariateMedianValues,covariateMedianNames,covariateCATNames,covariateCATValues,IIVdistribution,COVestimate )
+%%
+beta_parameters     = {};
+beta_parameters_cov_project_info     = {};
+beta_parameters_cat_project_info     = {};
+THETA_INDEX_BETA    = [];
+cov_type_continuous = [];
+covparam            = {};
+covcov              = {};
+
+COV_transformation_info = {};
+CAT_reference_info = {};
+CAT_categories_info = {};
+
+COVCATestimate_info = [];
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle the CONTINUOUS covariate definitions and their introduction into
+% the MU referencing.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+parameter_add_cov   = {};
+cov_add_cov         = {};
+cov_add_median      = [];
+covTrans_text       = {};
+count = 1;
+for kcov=1:length(covariateModel),
+    covParam = covariateModel{kcov}{1};
+    covCOVs  = covariateModel{kcov}(2:end);
+    for k2=1:length(covCOVs),
+        if ismember(covCOVs{k2},covariateMedianNames),
+            beta_parameters{end+1}      = sprintf('beta_%s(%s)',covParam,covCOVs{k2});
+            theta_index                 = length(param_est)+count;
+            THETA_INDEX_BETA(end+1)     = theta_index;
+            cov_type_continuous(end+1)  = 1;
+            count                       = count+1;
+            parameter_add_cov{end+1}    = covParam;
+            cov_add_cov{end+1}          = covCOVs{k2};
+            cov_median                  = covariateMedianValues(strmatchIQM(covCOVs{k2},covariateMedianNames,'exact'));
+            cov_add_median(end+1)       = cov_median;
+            
+            COVCATestimate_info(end+1)  = COVestimate{kcov}(k2);
+            
+            % find index of parameter to add covariate to
+            ix                          = strmatchIQM(covParam,{param_est.name},'exact');
+            % Get transformation
+            TRANS                       = IIVdistribution{ix};
+            if TRANS=='N',
+                covTrans_text{end+1} = sprintf('+ THETA(%d)*log(%s/%g) ',theta_index,covCOVs{k2},cov_median);
+%                 covTrans_text{end+1} = sprintf('+ THETA(%d)*(%s/%g) ',theta_index,covCOVs{k2},cov_median);
+%                 COV_transformation_info{end+1} = sprintf('cov/%g',cov_median);
+                COV_transformation_info{end+1} = sprintf('log(cov/%g)',cov_median);
+            elseif TRANS=='L',
+                covTrans_text{end+1} = sprintf('+ THETA(%d)*log(%s/%g) ',theta_index,covCOVs{k2},cov_median);
+                COV_transformation_info{end+1} = sprintf('log(cov/%g)',cov_median);
+            elseif TRANS=='G',
+                covTrans_text{end+1} = sprintf('+ THETA(%d)*log(%s/%g) ',theta_index,covCOVs{k2},cov_median);
+%                 covTrans_text{end+1} = sprintf('+ THETA(%d)*log(%s/(%g-%s)) ',theta_index,covCOVs{k2},cov_median,covCOVs{k2});
+%                 COV_transformation_info{end+1} = sprintf('log(cov./(%g-cov))',cov_median);
+                COV_transformation_info{end+1} = sprintf('log(cov/%g)',cov_median);
+            end
+        end
+    end
+end
+% Aggregate covariate text for each parameter
+cov_add_text_param = cell(1,length(param_est));
+cov_add_text_param(1:end) = {''};
+for k=1:length(parameter_add_cov),
+    ix = strmatchIQM(parameter_add_cov{k},{param_est.name},'exact');
+    cov_add_text_param{ix} = [cov_add_text_param{ix} covTrans_text{k}];
+end
+% Add continuous covariates into MU_param_text
+for k=1:length(MU_param_text),
+    MU_param_text{k} = strrep(MU_param_text{k},'X#X#X',[strtrim(cov_add_text_param{k}) 'X#X#X']);
+end
+% Save for later
+covparam            = parameter_add_cov;
+covcov              = cov_add_cov;
+
+beta_parameters_cov_project_info     = beta_parameters;
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle the categorical covariates
+% 
+% Example:
+% SEX_1 = 0 (can be omitted)
+% SEX_2 = 0
+% SEX_3 = 0
+% IF SEX==1 THEN SEX_1 = 1 (can be omitted)
+% IF SEX==2 THEN SEX_2 = 1
+% IF SEX==3 THEN SEX_3 = 1
+%     
+% MU_3  = THETA(3) + beta_SEX_2_WT*SEX_2 + beta_SEX_3_WT*SEX_3
+% 
+% Assume reference is always the first one with the smallest number
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+text_defining_cat_auxiliaries = '';
+cov_text = cell(1,length(param_est));
+cov_text(1:end) = {''};
+covs_handled_text_defining_cat_auxiliaries = {};
+for kcov=1:length(covariateModel),
+    covParam = covariateModel{kcov}{1};
+    covCOVs  = covariateModel{kcov}(2:end);
+    for k2=1:length(covCOVs),
+        if ismember(covCOVs{k2},covariateCATNames),
+            cov                         = covCOVs{k2};
+            cov_values                  = covariateCATValues{strmatchIQM(covCOVs{k2},covariateCATNames,'exact')};
+            reference_value             = cov_values(1);
+            other_values                = cov_values(2:end);
+            
+            CAT_reference_info{end+1}   = reference_value;
+            CAT_categories_info{end+1}  = cov_values;
+                        
+            % Define the auxiliary text to be added before the MU thingy
+            if ~ismember(cov,covs_handled_text_defining_cat_auxiliaries),
+                for kaux=1:length(other_values),
+                    text_defining_cat_auxiliaries = sprintf('%s    %s_%d = 0 ; reference: %d\r\n',text_defining_cat_auxiliaries,cov,other_values(kaux),reference_value);
+                end
+                for kaux=1:length(other_values),
+                    text_defining_cat_auxiliaries = sprintf('%s    IF(%s.EQ.%d) %s_%d = 1\r\n',text_defining_cat_auxiliaries,cov,other_values(kaux),cov,other_values(kaux));
+                end
+                % Set cov as handled
+                covs_handled_text_defining_cat_auxiliaries{end+1} = cov;
+            end
+            
+            % Define the rest
+            for kaux=1:length(other_values),
+                COVCATestimate_info(end+1)  = COVestimate{kcov}(k2);
+                
+                covparam{end+1} = covParam;
+                covcov{end+1} = cov;
+                beta_parameters{end+1}      = sprintf('beta_%s(%s_%d)',covParam,cov,other_values(kaux));
+                
+                % Check if beta_parameters_cat_project_info already
+                % contains element
+                element_add_check = sprintf('beta_%s(%s)',covParam,cov);
+                if isempty(strmatchIQM(element_add_check,beta_parameters_cat_project_info,'exact')),
+                    % not present => add it
+                    beta_parameters_cat_project_info{end+1} = element_add_check;
+                end
+                
+                if isempty(THETA_INDEX_BETA),
+                    nextindex = length(param_est)+1;
+                else
+                    nextindex                   = max(THETA_INDEX_BETA)+1;
+                end
+                THETA_INDEX_BETA(end+1)     = nextindex;
+                cov_type_continuous(end+1)  = 0;
+                ixParam                     = strmatchIQM(covParam,{param_est.name},'exact');
+                cov_text{ixParam}           = sprintf('%s + THETA(%d)*%s_%d',cov_text{ixParam},nextindex,cov,other_values(kaux));
+            end
+        end
+    end
+end
+
+% Add continuous covariates into MU_param_text
+for k=1:length(MU_param_text),
+    MU_param_text{k} = strrep(MU_param_text{k},'X#X#X',cov_text{k});
+end
+
+% CAT_reference_info = {};
+% CAT_categories_info = {};
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/modelconversion/handleNONMEMminmaxIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/modelconversion/handleNONMEMminmaxIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..5fd5f63ee7a3a4cb24a6719ebfb24b669ba40b6e
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/modelconversion/handleNONMEMminmaxIQM.m	
@@ -0,0 +1,52 @@
+function [ changedformula ] = handleNONMEMminmaxIQM(name,formula,type)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE PIECEWISE EXPRESSIONS => if elseif else end
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+formula = strtrim(formula);
+% 1) Check that only a single piecewise expression 
+index = strfind(formula,[type '(']);
+if length(index) > 1,
+    error('More than one min or max expression in formula ''%s''. Only one is allowed.',formula);
+end
+% 2) Get the expression
+mmformula = strtrim(formula(index:end));
+offset = length([type '('])+1;
+po = 1;
+while po~=0,
+    if mmformula(offset) == '(',
+        po = po+1;
+    end
+    if mmformula(offset) == ')',
+        po = po-1;
+    end
+    offset = offset+1;
+end
+mmformula = mmformula(1:offset-1);
+% 3) Check length mmformula against formula. If not same => error, since
+% then additional terms are present in the formula.
+if length(formula) ~= length(mmformula),
+    error('Formula ''%s'' contains more than a simple min or max expression => please reformulate the IQMmodel.',formula);
+end
+% 4) Get elements of expression
+elements = explodePCIQM(mmformula(5:end-1));
+% 5) contruct the IF THEN expression
+
+% if 
+if strcmp(type,'max'),
+    text = sprintf('IF((%s).GT.(%s)) THEN\r\n',elements{1},elements{2});
+    text = sprintf('%s        %s = %s\r\n',text,name,elements{1});
+    text = sprintf('%s    ELSE\r\n',text);
+    text = sprintf('%s        %s = %s\r\n',text,name,elements{2});
+    text = sprintf('%s    ENDIF',text);
+else
+    text = sprintf('IF((%s).LT.(%s)) THEN\r\n',elements{1},elements{2});
+    text = sprintf('%s        %s = %s\r\n',text,name,elements{1});
+    text = sprintf('%s    ELSE\r\n',text);
+    text = sprintf('%s        %s = %s\r\n',text,name,elements{2});
+    text = sprintf('%s    ENDIF',text);
+end
+changedformula = text;
+return
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/modelconversion/handleNONMEMpiecewiseIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/modelconversion/handleNONMEMpiecewiseIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..3fe42c554c8c8a8fcf20bdebabcf9b4684985d99
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/modelconversion/handleNONMEMpiecewiseIQM.m	
@@ -0,0 +1,110 @@
+function [ changedformula ] = handleNONMEMpiecewiseIQM(name,formula)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE PIECEWISE EXPRESSIONS => if elseif else end
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+formula = strtrim(formula);
+% 1) Check that only a single piecewise expression 
+index = strfind(formula,'piecewiseIQM');
+if length(index) > 1,
+    error('More than one piecewise expression in formula ''%s''. Only one is allowed.',formula);
+end
+% 2) Get the piecewise expression
+pwformula = strtrim(formula(index:end));
+offset = length('piecewiseIQM(')+1;
+po = 1;
+while po~=0,
+    if pwformula(offset) == '(',
+        po = po+1;
+    end
+    if pwformula(offset) == ')',
+        po = po-1;
+    end
+    offset = offset+1;
+end
+pwformula = pwformula(1:offset-1);
+% 3) Check length pwformula against formula. If not same => error, since
+% then additional terms are present in the formula.
+if length(formula) ~= length(pwformula),
+    error('Formula ''%s'' contains more than a simple piecewise expression => please reformulate the IQMmodel.',formula);
+end
+% 4) Get elements of pw expression
+elements = explodePCIQM(pwformula(14:end-1));
+% 5) parse and convert the trigger expressions
+for k=2:2:length(elements),
+    elements{k} = convertlogicalrelationalexpressions(elements{k});
+end
+% 6) check if an else is present
+n = length(elements);
+if n/2 == floor(n/2),
+    elsepresent = 0;
+else
+    elsepresent = 1;
+end
+% 6) construct the if elseif else text
+if elsepresent,
+    elseelement = elements{end};
+    elements = elements(1:end-1);
+end
+% if 
+text = sprintf('IF(%s) THEN\r\n        %s = %s\r\n',elements{2},name,elements{1});
+% elseif
+if length(elements) > 2,
+    for k=4:2:length(elements),
+        text = sprintf('%s    ELSEIF(%s) THEN\r\n        %s = %s\r\n',text,elements{k},name,elements{k-1});        
+    end
+end
+% else
+if elsepresent,
+    text = sprintf('%s    ELSE\r\n        %s = %s\r\n',text,name,elseelement);
+end
+% end
+text = sprintf('%s    ENDIF',text);
+% done
+changedformula = text;
+return
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PARSE AND CONVERT LOGICAL AND RELATIONAL OPERATORS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% the syntax of MLXTRAN only allows two elements for each and, or, ...
+% and(gt(time,5),lt(time,10)) => (time.gt.5).and.(time.lt.10)
+function [exp] = convertlogicalrelationalexpressions(exp)
+operatorsfind = {'and','or','andIQM','orIQM','lt','gt','le','ge','eq','ne'};
+operatorsuse  = {'.AND.','.OR.','.AND.','.OR.',' < ',' > ',' <= ',' >= ',' == ',' /= '};
+exp = ['#' exp '#'];
+for k=1:length(operatorsfind),
+    index = regexp(exp,['\W' operatorsfind{k} '\W']);
+    if ~isempty(index),
+        % get pre text
+        exppre = exp(1:index);
+        % get post text and arguments
+        temp = exp(index+1+length(operatorsfind{k})+1:end);
+        po = 1;
+        offset = 1;
+        while po~= 0,
+            if temp(offset) == '(',
+                po = po+1;
+            end
+            if temp(offset) == ')',
+                po = po-1;
+            end
+            offset = offset + 1;
+        end
+        args = explodePCIQM(temp(1:offset-2));
+        if length(args) > 2,
+            error('Only two arguments allowed in an ''andIQM'' or ''orIQM'' when converting piecewiseIQM to MLXTRAN.');
+        end
+        exppost = temp(offset:end);
+        % get args
+        exp = [exppre '(' args{1} ')' operatorsuse{k} '(' args{2} ')'   exppost];
+    end
+end
+exp = exp(2:end-1);
+return
+
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/modelconversion/processDataAndGetMedianValuesIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/modelconversion/processDataAndGetMedianValuesIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..4d336b173adc0012a1cf45266667a1419a64d551
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/modelconversion/processDataAndGetMedianValuesIQM.m	
@@ -0,0 +1,111 @@
+function [ covariateMedianNames,covariateMedianValues,covariateCATNames,covariateCATValues,dataheader,dataCSV ] = processDataAndGetMedianValuesIQM( oldpath,dataRelPathFromProject,dataFileName,dataHeaderIdent,SILENT,COVcentering_covs,COVcentering_values  )
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check if datafile exists and csv file and load some information
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+dataFile = fullfile(dataRelPathFromProject,dataFileName);
+try
+    dataheader = IQMloadCSVdataset(dataFile,1);
+catch
+    cd(oldpath);
+    error('Please check if the data file "%s" exists.',dataFile)
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check if length of header identical to dataHeaderIdent
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if length(explodePCIQM(dataHeaderIdent,',')) ~= length(dataheader),
+    cd(oldpath);
+    error('Please check: The data header identifiers do not have the same length as the number of columns in the dataset.')
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Load dataset and get header information
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+dataCSV     = IQMloadCSVdataset(fullfile(dataRelPathFromProject,dataFileName));
+dataheader  = dataCSV.Properties.VariableNames;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check the NLME dataset for the minimal required columns
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+IQMcheckNLMEdatasetHeader(dataCSV);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Determine medians for covariates
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Determine index of COV columns and their names
+terms                   = explodePCIQM(dataHeaderIdent);
+ixCOVs                  = strmatchIQM('COV',terms,'exact');
+
+covariateMedianValues = [];
+covariateMedianNames = {};
+if ~isempty(ixCOVs),
+    dataheaderCOVs      = dataheader(ixCOVs);
+    
+    % Determine index of ID column and ID name
+    terms               = explodePCIQM(dataHeaderIdent);
+    ixID                = strmatchIQM('ID',terms,'exact');
+    dataheaderID        = dataheader(ixID);
+    
+    % Get covariate values for each individual
+    allID               = unique(dataCSV.(dataheaderID{1}));
+    allCOVs             = NaN(length(allID),length(ixCOVs));
+    for k=1:length(allID),
+        datak           = dataCSV(dataCSV.(dataheaderID{1})==allID(k),ixCOVs);
+        allCOVs(k,:)    = table2array(datak(1,:));
+    end
+    
+    % Determine median
+    covariateMedianValues   = median(allCOVs);
+    covariateMedianNames    = dataheaderCOVs;
+    
+    % Handle custom centering values
+    for k=1:length(COVcentering_covs),
+        ix = strmatchIQM(COVcentering_covs{k},covariateMedianNames,'exact');
+        covariateMedianValues(ix) = COVcentering_values(k);
+    end
+    
+    if ~SILENT,
+        disp(' ')
+        disp('Analysis of dataset for covariates - determine the centering values  ')
+        disp('These are the median values, if not defined differently by the user.')
+        disp(' Results:');
+        for k=1:length(covariateMedianValues),
+            disp(sprintf('   median(%s) = %g',covariateMedianNames{k},covariateMedianValues(k)));
+        end
+        disp('These values will be used to center the continuous covariates')
+        disp(' ')
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Determines the categorical covariates and the elements they can take
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Determine index of COV columns and their names
+terms                   = explodePCIQM(dataHeaderIdent);
+ixCATs                  = strmatchIQM('CAT',terms,'exact');
+
+covariateCATValues = {};
+covariateCATNames = {};
+if ~isempty(ixCATs),
+    dataheaderCATs      = dataheader(ixCATs);
+    
+    % Get unique elements for each cat covariate and names ...
+    for k=1:length(ixCATs),
+        covariateCATNames{k} = dataheaderCATs{k};
+        covariateCATValues{k} = unique(dataCSV.(dataheaderCATs{k}));
+        if sum(isnan(unique(dataCSV.(dataheaderCATs{k})))) > 0,
+            error('The categorical covariate "%s" contains NaN => please impute before running the parameter estimation.',dataheaderCATs{k});
+        end
+    end
+    
+    % Print information about reference values
+    if ~SILENT,
+        disp(' ');
+        disp('The following values for the categorical covariates are used as reference values:');
+        for k=1:length(covariateCATNames),
+            disp(sprintf('\t%s%s: %d',covariateCATNames{k},char(32*ones(1,cellmaxlengthIQM(covariateCATNames)-length(covariateCATNames{k})+5)),covariateCATValues{k}(1)));
+        end
+        disp(' ');
+    end
+end
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/modelconversion/reorderParameters4NONMEMcovIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/modelconversion/reorderParameters4NONMEMcovIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..5352c9a0f4467fff6d828dcf6a20c8f7e5660b6e
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/modelconversion/reorderParameters4NONMEMcovIQM.m	
@@ -0,0 +1,48 @@
+function [param_est_trans,POPestimate_trans,POPvalues0_trans,IIVestimate_trans,IIVvalues0_trans,IIVdistribution_trans] = reorderParameters4NONMEMcovIQM(covarianceModel,param_est,POPestimate,POPvalues0,IIVestimate,IIVvalues0,IIVdistribution)
+% Change the order of parameters in relvant variables based on the
+% covariance model information (we need to allow for block diagonal
+% covariance matrices)
+
+if strcmp(covarianceModel,'diagonal') || isempty(covarianceModel),
+    % Keep parameters in the given order
+    POPestimate_trans       = POPestimate;
+    POPvalues0_trans        = POPvalues0;
+    IIVestimate_trans       = IIVestimate;
+    IIVvalues0_trans        = IIVvalues0;
+    param_est_trans         = param_est;
+    IIVdistribution_trans   = IIVdistribution;    
+else
+    % Need to rearrange
+    % Determine the order of parameters as they appear in the
+    % covarianceModel definition
+    x = strrep(covarianceModel,'{','');
+    x = strrep(x,'}','');
+    terms = explodePCIQM(x);
+    % Check which parameters are missing
+    paramnames_order = terms;
+    for k=1:length(param_est),
+        if ~ismember(param_est(k).name,paramnames_order),
+            paramnames_order{end+1} = param_est(k).name;
+        end
+    end
+    % Determine the transformation indices
+    index_trans = [];
+    for k=1:length(paramnames_order),
+        index_trans(k) = strmatchIQM(paramnames_order{k},{param_est.name},'exact');
+    end
+    % Ok, we got the new order of the parameters, now we need to change the
+    % order in a couple of things
+    % POPestimate
+    % POPvalues0
+    % IIVdistribution
+    % IIVestimate
+    % IIVvalues0
+    % param_est
+    POPestimate_trans       = POPestimate(index_trans);
+    POPvalues0_trans        = POPvalues0(index_trans);
+    IIVestimate_trans       = IIVestimate(index_trans);
+    IIVvalues0_trans        = IIVvalues0(index_trans);
+    param_est_trans         = param_est(index_trans);
+    IIVdistribution_trans   = IIVdistribution(index_trans);
+end
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/modelconversion/wrapRowTextIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/modelconversion/wrapRowTextIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..b566dd76967bfedcceae6068dbc4c3822653de4c
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/modelconversion/wrapRowTextIQM.m	
@@ -0,0 +1,20 @@
+function [ wraptext ] = wrapRowTextIQM( text,ncol, npre )
+% wrapRowTextIQM: wraps the text to max ncol characters per row and adds
+% npre spaces at the beginning of all subsequent rows
+
+textwork            = text;
+wraptext            = '';
+while length(textwork)>ncol,
+    ixSpace = find(double(textwork)==32);
+    ixSpaceAbove = find(ixSpace>ncol);
+    if ~isempty(ixSpaceAbove),
+        ixSpaceLimit = ixSpace(ixSpaceAbove(1)-1);
+    else
+        ixSpaceLimit = ixSpace(end);
+    end
+    wraptext = sprintf('%s%s\r\n',wraptext,textwork(1:ixSpaceLimit-1));
+    textwork = [char(32*ones(1,npre)) textwork(ixSpaceLimit+1:end)];
+end
+wraptext = strtrim(sprintf('%s%s\r\n',wraptext,textwork));
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/modelconversion/writeOutConversionNONMEMinformationIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/modelconversion/writeOutConversionNONMEMinformationIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..1145ad5c83df8707764c775b7553b9f3d73d3050
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/modelconversion/writeOutConversionNONMEMinformationIQM.m	
@@ -0,0 +1,31 @@
+function [ ] = writeOutConversionNONMEMinformationIQM( param_est, IIVdistribution, IIVestimate )
+
+% Print table parameter names and IIV distributions
+disp(' ');
+disp('Please check that the following matches between parameters and used IIV distributions are correct:');
+for k=1:length(param_est),
+    if IIVdistribution{k} == 'L', dtext = 'logNormal'; end
+    if IIVdistribution{k} == 'N', dtext = 'Normal'; end
+    if IIVdistribution{k} == 'G', dtext = 'logitNormal'; end
+    fprintf('\t%s%s: %s\n',param_est(k).name,char(32*ones(1,15-length(param_est(k).name))),dtext)
+end
+
+% Print table parameter names and IIV esimations
+disp(' ');
+disp('Please check that the following matches between parameters and used estimated IIVs are correct:');
+for k=1:length(param_est),
+    if IIVestimate(k) == 0,
+        fprintf('\t%s%s: IIV NOT ESTIMATED (kept on 0)\n',param_est(k).name,char(32*ones(1,15-length(param_est(k).name))));
+    elseif IIVestimate(k) == 1,
+        fprintf('\t%s%s: IIV ESTIMATED\n',param_est(k).name,char(32*ones(1,15-length(param_est(k).name))));
+    elseif IIVestimate(k) == 2,
+        fprintf('\t%s%s: IIV NOT ESTIMATED (kept on initial value)\n',param_est(k).name,char(32*ones(1,15-length(param_est(k).name))));
+    end
+end
+disp(' ');
+
+disp('Parameters selected to be estimated and their values in the model (this order):');
+for k=1:length(param_est),
+    fprintf('\t%d)\t%s%s: %g\n',k,param_est(k).name,char(32*ones(1,15-length(param_est(k).name))),param_est(k).value0(1));
+end
+disp(' ');
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/parseNONMEMetasIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/parseNONMEMetasIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..8adfcc9e730014521351f7333a6c51c05e2cb728
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/parseNONMEMetasIQM.m	
@@ -0,0 +1,45 @@
+function [ dataeta, OMEGA, OMEGAnames ] = parseNONMEMetasIQM( projectPath )
+% Parses a NONMEM project and returns the ETAs.
+% 
+% [SYNTAX]
+% [ dataeta, OMEGA, OMEGAnames ] = parseNONMEMetasIQM( projectPath )
+%
+% [INPUT]
+% projectPath:      Project to return the ETA information
+%
+% [OUTPUT]
+% dataeta:          ETA data
+% OMEGA:            OMEGA data
+% OMEGAnames:       Names of omegas
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Construct RESULTS path
+resultsPath = [projectPath '/RESULTS'];
+    
+% Check the projectPath
+if ~exist(resultsPath),
+    error(sprintf('The provided project path "%s" does not point to a valid NONMEM project.\nPlease make sure a "RESULTS" folder is in the provided path.',projectPath));
+end
+
+% Check that indiv_eta.txt is present in the RESULTS folder
+indiv_eta_file = [resultsPath '/project.eta'];
+if ~exist(indiv_eta_file)
+    error('The "project.eta" file does not exist in the RESULTS folder.');
+end
+
+% Determine random effect estimates for shrinkage determination
+x = parseNONMEMresultsIQM(projectPath);
+y = sampleNONMEMpopulationParametersIQM(x,0,1);
+OMEGA       = y.randomEffects.values;
+OMEGAnames  = y.randomEffects.names;
+
+% Load eta file
+indiv_eta   = IQMloadNONCSVdataset([resultsPath '/project.eta'],1);
+
+% Get eta modes
+dataeta = table();
+for k=1:length(OMEGAnames),
+    dataeta.(OMEGAnames{k}) = indiv_eta.(['ETA_' OMEGAnames{k}]);
+end
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/parseNONMEMindivparamIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/parseNONMEMindivparamIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..b0c7005518135e36fdafbe27de42a7d34e52d87a
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/parseNONMEMindivparamIQM.m	
@@ -0,0 +1,32 @@
+function [ indiv_param ] = parseNONMEMindivparamIQM( projectPath,numberParameters )
+% Returns the individual parameters from a NONMEM fit. numberParameters
+% needs to be provided to know how many they are, since this can change
+% depending on the settings. 
+% 
+% [SYNTAX]
+% [ indiv_param ] = parseNONMEMindivparamIQM( projectPath,numberParameters )
+%
+% [INPUT]
+% projectPath:      Project to return the ETA information
+% numberParameters: Number of parameters 
+%
+% [OUTPUT]
+% indiv_param:      MATLAB table with individual parameters
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+indiv_param             = IQMloadNONCSVdataset([projectPath '/RESULTS/project.indiv'],1);
+indiv_param             = indiv_param(:,1:numberParameters+1);
+
+% Check case of parameter names (might be changed by really cute NONMEM
+% program ...)
+X = parseNONMEMprojectHeaderIQM(projectPath);
+PN = X.PARAMNAMES;
+VN = indiv_param.Properties.VariableNames;
+for k=1:length(VN),
+    ix = strmatch(lower(VN{k}),lower(PN),'exact');
+    if ~isempty(ix),
+        VN{k} = PN{ix};
+    end
+end
+indiv_param.Properties.VariableNames = VN;
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/parseNONMEMpredictionsIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/parseNONMEMpredictionsIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..30df0443648058e3db9308c578f78f2fb9de1563
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/parseNONMEMpredictionsIQM.m	
@@ -0,0 +1,34 @@
+function [ predictions ] = parseNONMEMpredictionsIQM( projectPath,outputNumber )
+% Parses a NONMEM project and returns the predictions for a given output number.
+% Doses (EVID=1) and missing data (MDV=1) is removed.
+% 
+% [SYNTAX]
+% [ predictions ] = parseNONMEMpredictionsIQM( projectPath,outputNumber )
+%
+% [INPUT]
+% projectPath:      Project to return the ETA information
+% outputNumber:     Output for which to return the predictions
+%
+% [OUTPUT]
+% predictions:      MATLAB table with predictions for selected output
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Construct RESULTS path
+resultsPath = [projectPath '/RESULTS'];
+    
+% Check the projectPath
+if ~exist(resultsPath),
+    error(sprintf('The provided project path "%s" does not point to a valid NONMEM project.\nPlease make sure a "RESULTS" folder is in the provided path.',projectPath));
+end
+
+% Load predictions
+predictions = IQMloadNONCSVdataset([resultsPath '/project.pred'],1);
+
+% Select the right output, remove doses (EVID=1) and MDV values (MDV=1)
+predictions(predictions.EVID==1,:) = [];
+predictions(predictions.MDV==1,:) = [];
+predictions = predictions(predictions.YTYPE==outputNumber,:);
+
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/parseNONMEMprojectHeaderIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/parseNONMEMprojectHeaderIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..e93fde80ef05068ee0c6a9fb0b74bb0797cfd364
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/parseNONMEMprojectHeaderIQM.m	
@@ -0,0 +1,40 @@
+function [projectinfo] = parseNONMEMprojectHeaderIQM(projectPath)
+% Parses the project header information from the NONMEM control foile
+% (project.nmctl) and returns it. 
+%
+% [SYNTAX]
+% [projectinfo] = parseNONMEMprojectHeaderIQM(projectPath)
+%
+% [INPUT]
+% projectPath:      Project to return the project header
+%
+% [OUTPUT]
+% projectinfo:      Structure with information
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Check if project.nmctl in project folder
+if exist([projectPath '/project.nmctl']),
+    project = fileread([projectPath '/project.nmctl']);
+else
+    error('project.nmctl file could not be found.');
+end
+
+% Get the header
+ixstart = strfind(project,'; ==PROJECT HEADER START===================================================');
+ixend = strfind(project,  '; ==PROJECT HEADER END=====================================================');
+if isempty(ixstart) || isempty(ixend),
+    error('Project header could not be found in project.nmctl file.');
+end
+headertext = strtrim(project(ixstart+75:ixend-1));
+headerterms = explodePCIQM(headertext,char(10));
+
+% Construct output
+projectinfo = [];
+for k=1:length(headerterms),
+    eval(['projectinfo.' strrep(strtrim(headerterms{k}(2:end)),'=','=explodePCIQM(') ');']);
+end
+
+% Add project.nmctl to header
+projectinfo.projectFile = 'project.nmctl';
+projectinfo.TOOL        = 'NONMEM';
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/parseNONMEMresultsIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/parseNONMEMresultsIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..f5a38fcef165d371b3c9505f2d5c768a84156806
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/parseNONMEMresultsIQM.m	
@@ -0,0 +1,519 @@
+function [ output ] = parseNONMEMresultsIQM( path_to_nonmem_project_folder, transformFlag )
+% This function parses the output of NONMEM and returns all information in
+% a structure. The NONMEM project needs to have been created with IQM Tools!
+% If more than one estimation methods have been concatenated, the results
+% of the last one are reported. 
+%
+% The parameters are not backtransformed from the MU referencing. But the
+% required transformations are defined in the output structure. This does
+% only apply to the fixed effect parameters in the THETAs.
+%
+% [SYNTAX]
+% output = parseNONMEMresultsIQM( path_to_nonmem_project_folder )
+% output = parseNONMEMresultsIQM( path_to_nonmem_project_folder, transformFlag )
+%
+% [INPUT]
+% path_to_nonmem_project_folder: path to the NONMEM project folder.
+% transformFlag: =0 (default): do not back transform the fixed effect
+%                parameters in the output.rawParameterInfo.fixedEffects and
+%                output.parameters.values based on the MU referencing
+%                transformation. 
+%                =1: do back transform ... will also approximate the
+%                standard errors by sampling.
+%                Note: these backtransformed parameters are for analysis
+%                purpose only ... for reporting the original parameters
+%                need to be used - or careful wording.
+% [OUTPUT]
+% Structure with the certain outputs.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Set seed to lead to consistent sampling results
+if nargin == 1,
+    transformFlag = 0;
+end
+
+% Check if folder exists and that RESULTS folder exists within
+% and that the project.nmctl file exists
+if exist(path_to_nonmem_project_folder) ~= 7,
+    error('The specified NONMEM project folder "%s" does not exist.',path_to_nonmem_project_folder);
+end
+if exist([path_to_nonmem_project_folder '/RESULTS']) ~= 7,
+    error('The "RESULTS" folder within the project folder "%s" does not exist.',path_to_nonmem_project_folder);
+end
+if ~exist([path_to_nonmem_project_folder '/project.nmctl']),
+    error('The "project.nmctl" in the NONMEM project folder "%s" does not exist.',path_to_nonmem_project_folder);
+end
+if ~exist(fullfile(path_to_nonmem_project_folder, 'RESULTS', 'project.xml')), 
+    error('Please check if the "%s" folder contains the ''project.xml'' file.',path_to_nonmem_project_folder);
+end
+
+% Load project info
+PROJECTINFO = parseNONMEMprojectHeaderIQM(path_to_nonmem_project_folder);
+
+% Parse the xml results
+RESULTS = parseNONMEMxmlFileIQM(path_to_nonmem_project_folder);
+
+% Initialize the output structure and enter already the simple things
+
+output                          = [];
+output.type                     = 'NONMEM';
+output.method                   = PROJECTINFO.METHOD;
+output.termination_info         = RESULTS.termination_info;
+output.path                     = path_to_nonmem_project_folder;
+output.parameters               = [];
+output.objectivefunction        = [];
+output.residualerrormodels      = PROJECTINFO.ERRORMODELS; % mapping inv/trans OK
+output.trans_randeffects        = PROJECTINFO.PARAMTRANS;
+output.inv_trans_randeffects    = PROJECTINFO.PARAMINVTRANS;
+% output.covariates.names         = PROJECTINFO.COVARIATENAMES;
+output.rawParameterInfo         = [];
+output.PROJECTINFO              = PROJECTINFO;
+
+% Determine AIC and BIC
+OFVvalue                        = RESULTS.objectivefunction;
+NRPARAMETERS_ESTIMATED          = eval(PROJECTINFO.NRPARAM_ESTIMATED{1});
+NROBSERVATIONS                  = eval(PROJECTINFO.NROBSERVATIONS{1});
+% AIC: OFVvalue+2*numberParametersEstimated
+AIC                             = OFVvalue + 2*NRPARAMETERS_ESTIMATED;
+% BIC: 
+BIC                             = OFVvalue + NRPARAMETERS_ESTIMATED*(log(NROBSERVATIONS) + log(2*pi));
+% Add to output structure
+output.objectivefunction.OBJ    = OFVvalue;
+output.objectivefunction.AIC    = AIC;
+output.objectivefunction.BIC    = BIC;
+
+if isnan(OFVvalue),
+    return
+end
+
+% Get real THETA names and transformations
+names_real                      = {};
+names                           = RESULTS.THETA.names;
+theta_ix                        = 1:length(names);
+% Match with THETANAMES etc. (order is correct)
+names_real                      = PROJECTINFO.THETANAMES(theta_ix)';
+% Get transformations for all thetas but do not transform
+trans                           = cell(1,length(names_real));
+trans(1:end)                    = {''};
+for k=1:length(PROJECTINFO.PARAMNAMES),
+    param                       = PROJECTINFO.PARAMNAMES{k};
+    % find index in theta_names
+    ix                          = strmatchIQM(param,names_real,'exact');
+    trans{ix}                   = PROJECTINFO.PARAMTRANS{k};
+end
+RESULTS.THETA.names_real        = names_real(:)';
+RESULTS.THETA.trans             = trans(:)';
+
+% Change names for OMEGA2
+names_real                      = {};
+names_real_alternative          = {};
+names                           = RESULTS.OMEGA2.names;
+for k=1:length(names),
+    n                           = names{k};
+    n                           = strrep(n,'OMEGA2','');
+    n                           = strrep(n,'_','');
+    terms                       = explodePCIQM(n);
+    row                         = eval(terms{1});
+    col                         = eval(terms{2});
+    if row==col,
+        names_real{end+1}               = sprintf('omega2(%s)',PROJECTINFO.PARAMNAMES{row});
+        names_real_alternative{end+1}   = sprintf('omega2(%s)',PROJECTINFO.PARAMNAMES{row});
+    else
+        names_real{end+1}               = sprintf('omega2(%s,%s)',PROJECTINFO.PARAMNAMES{row},PROJECTINFO.PARAMNAMES{col});
+        names_real_alternative{end+1}   = sprintf('omega2(%s,%s)',PROJECTINFO.PARAMNAMES{col},PROJECTINFO.PARAMNAMES{row});
+    end
+end
+RESULTS.OMEGA2.names_real               = names_real(:)';
+RESULTS.OMEGA2.names_real_alternative   = names_real_alternative(:)';
+
+% Change names for OMEGAC
+names_real                      = {};
+names_real_alternative          = {};
+names                           = RESULTS.OMEGAC.names;
+for k=1:length(names),
+    n                           = names{k};
+    n                           = strrep(n,'OMEGAC','');
+    n                           = strrep(n,'_','');
+    terms                       = explodePCIQM(n);
+    row                         = eval(terms{1});
+    col                         = eval(terms{2});
+    if row==col,
+        names_real{end+1}               = sprintf('omega(%s)',PROJECTINFO.PARAMNAMES{row});
+        names_real_alternative{end+1}   = sprintf('omega(%s)',PROJECTINFO.PARAMNAMES{row});
+    else
+        names_real{end+1}               = sprintf('corr(%s,%s)',PROJECTINFO.PARAMNAMES{row},PROJECTINFO.PARAMNAMES{col});
+        names_real_alternative{end+1}   = sprintf('corr(%s,%s)',PROJECTINFO.PARAMNAMES{col},PROJECTINFO.PARAMNAMES{row});
+    end
+end
+RESULTS.OMEGAC.names_real               = names_real(:)';
+RESULTS.OMEGAC.names_real_alternative   = names_real_alternative(:)';
+
+% Change names for CORRELATION and COVARIANCE matrices
+names_real                      = {};
+names_real_alternative          = {};
+names                           = RESULTS.COV_COR_MATRIX_NAMES;
+names_notcell                   = {};
+for k=1:length(names),
+    x                           = names{k}{1};
+    names_notcell{end+1}        = x;
+    % check if THETA
+    if ~isempty(strfind(x,'THETA')),
+        names_real{k}               = RESULTS.THETA.names_real{eval(strrep(x,'THETA',''))};
+        names_real_alternative{k}   = RESULTS.THETA.names_real{eval(strrep(x,'THETA',''))};
+    end
+    % Check if OMEGA
+    if ~isempty(strfind(x,'OMEGA')),
+        x                           = strrep(x,'OMEGA','');
+        x                           = strrep(x,'_','');
+        terms                       = explodePCIQM(x);
+        row                         = eval(terms{1});
+        col                         = eval(terms{2});
+        if row==col,
+            names_real{k}               = sprintf('omega2(%s)',PROJECTINFO.PARAMNAMES{row});
+            names_real_alternative{k}   = sprintf('omega2(%s)',PROJECTINFO.PARAMNAMES{row});
+        else
+            names_real{k}               = sprintf('omega2(%s,%s)',PROJECTINFO.PARAMNAMES{row},PROJECTINFO.PARAMNAMES{col});
+            names_real_alternative{k}   = sprintf('omega2(%s,%s)',PROJECTINFO.PARAMNAMES{col},PROJECTINFO.PARAMNAMES{row});
+        end    
+    end
+    % Check if SIGMA (not needed)
+    if ~isempty(strfind(x,'SIGMA')),
+        names_real{k}                   = 'SIGMA';
+        names_real_alternative{k}       = 'SIGMA';
+    end
+end
+RESULTS.COVARIANCEMATRIX.names                  = names_notcell(:)';
+RESULTS.COVARIANCEMATRIX.names_real             = names_real(:)';
+RESULTS.COVARIANCEMATRIX.names_real_alternative = names_real_alternative(:)';
+RESULTS.COVARIANCEMATRIX.matrix                 = RESULTS.COVARIANCE_MATRIX;
+RESULTS                                         = rmfield(RESULTS,'COVARIANCE_MATRIX');
+
+RESULTS.CORRELATIONMATRIX.names                     = names_notcell(:)';
+RESULTS.CORRELATIONMATRIX.names_real                = names_real(:)';
+RESULTS.CORRELATIONMATRIX.names_real_alternative    = names_real_alternative(:)';
+RESULTS.CORRELATIONMATRIX.matrix                    = RESULTS.CORRELATION_MATRIX;
+RESULTS                                             = rmfield(RESULTS,'CORRELATION_MATRIX');
+
+RESULTS                                             = rmfield(RESULTS,'COV_COR_MATRIX_NAMES');
+
+% rawParameters field: information only for displaying but not for sampling
+
+% Create the rawParameterInfo field - fixedEffects
+% Based on RESULTS.THETA
+fixedEffects            = [];
+fixedEffects.names      = PROJECTINFO.PARAMNAMES;
+fixedEffects.estimated  = [];
+fixedEffects.trans      = PROJECTINFO.PARAMTRANS;
+fixedEffects.invtrans   = PROJECTINFO.PARAMINVTRANS;
+fixedEffects.values     = [];
+fixedEffects.stderr     = [];
+fixedEffects.rse        = [];
+for k=1:length(fixedEffects.names),
+    % Determine if parameter was estimated
+    ix = strmatchIQM(fixedEffects.names{k},PROJECTINFO.THETANAMES,'exact');
+    fixedEffects.estimated(k) = eval(PROJECTINFO.THETAESTIMATE{ix});
+    
+    % Always report value ... if estimated or not
+    % Determine index of parameter in results
+    ix = strmatchIQM(fixedEffects.names{k},RESULTS.THETA.names_real,'exact');
+    fixedEffects.values(k)  = RESULTS.THETA.values(ix);
+    fixedEffects.stderr(k)  = RESULTS.THETA.standarderror(ix);
+    fixedEffects.rse(k)     = abs(100*fixedEffects.stderr(k)/fixedEffects.values(k));
+    
+    % But if not estimated then set stderr and rse to NaN
+    if fixedEffects.estimated(k)==0,
+        fixedEffects.stderr(k)  = NaN;
+        fixedEffects.rse(k)     = NaN;
+    end
+end
+% Add to output
+output.rawParameterInfo.fixedEffects        = fixedEffects;
+output.rawParameterInfo.fixedEffects.distribution_info  = output.inv_trans_randeffects;
+
+% Create the rawParameterInfo field - randomEffects
+% Based on RESULTS.OMEGAC
+randomEffects = [];
+randomEffects.names = PROJECTINFO.ETANAMES;
+randomEffects.values = [];
+randomEffects.estimated = [];
+randomEffects.stderr = [];
+randomEffects.rse = [];
+for k=1:length(randomEffects.names),
+    % Determine if parameter was estimated
+    ix = strmatchIQM(randomEffects.names{k},PROJECTINFO.ETANAMES,'exact');
+    randomEffects.estimated(k) = eval(PROJECTINFO.ETAESTIMATE{ix});
+    
+    ix = strmatchIQM(randomEffects.names{k},RESULTS.OMEGAC.names_real,'exact');
+    if randomEffects.estimated(k)==1,
+    % If estimated provide values
+        randomEffects.values(k)  = RESULTS.OMEGAC.values(ix);
+        randomEffects.stderr(k)  = RESULTS.OMEGAC.standarderror(ix);
+        randomEffects.rse(k)     = abs(100*randomEffects.stderr(k)/randomEffects.values(k));
+    elseif randomEffects.estimated(k)==2,
+    % If fixed then provide values but NaN for stderr and rse
+        randomEffects.values(k)  = RESULTS.OMEGAC.values(ix);
+        randomEffects.stderr(k)  = NaN;
+        randomEffects.rse(k)     = NaN;
+    elseif randomEffects.estimated(k)==0,
+    % Not considered => value=0 and set stderr and rse to NaN
+        randomEffects.values(k)  = RESULTS.OMEGAC.values(ix);
+        randomEffects.stderr(k)  = NaN;
+        randomEffects.rse(k)     = NaN;
+    end    
+end
+% Add to output
+output.rawParameterInfo.randomEffects                           = randomEffects;
+
+% Create the rawParameterInfo field - correlation
+correlation = [];
+correlation.names = PROJECTINFO.CORRELATIONNAMES;
+ix_remove = [];
+for k=1:length(correlation.names),
+    if isempty(correlation.names{k}),
+        ix_remove(end+1) = k;
+    end
+end
+correlation.names(ix_remove) = [];
+correlation.values = [];
+correlation.estimated = [];
+correlation.stderr = [];
+correlation.rse = [];
+for k=1:length(correlation.names),
+    if ~isempty(correlation.names{k}),
+        % So far correlations appearing in results always estimated
+        correlation.estimated(k) = 1;
+
+        % Only handle if estimated, otherwise set to NaN
+        if correlation.estimated(k),
+            % Determine index of parameter in results
+            ix1 = strmatchIQM(correlation.names{k},RESULTS.OMEGAC.names_real,'exact');
+            ix2 = strmatchIQM(correlation.names{k},RESULTS.OMEGAC.names_real_alternative,'exact');
+            ix = unique([ix1 ix2]);
+            if isempty(ix), error('Please check.'); end
+            correlation.values(k)  = RESULTS.OMEGAC.values(ix);
+            correlation.stderr(k)  = RESULTS.OMEGAC.standarderror(ix);
+            correlation.rse(k)     = abs(100*correlation.stderr(k)/correlation.values(k));
+        else
+            correlation.values(k)  = RESULTS.OMEGAC.values(ix);
+            correlation.stderr(k)  = NaN;
+            correlation.rse(k)     = NaN;
+        end
+    end
+end
+% Add to output
+output.rawParameterInfo.correlation = correlation;
+
+% Create the rawParameterInfo field - covariate
+covariate = [];
+covariate.names = RESULTS.THETA.names_real(strmatchIQM('beta_',RESULTS.THETA.names_real));
+covariate.values = [];
+covariate.stderr = [];
+covariate.estimated = [];
+covariate.rse = [];
+for k=1:length(covariate.names),
+    % Determine if parameter was estimated
+    ix = strmatchIQM(covariate.names{k},PROJECTINFO.THETANAMES,'exact');
+    covariate.estimated(k) = eval(PROJECTINFO.THETAESTIMATE{ix});
+    
+    % Only handle if estimated, otherwise set to NaN
+    if covariate.estimated(k),
+        % Determine index of parameter in results
+        ix = strmatchIQM(covariate.names{k},RESULTS.THETA.names_real,'exact');
+        covariate.values(k)  = RESULTS.THETA.values(ix);
+        covariate.stderr(k)  = RESULTS.THETA.standarderror(ix);
+        covariate.rse(k)     = abs(100*covariate.stderr(k)/covariate.values(k));
+    else
+        covariate.values(k)  = RESULTS.THETA.values(ix);
+        covariate.stderr(k)  = NaN;
+        covariate.rse(k)     = NaN;
+    end    
+end
+% Add to output
+output.rawParameterInfo.covariate = covariate;
+
+% Create the rawParameterInfo field - errorParameter
+errorParameter = [];
+errorParameter.names = RESULTS.THETA.names_real(strmatchIQM('error_',RESULTS.THETA.names_real));
+errorParameter.values = [];
+errorParameter.stderr = [];
+errorParameter.estimated = [];
+errorParameter.rse = [];
+for k=1:length(errorParameter.names),
+    % Determine if parameter was estimated
+    ix = strmatchIQM(errorParameter.names{k},PROJECTINFO.THETANAMES,'exact');
+    errorParameter.estimated(k) = eval(PROJECTINFO.THETAESTIMATE{ix});
+    
+    % Only handle if estimated, otherwise set to NaN
+    if errorParameter.estimated(k),
+        % Determine index of parameter in results
+        ix = strmatchIQM(errorParameter.names{k},RESULTS.THETA.names_real,'exact');
+        errorParameter.values(k)  = RESULTS.THETA.values(ix);
+        errorParameter.stderr(k)  = RESULTS.THETA.standarderror(ix);
+        errorParameter.rse(k)     = abs(100*errorParameter.stderr(k)/errorParameter.values(k));
+    else
+        errorParameter.values(k)  = RESULTS.THETA.values(ix);
+        errorParameter.stderr(k)  = NaN;
+        errorParameter.rse(k)     = NaN;
+    end    
+end
+% Add to output
+output.rawParameterInfo.errorParameter = errorParameter;
+
+% parameters field: contains information for sampling from uncertainty
+% distribution. all based on omega2 ... since for that the covariance
+% matrix works.
+
+% Construct the names field
+names = [PROJECTINFO.THETANAMES PROJECTINFO.ETANAMES PROJECTINFO.CORRELATIONNAMES];
+names = strrep(names,'omega(','omega2(');
+names = strrep(names,'corr(','omega2(');
+% Remove empty fields (can happen due to PROJECTINFO.CORRELATIONNAMES)
+ix_remove = [];
+for k=1:length(names),
+    if isempty(names{k}),
+        ix_remove(end+1) = k;
+    end
+end
+names(ix_remove) = [];
+parameters = [];
+parameters.names = names;
+
+% Construct the FLAGestimated vector based on PROJECTINFO
+x = [PROJECTINFO.THETAESTIMATE PROJECTINFO.ETAESTIMATE PROJECTINFO.CORRESTIMATE];
+x(ix_remove) = [];
+FLAGestimated = [];
+for k=1:length(x),
+    FLAGestimated(k) = eval(x{k});
+end
+parameters.FLAGestimated = FLAGestimated;
+
+% Add the transformation information
+transformation = cell(1,length([PROJECTINFO.ETAESTIMATE PROJECTINFO.CORRESTIMATE]));
+transformation(1:end) = {''};
+transformation = [RESULTS.THETA.trans transformation];
+transformation(ix_remove) = [];
+parameters.transformation = transformation;
+
+% Construct the values vector
+nmnames1 = [RESULTS.THETA.names_real(:)' RESULTS.OMEGA2.names_real(:)'];
+nmnames2 = [RESULTS.THETA.names_real(:)' RESULTS.OMEGA2.names_real_alternative(:)'];
+nmvalues = [RESULTS.THETA.values(:)'     RESULTS.OMEGA2.values(:)'];
+values = [];
+for k=1:length(parameters.names),
+    ix1 = strmatchIQM(names{k},nmnames1,'exact');
+    ix2 = strmatchIQM(names{k},nmnames2,'exact');
+    ix = unique([ix1 ix2]);
+    if isempty(ix),
+        error('Please check!');
+    end
+    values(k) = nmvalues(ix);
+end
+parameters.values = values;
+
+% Construct the standard errors vector
+if ~isempty(RESULTS.CORRELATIONMATRIX.matrix),
+    nmnames1 = [RESULTS.THETA.names_real(:)'        RESULTS.OMEGA2.names_real(:)'];
+    nmnames2 = [RESULTS.THETA.names_real(:)'        RESULTS.OMEGA2.names_real_alternative(:)'];
+    nmvalues = [RESULTS.THETA.standarderror(:)'     RESULTS.OMEGA2.standarderror(:)'];
+    stderrors = [];
+    for k=1:length(parameters.names),
+        ix1 = strmatchIQM(names{k},nmnames1,'exact');
+        ix2 = strmatchIQM(names{k},nmnames2,'exact');
+        ix = unique([ix1 ix2]);
+        if isempty(ix),
+            error('Please check!');
+        end
+        stderrors(k) = nmvalues(ix);
+    end
+else
+    stderrors = NaN(size(values));
+end
+parameters.stderrors = stderrors;
+
+% Construct the correlation and covariance matrices
+if ~isempty(RESULTS.CORRELATIONMATRIX.matrix),
+    nmnames1 = RESULTS.COVARIANCEMATRIX.names_real;
+    nmnames2 = RESULTS.COVARIANCEMATRIX.names_real_alternative;
+    ix_permutate = [];
+    for k=1:length(names)
+        ix1 = strmatchIQM(parameters.names{k},nmnames1,'exact');
+        ix2 = strmatchIQM(parameters.names{k},nmnames2,'exact');
+        ix = unique([ix1 ix2]);
+        if isempty(ix),
+            error('Please check!');
+        end
+        ix_permutate(k) = ix;
+    end
+    correlationmatrix = RESULTS.CORRELATIONMATRIX.matrix(ix_permutate,ix_permutate);
+    covariancematrix = RESULTS.COVARIANCEMATRIX.matrix(ix_permutate,ix_permutate);
+    % Need to set diagonal elements of correlationmatrix to 1
+    for k=1:length(correlationmatrix),
+        correlationmatrix(k,k) = 1;
+    end
+else
+    correlationmatrix = [];
+    covariancematrix = [];
+end
+parameters.correlationmatrix = correlationmatrix;
+parameters.covariancematrix = covariancematrix;
+
+% Need to make covariancematrix positive semidefinite
+parameters.covariancematrix = makePosSemiDefIQM(parameters.covariancematrix);
+
+% Add parameters to output
+output.parameters = parameters;
+
+% Finally, check if the parameters should be back
+% transformed ... including approximation of standard errors.
+%
+% Application to output.parameters and output.rawParameterInfo.fixedEffects
+if transformFlag,
+    % Handle output.rawParameterInfo.fixedEffects
+    values = output.rawParameterInfo.fixedEffects.values;
+    stderr = output.rawParameterInfo.fixedEffects.stderr;
+    transf = output.rawParameterInfo.fixedEffects.trans;
+    for k=1:length(values),
+        if ~isempty(transf{k}),
+            phi     = values(k);
+            val     = eval(transf{k});
+            % sample standard error
+            if stderr(k)==0,
+                ste = 0;
+            else
+                phi = values(k)+stderr(k)*randn(1,100000);
+                ste = std(eval(trans{k}));
+            end
+            values(k) = val;
+            stderr(k) = ste;
+            transf{k} = '';
+            output.rawParameterInfo.fixedEffects.invtrans{k} = '';
+        end
+    end
+    output.rawParameterInfo.fixedEffects.values = values;
+    output.rawParameterInfo.fixedEffects.stderr = stderr;
+    output.rawParameterInfo.fixedEffects.trans  = transf;      
+    % Determine new RSEs
+    output.rawParameterInfo.fixedEffects.rse    = 100*stderr./values;
+%     disp('NONMEM project: If IIV distributions other than "normal" have been used then the standard errors');
+%     disp('                of the fixed effects are approximated by sampling in the back transformation.');
+%     disp('                Impacting only: rawParameterInfo output from function parseNONMEMresultsIQM.');
+end
+
+% Next finally, set stderr and RSEs for not estimated parameters to 0
+output.rawParameterInfo.fixedEffects.stderr(output.rawParameterInfo.fixedEffects.estimated~=1)      = 0;
+output.rawParameterInfo.fixedEffects.rse(output.rawParameterInfo.fixedEffects.estimated~=1)         = 0;
+
+output.rawParameterInfo.randomEffects.stderr(output.rawParameterInfo.randomEffects.estimated~=1)    = 0;
+output.rawParameterInfo.randomEffects.rse(output.rawParameterInfo.randomEffects.estimated~=1)       = 0;
+
+output.rawParameterInfo.correlation.stderr(output.rawParameterInfo.correlation.estimated~=1)        = 0;
+output.rawParameterInfo.correlation.rse(output.rawParameterInfo.correlation.estimated~=1)           = 0;
+
+output.rawParameterInfo.covariate.stderr(output.rawParameterInfo.covariate.estimated~=1)            = 0;
+output.rawParameterInfo.covariate.rse(output.rawParameterInfo.covariate.estimated~=1)               = 0;
+
+output.rawParameterInfo.errorParameter.stderr(output.rawParameterInfo.errorParameter.estimated~=1)  = 0;
+output.rawParameterInfo.errorParameter.rse(output.rawParameterInfo.errorParameter.estimated~=1)     = 0;
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/parseNONMEMxmlFileIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/parseNONMEMxmlFileIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..4bb9464cf9a36ed8a17ba497d977770d54b0f905
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/parseNONMEMxmlFileIQM.m	
@@ -0,0 +1,316 @@
+function [ output ] = parseNONMEMxmlFileIQM( projectPath )
+% This function parses the xml file from NONMEM and returns all the
+% information. In case that multiple methods have been run, only the
+% results from the last one are reported.
+%
+% [SYNTAX]
+% output = parseNONMEMxmlFile( projectPath )
+%
+% [INPUT]
+% projectPath: path to the NONMEM project folder.
+%
+% [OUTPUT]
+% Structure with information stored in the XML file
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Check if folder exists and that RESULTS folder exists within
+% and that the project.nmctl file exists
+if exist(projectPath) ~= 7,
+    error('The specified NONMEM project folder "%s" does not exist.',projectPath);
+end
+if exist([projectPath '/RESULTS']) ~= 7,
+    error('The "RESULTS" folder within the project folder "%s" does not exist.',projectPath);
+end
+if ~exist([projectPath '/project.nmctl']),
+    error('The "project.nmctl" in the NONMEM project folder "%s" does not exist.',projectPath);
+end
+if ~exist(fullfile(projectPath, 'RESULTS', 'project.xml')), 
+    error('Please check if the "%s" folder contains the ''project.xml'' file.',projectPath);
+end
+
+% Initialize the output structure and enter already the simple things
+
+output                          = [];
+output.projectPath              = projectPath;
+
+% Load the project.xml file and 
+% remove the namespace thingy ... NONMEM does not seem to be consistently using it :-(
+content  = fileread(fullfile(projectPath,'RESULTS','project.xml'));
+content  = strrep(content,'nm:','');
+
+% Get termination information
+ixstart  = strfind(content,'<termination_information>');
+ixend    = strfind(content,'</termination_information>');
+termination_info = {};
+for k=1:min(length(ixstart),length(ixend)),
+    x = content(ixstart(k)+25:ixend(k)-1);
+    x = strrep(x,'<![CDATA[','');
+    x = strtrim(strrep(x,']]>',''));
+    x = explodePCIQM(x,char(10));
+    y = '';
+    for k2=1:length(x),
+        y = sprintf('    %s\n',y,strtrim(x{k2}));
+    end
+    y = strrep(y,char([10 10]),char(10));
+    termination_info{k} = sprintf('    %s\n',strtrim(y));
+end
+output.termination_info = termination_info;
+
+% Parse objective function
+% In case of concatemated estimation methods only get the last one.
+ixstart  = strfind(content,'<final_objective_function>');
+ixend    = strfind(content,'</final_objective_function>');
+if ~isempty(ixstart),
+    OFVvalue = eval(content(ixstart(end)+26:ixend(end)-1));
+else
+    OFVvalue = NaN;
+end
+output.objectivefunction = OFVvalue;
+
+% Get THETA estimates
+ixstart    = strfind(content,'<theta>');
+ixend      = strfind(content,'</theta>');
+if ~isempty(ixstart),
+    theta_text = strtrim(content(ixstart(end)+7:ixend(end)-1));
+    theta_text = strrep(theta_text,'</val>','');
+    theta_text = strrep(theta_text,sprintf('<val name='''),'');
+    theta_text = strrep(theta_text,sprintf('''>'),', ');
+    theta_vec  = eval(['[' theta_text ']']);
+    output.THETA.names = {};
+    output.THETA.values = theta_vec(:,2)';
+    for k=1:length(output.THETA.values),
+        output.THETA.names{k} = sprintf('THETA%d',k);
+    end
+else
+    output.THETA.names = {};
+    output.THETA.values = [];
+end
+
+% Get the OMEGA2 
+ixstart    = strfind(content,'<omega>');
+ixend      = strfind(content,'</omega>');
+if ~isempty(ixstart),
+    omega_text = strtrim(content(ixstart(end)+7:ixend(end)-1));
+    omega_text = strrep(omega_text,'</row>','#');
+    omega_text = strrep(omega_text,'</col>','');
+    omega_text = strrep(omega_text,'<row rname=','');
+    omega_text = strrep(omega_text,'<col cname=','');
+    omega_text = strrep(omega_text,'''','');
+    omega_text = regexprep(omega_text,'\<[0-9]+>','');
+    terms = explodePCIQM(omega_text,'#');
+    terms = terms(1:end-1);
+    OMEGA2 = [];
+    OMEGA2_names  = {};
+    OMEGA2_values  = [];
+    for row=1:length(terms),
+        rowtext = strtrim(terms{row});
+        colterms = explodePCIQM(rowtext,char(10));
+        for col=1:length(colterms),
+            OMEGA2(row,col) = eval(colterms{col});
+            OMEGA2(col,row) = eval(colterms{col});
+            OMEGA2_names{end+1} = sprintf('OMEGA2_%d,%d_',row,col);
+            OMEGA2_values(end+1) = eval(colterms{col});
+        end
+    end
+    output.OMEGA2.names = OMEGA2_names;
+    output.OMEGA2.values = OMEGA2_values;
+    output.OMEGA2.matrix = OMEGA2;
+else
+    output.OMEGA2.names = {};
+    output.OMEGA2.values = [];
+    output.OMEGA2.matrix = [];
+end
+
+% Get the OMEGAC
+ixstart    = strfind(content,'<omegac>');
+ixend      = strfind(content,'</omegac>');
+if ~isempty(ixstart),
+    omega_text = strtrim(content(ixstart(end)+8:ixend(end)-1));
+    omega_text = strrep(omega_text,'</row>','#');
+    omega_text = strrep(omega_text,'</col>','');
+    omega_text = strrep(omega_text,'<row rname=','');
+    omega_text = strrep(omega_text,'<col cname=','');
+    omega_text = strrep(omega_text,'''','');
+    omega_text = regexprep(omega_text,'\<[0-9]+>','');
+    terms = explodePCIQM(omega_text,'#');
+    terms = terms(1:end-1);
+    OMEGA2 = [];
+    OMEGA2_names  = {};
+    OMEGA2_values = [];
+    for row=1:length(terms),
+        rowtext = strtrim(terms{row});
+        colterms = explodePCIQM(rowtext,char(10));
+        for col=1:length(colterms),
+            OMEGA2(row,col) = eval(colterms{col});
+            OMEGA2(col,row) = eval(colterms{col});
+            OMEGA2_names{end+1} = sprintf('OMEGAC_%d,%d_',row,col);
+            OMEGA2_values(end+1) = eval(colterms{col});
+        end
+    end
+    output.OMEGAC.names = OMEGA2_names;
+    output.OMEGAC.values = OMEGA2_values;
+    output.OMEGAC.matrix = OMEGA2;
+else
+    output.OMEGAC.names = {};
+    output.OMEGAC.values = [];
+    output.OMEGAC.matrix = [];
+end
+
+% Get THETA standard error estimates
+ixstart    = strfind(content,'<thetase>');
+ixend      = strfind(content,'</thetase>');
+if ~isempty(ixstart),
+    theta_text = strtrim(content(ixstart(end)+9:ixend(end)-1));
+    theta_text = strrep(theta_text,'</val>','');
+    theta_text = strrep(theta_text,sprintf('<val name='''),'');
+    theta_text = strrep(theta_text,sprintf('''>'),', ');
+    theta_vec  = eval(['[' theta_text ']']);
+    output.THETA.standarderror = theta_vec(:,2)';
+else
+    output.THETA.standarderror = NaN(size(output.THETA.names));
+end
+
+% Get the OMEGA2 standarderror 
+ixstart    = strfind(content,'<omegase>');
+ixend      = strfind(content,'</omegase>');
+if ~isempty(ixstart),
+    omega_text = strtrim(content(ixstart(end)+9:ixend(end)-1));
+    omega_text = strrep(omega_text,'</row>','#');
+    omega_text = strrep(omega_text,'</col>','');
+    omega_text = strrep(omega_text,'<row rname=','');
+    omega_text = strrep(omega_text,'<col cname=','');
+    omega_text = strrep(omega_text,'''','');
+    omega_text = regexprep(omega_text,'\<[0-9]+>','');
+    terms = explodePCIQM(omega_text,'#');
+    terms = terms(1:end-1);
+    OMEGA2 = [];
+    OMEGA2_values = [];
+    for row=1:length(terms),
+        rowtext = strtrim(terms{row});
+        colterms = explodePCIQM(rowtext,char(10));
+        for col=1:length(colterms),
+            OMEGA2(row,col) = eval(colterms{col});
+            OMEGA2(col,row) = eval(colterms{col});
+            OMEGA2_values(end+1) = eval(colterms{col});
+        end
+    end
+    output.OMEGA2.standarderror = OMEGA2_values;
+    output.OMEGA2.standarderrorMATRIX = OMEGA2;
+else
+    output.OMEGA2.standarderror = NaN(size(output.OMEGA2.names));
+    output.OMEGA2.standarderrorMATRIX = NaN(length(output.OMEGA2.names),length(output.OMEGA2.names));
+end
+
+% Get the OMEGAC standarderror
+ixstart    = strfind(content,'<omegacse>');
+ixend      = strfind(content,'</omegacse>');
+if ~isempty(ixstart),
+    omega_text = strtrim(content(ixstart(end)+10:ixend(end)-1));
+    omega_text = strrep(omega_text,'</row>','#');
+    omega_text = strrep(omega_text,'</col>','');
+    omega_text = strrep(omega_text,'<row rname=','');
+    omega_text = strrep(omega_text,'<col cname=','');
+    omega_text = strrep(omega_text,'''','');
+    omega_text = regexprep(omega_text,'\<[0-9]+>','');
+    terms = explodePCIQM(omega_text,'#');
+    terms = terms(1:end-1);
+    OMEGA2 = [];
+    OMEGA2_values = [];
+    for row=1:length(terms),
+        rowtext = strtrim(terms{row});
+        colterms = explodePCIQM(rowtext,char(10));
+        for col=1:length(colterms),
+            OMEGA2(row,col) = eval(colterms{col});
+            OMEGA2(col,row) = eval(colterms{col});
+            OMEGA2_values(end+1) = eval(colterms{col});
+        end
+    end
+    output.OMEGAC.standarderror = OMEGA2_values.*(output.OMEGA2.standarderror~=0);
+    output.OMEGAC.standarderrorMATRIX = OMEGA2.*(output.OMEGA2.standarderrorMATRIX~=0);
+else
+    output.OMEGAC.standarderror = NaN(size(output.OMEGAC.names));
+    output.OMEGAC.standarderrorMATRIX = NaN(length(output.OMEGAC.names),length(output.OMEGAC.names));
+end
+
+% Get covariance matrix
+ixstart    = strfind(content,'<covariance>');
+ixend      = strfind(content,'</covariance>');
+
+if ~isempty(ixstart) && ~isempty(ixend),
+    cormatrix_text = strtrim(content(ixstart(end)+12:ixend(end)-1));
+    cormatrix_text = strrep(cormatrix_text,'''','');
+    cormatrix_text = strrep(cormatrix_text,'</row>','#');
+    cormatrix_text = strrep(cormatrix_text,'</col>','');
+    cormatrix_text = strrep(cormatrix_text,'<col cname=','');
+    cormatrix_text = strrep(cormatrix_text,'<','');
+    cormatrix_text = strrep(cormatrix_text,'>',' ');
+    cormatrix_text = strrep(cormatrix_text,'(','_');
+    cormatrix_text = strrep(cormatrix_text,')','_');
+    
+    % Get the names of the rows/cols
+    cormatrix_names = regexp(cormatrix_text,'row rname=([A-Z_,0-9]+)','tokens');
+    
+    cormatrix_text = regexprep(cormatrix_text,'row rname=([A-Z_,0-9]+)','');
+    cormatrix_text = regexprep(cormatrix_text,'\<([A-Z_,0-9]+) ','');
+    
+    terms = explodePCIQM(cormatrix_text,'#');
+    terms = terms(1:end-1);
+    
+    COV_MATRIX = [];
+    for row=1:length(terms),
+        rowtext = strtrim(terms{row});
+        colterms = explodePCIQM(rowtext,char(10));
+        for col=1:length(colterms),
+            value = eval(colterms{col});
+            COV_MATRIX(row,col) = value;
+            COV_MATRIX(col,row) = value;
+        end
+    end
+else
+    COV_MATRIX = [];
+    cormatrix_names = {};
+end
+output.COVARIANCE_MATRIX = COV_MATRIX;
+
+% Get correlation matrix
+ixstart    = strfind(content,'<correlation>');
+ixend      = strfind(content,'</correlation>');
+
+if ~isempty(ixstart) && ~isempty(ixend),
+    cormatrix_text = strtrim(content(ixstart(end)+13:ixend(end)-1));
+    cormatrix_text = strrep(cormatrix_text,'''','');
+    cormatrix_text = strrep(cormatrix_text,'</row>','#');
+    cormatrix_text = strrep(cormatrix_text,'</col>','');
+    cormatrix_text = strrep(cormatrix_text,'<col cname=','');
+    cormatrix_text = strrep(cormatrix_text,'<','');
+    cormatrix_text = strrep(cormatrix_text,'>',' ');
+    cormatrix_text = strrep(cormatrix_text,'(','_');
+    cormatrix_text = strrep(cormatrix_text,')','_');
+    
+    % Get the names of the rows/cols
+    cormatrix_names = regexp(cormatrix_text,'row rname=([A-Z_,0-9]+)','tokens');
+    
+    cormatrix_text = regexprep(cormatrix_text,'row rname=([A-Z_,0-9]+)','');
+    cormatrix_text = regexprep(cormatrix_text,'\<([A-Z_,0-9]+) ','');
+    
+    terms = explodePCIQM(cormatrix_text,'#');
+    terms = terms(1:end-1);
+    
+    CORRELATION_MATRIX = [];
+    for row=1:length(terms),
+        rowtext = strtrim(terms{row});
+        colterms = explodePCIQM(rowtext,char(10));
+        for col=1:length(colterms),
+            value = eval(colterms{col});
+            CORRELATION_MATRIX(row,col) = value;
+            CORRELATION_MATRIX(col,row) = value;
+        end
+    end
+else
+    CORRELATION_MATRIX = [];
+    cormatrix_names = {};
+end
+output.CORRELATION_MATRIX = CORRELATION_MATRIX;
+output.COV_COR_MATRIX_NAMES = cormatrix_names;
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/sampleNONMEMpopulationParametersIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/sampleNONMEMpopulationParametersIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..32e808d47c251cdcf66eb250a443e1928abeda85
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/auxiliary/sampleNONMEMpopulationParametersIQM.m	
@@ -0,0 +1,395 @@
+function [ output ] = sampleNONMEMpopulationParametersIQM( input, varargin )
+% This function uses the output of the parseNONMEMresultsIQM function.
+% It samples once the distributions to obtain population parameters.
+% Then it splits these up into fixed effects, random effects, residual 
+% error models, covariates. The resulting fixed effect parameters will be
+% in the untransformed domain (not in the MU referencing one).
+%
+% Not everything is handled, but if things are found that can not be handled, 
+% then an error message is shown.
+%
+% [SYNTAX]
+% output = sampleNONMEMpopulationParametersIQM( input )
+% output = sampleNONMEMpopulationParametersIQM( input, FLAG_SAMPLE )
+% output = sampleNONMEMpopulationParametersIQM( input, FLAG_SAMPLE, FLAG_SILENT )
+%
+% [INPUT]
+% input        : output structure from the parseNONMEMresultsIQM function
+% FLAG_SAMPLE  : 1=sample population parameters from uncertainty distribution (default case)
+%                0=use estimated population parameters and do not consider uncertainty
+% FLAG_SILENT  : 1=do not output any warnings and messages, only errors 
+%                0=do output any warnings and messages, only errors (default)
+%
+% [OUTPUT]
+% Structure with the following fields:
+%
+% output.path                               : the path provided by the user from which Monolix results have been read
+%
+% output.fixedEffects.names                 : cell-array with names of fixed effect parameters
+% output.fixedEffects.values                : vector with sampled values of fixed effect parameters
+%
+% output.randomEffects.names                : cell-array with names of random effect parameters (same as fixed effect param names)
+% output.randomEffects.values               : vector with sampled values of random effect parameters
+% output.randomEffects.covariancematrix     : covariance matrix of random effects
+% output.randomEffects.transformation       : formula of the transformation
+% output.randomEffects.inv_transformation   : inverse of the formula
+% output.randomEffects.correlationmatrix    : correlation matrix of random effects
+% 
+% output.residualErrorModel.alias           : for each output/residual error model one substructure in the order of the outpt numbering. "alias" is a string with the name of the error model
+% output.residualErrorModel.abcr            : vector with 4 elements for the a,b,c,rho parameters. If undefined then NaN
+% output.residualErrorModel.formula         : formula of the transformation
+% 
+% output.covariates.continuous.parameter               : one substructure per parameter. "parameter" is a string with the parameter name
+% output.covariates.continuous.covariates              : cell-array with the covariates on this parameter
+% output.covariates.continuous.information             : cell-array with covariate transformation in formation (categorical:reference group, continuous:transformation formula and centering value)
+% output.covariates.continuous.information.categories  : vector with numerical categories (only numerical ones are accepted)
+% output.covariates.continuous.information.values      : vector with estimated covariate coefficients for each category (same order). Reference group has 0 value
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+FLAG_SAMPLE = 1;
+FLAG_SILENT = 0;
+if nargin == 2,
+    FLAG_SAMPLE = varargin{1};
+elseif nargin == 3,
+    FLAG_SAMPLE = varargin{1};
+    FLAG_SILENT = varargin{2};
+end    
+
+% Check if information present, otherwise return empty
+if isnan(input.objectivefunction.OBJ)
+    output = [];
+    return
+end
+
+% Define output structure
+output = [];
+output.type                                 = 'NONMEM';
+output.path                                 = '';
+
+output.fixedEffects.names                   = {};
+output.fixedEffects.values                  = [];   % Vector
+
+output.randomEffects.names                  = {};
+output.randomEffects.values                 = [];   % Vector
+output.randomEffects.covariancematrix       = [];   % Matrix 
+output.randomEffects.transformation          = {};   % cell-array defining the transformation (normal, lognormal, etc.)
+output.randomEffects.inv_transformation      = {};   % cell-array defining the inverse transformation
+
+output.residualErrorModel.alias             = '';   % One substructure per output alias=string
+output.residualErrorModel.abcr              = [];   % Vector with 4 elements (a,b,c,d - parameters in error model)
+output.residualErrorModel.formula           = '';   % Formula of the transformation
+output.residualErrorModel.inv_formula       = '';   % Inverse of the formula if there is a transformation
+output.residualErrorModel.FlagTransf        = 0;    % Flag if there is a transformation or not (t) 0 if there is not, 1 if there is.
+
+output.covariates.continuous.parameter                 = [];   % One substructure per parameter
+output.covariates.continuous.covariates                = {};   % cell array with all covariates
+output.covariates.continuous.values                    = [];   % vector with corresponding values
+output.covariates.continuous.transformation            = {};   % cell-array with covariate transformation: formula and centering value
+
+output.covariates.categorical.parameter                = [];   % One substructure per parameter
+output.covariates.categorical.covariates               = {};   % cell array with all covariates
+output.covariates.categorical.information              = {};   % cell-array with covariate transformation: 
+                                     
+% Write the path of the folder with all the results
+output.path = input.path;
+
+% Sample ALL parameters from the distribution 
+names      = input.parameters.names;
+values     = input.parameters.values;
+covariance = input.parameters.covariancematrix;
+
+% Handle the sampling flag and sample if desired and possible from the
+% uncertainty distribution to obtain a new set of population
+% parameters
+if FLAG_SAMPLE,
+    if ~isempty(covariance),
+        covariance = makePosSemiDefIQM(covariance);
+        samples = mvnrndIQM(values,covariance);
+    else
+        if ~FLAG_SILENT,
+            disp('The FIM was not estimated => No sampling of population parameters from uncertainty distributions.');
+        end
+        samples = values;
+    end
+else
+    samples = values;
+    if ~FLAG_SILENT,
+        disp('No sampling of population parameters from uncertainty distributions.');
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle Random Effects 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Names determined by "omega2("
+% Covariances have a commata in them
+
+ixo = strmatchIQM('omega2(',names);
+n = names(ixo);
+ixno = strfind(n,',');
+no = {};
+ixouseo = [];
+for k=1:length(ixno),
+    if isempty(ixno{k}),
+        no{end+1} = n{k};
+        ixouseo(end+1) = ixo(k);
+    end
+end
+no = strrep(no,'omega2(','');
+no = strrep(no,')','');
+output.randomEffects.names = no;
+output.randomEffects.values = sqrt(samples(ixouseo));
+
+% Determine the covariance matrix
+covariancematrix = diag(samples(ixouseo));
+ixo = strmatchIQM('omega2(',names);
+n = names(ixo);
+ixno = strfind(n,',');
+no = {};
+ixousec = [];
+for k=1:length(ixno),
+    if ~isempty(ixno{k}),
+        no{end+1} = n{k};
+        ixousec(end+1) = ixo(k);
+    end
+end
+no = strrep(no,'omega2(','');
+recovnames = strrep(no,')','');
+recovvalues = samples(ixousec);
+% Run through the correlations and update the correlation matrix
+if ~isempty(recovnames)
+    for k=1:length(recovnames),
+        % Find the two correlated things
+        terms = explodePCIQM(recovnames{k});
+        ix1 = strmatchIQM(terms{1},output.randomEffects.names,'exact');
+        ix2 = strmatchIQM(terms{2},output.randomEffects.names,'exact');
+        % Update matrix
+        covariancematrix(ix1,ix2) = recovvalues(k);
+        covariancematrix(ix2,ix1) = recovvalues(k);
+    end
+end
+% Make sampled covariance matrix pos semidefinite
+output.randomEffects.covariancematrix = makePosSemiDefIQM(covariancematrix);
+
+% Determine correlation matrix
+corrmatrix = NaN(size(covariancematrix));
+for krow=1:length(corrmatrix),
+    for kcol=1:length(corrmatrix),
+        corrmatrix(krow,kcol) = covariancematrix(krow,kcol)/sqrt(covariancematrix(krow,krow)*covariancematrix(kcol,kcol));
+    end
+end
+output.randomEffects.correlationmatrix = corrmatrix;
+
+% Remove omega_... and corr(... from samples and names
+ix = [ixouseo(:)' ixousec(:)'];
+samples(ix) = [];
+names(ix) = [];
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Second determine the fixed effects
+% In the input structure it has been made sure that all names that appear as fixed effects also appear in random effects
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+output.fixedEffects.names = output.randomEffects.names;
+% Get the values
+ixfe = [];
+for k=1:length(output.fixedEffects.names),
+    ix = strmatchIQM(output.fixedEffects.names{k},names,'exact');
+    output.fixedEffects.values(k) = samples(ix);
+    ixfe = [ixfe ix];
+end
+% Remove fixed effects from samples and names
+samples(ixfe) = [];
+names(ixfe) = [];
+
+% Add the distribution of the random effects to the output
+output.randomEffects.transformation = input.trans_randeffects;
+output.randomEffects.inv_transformation = input.inv_trans_randeffects;
+output.fixedEffects.transformation = input.trans_randeffects;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Third get residual error information
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+Noutput = length(input.residualerrormodels);
+removeIX = [];
+for k=1:Noutput,
+    output.residualErrorModel(k).alias = input.residualerrormodels{k};
+    output.residualErrorModel(k).abcr = NaN(1,2);
+    ix = strmatchIQM(['error_ADD' num2str(k)],names,'exact'); if ~isempty(ix), output.residualErrorModel(k).abcr(1) = samples(ix); removeIX = [removeIX ix]; end
+    ix = strmatchIQM(['error_PROP' num2str(k)],names,'exact'); if ~isempty(ix), output.residualErrorModel(k).abcr(2) = samples(ix); removeIX = [removeIX ix]; end
+end
+% Remove the handled elements
+samples(removeIX) = [];
+names(removeIX) = [];
+
+% Save the formula of the function of the residual error.
+for k = 1:Noutput
+    ix = strmatchIQM(output.residualErrorModel(k).alias,'const','exact'); if ~isempty(ix), output.residualErrorModel(k).formula = 'abcr(1).*ones(size(f))'; output.residualErrorModel(k).FlagTransf = 0; end
+    ix = strmatchIQM(output.residualErrorModel(k).alias,'prop','exact'); if ~isempty(ix), output.residualErrorModel(k).formula = 'abcr(2).*f'; output.residualErrorModel(k).FlagTransf = 0; end
+    ix = strmatchIQM(output.residualErrorModel(k).alias,'comb1','exact'); if ~isempty(ix), output.residualErrorModel(k).formula = 'abcr(1) + abcr(2).*f'; output.residualErrorModel(k).FlagTransf = 0; end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Fourth get covariate information
+% On one hand just the parameter estimates which are defined by "beta(..." which is easy.
+% On the other hand we need to obtain information about the transformation of the covariates (lets see where we can find this)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ix              = strmatchIQM('beta_',names);
+covariates      = names(ix);
+covariatevalues = samples(ix);
+% Remove the handled elements
+samples(ix)     = [];
+names(ix)       = [];
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get info of categorical covariates
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+categorical_covariates              = [];
+categorical_covariates.parameter    = {};
+categorical_covariates.covariate    = {};
+categorical_covariates.categories   = {};
+categorical_covariates.reference    = {};
+categorical_covariates.value         = {};
+
+for k=1:length(input.PROJECTINFO.BETACATNAMES),
+    if ~isempty(input.PROJECTINFO.BETACATNAMES{k}),
+        bcnk = input.PROJECTINFO.BETACATNAMES{k};
+        bcnk = strrep(bcnk,'beta_','');
+        bcnk = strrep(bcnk,'(',',');
+        bcnk = strrep(bcnk,')','');
+        terms = explodePCIQM(bcnk);
+        categories = eval(input.PROJECTINFO.BETACATCATEGORIES{k});
+        reference  = eval(input.PROJECTINFO.BETACATREFERENCE{k});
+        categorical_covariates.parameter{end+1} = terms{1};
+        categorical_covariates.covariate{end+1} = terms{2};
+        categorical_covariates.categories{end+1} = categories;
+        categorical_covariates.reference{end+1} = reference;
+        for k2=1:length(categories),
+            n = strrep(input.PROJECTINFO.BETACATNAMES{k},')',sprintf('_%d)',categories(k2)));
+            if categories(k2) == reference,
+                value = 0;
+            else
+                value = covariatevalues(strmatchIQM(n,covariates,'exact'));
+            end
+            categorical_covariates.value{k}(k2) = value;
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get info of continuous covariates
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+continuous_covariates = [];
+continuous_covariates.parameter = {};
+continuous_covariates.covariate = {};
+continuous_covariates.formula   = {};
+continuous_covariates.value   = [];
+
+for k=1:length(input.PROJECTINFO.BETACOVNAMES),
+    if ~isempty(input.PROJECTINFO.BETACOVNAMES{k}),
+        bcnk = input.PROJECTINFO.BETACOVNAMES{k};
+        bcnk = strrep(bcnk,'beta_','');
+        bcnk = strrep(bcnk,'(',',');
+        bcnk = strrep(bcnk,')','');
+        terms = explodePCIQM(bcnk);
+        continuous_covariates.parameter{end+1}  = terms{1};
+        continuous_covariates.covariate{end+1}  = terms{2};
+        continuous_covariates.formula{end+1}    = input.PROJECTINFO.BETACOVTRANS{k};
+        continuous_covariates.value(end+1)      = covariatevalues(strmatchIQM(input.PROJECTINFO.BETACOVNAMES{k},covariates,'exact'));
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle CONTINUOUS covariates
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+continuous = [];
+continuous.parameter = {};
+continuous.covariates = {};
+continuous.values = [];
+continuous.formula = {};
+empty = 1;
+for k=1:length(continuous_covariates.parameter),
+    if empty,
+        continuous(1).parameter = continuous_covariates.parameter{k};
+        continuous(1).covariates{end+1} = continuous_covariates.covariate{k};
+        continuous(1).values(end+1) = continuous_covariates.value(k);
+        continuous(1).formula{end+1} = continuous_covariates.formula{k};
+        empty = 0;
+    else
+        ix = strmatchIQM(continuous_covariates.parameter{k},{continuous.parameter},'exact');
+        if isempty(ix),
+            continuous(end+1).parameter = continuous_covariates.parameter{k};
+            continuous(end).covariates{end+1} = continuous_covariates.covariate{k};
+            continuous(end).values(end+1) = continuous_covariates.value(k);
+            continuous(end).formula{end+1} = continuous_covariates.formula{k};
+        else
+            continuous(ix).covariates{end+1} = continuous_covariates.covariate{k};
+            continuous(ix).values(end+1) = continuous_covariates.value(k);
+            continuous(ix).formula{end+1} = continuous_covariates.formula{k};
+        end
+    end
+end
+output.covariates.continuous = continuous;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle CATEGORICAL covariates
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+categorical = [];
+categorical.parameter = {};
+categorical.covariates = {};
+categorical.information = [];
+empty = 1;
+for k=1:length(categorical_covariates.parameter),
+    if empty,
+        categorical(1).parameter = categorical_covariates.parameter{k};
+        categorical(1).covariates{end+1} = categorical_covariates.covariate{k};
+        categorical(1).information(end+1).categories = categorical_covariates.categories{k};
+        categorical(1).information(end).values = categorical_covariates.value{k};
+        empty = 0;
+    else
+        ix = strmatchIQM(categorical_covariates.parameter{k},{categorical.parameter},'exact');
+        if isempty(ix),
+            categorical(end+1).parameter = categorical_covariates.parameter{k};
+            categorical(end).covariates{end+1} = categorical_covariates.covariate{k};
+            categorical(end).information(end+1).categories = categorical_covariates.categories{k};
+            categorical(end).information(end).values = categorical_covariates.value{k};
+        else
+            categorical(ix).covariates{end+1} = categorical_covariates.covariate{k};
+            categorical(ix).information(end+1).categories = categorical_covariates.categories{k};
+            categorical(ix).information(end).values = categorical_covariates.value{k};
+        end
+    end
+end
+output.covariates.categorical = categorical;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check if everything was handled
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(names),
+    if ~FLAG_SILENT,
+        disp('Warning: The NONMEM output contained information that are currently not handled.');
+        disp('This could be IOV or other things. Please have a look at the following unhandled names:');
+        for k=1:length(names),
+            fprintf('\t%s\n',names{k})
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Very last thing: transform the parameters into the true domain.
+% For sampling later everything is going to be handled correctly, since 
+% information about covariate transformation and random effect
+% transformation is present ...
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+values  = output.fixedEffects.values;
+trans   = output.fixedEffects.transformation;
+tvalues = [];
+for k=1:length(values),
+    phi = values(k);
+    tvalues(k) = eval(trans{k});
+end
+output.fixedEffects.values = tvalues;
+output.fixedEffects = rmfield(output.fixedEffects,'transformation');
+
+%% DONE!
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/isNONMEMprojectIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/isNONMEMprojectIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..db2239566fa5158db75871aab939922457dc21f3
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/05-NLMEtoolsInterfaces/02-NONMEM/isNONMEMprojectIQM.m	
@@ -0,0 +1,24 @@
+function [ output ] = isNONMEMprojectIQM( projectPath )
+% Checks if given project path is a NONMEM project. This is checked by 
+% requiring a project.nmctl file in this folder.
+% 
+% [SYNTAX]
+% [output] = isNONMEMprojectIQM( projectPath )
+%
+% [INPUT]
+% projectPath:  Path to check if NONMEM project
+%
+% [OUTPUT]
+% output = 0: No NONMEM project
+% output = 1: NONMEM project
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+testfile = fullfile(projectPath,'project.nmctl');
+if ~exist(testfile),
+    output = 0;
+else
+    output = 1;
+end
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/06-NMLEprojectHandling/IQMcreateNLMEmodelGENcode.m b/IQMtools V1.2.2.2/IQMpro/tools/06-NMLEprojectHandling/IQMcreateNLMEmodelGENcode.m
new file mode 100644
index 0000000000000000000000000000000000000000..d08a08bd6ba49e2e582e25e343f8559ca2922210
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/06-NMLEprojectHandling/IQMcreateNLMEmodelGENcode.m	
@@ -0,0 +1,347 @@
+function [] = IQMcreateNLMEmodelGENcode(modelPath,dosingPath,dataPath,projectPath)
+% Generates code that can be used to generate a NONMEM or MONOLIX NLME
+% project. This code is created in a temporary file and opened in the editor
+% to allow for copy and pasting where needed.
+%
+% It will take all parameters in the model that are set to <estimate> and 
+% create the needed structures. It will also check for regression parameters 
+% and handle them accordingly. 
+%
+% [SYNTAX]
+% [] = IQMcreateNLMEmodelGENcode(modelPath,dosingPath,dataPath,projectPath)
+%
+% modelPath: 	 Path to the IQMmodel file to use 
+% dosingPath: 	 Path to the IQMdosing scheme to use
+% dataPath:      Path to the CSV dataset to use 
+% projectPath:   Path to the folder in which to create the project
+% 
+% [OUTPUT]
+% The output is done in a temporary file which is opened in the editor
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Define algorithm text
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+textAlgorithm = '';
+textAlgorithm = sprintf('%s\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%',textAlgorithm);
+textAlgorithm = sprintf('%s\n%%%% Algorithm generation code template',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% Below you can find code that is required to set-up algorithm',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% settings for NLME model fits for both NONMEM and MONOLIX.',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% It covers the most important ones, which will lead to reasonable',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% results in most cases.',textAlgorithm);
+textAlgorithm = sprintf('%s\n%%',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% The different parts are commented to explain what can be edited, etc.',textAlgorithm);
+textAlgorithm = sprintf('%s\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%',textAlgorithm);
+textAlgorithm = sprintf('%s\n',textAlgorithm);
+
+textAlgorithm = sprintf('%s\nalgorithm                       = [];',textAlgorithm);
+textAlgorithm = sprintf('%s\n',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% General settings',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% ================',textAlgorithm);
+textAlgorithm = sprintf('%s\n',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% Six digit number, defining the SEED of the random generators.',textAlgorithm);
+textAlgorithm = sprintf('%s\nalgorithm.SEED                  = 123456;',textAlgorithm);
+textAlgorithm = sprintf('%s\n',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% K1 and K2 need to be defined big enough to ensure that the convergence',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% trajectories are reasonably stable (only needed for SAEM).',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% 200 for K2 is fine in most cases. 500-2000 for K1 is reasonable.',textAlgorithm);
+textAlgorithm = sprintf('%s\nalgorithm.K1                    = 500;',textAlgorithm);
+textAlgorithm = sprintf('%s\nalgorithm.K2                    = 200;',textAlgorithm);
+textAlgorithm = sprintf('%s\n',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% NRCHAINS can be increased in the case that few subjects only available in',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% the dataset.',textAlgorithm);
+textAlgorithm = sprintf('%s\nalgorithm.NRCHAINS              = 1;',textAlgorithm);
+textAlgorithm = sprintf('%s\n',textAlgorithm);
+
+textAlgorithm = sprintf('%s\n%% NONMEM specific settings',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% ========================',textAlgorithm);
+textAlgorithm = sprintf('%s\n',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% Please choose the NONMEM algorithm you want to use for the parameter ',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% estimation. "SAEM" works just fine, while the older algorithms',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% "FOCE" and "FOCEI" are not the most robust ones. The use of "FO" should',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% be avoided.',textAlgorithm);
+textAlgorithm = sprintf('%s\nalgorithm.METHOD                = ''SAEM'';  %% ''SAEM'' (default) or ''FO'', ''FOCE'', ''FOCEI''',textAlgorithm);
+textAlgorithm = sprintf('%s\n',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% ITS=1 performs an iterative two stage parameter estimation before the main',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% algorithm. If this improves the results can be debated ... but it might give',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% you a good feeling to do something cool ... if you do not want that, than',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% set ITS=0.',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% ITS_ITERATIONS defines the number of ITS iterations. 10 is just fine ...',textAlgorithm);
+textAlgorithm = sprintf('%s\nalgorithm.ITS                   = 1;',textAlgorithm);
+textAlgorithm = sprintf('%s\nalgorithm.ITS_ITERATIONS        = 10;',textAlgorithm);
+textAlgorithm = sprintf('%s\n',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% IMPORTANCESAMPLING=1 is needed only in the case when "SAEM" is used as',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% parameter estimation method. It will after the main estimation calculate the ',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% true objective function value that is needed for OFV bean-counting ...',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% IMP_ITERATIONS defines the number of IMP iterations. Avoid large numbers ...',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% 5-20 is typically just fine. ',textAlgorithm);
+textAlgorithm = sprintf('%s\nalgorithm.IMPORTANCESAMPLING    = 1;',textAlgorithm);
+textAlgorithm = sprintf('%s\nalgorithm.IMP_ITERATIONS        = 10;',textAlgorithm);
+textAlgorithm = sprintf('%s\n',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% MAXEVAL is used for the "FO", "FOCE", and "FOCEI" algorithms and determines ',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% the maximum number of objective function evaluations that are performed.',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% 9999 is the default value and if the optimum has not been reached by then, ',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% then you have problems with your model anyway.',textAlgorithm);
+textAlgorithm = sprintf('%s\nalgorithm.MAXEVAL               = 9999;',textAlgorithm);
+textAlgorithm = sprintf('%s\n',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% Please read the NONMEM manual what this means ... in modern programming languages ',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% this option would not be needed ...',textAlgorithm);
+textAlgorithm = sprintf('%s\nalgorithm.SIGDIGITS             = 3;',textAlgorithm);
+textAlgorithm = sprintf('%s\n',textAlgorithm);
+textAlgorithm = sprintf('%s\n',textAlgorithm);
+textAlgorithm = sprintf('%s%% In the generation of the NONMEM code the BLLOQ methods M3 and M4 can be handled.\n',textAlgorithm);
+textAlgorithm = sprintf('%s%% Other methods (M1, M5, M6, M7) are handled purely by changes in the dataset.\n',textAlgorithm);
+textAlgorithm = sprintf('%s%% The M4 options allows to select between M3 and M4 method M4=0 (default) uses the\n',textAlgorithm);
+textAlgorithm = sprintf('%s%% M3 method and M4=1 uses the M4 method. In order for these methods to be coded\n',textAlgorithm);
+textAlgorithm = sprintf('%s%% in the NONMEM model to create the dataset has to fullfil the following requirements:\n',textAlgorithm);
+textAlgorithm = sprintf('%s%% A CENS column needs to be present (just as in MONOLIX). CENS=0 for values above the LLOQ,\n',textAlgorithm);
+textAlgorithm = sprintf('%s%% CENS=1 for values below the LLOQ. For BLLOQ values DV needs to be set to the LLOQ (just\n',textAlgorithm);
+textAlgorithm = sprintf('%s%% as in MONOLIX). If no CENS=1 values are present in the dataset, neither the M3 not the\n',textAlgorithm);
+textAlgorithm = sprintf('%s%% M4 method are coded in the NONMEM control file.\n',textAlgorithm);
+textAlgorithm = sprintf('%salgorithm.M4 = 0;  \n',textAlgorithm);
+textAlgorithm = sprintf('%s\n',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% MONOLIX specific settings',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% =========================',textAlgorithm);
+textAlgorithm = sprintf('%s\n',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% LLsetting defines if the objective function value is determined by linearization ',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% or by importance sampling. If your model runs fast, you might consider ',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% "importantsampling". For large datasets and if ODE models are needed, the time',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% for calculation of the objective function might get prohibitively long. Then',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% use "linearization". I use "linearization" most of the time.',textAlgorithm);
+textAlgorithm = sprintf('%s\nalgorithm.LLsetting             = ''linearization'';   %% or ''linearization'' (default) or ''importantsampling''',textAlgorithm);
+textAlgorithm = sprintf('%s\n',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% FIMsetting defines if the Fischer Information Matrix is determined by "stochasticApproximation" (slow)',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% or by "linearization". "linearization" is fine in all cases, involving continuous readouts. ',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% The standard errors are calculated reasonably close to "stochasticApproximation" and the PKPD reviewers',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% at the health authorities will anyway want a bootstrap to be done => Do not waste time with ',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% calculating the Fischer Information Matrix with stochastic approximation, unless the model requires it.',textAlgorithm);
+textAlgorithm = sprintf('%s\nalgorithm.FIMsetting            = ''linearization'';   %% ''linearization'' (default) or ''stochasticApproximation''',textAlgorithm);
+textAlgorithm = sprintf('%s\n',textAlgorithm);
+textAlgorithm = sprintf('%s\n%% INDIVparametersetting: Just keep this setting --- it is just fine and leads to what you want in almost all cases.',textAlgorithm);
+textAlgorithm = sprintf('%s\nalgorithm.INDIVparametersetting = ''conditionalMode''; %% ''conditionalMode'' (default) ... others not considered for now',textAlgorithm);
+textAlgorithm = sprintf('%s\n',textAlgorithm);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Add covariate information
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+textCovariates = '';
+textCovariates = sprintf('%s\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%',textCovariates);
+textCovariates = sprintf('%s\n%%%% Define names of covariates',textCovariates);
+textCovariates = sprintf('%s\n%% If not done previously, please define below the names of the continuous',textCovariates);
+textCovariates = sprintf('%s\n%% and categorical covariates that you want to consider in the model and which',textCovariates);
+textCovariates = sprintf('%s\n%% are available in your dataset.',textCovariates);
+textCovariates = sprintf('%s\n%%',textCovariates);
+textCovariates = sprintf('%s\n%% Please note that these covariates are not allowed to vary over time.',textCovariates);
+textCovariates = sprintf('%s\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%',textCovariates);
+textCovariates = sprintf('%s\n',textCovariates);
+textCovariates = sprintf('%s\n%% "covNames" needs to contain the names of the CONTINUOUS covariates of',textCovariates);
+textCovariates = sprintf('%s\n%% interest in the dataset. Please exchange the names that are available with the',textCovariates);
+textCovariates = sprintf('%s\n%% names of covariates in your dataset.',textCovariates);
+textCovariates = sprintf('%s\ncovNames = {''WT0'' ''AGE0'' ''BMI0''};',textCovariates);
+textCovariates = sprintf('%s\n',textCovariates);
+textCovariates = sprintf('%s\n%% "catNames" needs to contain the names of the CATEGORICAL covariates of',textCovariates);
+textCovariates = sprintf('%s\n%% interest in the dataset. Please exchange the names that are available with the',textCovariates);
+textCovariates = sprintf('%s\n%% names of covariates in your dataset.',textCovariates);
+textCovariates = sprintf('%s\ncatNames = {''SEX'',''OBESE''};',textCovariates);
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Generate information for the model generation text
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Get model and dosing
+model       = IQMmodel(modelPath);
+dosing      = IQMdosing(dosingPath);
+
+% merge model
+moddos      = mergemoddosIQM(model,dosing);
+
+% Determine model estimation info
+modelinfo   = basicmodelparsingIQM(moddos);
+
+% Constructing relative path from project to data
+% Assumptions: 
+% - modeling dataset located in "Data" folder, 
+% - model somewhere in the "Models" folder hierarchy
+% - Structure with Models, Data, Scripts, Output used
+nStepsProject = length(strfind(projectPath,'/'));
+dataRelPathFromProject = '';
+for k=1:nStepsProject,
+    dataRelPathFromProject = sprintf('%s../',dataRelPathFromProject);
+end
+dataRelPathFromProject = [dataRelPathFromProject 'Data'];
+
+% Get data file parts
+[~,data_f,data_ext] = fileparts(dataPath);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Define model generation text
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+textModel = '';
+textModel = sprintf('%s\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%',textModel);
+textModel = sprintf('%s\n%%%% Model generation code template',textModel);
+textModel = sprintf('%s\n%% Below you can find code that is required to generate either a MONOLIX or',textModel);
+textModel = sprintf('%s\n%% NONMEM project, based on your selection of the model, the dosing, the',textModel);
+textModel = sprintf('%s\n%% data and the location of the project folder to be created.',textModel);
+textModel = sprintf('%s\n%%',textModel);
+textModel = sprintf('%s\n%% The different parts are commented to explain what can be edited, etc.',textModel);
+textModel = sprintf('%s\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%',textModel);
+textModel = sprintf('%s\n',textModel);
+
+textModel = sprintf('%s\n%% Load the model',textModel);
+textModel = sprintf('%s\nmodel                           = IQMmodel(''%s'');',textModel,modelPath);
+textModel = sprintf('%s\n',textModel);
+textModel = sprintf('%s\n%% Define the regression parameters',textModel);
+textModel = sprintf('%s\n%% They need to appear in the same order in the model and in the dataset (at least for MONOLIX)',textModel);
+textModel = sprintf('%s\nregressionParameters            = {',textModel);
+regressionParametersText = sprintf('''%s'' ',modelinfo.param_reg.name);
+textModel = sprintf('%s%s};',textModel,regressionParametersText(1:end-1));
+textModel = sprintf('%s\n',textModel);
+textModel = sprintf('%s\n%% Analyze the dataset to determine which column is what... this is done automatically',textModel);
+textModel = sprintf('%s\n%% and typically it is always correct ;-)',textModel);
+textModel = sprintf('%s\ndata                            = IQMloadCSVdataset(''%s'');',textModel,dataPath);
+textModel = sprintf('%s\ndataheader                      = IQMgetNLMEdataHeader(data,covNames,catNames,regressionParameters);',textModel);
+textModel = sprintf('%s\n',textModel);
+textModel = sprintf('%s\n%% Load the dosing scheme',textModel);
+textModel = sprintf('%s\ndosing                          = IQMdosing(''%s'');',textModel,dosingPath);
+textModel = sprintf('%s\n',textModel);
+textModel = sprintf('%s\n%% Define the data information for the generation of the MONOLIX or NONMEM',textModel);
+textModel = sprintf('%s\n%% project',textModel);
+textModel = sprintf('%s\ndataFIT                         = [];',textModel);
+textModel = sprintf('%s\n%% dataRelPathFromProject needs to be the relative path from the project',textModel);
+textModel = sprintf('%s\n%% folder to be created to the folder in which the dataset is located',textModel);
+textModel = sprintf('%s\n%% This needs to be checked carefully --- automatic generation of this path is challenging,',textModel);
+textModel = sprintf('%s\n%% or at least I have not spent enoug time on it yet.',textModel);
+textModel = sprintf('%s\ndataFIT.dataRelPathFromProject  = ''%s'';',textModel,dataRelPathFromProject);
+textModel = sprintf('%s\ndataFIT.dataHeaderIdent         = dataheader;',textModel);
+textModel = sprintf('%s\ndataFIT.dataFileName            = ''%s%s'';',textModel,data_f,data_ext);
+textModel = sprintf('%s\n',textModel);
+textModel = sprintf('%s\n%% Below we define options for what to estimate, how, etc.',textModel);
+textModel = sprintf('%s\noptions                         = [];',textModel);
+textModel = sprintf('%s\n',textModel);
+textModel = sprintf('%s\n%% These are the parameter names which are defined to be <estimate> ...',textModel);
+textModel = sprintf('%s\n%%                                  ',textModel);
+paramEstimation = {modelinfo.param_est.name};
+x = {};
+for k=1:length(modelinfo.param_est),
+    x{k} = sprintf('%s%s',modelinfo.param_est(k).name,char(32*ones(1,max(8-length(modelinfo.param_est(k).name),2))));
+end
+paramEstimationText = sprintf('%s',x{:});
+textModel = sprintf('%s%s',textModel,strtrim(paramEstimationText));
+
+textModel = sprintf('%s\n%% Initial guesses for the population mean parameters (fixed effects)',textModel);
+textModel = sprintf('%s\noptions.POPvalues0              = [',textModel);
+paramValuesText = '';
+for k=1:length(modelinfo.param_est),
+    y = sprintf('%1.3g%s',modelinfo.param_est(k).value0);
+    z = char(32*ones(1,length(x{k})-length(y)));
+    paramValuesText = sprintf('%s%s%s',paramValuesText,y,z);
+end
+textModel = sprintf('%s%s];',textModel,paramValuesText);
+
+textModel = sprintf('%s\n%% Vector defining what to estimate. A 0 means that this parameter is kept',textModel);
+textModel = sprintf('%s\n%% fixed on the initial guess. A 1 means that this parameter is estimated.',textModel);
+textModel = sprintf('%s\noptions.POPestimate             = [',textModel);
+paramValuesText = '';
+for k=1:length(modelinfo.param_est),
+    z = char(32*ones(1,length(x{k})-1));
+    paramValuesText = sprintf('%s1%s',paramValuesText,z);
+end
+textModel = sprintf('%s%s];',textModel,paramValuesText);
+
+textModel = sprintf('%s\n%% Initial guesses for the variability of this parameter in the population (random effects)',textModel);
+textModel = sprintf('%s\noptions.IIVvalues0              = [',textModel);
+paramValuesText = '';
+for k=1:length(modelinfo.param_est),
+    z = char(32*ones(1,length(x{k})-3));
+    paramValuesText = sprintf('%s0.5%s',paramValuesText,z);
+end
+textModel = sprintf('%s%s];',textModel,paramValuesText);
+
+textModel = sprintf('%s\n%% Vector defining what to estimate. A 0 means that the random effect for this parameter is not estimated (kept on 0)',textModel);
+textModel = sprintf('%s\n%% A 1 means that this parameter is estimated. A 2 means this parameter is',textModel);
+textModel = sprintf('%s\n%% kept fixed on its initial guess.',textModel);
+textModel = sprintf('%s\noptions.IIVestimate             = [',textModel);
+paramValuesText = '';
+for k=1:length(modelinfo.param_est),
+    z = char(32*ones(1,length(x{k})-1));
+    paramValuesText = sprintf('%s1%s',paramValuesText,z);
+end
+textModel = sprintf('%s%s];',textModel,paramValuesText);
+
+textModel = sprintf('%s\n%% Definition of the distribution of the interinvidiual parameters.',textModel);
+textModel = sprintf('%s\n%% ''L'' means: log normal',textModel);
+textModel = sprintf('%s\n%% ''N'' means: normal',textModel);
+textModel = sprintf('%s\n%% ''G'' means: logit normal',textModel);
+textModel = sprintf('%s\noptions.IIVdistribution         = {',textModel);
+paramValuesText = '';
+for k=1:length(modelinfo.param_est),
+    z = char(32*ones(1,length(x{k})-3));
+    paramValuesText = sprintf('%s''L''%s',paramValuesText,z);
+end
+textModel = sprintf('%s%s};',textModel,paramValuesText);
+
+textModel = sprintf('%s\n',textModel);
+
+textModel = sprintf('%s\n%% Definition of error models',textModel);
+textModel = sprintf('%s\noptions.errorModels             = ''',textModel);
+paramValuesText = '';
+for k=1:length(modelinfo.outputs),
+    paramValuesText = sprintf('%scomb1,',paramValuesText);
+end
+textModel = sprintf('%s%s'';',textModel,paramValuesText(1:end-1));
+
+textModel = sprintf('%s\noptions.errorParam0             = [',textModel);
+paramValuesText = '';
+for k=1:length(modelinfo.outputs),
+    paramValuesText = sprintf('%s1,0.3,',paramValuesText);
+end
+textModel = sprintf('%s%s];',textModel,paramValuesText(1:end-1));
+
+textModel = sprintf('%s\n',textModel);
+
+textModel = sprintf('%s\n%% Definition of covariance and covariate models',textModel);
+textModel = sprintf('%s\noptions.covarianceModel         = '''';',textModel);
+textModel = sprintf('%s\noptions.covariateModel          = '''';',textModel);
+textModel = sprintf('%s\n',textModel);
+
+textModel = sprintf('%s\n%% Robustness analysis. If Ntests>1 then Ntests models will be generated in the project folder,',textModel);
+textModel = sprintf('%s\n%% each starting from randomly selected initial guesses (based on std_noise_setting).',textModel);
+textModel = sprintf('%s\noptions.Ntests                  = 1;',textModel);
+textModel = sprintf('%s\noptions.std_noise_setting       = 0;',textModel);
+textModel = sprintf('%s\n',textModel);
+
+textModel = sprintf('%s\n%% Assignment of algorithm options',textModel);
+textModel = sprintf('%s\noptions.algorithm               = algorithm;',textModel);
+textModel = sprintf('%s\n',textModel);
+
+textModel = sprintf('%s\n%% Defnition of where to store the NLME project files',textModel);
+textModel = sprintf('%s\nprojectPath                     = ''%s'';',textModel,projectPath);
+textModel = sprintf('%s\n',textModel);
+
+textModel = sprintf('%s\n%% Run the function that creates the project files and run the model',textModel);
+textModel = sprintf('%s\n%% =================================================================',textModel);
+textModel = sprintf('%s\n',textModel);
+textModel = sprintf('%s\n%% For MONOLIX use:',textModel);
+textModel = sprintf('%s\nIQMcreateNLMEproject(''MONOLIX'',model,dosing,dataFIT,projectPath,options)',textModel);
+textModel = sprintf('%s\n',textModel);
+textModel = sprintf('%s\n%% For NONMEM use:',textModel);
+textModel = sprintf('%s\nIQMcreateNLMEproject(''NONMEM'',model,dosing,dataFIT,projectPath,options)',textModel);
+textModel = sprintf('%s\n',textModel);
+textModel = sprintf('%s\n%% Run the model:',textModel);
+textModel = sprintf('%s\nIQMrunNLMEproject(projectPath)',textModel);
+textModel = sprintf('%s\n',textModel);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Output to tempfile
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+filename = fullfile(tempdir,'generatedCode.txt');
+fid = fopen(filename,'w');
+fprintf(fid,'%s\n\n%s\n\n%s\n',textAlgorithm,textCovariates,textModel);
+fclose(fid);
+open(filename);
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/06-NMLEprojectHandling/IQMcreateNLMEproject.m b/IQMtools V1.2.2.2/IQMpro/tools/06-NMLEprojectHandling/IQMcreateNLMEproject.m
new file mode 100644
index 0000000000000000000000000000000000000000..ccfaeabf5ce90db98ae5b957dc0fe5d84f6ad1b5
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/06-NMLEprojectHandling/IQMcreateNLMEproject.m	
@@ -0,0 +1,153 @@
+function [] = IQMcreateNLMEproject(TOOL,model,dosing,data,projectPath,options)
+% Creates a NONMEM or MONOLIX roject from an IQMmodel and an IQMdosing scheme. 
+%
+% Basically a wrapper function for IQMcreateNONMEMproject and
+% IQMcreateMONOLIXproject. The only additional argument is the definition
+% of the TOOL to be used ('MONOLIX' or 'NONMEM').
+%
+% The user needs to ensure that the algorithm options are chosen adequately
+% for the selected parameter estimation tool. If NONMEM is chosen, the
+% Monolix specific settings are ignored. If MONOLIX is chosen, the NONMEM
+% specific settings are ignored.
+%
+% [SYNTAX]
+% [] = IQMcreateNLMEproject(TOOL,model,dosing,data,projectPath)
+% [] = IQMcreateNLMEproject(TOOL,model,dosing,data,projectPath,options)
+%
+% [INPUT]
+% model:            IQMmodel - with additional annotation:
+%                       Variables OUTPUT1-N where 1-N matches the YTYPE definitions in the dataset.
+%                       <estimate> as comment on parameters to be estimated.
+%                       <regression> as comment on parameters to be obtained from dataset.
+% dosing:           IQMdosing object (or empty [] if no INPUT defined in model)
+% data:             Structure with following fields:
+%       data.dataRelPathFromProject:    path to data file - relative to the
+%                                       projectPath folder.
+%       data.dataFileName:              data file filename
+%       data.dataHeaderIdent:           String with datafile header identifiers (example: 'ID,TIME,Y,MDV,EVID,AMT,TINF,ADM,YTYPE,COV,COV,CAT') 
+% projectPath:      String with the path/foldername to which the project files are to be written (example: 'FIT_01' or 'Models/FITS/FIT_01') 
+% parameterOrder:   Used to reorder parameters (used by the popPK workflow, do not use otherwise)
+%
+% options:      Structure with following fields (all optional with default settings):
+%       options.POPestimate:            Vector with 0 and 1 entries. 1 if pop parameter is estimated, 0 if not. Default or []: => all are estimated
+%       options.POPvalues0:             Vector with pop parameter initial values. Default or []: => values stored in model and dosing scheme
+%       options.IIVdistribution:        Cell-array with information about parameter distribution. L (lognormal), N (normal), G (logit)
+%                                       Example: {'L' 'L' 'L' 'L' 'N' 'L' 'L' 'L'}. Default or {}: => use lognormal for all
+%       options.IIVestimate:            Vector with 0 and 1 entries. 1 if random effect is estimated, 0 if not. Default or []: => all are estimated
+%                                       0: IIV not estimated (IIVvalues0 not used) 
+%                                       1: IIV estimated (IIVvalues0 as starting guesses)
+%                                       2: IIV not estimated but fixed on IIVvalues0 value
+%       options.IIVvalues0:             Vector with random effect parameter
+%                                       initial values. Default or []: => all set to 0.5
+%                                       If IIV not estimated then defined initial guess not used but replaced by 0
+%       options.errorModels:            String with definition of residual error models, comma separated for each output.
+%                                       Possible values: const,prop,comb1. Example: 'comb1,prop', Default or '': => const for all outputs
+%       options.errorParam0:            Vector allowing to pass initial guesses for error model parameters. Same order as error models. 
+%                                       'const': a, 'prop': b, 'comb1': a,b
+%       options.covarianceModel:        Definition of covariance model. String with cell-array text inside, grouping the parameters to consider having 
+%                                       correlated random effects. Example: '{CL,Vc},{Q,Vp,KM}'. Default: 'diagonal'
+%       options.covariateModel:         Definition of covariate model. Cell-array. Each element is a sub-cell-array. First element in sub-cell-array is the 
+%                                       parameter to which to add the covariate, all following elements define the covariates as named in the dataset.
+%                                       Example: '{CL,BMI0}, {Fsubcut,WT0}, {Vc,SEX,BMI0}'. Default: '' => no covariates
+%                                       By default (and so far not changeable, the continuous covariates are all weighted by their median, determined from the dataset)
+%                                       >>>Covariates can be added to all parameters for which not both IIVestimate and POPestimate are 0.
+%       options.covariateModelValues:   Definition of covariate coefficients for the selected covariate model. 
+%                                       Syntax is similar to options.covariateModel. It is a cell-array containing vectors instead of cell-arrays.
+%                                       Each vector contains values for the covariate coefficients, matching the covariateModel definition order.
+%                                       Example: if options.covariateModel = '{CL,BMI0,AGE0}, {Fsubcut,WT0}, {Vc,SEX,BMI0}'
+%                                       Then: options.covariateModelValues = {[0.5,0], [0.75], [0,0]}
+%                                       Defines the initial guesses for the covariate coefficients for BMI0 on CL to be 0.5, WT0 on Fsubcut to be 0.75, and the other ones are 0.
+%                                       If not defined, all covariate coefficients start from 0 in the estimation.
+%       options.COVestimate:            Same structure as options.covariateModelValues but with entries 0 or 1. 0 means not estimated, 1 means estimated.
+%                                       By default all are estimated.
+%                                       In the example above options.COVestimate = {[0,1], [1], [1,0]}   will estimate AE0 on CL, WT0 on Fsubcut, SEX on Vc.
+%                                       The other coefficients will be kept fixed.
+%       options.COVcentering.covs:      Cell-array with covariates that should be centered around a custom value. 
+%       options.COVcentering.values:    Vector with centering values. 
+%       options.Ntests:                 Doing robustness analysis - number of models to generate with different initial guesses (randomly generated based on POPvalues0)
+%                                       Default: 1 (no robustness analysis, using initial guesses as provided)
+%       options.std_noise_setting:      Standard deviation to use to add noise to the initial parameter guesses (default=0.5 (50%CV))
+%                                       Normal:         Parameter_guess + std_noise_setting*Parameter_guess*randomNumbers(0-1)
+%                                       Lognormal:      Parameter_guess * exp(std_noise_setting*randomNumbers(0-1))
+%                                       Logitnormal:    Similar and between 0-1
+%       options.keepProjectFolder:      =0: remover already existing folder, =1: keep it
+%
+% ALGORITHM SETTINGS - NONMEM & MONOLIX
+% =====================================
+%       options.algorithm.SEED:         Seed setting. Defualt: 123456
+%       options.algorithm.K1:           First iterations. Default: 500
+%       options.algorithm.K2:           Final iterations. Default: 200
+%       options.algorithm.NRCHAINS:     Number of parallel chains. Default: 1
+%
+% ALGORITHM SETTINGS - NONMEM
+% ===========================
+%       options.algorithm.METHOD:       'FO','FOCE','FOCEI','SAEM' (default: SAEM)
+%       options.algorithm.MAXEVAL:      Default: 9999
+%       options.algorithm.SIGDIGITS:    Default: 3
+%       options.algorithm.PRINT:        Default: 1
+%
+%       options.algorithm.M4:           Default: 0 (default: M3 method if dataset formated with CENS column and non-zero entries in it.)
+%
+%       options.algorithm.ITS:                  Allow to run an ITS method as first method befor all other methods (METHOD)
+%                                               ITS = 0 or 1 (default: 0 if not FO) - ITS=1 only accepted if not FO!
+%       options.algorithm.ITS_ITERATIONS:       Number of iterations for ITS (default: 10)
+%
+%       options.algorithm.IMPORTANCESAMPLING:   Allow determination of the OFV - only accepted after SAEM
+%                                               Default: 0, If 1 then do the importance sampling
+%       options.algorithm.IMP_ITERATIONS:       Number of iterations for importance sampling (default: 5)
+% 
+% ALGORITHM SETTINGS - MONOLIX
+% ============================
+%       options.algorithm.LLsetting:    'linearization' (default) or 'importantsampling'
+%       options.algorithm.FIMsetting:   'linearization' (default) or 'stochasticApproximation'
+%       options.algorithm.INDIVparametersetting: 'conditionalMode' (default) ... others not considered for now. 
+%       options.algorithm.startTime:    start time of integration. default: [] (not set).
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle input arguments
+if nargin == 5,
+    options = [];
+end
+
+% Check TOOL definition
+if ~strcmp(lower(TOOL),'nonmem') && ~strcmp(lower(TOOL),'monolix'),
+    error('Please select as first input argument either ''NONMEM'' or ''MONOLIX''');
+end
+
+% Check if datafile present ... and adjust if needed. Only do that if
+% options.Ntests=>1
+try Ntests = options.Ntests; catch, Ntests = 1; end
+if Ntests>1,
+    warning off
+    mkdir(projectPath)
+    warning on
+    oldpath         = pwd();
+    cd(projectPath)
+    datapath        = data.dataRelPathFromProject;
+    datafile        = data.dataFileName;
+    datapathfile    = [datapath '/' datafile];
+    if exist(datapathfile,'file') == 2,
+        % User has provided the path from the projectPath ... dont need to
+        % add anything.
+        datapath        = data.dataRelPathFromProject;
+    else
+        % User pbly has provided the path from the projectPath
+        datapath        = data.dataRelPathFromProject(4:end);
+        datapathfile    = [datapath '/' datafile];
+        if exist(datapathfile,'file') ~= 2,
+            error('Please check the definition of data.dataRelPathFromProject');
+        end
+    end
+    % Update the path
+    data.dataRelPathFromProject = datapath;
+    cd(oldpath);
+end
+
+% Create the model
+if strcmp(lower(TOOL),'nonmem')
+    IQMcreateNONMEMproject(model,dosing,data,projectPath,options);
+elseif strcmp(lower(TOOL),'monolix'),
+    IQMcreateMONOLIXproject(model,dosing,data,projectPath,options);
+end    
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/06-NMLEprojectHandling/IQMgetNLMEfitIndivPopMeanParam.m b/IQMtools V1.2.2.2/IQMpro/tools/06-NMLEprojectHandling/IQMgetNLMEfitIndivPopMeanParam.m
new file mode 100644
index 0000000000000000000000000000000000000000..5d6396d7a6acee5710c4bd02cc5e0031d560657a
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/06-NMLEprojectHandling/IQMgetNLMEfitIndivPopMeanParam.m	
@@ -0,0 +1,117 @@
+function [ popmean_param ] = IQMgetNLMEfitIndivPopMeanParam( projectPath, data )
+% This function returns the individual population mean parameters for all
+% subjects in the NLME fit. These parameters that determined from the point
+% estimates of the population mean + changes introduced due to potential
+% covariates that are present in the model. In this sense the returned
+% parameters are "individual" but not taking the true individual
+% variability into account. 
+% 
+% [SYNTAX]
+% [ popmean_param ] = IQMgetNLMEfitIndivPopMeanParam( projectPath )
+% [ popmean_param ] = IQMgetNLMEfitIndivPopMeanParam( projectPath,data )
+%
+% [INPUT]
+% projectPath:      Project to return the individual parameters
+% data:             Dataset (or path to its file) to take the individual
+%                   covariates and USUBJID from. If not provided, the
+%                   fitting dataset from the project will be used. 
+%
+% [OUTPUT]
+% indiv_param:      Table with individual parameters - linked to USUBJID
+%                   instead of ID
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle variable input arguments
+if nargin<2,
+    data = table();
+end
+
+% Check project
+if ~isNLMEprojectIQM(projectPath),
+    error('Provided path does not contain an NLME project.');
+end
+
+% Read the project header
+header = parseNLMEprojectHeaderIQM(projectPath);
+
+% Handle data input argument if provided as string with path
+if ischar(data),
+    % Assume path to dataset is provided
+    data        = IQMloadCSVdataset(data);
+elseif isempty(data),
+    % Assume dataset is not provided - load it
+    oldpath     = pwd();
+    cd(projectPath);
+    data        = IQMloadCSVdataset(header.DATA{1});
+    cd(oldpath);
+end
+
+% process some things
+x = strmatchIQM('',header.CATNAMES);
+header.CATNAMES(x) = [];
+x = strmatchIQM('',header.COVNAMES);
+header.COVNAMES(x) = [];
+
+% Cycle through data and keep only first entry for a single USUBJID
+% (should not happen anyway)
+dataFIRST = data;
+allID = unique(dataFIRST.USUBJID);
+for k=1:length(allID),
+    ix = ixdataIQM(dataFIRST,'USUBJID',allID(k));
+    if length(ix)>1,
+        dataFIRST(ix(2:end),:) = [];
+    end
+end
+
+% Separate dataFIRST into continuous and categorical covariates
+if ~isempty(header.CATNAMES),
+    if ~isempty(header.CATNAMES{1}),
+        dataCAT = dataFIRST(:,{'USUBJID' header.CATNAMES{:}});
+    end
+else
+    dataCAT = [];
+end
+if ~isempty(header.COVNAMES),
+    if ~isempty(header.COVNAMES{1}),
+        dataCOV = dataFIRST(:,{'USUBJID' header.COVNAMES{:}});
+    end
+else
+    dataCOV = [];
+end
+
+% Sample population parameters from fit
+FLAG_SAMPLE = 3; % Use point estimates of population parameters (do not consider uncertainty)
+                 % Return Nsamples sets of population parameters with covariates taken into account.
+NSAMPLES    = height(dataFIRST);
+
+if isempty(dataCOV),
+    covNames = {};
+    covValues = [];
+else
+    covNames    = dataCOV.Properties.VariableNames(2:end);
+    covValues   = table2array(dataCOV(:,2:end));
+end
+
+if isempty(dataCAT),
+    catNames = {};
+    catValues = [];
+else
+    catNames    = dataCAT.Properties.VariableNames(2:end);
+    catValues   = table2array(dataCAT(:,2:end));
+end
+
+% Sample parameters
+param       = IQMsampleNLMEfitParam(projectPath,FLAG_SAMPLE,NSAMPLES,covNames,covValues,catNames,catValues);
+
+% Create table out of parameters and names
+popmean_param     = array2table(param.parameterValuesPopulation);
+popmean_param.Properties.VariableNames = param.parameterNames;
+
+% Add USUBJID to table (same order as for covariates)
+popmean_param.USUBJID = dataFIRST.USUBJID;
+
+% Reorder to have USUBJID in the front
+popmean_param = popmean_param(:,[end 1:end-1]);
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/06-NMLEprojectHandling/IQMgetNLMEfitIndivparam.m b/IQMtools V1.2.2.2/IQMpro/tools/06-NMLEprojectHandling/IQMgetNLMEfitIndivparam.m
new file mode 100644
index 0000000000000000000000000000000000000000..56de56108536fd8062f944b7b9a34d086e108f4e
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/06-NMLEprojectHandling/IQMgetNLMEfitIndivparam.m	
@@ -0,0 +1,46 @@
+function [ indiv_param ] = IQMgetNLMEfitIndivparam( projectPath )
+% Returns the individual parameters from an NLME fit (NONMEM or MONOLIX)
+% 
+% [SYNTAX]
+% [ indiv_param ] = IQMgetNLMEfitIndivparam( projectPath )
+%
+% [INPUT]
+% projectPath:      Project to return the individual parameters
+%
+% [OUTPUT]
+% indiv_param:      Table with individual parameters - linked to USUBJID
+%                   instead of ID
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Check project
+if ~isNLMEprojectIQM(projectPath),
+    error('Provided path does not contain an NLME project.');
+end
+
+% Read the project header
+header = parseNLMEprojectHeaderIQM(projectPath);
+
+% Determine number of estimated parameters
+NR_parameters = length(header.PARAMNAMES);
+
+% Get the parameters
+if isMONOLIXprojectIQM(projectPath),
+    indiv_param = parseMONOLIXindivparamIQM(projectPath,NR_parameters);
+elseif isNONMEMprojectIQM(projectPath),
+    indiv_param = parseNONMEMindivparamIQM(projectPath,NR_parameters);
+else
+    error('Unknown NLME project type.');
+end
+
+% Link to USUBJID
+oldpath = pwd();
+cd(projectPath);
+dataFit = IQMloadCSVdataset(header.DATA{1});
+cd(oldpath);
+dataUSUBJID_ID = unique(dataFit(:,{'USUBJID','ID'}));
+indiv_param = join(indiv_param,dataUSUBJID_ID);
+indiv_param.ID = [];
+indiv_param = indiv_param(:,[end 1:end-1]);
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/06-NMLEprojectHandling/IQMgetNLMEparameterResults.m b/IQMtools V1.2.2.2/IQMpro/tools/06-NMLEprojectHandling/IQMgetNLMEparameterResults.m
new file mode 100644
index 0000000000000000000000000000000000000000..acf4149c66fde776882580af8b66395d047039ba
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/06-NMLEprojectHandling/IQMgetNLMEparameterResults.m	
@@ -0,0 +1,23 @@
+function [ output ] = IQMgetNLMEparameterResults( projectPath )
+% This function parses an NLME project folder and returns the parameter
+% estimates and additional information.
+%
+% [SYNTAX]
+%  parameters ] = IQMgetNLMEparameterResults( projectPath )
+%
+% [INPUT]
+% projectPath: path to the NLME project folder.
+%
+% [OUTPUT]
+% Structure with the following fields:
+%
+% output.fixedEffects:      names, values, stderr, rse, estimated flag
+% output.randomEffects:     names, values, stderr, rse, estimated flag
+% output.correlation:       names, values, stderr, rse, estimated flag
+% output.covariate:         names, values, stderr, rse, estimated flag
+% output.errorParameter:    names, values, stderr, rse, estimated flag
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+projectresults  = parseNLMEprojectResults( projectPath );
+output          = projectresults.rawParameterInfo;
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/06-NMLEprojectHandling/IQMrunNLMEproject.m b/IQMtools V1.2.2.2/IQMpro/tools/06-NMLEprojectHandling/IQMrunNLMEproject.m
new file mode 100644
index 0000000000000000000000000000000000000000..0fe613fdb4bd84ba34576a9350fb8af71daf73e6
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/06-NMLEprojectHandling/IQMrunNLMEproject.m	
@@ -0,0 +1,35 @@
+function [] = IQMrunNLMEproject(projectPath,NPROCESSORS,NO_GOF_PLOTS)
+% This function runs a specified NLME project (NONMEM or MONOLIX).
+%
+% [SYNTAX]
+% [] = IQMrunNLMEproject(projectPath)
+% [] = IQMrunNLMEproject(projectPath,N_PROCESSORS)
+% [] = IQMrunNLMEproject(projectPath,N_PROCESSORS,NO_GOF_PLOTS)
+%
+% [INPUT]
+% projectPath:      Path to the NLME project
+% NPROCESSORS:      Number of processors if use of parallel (default: 1)
+% NO_GOF_PLOTS:     =0: Create GoF plots for all runs (default), 
+%                   =1: No Gof plots
+%
+% [OUTPUT]
+% Output generated in the RESULTS folder of the NLME project.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle variable input arguments
+if nargin == 1,
+    NPROCESSORS = 1;
+    NO_GOF_PLOTS = 0;
+elseif nargin == 2,
+    NO_GOF_PLOTS = 0;
+end
+
+% Run the project
+if isMONOLIXprojectIQM(projectPath),
+    IQMrunMONOLIXproject(projectPath,NPROCESSORS,NO_GOF_PLOTS);
+elseif isNONMEMprojectIQM(projectPath),
+    IQMrunNONMEMproject(projectPath,NPROCESSORS,NO_GOF_PLOTS);
+else
+    error('Specified "projectPath" does not point to an NLME project.');
+end    
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/06-NMLEprojectHandling/IQMrunNLMEprojectFolder.m b/IQMtools V1.2.2.2/IQMpro/tools/06-NMLEprojectHandling/IQMrunNLMEprojectFolder.m
new file mode 100644
index 0000000000000000000000000000000000000000..112d594a23bf24aab76b4ea9ed1e8ad8c7bd9603
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/06-NMLEprojectHandling/IQMrunNLMEprojectFolder.m	
@@ -0,0 +1,81 @@
+function [] = IQMrunNLMEprojectFolder(modelProjectsFolder,N_PROCESSORS_PAR,N_PROCESSORS_SINGLE,NO_GOF_PLOTS)
+% This functions runs all NLME projects (NONMEM and MONOLIX) in the specified folder.
+% Parallel computation is supported in two different ways. Parallel execution 
+% of models at the same time (parfor loop) and also allowing each single model
+% run to be parallelized (if the NONMEM and MONOLIX installation allows for it).
+% The function also generates tables in the modelProjectsFolder allowing to
+% compare individual model results.
+%
+% [SYNTAX]
+% [] = IQMrunNLMEprojectFolder(modelProjectsFolder)
+% [] = IQMrunNLMEprojectFolder(modelProjectsFolder,N_PROCESSORS_PAR)
+% [] = IQMrunNLMEprojectFolder(modelProjectsFolder,N_PROCESSORS_PAR,N_PROCESSORS_SINGLE)
+% [] = IQMrunNLMEprojectFolder(modelProjectsFolder,N_PROCESSORS_PAR,N_PROCESSORS_SINGLE,NO_GOF_PLOTS)
+%
+% [INPUT]
+% modelProjectsFolder:      Path to a folder with NONMEM project folders
+%                           to be run. Folder names are arbitrary, but a
+%                           project.nmctl file needs to be present in
+%                           each folder.
+% N_PROCESSORS_PAR:         Number of processors for parallel model evaluation (default: as specified in SETUP_PATHS_TOOLS_IQMPRO)
+% N_PROCESSORS_SINGLE:      Number of processors for parallelization of single model run (default: 1)
+% NO_GOF_PLOTS:             =0: Create GoF plots for all runs (default), =1: No Gof plots
+%
+% If N_PROCESSORS_PAR>1 then parallel nodes are requested via the matlabpool
+% command and N_PROCESSORS_PAR models will be run in parallel.
+%
+% [OUTPUT]
+% No output! The function just runs the NONMEM and MONOLIX projects. All results are
+% written to the relevant output folders ("RESULTS").
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle variable input arguments
+if nargin == 1,
+    N_PROCESSORS_PAR    = getN_PROCESSORS_PARIQM();
+    N_PROCESSORS_SINGLE = 1;
+    NO_GOF_PLOTS = 0;
+elseif nargin == 2,
+    N_PROCESSORS_SINGLE = 1;
+    NO_GOF_PLOTS = 0;
+elseif nargin == 3,
+    NO_GOF_PLOTS = 0;
+end
+
+% Get the projects to run in the folder
+projects = dir([modelProjectsFolder '/*']);
+% Remove . and ..
+ix_dot = strmatchIQM('.',{projects.name});
+projects(ix_dot) = [];
+% Remove files
+projects(find(~[projects.isdir])) = [];
+
+% Request processors
+% Request min(N_PROCESSORS,length(projects))
+N_PROCESSORS_NEEDED = min(N_PROCESSORS_PAR,length(projects));
+killMATLABpool = startParallelIQM(N_PROCESSORS_NEEDED);
+
+% Run the models
+parfor k=1:length(projects),
+    fprintf('Running project %d of %d ...\n',k,length(projects));
+    pathfolder = [modelProjectsFolder '/' projects(k).name];
+    try
+        if isNONMEMprojectIQM(pathfolder),
+            IQMrunNONMEMproject(pathfolder,N_PROCESSORS_SINGLE,NO_GOF_PLOTS);
+        elseif isMONOLIXprojectIQM(pathfolder),
+            IQMrunMONOLIXproject(pathfolder,N_PROCESSORS_SINGLE,NO_GOF_PLOTS);
+        end
+    catch
+    end
+end
+    
+% Release processors
+stopParallelIQM(killMATLABpool);
+
+% Prepare tables for model comparison in the folder
+SETUP_PATHS_TOOLS_IQMPRO
+rehash
+IQMfitsummaryAll(modelProjectsFolder,'',NLME_ORDER_CRITERION);
+
+% Done!
+fprintf('\nEstimations READY!\n\n');
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/06-NMLEprojectHandling/IQMsampleNLMEfitParam.m b/IQMtools V1.2.2.2/IQMpro/tools/06-NMLEprojectHandling/IQMsampleNLMEfitParam.m
new file mode 100644
index 0000000000000000000000000000000000000000..4bbe88f0251c6d8f2c08b1881372c1246a57df88
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/06-NMLEprojectHandling/IQMsampleNLMEfitParam.m	
@@ -0,0 +1,74 @@
+function [output] = IQMsampleNLMEfitParam( projectPath, FLAG_SAMPLE, Nsamples, covNames, covValues, catNames, catValues )
+% This function samples parameters from both uncertainty and variability distributions from a NLME
+% fit which has been done using MONOLIX or NONMEM. Essentually it is a wrapper for the two tool 
+% specific functions (IQMsampleNONMEMparam and IQMsampleMONOLIXparam)
+% 
+% The result is a structure with sampled population parameters and sampled individual parameters. 
+% The desired number of parameter sets can be specified.
+%
+% This function is very useful for trial simulation purposes.
+%
+% Handles automatically different parameter distributions (logNormal, Normal, logitNormal)
+%
+% [SYNTAX]
+% output = IQMsampleNLMEfitParam( projectPath, FLAG_SAMPLE, Nsamples )
+% output = IQMsampleNLMEfitParam( projectPath, FLAG_SAMPLE, Nsamples, covNames, covValues, catNames, catValues )
+%
+% [INPUT]
+% projectPath: path to the NLME project folder. NONMEM and MONOLIX projects
+%              need to have been generated with IQM Tools.
+% FLAG_SAMPLE:                    0=use point estimates of population parameters (do not consider uncertainty) and sample Nsample 
+%                                   individual patients based on these. Covariates considered if defined by user and used in model.
+%                                   Please note: population parameters do not take covariates into account!
+%                                 1=sample single set of population parameters from uncertainty distribution and sample Nsample 
+%                                   individual patient parameters based on these. Covariates considered if defined by user and used in model.
+%                                   Please note: population parameters do not take covariates into account!
+%                                 2=sample Nsample sets of population parameters from uncertainty distribution 
+%                                   Do not sample from variability distribution and do not take into account covariates (even if user specified).
+%                                 3=use point estimates of population parameters (do not consider uncertainty)
+%                                   Return Nsamples sets of population parameters with covariates taken into account.
+%                                 4=sample single set of population parameters from uncertainty distribution 
+%                                   Return Nsamples sets of population parameters with covariates taken into account.
+%                                 5=sample Nsamples sets of population parameters from uncertainty distribution 
+%                                   And take provided covariates into account.
+% 
+% Nsamples:                       Number of individual parameter sets to sample
+%
+% covNames:                       Cell-array with names of continuous covariates to consider in the parameter sampling (only used for FLAG_SAMPLE=0 or 1)
+%                                 Default: {}
+% covValues:                      Matrix with Nsamples rows and as many columns as continuous covariate names in covNames (only used for FLAG_SAMPLE=0 or 1)
+% catNames:                       Cell-array with names of categorical covariates to consider in the parameter sampling (only used for FLAG_SAMPLE=0 or 1)
+%                                 Default: {}
+% catValues:                      Matrix with Nsamples rows and as many columns as categorical covariate names in covNames (only used for FLAG_SAMPLE=0 or 1)
+%
+% [OUTPUT]
+% Structure with the following fields:
+% output.parameterNames:                Cell-array with parameter names
+% output.FLAG_SAMPLE:                   Sampling flag used (see above for definition)
+% output.Nsamples:                      Number of sampled parameter sets (type of parameter sets sampled depends on FLAG_SAMPLE)
+% output.parameterValuesPopulation:     Vector or Matrix with (sampled) population parameters
+% output.parameterValuesIndividual:     Matrix with samples individual parameter sets (one set per row, one parameter per column)
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle variable input arguments
+if nargin == 3,
+    covNames = {};
+    covValues = []; 
+    catNames = {}; 
+    catValues = [];
+elseif nargin ==5,
+    catNames = {}; 
+    catValues = [];
+elseif nargin ==7,
+else
+    error('Incorrect number of input arguments.');
+end
+
+% Handle NONMEM or MONOLIX
+if isNONMEMprojectIQM(projectPath),
+    output = IQMsampleNONMEMparam(projectPath, FLAG_SAMPLE, Nsamples, covNames, covValues, catNames, catValues);
+else
+    output = IQMsampleMONOLIXparam(projectPath, FLAG_SAMPLE, Nsamples, covNames, covValues, catNames, catValues);
+end
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/06-NMLEprojectHandling/auxiliary/parseNLMEprojectHeaderIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/06-NMLEprojectHandling/auxiliary/parseNLMEprojectHeaderIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..56356e097ffbc901502fe1805b4815d5f9a21c82
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/06-NMLEprojectHandling/auxiliary/parseNLMEprojectHeaderIQM.m	
@@ -0,0 +1,22 @@
+function [projectinfo] = parseNLMEprojectHeaderIQM(projectPath)
+% Parses the project header information from an NLME project (MONOLIX or NONMEM)
+% 
+% [SYNTAX]
+% [projectinfo] = parseNLMEprojectHeaderIQM(projectPath)
+%
+% [INPUT]
+% projectPath:      Project to return the header information
+%
+% [OUTPUT]
+% projectinfo:      Structure with information
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Check if project.nmctl in project folder
+if isMONOLIXprojectIQM(projectPath),
+    projectinfo = parseMONOLIXprojectHeaderIQM(projectPath);
+elseif isNONMEMprojectIQM(projectPath),
+    projectinfo = parseNONMEMprojectHeaderIQM(projectPath);
+else
+    error('Provided projectPath does not point to an NLME project.');
+end
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/06-NMLEprojectHandling/auxiliary/parseNLMEprojectResults.m b/IQMtools V1.2.2.2/IQMpro/tools/06-NMLEprojectHandling/auxiliary/parseNLMEprojectResults.m
new file mode 100644
index 0000000000000000000000000000000000000000..bd8997852640a2bf53835a96daa37e76206218f1
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/06-NMLEprojectHandling/auxiliary/parseNLMEprojectResults.m	
@@ -0,0 +1,53 @@
+function [ output ] = parseNLMEprojectResults( projectPath )
+% This function parses the output of an NLME project and returns all information in a structure
+%
+% [SYNTAX]
+% output = parseNLMEprojectResults( projectPath )
+%
+% [INPUT]
+% projectPath: path to the NLME project folder. 
+%
+% [OUTPUT]
+% Structure with the following fields:
+%
+% output.path                         : path from which the results are read (project folder+RESULTS)
+% output.parameters                   : a structure with all parameter information
+% output.parameters.names             : cell-array with the parameter names
+% output.parameters.values            : vector with estimated values
+% output.parameters.stderrors         : vector with standard errors of estimation
+% output.parameters.correlationmatrix : full correlation matrix for estimates
+% output.parameters.FLAGestimated     : vector with flags 1 if estimated, 0 if not estimated
+% output.parameters.covariancematrix  : full covariance matrix for parameter estimates, determined
+%                                       from correlationmatrix and standard errors
+% output.objectivefunction            : structure with the values for the log-likelihood, AIC and BIC for
+%                                       both linearization and importance sampling. NaN if not determined
+% output.residualerrormodels          : cell-array with the aliases of the residual error models in the order 
+%                                       of the outputs, as defined in the MLXTRAN models
+% output.trans_randeffects            : a cell-array with the transformation of the random effects 
+% output.inv_trans_randeffects        : a cell-array with the inverse transformation of the random effects
+%
+% output.covariates.covNames          : cell-array with names of continuous covariates
+% output.covariates.covTransformation : cell-array with transformations of continuous covariates 
+% output.covariates.catNames          : cell-array with names of categorical covariates 
+% output.covariates.catCategories     : cell-array with categories of categorical covariates  
+% output.covariates.catReference      : cell-array with reference values of categorical covariates 
+
+% output.rawParameterInfo             : Info about fixed, random effects, covariates, correlations, error model etc.
+%
+% [ASSUMPTIONS]
+% String assumptions about the structure and syntax of the pop_parameters.txt file were made.
+% Need to reassess when new functions of Monolix arrive.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Check if project.nmctl in project folder
+if isMONOLIXprojectIQM(projectPath),
+    projectresults = parseMONOLIXresultsIQM(projectPath);
+elseif isNONMEMprojectIQM(projectPath),
+    transformFlag = 1;
+    projectresults = parseNONMEMresultsIQM(projectPath,transformFlag);
+else
+    error('Provided projectPath does not point to an NLME project.');
+end
+
+output = projectresults;
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/06-NMLEprojectHandling/isNLMEprojectIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/06-NMLEprojectHandling/isNLMEprojectIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..a08bb554684dc2ae0be46a68a48bfe48c316194c
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/06-NMLEprojectHandling/isNLMEprojectIQM.m	
@@ -0,0 +1,21 @@
+function [ output ] = isNLMEprojectIQM( projectPath )
+% Checks if given project path is an NMLE project folder (NONMEM or
+% MONOLIX).
+% 
+% [SYNTAX]
+% [output] = isNLMEprojectIQM( projectPath )
+%
+% [INPUT]
+% projectPath:  Path to check if NLME project
+%
+% [OUTPUT]
+% output = 0: No NLME project
+% output = 1: NLME project
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+output = isNONMEMprojectIQM(projectPath) + isMONOLIXprojectIQM(projectPath);
+
+if output>1,
+    error('Seems to be both a NONMEM and a MONOLIX project => can not really be.');
+end
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/07-NLMEfitAnalysis/IQMfitanalysisConditionNumber.m b/IQMtools V1.2.2.2/IQMpro/tools/07-NLMEfitAnalysis/IQMfitanalysisConditionNumber.m
new file mode 100644
index 0000000000000000000000000000000000000000..7e726fca419220b1b0c5b8a66b680a7ac1ccb524
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/07-NLMEfitAnalysis/IQMfitanalysisConditionNumber.m	
@@ -0,0 +1,78 @@
+function [cNfull,cNfebeta,cNreerror,cNcorr] = IQMfitanalysisConditionNumber(projectPath)
+% Determine the condition number for an NLME fit.
+% Several condition numbers will be generated:
+% - condition number for the full covariance matrix (cNfull)
+% - condition number for fixed effects + covariate coefficients (cNfebeta)
+% - condition number for random effects + error model parameters (cNreerror) 
+% - condition number for correlation parameters (cNcorr) 
+%
+% [SYNTAX]
+% [cNfull,cNfebeta,cNreerror,cNcorr] = IQMfitanalysisConditionNumber(projectPath)
+%
+% [INPUT]
+% projectPath:      Path to the project.nmctl NONMEM project file
+%
+% [OUTPUT]
+% Different condition numbers
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% parse the results
+if isNONMEMprojectIQM(projectPath),
+    x = parseNONMEMresultsIQM(projectPath);
+elseif isMONOLIXprojectIQM(projectPath),
+    x = parseMONOLIXresultsIQM(projectPath);
+else
+    error('Unknown project type.');
+end
+
+cNfull      = NaN;
+cNfebeta    = NaN;
+cNreerror   = NaN;
+cNcorr      = NaN;
+
+if ~isempty(x.parameters.correlationmatrix),   
+    
+    cNfull = cond(x.parameters.correlationmatrix);
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % fE and beta
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    names = [x.rawParameterInfo.fixedEffects.names x.rawParameterInfo.covariate.names];
+    ix_all = [];
+    for k=1:length(names),
+        ix_all(k) = strmatchIQM(names{k},x.parameters.names,'exact');
+    end
+    cNfebeta = cond(x.parameters.correlationmatrix(ix_all,ix_all));
+    
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % omegas and error parameters
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    if isNONMEMprojectIQM(projectPath),
+        names = [strrep(x.rawParameterInfo.randomEffects.names,'omega','omega2') x.rawParameterInfo.errorParameter.names];
+    else
+        names = [x.rawParameterInfo.randomEffects.names x.rawParameterInfo.errorParameter.names];
+    end
+    ix_all = [];
+    for k=1:length(names),
+        ix_all(k) = strmatchIQM(names{k},x.parameters.names,'exact');
+    end
+    cNreerror = cond(x.parameters.correlationmatrix(ix_all,ix_all));
+
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    % Correlation of correlations
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    if isNONMEMprojectIQM(projectPath),
+        names = [strrep(x.rawParameterInfo.correlation.names,'corr(','omega2(')];
+    else
+        names = x.rawParameterInfo.correlation.names;
+    end
+    if length(names) >= 1,
+        ix_all = [];
+        for k=1:length(names),
+            ix_all(k) = strmatchIQM(names{k},x.parameters.names);
+        end
+        cNcorr = cond(x.parameters.correlationmatrix(ix_all,ix_all));
+    end
+end
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/07-NLMEfitAnalysis/IQMfitanalysisETAvsCOV.m b/IQMtools V1.2.2.2/IQMpro/tools/07-NLMEfitAnalysis/IQMfitanalysisETAvsCOV.m
new file mode 100644
index 0000000000000000000000000000000000000000..8608f64cd25f3bcae46a6040c495968326cd9a35
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/07-NLMEfitAnalysis/IQMfitanalysisETAvsCOV.m	
@@ -0,0 +1,45 @@
+function [] = IQMfitanalysisETAvsCOV(projectPath,filename,options)
+% This function is used to plot the individual variations over covariates
+% and categorical covariates. It can be used for a first assessment which
+% variables could be potentially interesting covariates in the model.
+%
+% Whiskers on the boxplot define the 5th and 95th percentiles of the plotted data.
+%
+% [SYNTAX]
+% [] = IQMfitanalysisETAvsCOV(projectPath)
+% [] = IQMfitanalysisETAvsCOV(projectPath,filename)
+% [] = IQMfitanalysisETAvsCOV(projectPath,filename,options)
+%
+% [INPUT]
+% projectPath:  Path to a NONMEM or MONOLIX project folder. 
+% filename:     If a filename is provided, then the results are exported
+%               into a PDF document with this name (and path).
+% options:      MATLAB structure with plotting optins:
+%                   
+%                   options.corrcoeffThreshold: number between 0 and 1. If
+%                          correlation above this value, then data plotted in red.
+%                          (default: 0.3)
+%                   options.labels: =1: adds ID labels next to each value (default)
+%                                   =0: does not add labels 
+%
+% [OUTPUT]
+% Plots, ETAs over covariates - and PDF if desired.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle variable input arguments
+if nargin<2,
+    filename    = '';
+end
+if nargin<3,
+    options = [];
+end
+
+if isMONOLIXprojectIQM(projectPath),
+    fitanalysisETAvsCOVmonolixIQM(projectPath,filename,options)    
+elseif isNONMEMprojectIQM(projectPath),
+    fitanalysisETAvsCOVnonmemIQM(projectPath,filename,options)    
+else
+    error('Unknown project type.');
+end
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/07-NLMEfitAnalysis/IQMfitanalysisGOFplots.m b/IQMtools V1.2.2.2/IQMpro/tools/07-NLMEfitAnalysis/IQMfitanalysisGOFplots.m
new file mode 100644
index 0000000000000000000000000000000000000000..cdf7ed7d5f648f24f9cee55a7fd8d50d9c68e64d
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/07-NLMEfitAnalysis/IQMfitanalysisGOFplots.m	
@@ -0,0 +1,449 @@
+function [] = IQMfitanalysisGOFplots(projectPath,filename,outputNumber,options)
+% This function produces several plots that can be used for checking the 
+% goodness of fit. 
+%
+% Ignored records with MDV=1 are not considered in the plotting (only
+% relevant for NONMEM, since in MONOLIX output they are not present
+% anyway). Also CENS=1 values are not considered (for NONMEM).
+%
+% [SYNTAX]
+% [] = IQMfitanalysisGOFplots(projectPath)
+% [] = IQMfitanalysisGOFplots(projectPath,filename)
+% [] = IQMfitanalysisGOFplots(projectPath,filename,outputNumber)
+% [] = IQMfitanalysisGOFplots(projectPath,filename,outputNumber,options)
+%
+% [INPUT]
+% projectPath:  Path to a NONMEM or MONOLIX project folder. 
+% filename:     If a filename is provided, then the results are exported
+%               into a PDF document with this name (and path).
+% outputNumber: Number of the output in the model to consider for plotting
+%               If not specified, then output number 1 is assumed (or if
+%               only single output in model, then this is used)
+% options:      MATLAB structure with plotting optins:
+%
+%                   options.labels:     =1: adds ID labels next to each value in some plots (default)
+%                                       =0: does not add labels 
+%                   options.minPRED:    Defines the minimum acceptable PRED
+%                                       value. By default -Inf but since NONMEM
+%                                       happily produces negative PRED values
+%                                       for PK it is good to be able to limit
+%                                       them to 0 or eps. :). Default is
+%                                       set by "[]".
+%
+% [OUTPUT]
+% Plots or PDF/PS file
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle variable input arguments
+if nargin<2,
+    filename = '';
+end
+if nargin<3,
+    outputNumber = 1;
+end
+if nargin<4,
+    options = [];
+end
+
+% Handle options
+try labels              = options.labels; catch, labels = 1; end
+try minPRED             = options.minPRED; catch, minPRED = []; end
+
+% Initialize PDF output
+IQMstartNewPrintFigure(filename);
+
+% Handle NONMEM/MONOLIX
+if isMONOLIXprojectIQM(projectPath),
+    predictions         = parseMONOLIXpredictionsIQM(projectPath,outputNumber);
+    
+    % Get the data
+    data                = table();
+    data.ID             = predictions.ID;
+    data.TIME           = predictions.time;
+    data.DV             = predictions.(['y' num2str(outputNumber)]);
+    data.popPred        = predictions.popPred;
+    data.indPred_mode   = predictions.indPred_mode;
+    data.meanWRes       = predictions.meanWRes;
+    data.indWRes_mode   = predictions.indWRes_mode;
+    data.NPDE           = predictions.NPDE;
+
+    IWRES               = 'indWRes_mode';
+    IPRED               = 'indPred_mode';
+    PRED                = 'popPred';
+    PWRES               = 'meanWRes';
+    TIME                = 'TIME';
+
+elseif isNONMEMprojectIQM(projectPath),
+    predictions         = parseNONMEMpredictionsIQM(projectPath,outputNumber);
+    
+    % Remove doses and MDV==1 observations
+    predictions(predictions.EVID==1,:) = [];
+    predictions(predictions.MDV==1,:) = [];
+    predictions(predictions.CENS==1,:) = [];
+
+    % Get the right name for PRED
+    ph                  = parseNONMEMprojectHeaderIQM(projectPath);
+    PRED                = ph.RESIDUAL_NAMES_ORIG{strmatchIQM('XPRED',ph.RESIDUAL_NAMES_USED)};
+    PWRES               = ph.RESIDUAL_NAMES_ORIG{strmatchIQM('XWRES',ph.RESIDUAL_NAMES_USED)};
+    TIME                = 'TIME2';
+    IPRED               = 'IPRED';
+    IWRES               = 'IWRES';
+    
+    % Get the data
+    data                = table();
+    data.ID             = predictions.ID;    
+    data.(TIME)         = predictions.TIME2;
+    data.DV             = predictions.DV;
+    data.(PRED)         = predictions.XPRED;
+    data.(IPRED)        = predictions.IPRED;
+    data.(PWRES)        = predictions.XWRES;
+    data.(IWRES)        = predictions.IWRES;
+    data.NPDE           = predictions.NPDE;
+else
+    error('Unknown project type.');
+end
+
+%% Apply minPRED setting (if defined)
+if ~isempty(minPRED),
+    data(data.(PRED)<=minPRED,:) = [];
+end
+
+%% DV vs. (I)PRED: linear
+nameX                           = 'DV';
+nameY                           = {PRED IPRED};
+optionsPlot                     = [];
+optionsPlot.logX                = 0;
+optionsPlot.logY                = 0;
+optionsPlot.sameaxes            = 1;
+optionsPlot.squareaxes          = 1;
+optionsPlot.showregressionline  = 0; 
+optionsPlot.showloessline       = 1;
+optionsPlot.showslope1line      = 1;
+optionsPlot.markersize          = 10;
+optionsPlot.linecolor           = [0.0549    0.4471    0.7294];
+optionsPlot.slope1linecolor     = [1 0 0];
+optionsPlot.axescolor           = 0.2*[1 1 1];
+if labels==1,
+    optionsPlot.nameText        = 'ID';
+    optionsPlot.nameTextLines   = 0;
+end
+IQMplotXY(data,nameX,nameY,optionsPlot)
+
+%%
+
+% Print figure to PDF
+IQMprintFigure(gcf,filename);
+if ~isempty(filename),
+    close(gcf);
+end
+
+%% DV vs. (I)PRED: log
+try
+    nameX                           = 'DV';
+    nameY                           = {PRED IPRED};
+    optionsPlot                     = [];
+    optionsPlot.logX                = 1;
+    optionsPlot.logY                = 1;
+    optionsPlot.sameaxes            = 1;
+    optionsPlot.squareaxes          = 1;
+    optionsPlot.showregressionline  = 0;
+    optionsPlot.showloessline       = 1;
+    optionsPlot.showslope1line      = 1;
+    optionsPlot.markersize          = 10;
+    optionsPlot.linecolor           = [0.0549    0.4471    0.7294];
+    optionsPlot.slope1linecolor     = [1 0 0];
+    optionsPlot.axescolor           = 0.2*[1 1 1];
+    if labels==1,
+        optionsPlot.nameText        = 'ID';
+        optionsPlot.nameTextLines   = 0;
+    end
+    IQMplotXY(data,nameX,nameY,optionsPlot);
+    
+    % Print figure to PDF
+    IQMprintFigure(gcf,filename);
+    if ~isempty(filename),
+        close(gcf);
+    end
+catch
+    disp('If your data is already log transformed an additional log transform for plotting might lead to an error due to negative values.');
+end
+
+%% PWRES/IWRES/NPDE vs TIME
+nameX                           = TIME;
+nameY                           = {PWRES IWRES 'NPDE'};
+optionsPlot                     = [];
+optionsPlot.logX                = 0;
+optionsPlot.logY                = 0;
+optionsPlot.showmedian           = 0;
+optionsPlot.NbinsMedian          = 20;
+optionsPlot.showregressionline  = 0;
+optionsPlot.showloessline       = 1;
+optionsPlot.nrows               = 3;
+optionsPlot.ncols               = 1;
+optionsPlot.sameaxes            = 0;
+optionsPlot.showzeroLines       = 1;
+optionsPlot.zeroLinescolor      = [0 0 0];
+optionsPlot.markersize          = 10;
+optionsPlot.heighttitlebar      = 0.08;
+optionsPlot.linecolor           = [0.0549    0.4471    0.7294];
+optionsPlot.axescolor           = 0.2*[1 1 1];
+if labels==1,
+    optionsPlot.nameText        = 'ID';
+    optionsPlot.nameTextLines   = 0;
+end
+IQMplotXY(data,nameX,nameY,optionsPlot)
+% Print figure to PDF
+IQMprintFigure(gcf,filename);
+if ~isempty(filename),
+    close(gcf);
+end
+
+% PWRES/IWRES/NPDE vs TIME - logX
+nameX                           = TIME;
+nameY                           = {PWRES IWRES 'NPDE'};
+optionsPlot                     = [];
+optionsPlot.logX                = 1;
+optionsPlot.logY                = 0;
+optionsPlot.showmedian          = 0;
+optionsPlot.NbinsMedian         = 20;
+optionsPlot.showregressionline  = 0;
+optionsPlot.showloessline       = 1;
+optionsPlot.nrows               = 3;
+optionsPlot.ncols               = 1;
+optionsPlot.sameaxes            = 0;
+optionsPlot.showzeroLines       = 1;
+optionsPlot.zeroLinescolor      = [0 0 0];
+optionsPlot.markersize          = 10;
+optionsPlot.heighttitlebar      = 0.08;
+optionsPlot.linecolor           = [0.0549    0.4471    0.7294];
+optionsPlot.axescolor           = 0.2*[1 1 1];
+if labels==1,
+    optionsPlot.nameText        = 'ID';
+    optionsPlot.nameTextLines   = 0;
+end
+IQMplotXY(data,nameX,nameY,optionsPlot)
+% Print figure to PDF
+IQMprintFigure(gcf,filename);
+if ~isempty(filename),
+    close(gcf);
+end
+
+% PWRES/IWRES/NPDE vs PRED
+nameX                           = PRED;
+nameY                           = {PWRES, IWRES, 'NPDE'};
+optionsPlot                     = [];
+optionsPlot.logX                = 0;
+optionsPlot.logY                = 0;
+optionsPlot.showmedian          = 0;
+optionsPlot.NbinsMedian         = 20;
+optionsPlot.showregressionline  = 0;
+optionsPlot.showloessline       = 1;
+optionsPlot.nrows               = 3;
+optionsPlot.ncols               = 1;
+optionsPlot.sameaxes            = 0;
+optionsPlot.showzeroLines       = 1;
+optionsPlot.markersize          = 10;
+optionsPlot.zeroLinescolor      = [0 0 0];
+optionsPlot.heighttitlebar      = 0.08;
+optionsPlot.linecolor           = [0.0549    0.4471    0.7294];
+optionsPlot.axescolor           = 0.2*[1 1 1];
+if labels==1,
+    optionsPlot.nameText        = 'ID';
+    optionsPlot.nameTextLines   = 0;
+end
+IQMplotXY(data,nameX,nameY,optionsPlot)
+% Print figure to PDF
+IQMprintFigure(gcf,filename);
+if ~isempty(filename),
+    close(gcf);
+end
+
+% PWRES/IWRES/NPDE vs PRED - logX
+nameX                           = PRED;
+nameY                           = {PWRES, IWRES, 'NPDE'};
+optionsPlot                     = [];
+optionsPlot.logX                = 1;
+optionsPlot.logY                = 0;
+optionsPlot.showmedian          = 0;
+optionsPlot.NbinsMedian         = 20;
+optionsPlot.showregressionline  = 0;
+optionsPlot.showloessline       = 1;
+optionsPlot.nrows               = 3;
+optionsPlot.ncols               = 1;
+optionsPlot.sameaxes            = 0;
+optionsPlot.showzeroLines       = 1;
+optionsPlot.markersize          = 10;
+optionsPlot.zeroLinescolor      = [0 0 0];
+optionsPlot.heighttitlebar      = 0.08;
+optionsPlot.linecolor           = [0.0549    0.4471    0.7294];
+optionsPlot.axescolor           = 0.2*[1 1 1];
+if labels==1,
+    optionsPlot.nameText        = 'ID';
+    optionsPlot.nameTextLines   = 0;
+end
+IQMplotXY(data,nameX,nameY,optionsPlot)
+% Print figure to PDF
+IQMprintFigure(gcf,filename);
+if ~isempty(filename),
+    close(gcf);
+end
+
+%% Histogram of WRES, compared to normal distribution
+optionsPlot = [];
+optionsPlot.show2lines = 1;
+optionsPlot.stdNorm    = 1;
+optionsPlot.names      = {PWRES};
+IQMplotHistogram(data.(PWRES),optionsPlot)
+set(gcf,'Color',[1 1 1]);
+% Print figure to PDF
+IQMprintFigure(gcf,filename);
+if ~isempty(filename),
+    close(gcf);
+end
+
+%% Histogram of IWRES, compared to normal distribution
+optionsPlot = [];
+optionsPlot.show2lines = 1;
+optionsPlot.stdNorm    = 1;
+optionsPlot.names      = {IWRES};
+IQMplotHistogram(data.(IWRES),optionsPlot)
+set(gcf,'Color',[1 1 1]);
+% Print figure to PDF
+IQMprintFigure(gcf,filename);
+if ~isempty(filename),
+    close(gcf);
+end
+
+%% Histogram of NPDE, compared to normal distribution
+optionsPlot = [];
+optionsPlot.show2lines = 1;
+optionsPlot.stdNorm    = 1;
+optionsPlot.names      = {'NPDE'};
+IQMplotHistogram(data.NPDE,optionsPlot)
+set(gcf,'Color',[1 1 1]);
+% Print figure to PDF
+IQMprintFigure(gcf,filename);
+if ~isempty(filename),
+    close(gcf);
+end
+
+%% QQPlot of WRES
+optionsPlot = [];
+optionsPlot.names      = {PWRES};
+IQMplotQQ(data.(PWRES),optionsPlot);
+grid on;
+set(gcf,'Color',[1 1 1]);
+% Print figure to PDF
+IQMprintFigure(gcf,filename);
+if ~isempty(filename),
+    close(gcf);
+end
+
+%% QQPlot of IWRES
+optionsPlot = [];
+optionsPlot.names      = {IWRES};
+IQMplotQQ(data.(IWRES),optionsPlot);
+grid on;
+set(gcf,'Color',[1 1 1]);
+% Print figure to PDF
+IQMprintFigure(gcf,filename);
+if ~isempty(filename),
+    close(gcf);
+end
+
+%% QQPlot of NPDE
+optionsPlot = [];
+optionsPlot.names      = {'NPDE'};
+IQMplotQQ(data.NPDE,optionsPlot);
+grid on;
+set(gcf,'Color',[1 1 1]);
+% Print figure to PDF
+IQMprintFigure(gcf,filename);
+if ~isempty(filename),
+    close(gcf);
+end
+
+%% PDF plot of WRES
+figure;
+% Plot normal distribution
+x = linspace(-4,4,1000);
+y = normpdfIQM(x,0,1);
+plot(x,y,'b--','LineWidth',2); hold on
+% Plot empirical distribution
+if max(length(data.(PWRES))/100) < 10,
+    nrbinsuse = 10;
+else
+    nrbinsuse = round(length(data.(PWRES))/100);
+end
+[n,x] = hist(data.(PWRES),nrbinsuse);
+plot(x,n/max(n)*max(y),'r-','LineWidth',2); 
+% Axis etc
+axis([-4 4 0 0.5]);
+grid on;
+title(sprintf('PDF of %s vs. Standard Normal',PWRES),'FontSize',14,'FontWeight','bold','Interpreter','none');
+ylabel('PDF','FontSize',14,'Interpreter','none');
+xlabel(PWRES,'FontSize',14,'Interpreter','none');
+set(gca,'FontSize',12);
+% Print figure to PDF
+IQMprintFigure(gcf,filename);
+if ~isempty(filename),
+    close(gcf);
+end
+
+%% PDF plot of IWRES
+figure;
+% Plot normal distribution
+x = linspace(-4,4,1000);
+y = normpdfIQM(x,0,1);
+plot(x,y,'b--','LineWidth',2); hold on
+% Plot empirical distribution
+if max(length(data.(IWRES))/100) < 10,
+    nrbinsuse = 10;
+else
+    nrbinsuse = round(length(data.(IWRES))/100);
+end
+[n,x] = hist(data.(IWRES),nrbinsuse);
+plot(x,n/max(n)*max(y),'r-','LineWidth',2); 
+% Axis etc
+axis([-4 4 0 0.5]);
+grid on;
+title(sprintf('PDF of %s vs. Standard Normal',IWRES),'FontSize',14,'FontWeight','bold','Interpreter','none');
+ylabel('PDF','FontSize',14,'Interpreter','none');
+xlabel(IWRES,'FontSize',14,'Interpreter','none');
+set(gca,'FontSize',12);
+% Print figure to PDF
+IQMprintFigure(gcf,filename);
+if ~isempty(filename),
+    close(gcf);
+end
+
+%% PDF plot of NPDE
+figure;
+% Plot normal distribution
+x = linspace(-4,4,1000);
+y = normpdfIQM(x,0,1);
+plot(x,y,'b--','LineWidth',2); hold on
+% Plot empirical distribution
+if max(length(data.NPDE)/100) < 10,
+    nrbinsuse = 10;
+else
+    nrbinsuse = round(length(data.NPDE)/100);
+end
+[n,x] = hist(data.NPDE,nrbinsuse);
+plot(x,n/max(n)*max(y),'r-','LineWidth',2); 
+% Axis etc
+axis([-4 4 0 0.5]);
+grid on;
+title('PDF of NPDE vs. Standard Normal','FontSize',14,'FontWeight','bold','Interpreter','none');
+ylabel('PDF','FontSize',14,'Interpreter','none');
+xlabel('NPDE','FontSize',14,'Interpreter','none');
+set(gca,'FontSize',12);
+% Print figure to PDF
+IQMprintFigure(gcf,filename);
+if ~isempty(filename),
+    close(gcf);
+end
+
+%% PS2PDF
+IQMconvert2pdf(filename);
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/07-NLMEfitAnalysis/IQMfitanalysisGeneralPlots.m b/IQMtools V1.2.2.2/IQMpro/tools/07-NLMEfitAnalysis/IQMfitanalysisGeneralPlots.m
new file mode 100644
index 0000000000000000000000000000000000000000..2c71497cff6fac380e811c9cc95ac0bd099af23d
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/07-NLMEfitAnalysis/IQMfitanalysisGeneralPlots.m	
@@ -0,0 +1,49 @@
+function [] = IQMfitanalysisGeneralPlots(projectPath,options,basefilename)
+% This function is a wrapper for different fit analysis functions that plot
+% things that are independent of a specific output of the model:
+% - IQMfitanalysisRandomEffects
+% - IQMfitanalysisETAvsCOV
+% 
+% [SYNTAX]
+% [] = IQMfitanalysisGeneralPlots(projectPath)
+% [] = IQMfitanalysisGeneralPlots(projectPath,options)
+% [] = IQMfitanalysisGeneralPlots(projectPath,options,basefilename)
+%
+% [INPUT]
+% projectPath:  Path to a NONMEM or MONOLIX project folder. 
+% basefilename: Path and base part of the filenames where
+%               outputs are exported to. 
+%               Default: 'RESULTS/GOF_GENERAL/' in the selected project.
+% options:      MATLAB structure with plotting options:
+%               Currently no options to be set.
+%
+%                   options.labels: =1: adds ID labels next to each value in some plots (default)
+%                                   =0: does not add labels 
+%
+% [OUTPUT]
+% PDF files at specified location (basefilename)
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle variable input arguments
+if nargin<2,
+    options = [];
+end
+if nargin<3,
+    basefilename = [projectPath '/RESULTS/GOF_GENERAL/'];
+end
+    
+% Handle options
+try labels = options.labels; catch, labels = 1; end
+
+% Run IQMfitanalysisRandomEffects
+options = [];
+options.labels = labels;
+IQMfitanalysisRandomEffects(projectPath,[basefilename '01_Random_Effects'],options)
+
+% Run IQMfitanalysisETAvsCOV
+options = [];
+options.labels = labels;
+options.corrcoeffThreshold = 0.3;
+IQMfitanalysisETAvsCOV(projectPath,[basefilename '02_ETAs_vs_COVs'],options)
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/07-NLMEfitAnalysis/IQMfitanalysisIndividualFits.m b/IQMtools V1.2.2.2/IQMpro/tools/07-NLMEfitAnalysis/IQMfitanalysisIndividualFits.m
new file mode 100644
index 0000000000000000000000000000000000000000..9933d6113f717eb254160381e45e63acb8b9dd19
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/07-NLMEfitAnalysis/IQMfitanalysisIndividualFits.m	
@@ -0,0 +1,170 @@
+function [] = IQMfitanalysisIndividualFits(projectPath,filename,outputNumber,options)
+% This function plots individual fits and population prediction against
+% observed data over time. Per ID/USUBJID a single plot is done. The number of
+% plots per page can be selected.
+% The plots can additionally be exported to a PDF document.
+%
+% Ignored records with MDV=1 are not considered in the plotting (only
+% relevant for NONMEM, since in MONOLIX output they are not present
+% anyway). Also CENS=1 values are not considered (for NONMEM).
+%
+% [SYNTAX]
+% [] = IQMfitanalysisIndividualFits(projectPath)
+% [] = IQMfitanalysisIndividualFits(projectPath,filename)
+% [] = IQMfitanalysisIndividualFits(projectPath,filename,outputNumber)
+% [] = IQMfitanalysisIndividualFits(projectPath,filename,outputNumber,options)
+%
+% [INPUT]
+% projectPath:  Path to a NONMEM or MONOLIX project folder. 
+% filename:     If a filename is provided, then the results are exported
+%               into a PDF document with this name (and path).
+% outputNumber: Number of the output in the model to consider for plotting
+%               If not specified, then output number 1 is assumed (or if
+%               only single output in model, then this is used)
+% options:      MATLAB structure with plotting options:
+%                   
+%                   options.logY:       =1: semilogy plot, =0, linear plot (default: 0)
+%                   options.Nrows:      Number of rows of plots per figure (default: 5)
+%                   options.Ncols:      Number of columns of plots per figure (default: 5)
+% 					options.sameaxes:   =1: plot on same Y-axes (default: 0)
+%
+% [OUTPUT]
+% Plots of individual fits, population fits and observations over time
+% and export to PDF if desired.
+ 
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle variable input arguments
+if nargin<2,
+    filename = '';
+end
+if nargin<3,
+    outputNumber = 1;
+end
+if nargin<4,
+    options = [];
+end
+
+% Handle options
+try logY         = options.logY;            catch, logY = 0;            end
+try sameaxes     = options.sameaxes;        catch, sameaxes = 0;        end
+try Nrows        = options.Nrows;           catch, Nrows = 5;           end
+try Ncols        = options.Ncols;           catch, Ncols = 5;           end
+    
+% Load the data to obtain the USUBJID for each ID
+projectInfo = parseNLMEprojectHeaderIQM(projectPath);
+oldpath = pwd(); cd(projectPath); dataCSV = IQMloadCSVdataset(projectInfo.DATA{1}); cd(oldpath);
+data_ID_USUBJID = unique(dataCSV(:,{'USUBJID','ID'}));
+% Combine ID and USUBJID for display
+data_ID_USUBJID.IDUSUBJID = cell(height(data_ID_USUBJID),1);
+for k=1:height(data_ID_USUBJID),
+    data_ID_USUBJID.IDUSUBJID{k} = sprintf('%d/%s',data_ID_USUBJID.ID(k),data_ID_USUBJID.USUBJID{k});
+end
+
+% Handle NONMEM/MONOLIX
+if isMONOLIXprojectIQM(projectPath),
+    predictions = parseMONOLIXpredictionsIQM(projectPath,outputNumber);
+    
+    % Join predictions with USUBJID information
+    predictions = join(predictions,data_ID_USUBJID);
+    
+    % Prepare the data
+    % Get observations
+    dataY               = table();
+    dataY.IDUSUBJID     = predictions.IDUSUBJID;
+    dataY.TIME          = predictions.time;
+    dataY.DV            = eval(['predictions.y' num2str(outputNumber)]);
+    dataY.group         = 3*ones(height(dataY),1);
+    % Get population prediction (popPred)
+    dataP               = table();
+    dataP.IDUSUBJID     = predictions.IDUSUBJID;
+    dataP.TIME          = predictions.time;
+    dataP.DV            = predictions.popPred;
+    dataP.group         = 1*ones(height(dataP),1);
+    % Get individual prediction (indPred_mode)
+    dataI               = table();
+    dataI.IDUSUBJID     = predictions.IDUSUBJID;
+    dataI.TIME          = predictions.time;
+    dataI.DV            = predictions.indPred_mode;
+    dataI.group         = 2*ones(height(dataI),1);
+    % Combine the data for plotting
+    data                = [dataY; dataP; dataI];
+
+    PRED                = 'popPred';
+    IPRED               = 'indPred_mode';
+    
+elseif isNONMEMprojectIQM(projectPath),
+    predictions         = parseNONMEMpredictionsIQM(projectPath,outputNumber);
+    
+    % Remove doses and MDV==1 observations
+    predictions(predictions.EVID==1,:) = [];
+    predictions(predictions.MDV==1,:) = [];
+    predictions(predictions.CENS==1,:) = [];
+
+    % Join predictions with USUBJID information
+    predictions = join(predictions,data_ID_USUBJID);
+    
+    % Prepare the data
+    % Get observations
+    dataY               = table();
+    dataY.IDUSUBJID     = predictions.IDUSUBJID;
+    dataY.TIME          = predictions.TIME2;
+    dataY.DV            = predictions.DV;
+    dataY.group         = 3*ones(height(dataY),1);
+    % Get population prediction (popPred)
+    dataP               = table();
+    dataP.IDUSUBJID     = predictions.IDUSUBJID;
+    dataP.TIME          = predictions.TIME2;
+    dataP.DV            = predictions.XPRED;
+    dataP.group         = 1*ones(height(dataP),1);
+    % Get individual prediction (indPred_mode)
+    dataI               = table();
+    dataI.IDUSUBJID     = predictions.IDUSUBJID;
+    dataI.TIME          = predictions.TIME2;
+    dataI.DV            = predictions.IPRED;
+    dataI.group         = 2*ones(height(dataI),1);
+    % Combine the data for plotting
+    data                = [dataY; dataP; dataI];
+    
+    % Get the right name for PRED
+    ph                  = parseNONMEMprojectHeaderIQM(projectPath);
+    PRED                = ph.RESIDUAL_NAMES_ORIG{strmatchIQM('XPRED',ph.RESIDUAL_NAMES_USED)};
+    IPRED               = 'IPRED';
+    
+else
+    error('Unknown project type.');
+end
+
+% Plot the data
+nameGroup                       = 'IDUSUBJID'; 
+nameX                           = 'TIME';
+nameY                           = 'DV';
+
+optionsPlot                     = [];
+optionsPlot.logY                = logY;
+optionsPlot.nrows               = Nrows;
+optionsPlot.ncols               = Ncols;
+optionsPlot.nameSubGroup        = 'group';
+optionsPlot.nameColorGroup      = 'group';
+optionsPlot.showmarkers         = 1;
+optionsPlot.markersize          = 10;
+optionsPlot.linecolorsCustom    = [1 0 0; 0 0 1;0 0 0];
+optionsPlot.linetypesCustom     = {'--','o-','x'};
+optionsPlot.linewidth           = 2;
+optionsPlot.sameaxes            = sameaxes;
+optionsPlot.xlabelText          = 'Time';
+optionsPlot.ylabelText          = sprintf('Output %d (x: OBS, --: %s, o-: =%s)', outputNumber,PRED,IPRED);
+optionsPlot.heighttitlebar      = 0.12;
+optionsPlot.showlegend          = 0;
+optionsPlot.ylabelfirstonly     = 1;
+optionsPlot.filename            = filename;
+
+IQMplottrellis(data,nameGroup,nameX,nameY,optionsPlot)
+
+
+
+
+
+
+
+    
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/07-NLMEfitAnalysis/IQMfitanalysisOutlierDetection.m b/IQMtools V1.2.2.2/IQMpro/tools/07-NLMEfitAnalysis/IQMfitanalysisOutlierDetection.m
new file mode 100644
index 0000000000000000000000000000000000000000..8b085fb1272efeab26c46ae9dde70678345e2fcd
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/07-NLMEfitAnalysis/IQMfitanalysisOutlierDetection.m	
@@ -0,0 +1,116 @@
+function [] = IQMfitanalysisOutlierDetection(projectPath,filename,outputNumber,options)
+% This function considers PWRES and searches for outliers and displays info
+% about them.
+%
+% Ignored records with MDV=1 are not considered in the plotting (only
+% relevant for NONMEM, since in MONOLIX output they are not present
+% anyway). Also CENS=1 values are not considered (for NONMEM).
+%
+% [SYNTAX]
+% [] = IQMfitanalysisOutlierDetection(projectPath)
+% [] = IQMfitanalysisOutlierDetection(projectPath,filename)
+% [] = IQMfitanalysisOutlierDetection(projectPath,filename,outputNumber)
+% [] = IQMfitanalysisOutlierDetection(projectPath,filename,outputNumber,options)
+%
+% [INPUT]
+% projectPath:  Path to a NONMEM or MONOLIX project folder. 
+% filename:     If a filename is provided, then the results are exported
+%               into a PDF document with this name (and path).
+% outputNumber: Number of the output in the model to consider for plotting
+%               If not specified, then output number 1 is assumed (or if
+%               only single output in model, then this is used)
+% options:      MATLAB structure with plotting optins:
+%                   
+%                   options.PWRESthresholdOutlier: Threshold for |PWRES| (default value: 5)
+%                                       above which an observation will be considered an outlier
+%
+% [OUTPUT]
+% Text output in command window and if desired in a text file
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle variable input arguments
+if nargin<2,
+    filename = '';
+end
+if nargin<3,
+    outputNumber = 1;
+end
+if nargin<4,
+    options = [];
+end
+
+% Handle options
+try PWRESthresholdOutlier   = options.PWRESthresholdOutlier;        catch, PWRESthresholdOutlier = 5;       end
+
+% Handle NONMEM/MONOLIX
+if isMONOLIXprojectIQM(projectPath),
+    predictions = parseMONOLIXpredictionsIQM(projectPath,outputNumber);
+    
+    % Get ID and PWRES and |PWRES|
+    X           = table();
+    X.ID        = predictions.ID;
+    X.TIME      = predictions.time;
+    X.DV        = eval(['predictions.y' num2str(outputNumber)]);
+    X.PWRES     = predictions.meanWRes;
+    X.absPWRES  = abs(predictions.meanWRes);
+  
+    PWRES   = 'meanWRes';
+    TIME    = 'TIME';
+
+elseif isNONMEMprojectIQM(projectPath),
+    predictions = parseNONMEMpredictionsIQM(projectPath,outputNumber);
+    
+    % Remove doses and MDV==1 observations
+    predictions(predictions.EVID==1,:) = [];
+    predictions(predictions.MDV==1,:) = [];
+    predictions(predictions.CENS==1,:) = [];
+
+    % Get the right name for PRED
+    ph    = parseNONMEMprojectHeaderIQM(projectPath);
+    PWRES = ph.RESIDUAL_NAMES_ORIG{strmatchIQM('XWRES',ph.RESIDUAL_NAMES_USED)};
+    TIME  = 'TIME2';
+    
+    % Get ID and PWRES and |PWRES|
+    X           = table();
+    X.ID        = predictions.ID;
+    X.TIME      = predictions.TIME2;
+    X.DV        = predictions.DV;
+    X.PWRES     = predictions.XWRES;
+    X.absPWRES  = abs(predictions.XWRES);
+       
+else
+    error('Unknown project type.');
+end
+
+% Sort after |PWRES|
+Y = sortrows(X,'absPWRES','descend');
+
+% Remove the ones below threshold for |PWRES|
+Z = Y(Y.absPWRES>PWRESthresholdOutlier,:);
+
+% Create report
+textReport = '';
+textReport = sprintf('%s----------------------------------------------------------------------\n',textReport);
+textReport = sprintf('%sOutlier Detection |%s|>%g\n',textReport,PWRES,PWRESthresholdOutlier);
+textReport = sprintf('%s----------------------------------------------------------------------\n',textReport);
+if isempty(Z),
+    textReport = sprintf('%sNo outliers have been detected.\n\n',textReport);
+else
+    W = sortrows(Z,{'ID','TIME'});
+    allID = unique(W.ID);
+    for k=1:length(allID),
+        Wk = W(W.ID==allID(k),:);
+        textReport = sprintf('%s\n\tOutliers in ID: %d',textReport,allID(k));
+        textReport = sprintf('%s\n\t--------------------------------------\n',textReport);
+        textReport = sprintf('%s\t      %s          DV       %s\n',textReport,TIME,PWRES);
+        
+        for k2=1:height(Wk),
+            textReport = sprintf('%s\t%10.10g  %10.10g  %10.3g\n',textReport,Wk.TIME(k2),Wk.DV(k2),Wk.PWRES(k2));
+        end
+    end
+end
+disp(textReport);
+
+% Export file if filename given
+IQMwriteText2File(textReport,[strrep(filename,'.txt','') '.txt']);
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/07-NLMEfitAnalysis/IQMfitanalysisOutputPlots.m b/IQMtools V1.2.2.2/IQMpro/tools/07-NLMEfitAnalysis/IQMfitanalysisOutputPlots.m
new file mode 100644
index 0000000000000000000000000000000000000000..509b75fe43626f0e7285712ab6c39876f2712a78
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/07-NLMEfitAnalysis/IQMfitanalysisOutputPlots.m	
@@ -0,0 +1,85 @@
+function [] = IQMfitanalysisOutputPlots(projectPath,options,basefilename)
+% This function is a wrapper for different fit analysis functions that plot
+% things that are dependent of a specific output of the model:
+% - IQMfitanalysisIndividualFits
+% - IQMfitanalysisGOFplots
+% - IQMfitanalysisOutlierDetection
+%
+% Ignored records with MDV=1 are not considered in the plotting (only
+% relevant for NONMEM, since in MONOLIX output they are not present
+% anyway). Also CENS=1 values are not considered (for NONMEM).
+%
+% This function is applicable for models with any number of outputs and
+% will generate plots for all these outputs.
+% 
+% [SYNTAX]
+% [] = IQMfitanalysisOutputPlots(projectPath)
+% [] = IQMfitanalysisOutputPlots(projectPath,options)
+% [] = IQMfitanalysisOutputPlots(projectPath,options,basefilename)
+%
+% [INPUT]
+% projectPath:  Path to a NONMEM or MONOLIX project folder. 
+% basefilename: Path and base part of the filenames where
+%               outputs are exported to. 
+%               Default: 'RESULTS/GOF_OUTPUT_<number>_<name>/' in the
+%               selected project. 
+% options:      MATLAB structure with plotting options:
+%
+%                   options.labels: =1: adds ID labels next to each value in some plots (default)
+%                                   =0: does not add labels 
+%
+% [OUTPUT]
+% PDF files at specified location (basefilename)
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle variable input arguments
+if nargin<2,
+    options = [];
+end
+if nargin<3,
+    basefilename = [projectPath '/RESULTS'];
+end
+
+% Handle options
+try labels = options.labels; catch, labels = 1; end
+
+% Get output information
+PROJECTINFO     = parseNLMEprojectHeaderIQM(projectPath);
+outputNumberALL = [1:length(PROJECTINFO.OUTPUTS)];
+outputNamesALL  = PROJECTINFO.OUTPUTS;
+
+% Output specific GOF plots
+for k=1:length(outputNumberALL),
+    % Define location where to store the output specific results
+    basefilenameOutput = sprintf([basefilename '/GOF_OUTPUT_%d_%s/'],outputNumberALL(k),outputNamesALL{k});
+        
+    % Run IQMfitanalysisIndividualFits - linear
+    options = [];
+    options.logY = 0;
+    options.Nrows = 5;
+    options.Ncols = 5;
+    IQMfitanalysisIndividualFits(projectPath,[basefilenameOutput '01_Individual_Fits_LinearY'],outputNumberALL(k),options)
+    
+    % Run IQMfitanalysisIndividualFits - log
+    try
+        options = [];
+        options.logY = 1;
+        options.Nrows = 5;
+        options.Ncols = 5;
+        IQMfitanalysisIndividualFits(projectPath,[basefilenameOutput '02_Individual_Fits_LogY'],outputNumberALL(k),options)
+    catch
+        disp('If your data is already log transformed an additional log transform for plotting might lead to an error due to negative values.');
+    end
+        
+    % Run IQMfitanalysisGOFplots
+    options = [];
+    options.labels = labels;
+    IQMfitanalysisGOFplots(projectPath,[basefilenameOutput '03_GOF_Plots'],outputNumberALL(k),options)
+    
+    % Run IQMfitanalysisOutlierDetection
+    options = [];
+    IQMfitanalysisOutlierDetection(projectPath,[basefilenameOutput '04_OutlierDetection.txt'],outputNumberALL(k),options)
+end
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/07-NLMEfitAnalysis/IQMfitanalysisRandomEffects.m b/IQMtools V1.2.2.2/IQMpro/tools/07-NLMEfitAnalysis/IQMfitanalysisRandomEffects.m
new file mode 100644
index 0000000000000000000000000000000000000000..cbefba229e294838c5dbebdd1892144e8d343a00
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/07-NLMEfitAnalysis/IQMfitanalysisRandomEffects.m	
@@ -0,0 +1,129 @@
+function [] = IQMfitanalysisRandomEffects(projectPath,filename,options)
+% This function plots information about the random effects in different
+% ways. Whiskers on the boxplots indicate the 5th and 95th percentile of
+% the plotted data. 
+%
+% [SYNTAX]
+% [] = IQMfitanalysisRandomEffects(projectPath)
+% [] = IQMfitanalysisRandomEffects(projectPath,filename)
+% [] = IQMfitanalysisRandomEffects(projectPath,filename,options)
+%
+% [INPUT]
+% projectPath:  Path to a NONMEM or MONOLIX project folder. 
+% filename:     If a filename is provided, then the results are exported
+%               into a PDF document with this name (and path).
+% options:      MATLAB structure with plotting optins:
+%                   
+%                   options.labels: =1: adds ID labels next to each value (default)
+%                                   =0: does not add labels 
+%                   options.corrcoeffThreshold: number between 0 and 1. If
+%                          correlation above this value, then data plotted in red.
+%                          (default: 0.3)
+%
+% [OUTPUT]
+% Plots of ETAs and correlations - and export to PDF if desired.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle variable input arguments
+if nargin<2,
+    filename = '';
+end
+if nargin<3,
+    options = [];
+end
+
+% Handle options
+try corrcoeffThreshold = options.corrcoeffThreshold; catch, corrcoeffThreshold = 0.3; end
+try withlabels = options.labels; catch, withlabels = 1; end
+    
+% Start PDF output if desired
+IQMstartNewPrintFigure(filename);
+
+% Handle NONMEM/MONOLIX
+if isMONOLIXprojectIQM(projectPath),
+    [ dataeta, OMEGA, OMEGAnames ] = parseMONOLIXetasIQM( projectPath );
+elseif isNONMEMprojectIQM(projectPath),
+    [ dataeta, OMEGA, OMEGAnames ] = parseNONMEMetasIQM( projectPath );
+else
+    error('Unknown project type.');
+end
+
+% Determine shrinkage in percent
+eta_shrinkage_percent = 100*(1-std(table2array(dataeta))./OMEGA);
+
+% Remove the NaNs
+ix = find(~isnan(eta_shrinkage_percent));
+OMEGA_est                   = OMEGA(ix);
+OMEGAnames_est              = OMEGAnames(ix);
+dataeta_est                 = dataeta(:,ix);
+eta_shrinkage_percent_est   = eta_shrinkage_percent(ix);
+
+% Plot the etas and the shrinkage
+figure;
+Netas = length(OMEGAnames_est);
+Nrows = ceil(sqrt(Netas));
+Ncols = ceil(Netas/Nrows);
+for k2=1:Netas,
+    subplot(Nrows,Ncols,k2);
+    % Plot histogram
+    [N,X] = hist(table2array(dataeta_est(:,k2)));
+    bar(X,N/max(N),'FaceColor',0.5*[1 1 1]); hold on
+    % Adjust X-axis to some reasonable setting
+    axis([-5*OMEGA_est(k2) 5*OMEGA_est(k2) get(gca,'YLim')]);
+    % Plot gaussian with estimated population std
+    XLim = get(gca,'XLim');
+    x = linspace(XLim(1),XLim(2),100);
+    y = normpdfIQM(x,0,OMEGA_est(k2));
+    plot(x,y./max(y),'Color',[0.7 0 0],'LineWidth',2);
+    % Axes
+    title(sprintf('eta%s',OMEGAnames_est{k2}),'FontSize',14,'Interpreter','none')
+    set(gca,'FontSize',12);
+    if k2==1,
+        legend('Individual ETAs','Population distribution');
+    end
+    % Print the shrinkage
+    text(XLim(1)+(XLim(2)-XLim(1))*0.05,0.75,sprintf('Shrinkage: %1.2g%%',eta_shrinkage_percent_est(k2)),'FontSize',12,'FontWeight','bold');
+end
+set(gcf,'Color',[1 1 1]);
+IQMprintFigure(gcf,filename);
+if ~isempty(filename),
+    close(gcf);
+end
+
+% Boxplot for random effects - Use 5th and 95th percentile for plotting the whiskers on the boxplot
+figure
+optionsBoxplot                      = [];
+optionsBoxplot.verticalFlag         = 1;
+optionsBoxplot.outliers             = 0;
+optionsBoxplot.whiskerPercentiles   = [5 95];
+optionsBoxplot.samplenames          = strcat('eta',OMEGAnames_est);
+boxplotIQM(table2array(dataeta_est),optionsBoxplot);
+
+set(gcf,'Color',[1 1 1]);
+plot(get(gca,'XLim'),[0 0],'k-');
+title('Random Effects - Boxplot','FontSize',12,'Interpreter','none');
+grid on;
+IQMprintFigure(gcf,filename);
+if ~isempty(filename),
+    close(gcf);
+end
+
+% Joint distribution of random effects
+figure
+options = [];
+options.names = {};
+for k=1:length(OMEGAnames_est),
+    options.names{k} = ['eta' OMEGAnames_est{k}];
+end
+options.CorrThres = corrcoeffThreshold;
+IQMplotpairwiseCorr(dataeta_est,options)
+set(gcf,'Color',[1 1 1]);
+IQMprintFigure(gcf,filename);
+if ~isempty(filename),
+    close(gcf);
+end
+
+% PS2PDF
+IQMconvert2pdf(filename);
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/07-NLMEfitAnalysis/IQMfitanalysisShrinkage.m b/IQMtools V1.2.2.2/IQMpro/tools/07-NLMEfitAnalysis/IQMfitanalysisShrinkage.m
new file mode 100644
index 0000000000000000000000000000000000000000..0833667f450409d2295e326efe11508e51c83259
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/07-NLMEfitAnalysis/IQMfitanalysisShrinkage.m	
@@ -0,0 +1,31 @@
+function [OMEGAnames,eta_shrinkage_percent] = IQMfitanalysisShrinkage(projectPath)
+% This function determines the ETA shrinkage for the random effects
+% ETA Shrinkage is defined as:
+%
+% eta_shrinkage_percent = 100*(1-std(eta))/OMEGA;
+%
+% [SYNTAX]
+% [OMEGAnames,eta_shrinkage_percent] = IQMfitanalysisShrinkage(projectPath)
+%
+% [INPUT]
+% projectPath:  Path to a NONMEM or MONOLIX project folder. 
+%
+% [OUTPUT]
+% OMEGAnames:               Cell-array with names of all fixed effect parameters
+% eta_shrinkage_percent:    Vector with shrinkage values. NaN if parameter
+%                           was not having a random effect.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle NONMEM/MONOLIX
+if isMONOLIXprojectIQM(projectPath),
+    [ dataeta, OMEGA, OMEGAnames ] = parseMONOLIXetasIQM( projectPath );
+elseif isNONMEMprojectIQM(projectPath),
+    [ dataeta, OMEGA, OMEGAnames ] = parseNONMEMetasIQM( projectPath );
+else
+    error('Unknown project type.');
+end
+
+% Determine shrinkage in percent
+eta_shrinkage_percent = 100*(1-std(table2array(dataeta))./OMEGA);
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/08-NLMEfitSummary/IQMfitsummaryAll.m b/IQMtools V1.2.2.2/IQMpro/tools/08-NLMEfitSummary/IQMfitsummaryAll.m
new file mode 100644
index 0000000000000000000000000000000000000000..65e2706dc2f7b8a263258235619b455443b91bb5
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/08-NLMEfitSummary/IQMfitsummaryAll.m	
@@ -0,0 +1,56 @@
+function [] = IQMfitsummaryAll(pathProjects,pathOutput,order)
+% This function reads the fit result information of all the NONMEM or
+% MONOLIX fits in the specified folder. Each fit needs to be in an own
+% folder, following the standard that IQM tools use. It generates several
+% table, allowing to compare the parameter estimates, the covariate
+% estimates, the covariance estimates and some selected model metrics.
+% It is a wrapper function for:
+%   IQMfitsummaryMetrics
+%   IQMfitsummaryParameters
+%   IQMfitsummaryCovariances
+%   IQMfitsummaryCovariates
+%
+% [SYNTAX]
+% [] = IQMfitsummaryAll(pathProjects)
+% [] = IQMfitsummaryAll(pathProjects,pathOutput)
+% [] = IQMfitsummaryAll(pathProjects,pathOutput,order)
+%
+% [INPUT]
+% pathProjects:     Path to a folder with MONOLIX or NONMEM project folders
+%                   to generate the result tables for.
+% pathOutput:       Path to where to store the output files. Filenames used
+%                   as in the individual functions.
+% order:            'AIC', 'BIC', or 'OBJ'. The results are then
+%                   ordered according to these values. (default: as defined
+%                   in SETUP_PATHS_TOOLS_IQMPRO)
+%
+% [OUTPUT]
+% tableCell: cell table with information for reporting.
+% If desired, results exported to file.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle variable input arguments
+if nargin<2,
+    pathOutput = pathProjects;
+end
+if nargin<3,
+    SETUP_PATHS_TOOLS_IQMPRO
+    order = NLME_ORDER_CRITERION;
+end
+
+% Handle optional arguments
+if ~ismember(upper(order),{'AIC','BIC','OBJ',''}),
+    error('Ordering selector "%s" not recognized.',order);
+end
+if isempty(pathOutput),
+    pathOutput = pathProjects;
+end   
+
+% Run the functions
+IQMfitsummaryMetrics(pathProjects,[pathProjects '/model_metrics.txt'],order);
+IQMfitsummaryParameters(pathProjects,[pathProjects '/model_parameters.txt'],order);
+IQMfitsummaryCovariances(pathProjects,[pathProjects '/model_covariances.txt'],order);
+IQMfitsummaryCovariates(pathProjects,[pathProjects '/model_covariates.txt'],order);
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/08-NLMEfitSummary/IQMfitsummaryCovariances.m b/IQMtools V1.2.2.2/IQMpro/tools/08-NLMEfitSummary/IQMfitsummaryCovariances.m
new file mode 100644
index 0000000000000000000000000000000000000000..b5307f5d8e5dab3e51428541b43c141a39f8a8c9
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/08-NLMEfitSummary/IQMfitsummaryCovariances.m	
@@ -0,0 +1,126 @@
+function [] = IQMfitsummaryCovariances(pathProjects,filename,order)
+% This function reads the fit result information of all the NONMEM or
+% MONOLIX fits in the specified folder. Each fit needs to be in an own
+% folder, following the standard that IQM tools use. It generates a table
+% comparing parameter estimates for the correlations of the random effects.
+%
+% [SYNTAX]
+% [] = IQMfitsummaryCovariances(pathProjects)
+% [] = IQMfitsummaryCovariances(pathProjects,filename)
+% [] = IQMfitsummaryCovariances(pathProjects,filename,order)
+%
+% [INPUT]
+% pathProjects:     Path to a folder with MONOLIX or NONMEM project folders
+%                   to generate the result tables for.
+% filename:         Path and filename where to generate the output file.
+%                   default: pathProjects/model_covariances.txt
+% order:            'AIC', 'BIC', or 'OBJ'. The results are then
+%                   ordered according to these values. (default: as defined
+%                   in SETUP_PATHS_TOOLS_IQMPRO)
+%
+% [OUTPUT]
+% tableCell: cell table with information for reporting.
+% If desired, results exported to file.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle variable input arguments
+if nargin<2,
+    filename = [pathProjects '/model_covariances.txt'];
+end
+if nargin<3,
+    SETUP_PATHS_TOOLS_IQMPRO
+    order = NLME_ORDER_CRITERION;
+end
+
+% Handle optional arguments
+if ~ismember(upper(order),{'AIC','BIC','OBJ',''}),
+    error('Ordering selector "%s" not recognized.',order);
+end
+if isempty(filename),
+    filename = [pathProjects '/model_covariances.txt'];
+end    
+
+% Load project results
+RESULTS = parseProjectFolderResultsIQM(pathProjects,order);
+
+% If order empty then set OBJ just for display purposes, not ordering
+if isempty(order),
+    order = 'OBJ';
+end
+
+% Create cell-array with ordering name as first
+X = [{upper(order)} setdiff({'AIC','BIC','OBJ'},upper(order))];
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Process the RESULT information somewhat
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Determine all available random effect parameters in the models that also
+% have been estimated in at least one model
+ALLrandomEffectNames = {};
+for k=1:length(RESULTS),
+    if ~isempty(RESULTS(k).rawParameterInfo),
+        fek = RESULTS(k).rawParameterInfo.randomEffects.names(find(RESULTS(k).rawParameterInfo.randomEffects.estimated));
+        ALLrandomEffectNames = [ALLrandomEffectNames fek];
+    end
+end
+% strip the omega()
+ALLrandomEffectNames = unique(strrep(strrep(ALLrandomEffectNames,'omega(',''),')',''));
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Display covariance/correlation matrices
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+tableCell = cell(1,length(ALLrandomEffectNames)+3);
+tableCell{1,1} = '<TT>';
+tableCell{1,2} = 'Estimated random effect covariance matrices';
+for k=1:length(RESULTS),
+    if ~isempty(RESULTS(k).rawParameterInfo),
+        offset = size(tableCell,1);
+        tableCell{offset+1,1}  = '<TH>';
+        tableCell{offset+1,2}    = RESULTS(k).model;
+        tableCell(offset+1,4:end) = ALLrandomEffectNames;
+        % Initialize correlation cell matrix 
+        corrcell   = cell(length(ALLrandomEffectNames));
+        corrcell(1:end) = {'-'};
+        % Get correlation matrix for model and reorder into corrcell
+        % according to names
+        corrmatrix_model = RESULTS(k).correlationmatrixRandomEffects;
+        corrcell_model   = cell(size(corrmatrix_model));
+        for row=1:size(corrmatrix_model,1),
+            for col=1:size(corrmatrix_model,2),
+                corrcell_model(row,col) = {corrmatrix_model(row,col)};
+            end
+        end
+        % Get indices of estimate random effects
+        ix_estimated = find(RESULTS(k).rawParameterInfo.randomEffects.estimated);
+        % Get names of the estimated random effects
+        corrnames_model  = strrep(strrep(RESULTS(k).rawParameterInfo.randomEffects.names(ix_estimated),'omega(',''),')','');
+        % Reduce the corrcell_model matrix to estimated names only
+        corrcell_model = corrcell_model(ix_estimated,ix_estimated);
+        ix = [];
+        for k2=1:length(corrnames_model),
+            ix(end+1) = strmatchIQM(corrnames_model{k2},ALLrandomEffectNames,'exact');
+        end
+        corrcell(ix,ix) = corrcell_model;
+        % Add model correlations to corrcell
+        tableCell(offset+2:offset+size(corrcell,1)+1,4:end) = corrcell;
+        tableCell(offset+2:offset+size(corrcell,1)+1,1) = {'<TR>'};
+        if k<length(RESULTS),
+            tableCell(offset+size(corrcell,1)+2,1) = {'<HR>'};
+            tableCell{offset+2,2}         = sprintf('%s: %d',order,round(RESULTS(k).(order)));
+            tableCell(offset+2:end-1,3)   = ALLrandomEffectNames';
+        else
+            tableCell{offset+2,2}         = sprintf('%s: %d',order,round(RESULTS(k).(order)));
+            tableCell(offset+2:end,3)   = ALLrandomEffectNames';
+        end
+    end
+end
+
+% Convert to text and display text
+textDisplay = IQMconvertCellTable2ReportTable(tableCell,'text');     
+disp(textDisplay);
+
+% Convert to report text and export to file if filename defined
+text = IQMconvertCellTable2ReportTable(tableCell,'report');     
+IQMwriteText2File(text,[strrep(filename,'.txt','') '.txt']);
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/08-NLMEfitSummary/IQMfitsummaryCovariates.m b/IQMtools V1.2.2.2/IQMpro/tools/08-NLMEfitSummary/IQMfitsummaryCovariates.m
new file mode 100644
index 0000000000000000000000000000000000000000..2e5628c8e8b73f17d125ab9467822afb12f3287a
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/08-NLMEfitSummary/IQMfitsummaryCovariates.m	
@@ -0,0 +1,103 @@
+function [] = IQMfitsummaryCovariates(pathProjects,filename,order)
+% This function reads the fit result information of all the NONMEM or
+% MONOLIX fits in the specified folder. Each fit needs to be in an own
+% folder, following the standard that IQM tools use. It generates a table
+% comparing parameter estimates for the covariate coefficients.
+%
+% [SYNTAX]
+% [] = IQMfitsummaryCovariates(pathProjects)
+% [] = IQMfitsummaryCovariates(pathProjects,filename)
+% [] = IQMfitsummaryCovariates(pathProjects,filename,order)
+%
+% [INPUT]
+% pathProjects:     Path to a folder with MONOLIX or NONMEM project folders
+%                   to generate the result tables for.
+% filename:         Path and filename where to generate the output file.
+%                   default: pathProjects/model_covariates.txt
+% order:            'AIC', 'BIC', or 'OBJ'. The results are then
+%                   ordered according to these values. (default: as defined
+%                   in SETUP_PATHS_TOOLS_IQMPRO)
+%
+% [OUTPUT]
+% tableCell: cell table with information for reporting.
+% If desired, results exported to file.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle variable input arguments
+if nargin<2,
+    filename = [pathProjects '/model_covariates.txt'];
+end
+if nargin<3,
+    SETUP_PATHS_TOOLS_IQMPRO
+    order = NLME_ORDER_CRITERION;
+end
+
+% Handle optional arguments
+if ~ismember(upper(order),{'AIC','BIC','OBJ',''}),
+    error('Ordering selector "%s" not recognized.',order);
+end
+if isempty(filename),
+    filename = [pathProjects '/model_covariates.txt'];
+end    
+
+% Load project results
+RESULTS = parseProjectFolderResultsIQM(pathProjects,order);
+
+% If order empty then set OBJ just for display purposes, not ordering
+if isempty(order),
+    order = 'OBJ';
+end
+
+% Create cell-array with ordering name as first
+X = [{upper(order)} setdiff({'AIC','BIC','OBJ'},upper(order))];
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Display covariate information
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+tableCell = cell(1,5);
+tableCell{1,1} = '<TT>';
+tableCell{1,2} = 'Estimated covariate coefficients';
+for k=1:length(RESULTS),
+    offset = size(tableCell,1);
+    tableCell(offset+1,:) = {'<TH>' RESULTS(k).model 'Name' 'Value' '95% CI'};
+    if ~isempty(RESULTS(k).rawParameterInfo),
+        if ~isempty(RESULTS(k).rawParameterInfo.covariate.names),
+            info = RESULTS(k).rawParameterInfo.covariate;
+            for k2=1:length(info.names),
+                covName   = info.names{k2};
+                covValue  = info.values(k2);
+                covSTDERR = info.stderr(k2);
+                alpha = 0.05;
+                nFoldStdDev = norminvIQM(1-alpha/2,0,1);
+                covValueDn  = round(1000*(covValue-nFoldStdDev*covSTDERR))/1000;
+                covValueUp  = round(1000*(covValue+nFoldStdDev*covSTDERR))/1000;
+                if covValueDn*covValueUp > 0,
+                    signResult = 'X';
+                else
+                    signResult = '';
+                end
+                tableCell(offset+1+k2,:) = {'<TR>' '' covName sprintf('%6.3g',info.values(k2)) sprintf('[%8.3g,%8.3g] %s',covValueDn,covValueUp,signResult)};
+            end
+            if k<length(RESULTS),
+                tableCell(offset+1+k2+1,1) = {'<HR>'};
+            end
+            tableCell{offset+2,2}         = sprintf('%s: %d',order,round(RESULTS(k).(order)));
+        else
+            tableCell{end+1,1}         = '<TR>';
+            tableCell{end,2}         = sprintf('%s: %d',order,round(RESULTS(k).(order)));
+            if k<length(RESULTS),
+                tableCell(end+1,1) = {'<HR>'};
+            end
+        end            
+    end
+end
+
+% Convert to text and display text
+textDisplay = IQMconvertCellTable2ReportTable(tableCell,'text');     
+disp(textDisplay);
+
+% Convert to report text and export to file if filename defined
+text = IQMconvertCellTable2ReportTable(tableCell,'report');     
+IQMwriteText2File(text,[strrep(filename,'.txt','') '.txt']);
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/08-NLMEfitSummary/IQMfitsummaryMetrics.m b/IQMtools V1.2.2.2/IQMpro/tools/08-NLMEfitSummary/IQMfitsummaryMetrics.m
new file mode 100644
index 0000000000000000000000000000000000000000..567b46234fe64880a0cd41f62578d8ed1c299c70
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/08-NLMEfitSummary/IQMfitsummaryMetrics.m	
@@ -0,0 +1,107 @@
+function [] = IQMfitsummaryMetrics(pathProjects,filename,order)
+% This function reads the fit result information of all the NONMEM or
+% MONOLIX fits in the specified folder. Each fit needs to be in an own
+% folder, following the standard that IQM tools use. It generates a table
+% comparing different metrics for the model with each other.
+%
+% [SYNTAX]
+% [] = IQMfitsummaryMetrics(pathProjects)
+% [] = IQMfitsummaryMetrics(pathProjects,filename)
+% [] = IQMfitsummaryMetrics(pathProjects,filename,order)
+%
+% [INPUT]
+% pathProjects:     Path to a folder with MONOLIX or NONMEM project folders
+%                   to generate the result tables for.
+% filename:         Path and filename where to generate the output file.
+%                   default: pathProjects/model_metrics.txt
+% order:            'AIC', 'BIC', or 'OBJ'. The results are then
+%                   ordered according to these values. (default: as defined
+%                   in SETUP_PATHS_TOOLS_IQMPRO)
+%
+% [OUTPUT]
+% If desired, results exported to file.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle variable input arguments
+if nargin<2,
+    filename = [pathProjects '/model_metrics.txt'];
+end
+if nargin<3,
+    SETUP_PATHS_TOOLS_IQMPRO
+    order = NLME_ORDER_CRITERION;
+end
+
+% Handle optional arguments
+if ~ismember(upper(order),{'AIC','BIC','OBJ',''}),
+    error('Ordering selector "%s" not recognized.',order);
+end
+if isempty(filename),
+    filename = [pathProjects '/model_metrics.txt'];
+end    
+
+% Load project results
+RESULTS = parseProjectFolderResultsIQM(pathProjects,order);
+
+% If order empty then set OBJ just for display purposes, not ordering
+if isempty(order),
+    order = 'OBJ';
+end
+
+% Create cell-array with ordering name as first
+X = [{upper(order)} setdiff({'AIC','BIC','OBJ'},upper(order))];
+
+% Generate metrics table
+metricsTableCell = {'<TT>' 'Selected metrics for model assessment:' '' '' '' '' '' '' '' '' ''};
+metricsTableCell(end+1,:) = {'<TH>' 'MODEL' ['round(' X{1} ')'] ['round(' X{2} ')'] ['round(' X{3} ')'] 'NaN_RSE' 'maxRSE(fixedE)' 'maxRSE(randE)' 'max(randE)' 'maxRSE(corr)' 'max(|corr|)'};
+for k=1:length(RESULTS),
+    if ~isempty(RESULTS(k).rawParameterInfo),
+        maxfixedrse    = max(round(RESULTS(k).rawParameterInfo.fixedEffects.rse));
+        maxomegarse    = max(round(RESULTS(k).rawParameterInfo.randomEffects.rse));
+        maxomegaparval = max(RESULTS(k).rawParameterInfo.randomEffects.values);
+        maxcorrrse     = max(round(RESULTS(k).rawParameterInfo.correlation.rse));
+        maxcorrparval  = max(abs(RESULTS(k).rawParameterInfo.correlation.values));
+    else
+        maxfixedrse    = NaN;
+        maxomegarse    = NaN;
+        maxomegaparval = NaN;
+        maxcorrrse     = NaN;
+        maxcorrparval  = NaN;
+    end
+    zz = RESULTS(k).rawParameterInfo;
+    if ~isempty(zz),
+        NaN_RSE = sum(isnan([zz.fixedEffects.rse zz.randomEffects.rse zz.errorParameter.rse zz.covariate.rse zz.correlation.rse]).*...
+            [zz.fixedEffects.estimated zz.randomEffects.estimated zz.errorParameter.estimated zz.covariate.estimated zz.correlation.estimated]);
+    else
+        NaN_RSE = NaN;
+    end
+    if isempty(maxcorrrse),
+        maxcorrrse     = '-';
+        maxcorrparval  = '-';
+    else
+        maxcorrrse     = round(maxcorrrse);
+        maxcorrparval  = round(maxcorrparval*1000)/1000;
+    end
+    
+    metricsTableCell{k+2,1} = '<TR>';
+    metricsTableCell{k+2,2} = RESULTS(k).model;
+    metricsTableCell{k+2,3} = round(RESULTS(k).(X{1}));
+    metricsTableCell{k+2,4} = round(RESULTS(k).(X{2}));
+    metricsTableCell{k+2,5} = round(RESULTS(k).(X{3}));
+    metricsTableCell{k+2,6} = NaN_RSE;
+    metricsTableCell{k+2,7} = round(maxfixedrse);
+    metricsTableCell{k+2,8} = round(maxomegarse);
+    metricsTableCell{k+2,9} = round(maxomegaparval*1000)/1000;
+    metricsTableCell{k+2,10} = maxcorrrse;
+    metricsTableCell{k+2,11} = maxcorrparval;
+end
+metricsTableCell{end+1,1} = '<TF>';
+metricsTableCell{end,2} = sprintf('Models ordered by %s.',upper(order));
+
+% Convert to text and display text
+textDisplay = IQMconvertCellTable2ReportTable(metricsTableCell,'text');     
+disp(textDisplay);
+
+% Convert to report text and export to file if filename defined
+text = IQMconvertCellTable2ReportTable(metricsTableCell,'report');     
+IQMwriteText2File(text,[strrep(filename,'.txt','') '.txt']);
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/08-NLMEfitSummary/IQMfitsummaryParameters.m b/IQMtools V1.2.2.2/IQMpro/tools/08-NLMEfitSummary/IQMfitsummaryParameters.m
new file mode 100644
index 0000000000000000000000000000000000000000..62309a0e0793f73087eac56ef51a05803665be13
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/08-NLMEfitSummary/IQMfitsummaryParameters.m	
@@ -0,0 +1,281 @@
+function [] = IQMfitsummaryParameters(pathProjects,filename,order)
+% This function reads the fit result information of all the NONMEM or
+% MONOLIX fits in the specified folder. Each fit needs to be in an own
+% folder, following the standard that IQM tools use. It generates a table
+% comparing parameter estimates for the model with each other.
+%
+% [SYNTAX]
+% [] = IQMfitsummaryParameters(pathProjects)
+% [] = IQMfitsummaryParameters(pathProjects,filename)
+% [] = IQMfitsummaryParameters(pathProjects,filename,order)
+%
+% [INPUT]
+% pathProjects:     Path to a folder with MONOLIX or NONMEM project folders
+%                   to generate the result tables for.
+% filename:         Path and filename where to generate the output file.
+%                   default: pathProjects/model_parameters.txt
+% order:            'AIC', 'BIC', or 'OBJ'. The results are then
+%                   ordered according to these values. (default: as defined
+%                   in SETUP_PATHS_TOOLS_IQMPRO)
+%
+% [OUTPUT]
+% parametersTableCell: cell table with information for reporting.
+% If desired, results exported to file.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle variable input arguments
+if nargin<2,
+    filename = [pathProjects '/model_parameters.txt'];
+end
+if nargin<3,
+    SETUP_PATHS_TOOLS_IQMPRO
+    order = NLME_ORDER_CRITERION;
+end
+
+% Handle optional arguments
+if ~ismember(upper(order),{'AIC','BIC','OBJ',''}),
+    error('Ordering selector "%s" not recognized.',order);
+end
+if isempty(filename),
+    filename = [pathProjects '/model_parameters.txt'];
+end    
+
+% Load project results
+RESULTS = parseProjectFolderResultsIQM(pathProjects,order);
+
+% If order empty then set OBJ just for display purposes, not ordering
+if isempty(order),
+    order = 'OBJ';
+end
+
+% Create cell-array with ordering name as first
+X = [{upper(order)} setdiff({'AIC','BIC','OBJ'},upper(order))];
+  
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Process the RESULT information somewhat
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Determine all available fixed effect parameters in the models
+ALLfixEffectNames = {};
+for k=1:length(RESULTS),
+    if ~isempty(RESULTS(k).rawParameterInfo),
+        fek = RESULTS(k).rawParameterInfo.fixedEffects.names;
+        ALLfixEffectNames = [ALLfixEffectNames fek];
+    end
+end
+ALLfixEffectNames = unique(ALLfixEffectNames);
+
+% Determine all available error model parameters in the models
+ALLerrorNames = {};
+for k=1:length(RESULTS),
+    if ~isempty(RESULTS(k).rawParameterInfo),
+        fek = RESULTS(k).rawParameterInfo.errorParameter.names;
+        ALLerrorNames = [ALLerrorNames fek];
+    end
+end
+ALLerrorNames = unique(ALLerrorNames);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Create the parameter information table
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Generate FIXED EFFECT table - estimated and non-estimated parameter
+% values shown. Non-estimated get postfix (FIX).
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ALLNAMES = [ALLfixEffectNames ALLerrorNames];
+FixedEffectValuesTableCell = cell(1,3+length(ALLNAMES));
+FixedEffectValuesTableCell(1,1:2) = {'<TT>' 'Estimated fixed effect and error model parameters'};
+FixedEffectValuesTableCell(end+1,:) = {'<TH>' 'MODEL' ['round(' order ')'] ALLNAMES{:}};
+for k=1:length(RESULTS),
+    if ~isempty(RESULTS(k).rawParameterInfo),
+        % Get model specific parameter names and values
+        modelNAMES              = [RESULTS(k).rawParameterInfo.fixedEffects.names        RESULTS(k).rawParameterInfo.errorParameter.names];
+        modelVALUES             = [RESULTS(k).rawParameterInfo.fixedEffects.values       RESULTS(k).rawParameterInfo.errorParameter.values];
+        modelESTIMATED          = [RESULTS(k).rawParameterInfo.fixedEffects.estimated    RESULTS(k).rawParameterInfo.errorParameter.estimated];
+        % Sort the parameter values into the correct location
+        allValues               = NaN(1,length(ALLNAMES));
+        allEstimated            = zeros(1,length(ALLNAMES));
+        for kx=1:length(modelNAMES),
+            ix                  = strmatchIQM(modelNAMES{kx},ALLNAMES,'exact');
+            allValues(ix)       = modelVALUES(kx);
+            allEstimated(ix)    = modelESTIMATED(kx);            
+        end
+        % Create table row for current model
+        FixedEffectValuesTableCell{k+2,1} = '<TR>';
+        FixedEffectValuesTableCell{k+2,2} = RESULTS(k).model;
+        FixedEffectValuesTableCell{k+2,3} = round(RESULTS(k).(order));
+        for k2=1:length(ALLNAMES),
+            if allEstimated(k2),
+                FixedEffectValuesTableCell{k+2,k2+3} = sprintf('%1.3g',allValues(k2));
+            else
+                if ~isnan(allValues(k2)),
+                    FixedEffectValuesTableCell{k+2,k2+3} = sprintf('%1.3g (FIX)',allValues(k2));
+                else
+                    FixedEffectValuesTableCell{k+2,k2+3} = '-';
+                end
+            end
+        end
+    end
+end
+FixedEffectValuesTableCell{end+1,1} = '<TF>';
+FixedEffectValuesTableCell{end,2}   = 'Fixed effect parameter values from NONMEM models have been back-transformed from MU-referencing.';
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Generate RANDOM EFFECT table - estimated and non-estimated parameter
+% values shown. Non-estimated get postfix (FIX).
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ALLNAMES = [ALLfixEffectNames];
+RandomEffectValuesTableCell = cell(1,3+length(ALLNAMES));
+RandomEffectValuesTableCell(1,1:2) = {'<TT>' 'Estimated random effect parameters'};
+RandomEffectValuesTableCell(2,1:3) = {'<TH>' 'MODEL' ['round(' order ')']};
+for k=1:length(ALLNAMES),
+    RandomEffectValuesTableCell{2,3+k} = ['om(' ALLNAMES{k} ')'];
+end
+for k=1:length(RESULTS),
+    if ~isempty(RESULTS(k).rawParameterInfo),
+        % Get model specific parameter names and values
+        modelNAMES              = RESULTS(k).rawParameterInfo.fixedEffects.names;
+        modelVALUES             = RESULTS(k).rawParameterInfo.randomEffects.values;
+        modelESTIMATED          = RESULTS(k).rawParameterInfo.randomEffects.estimated;
+        % Sort the parameter values into the correct location
+        allValues               = NaN(1,length(ALLNAMES));
+        allEstimated            = zeros(1,length(ALLNAMES));
+        for kx=1:length(modelNAMES),
+            ix                  = strmatchIQM(modelNAMES{kx},ALLNAMES,'exact');
+            allValues(ix)       = modelVALUES(kx);
+            allEstimated(ix)    = modelESTIMATED(kx);            
+        end
+        % Create table row for current model
+        RandomEffectValuesTableCell{k+2,1} = '<TR>';
+        RandomEffectValuesTableCell{k+2,2} = RESULTS(k).model;
+        RandomEffectValuesTableCell{k+2,3} = round(RESULTS(k).(order));
+        for k2=1:length(ALLNAMES),
+            if allEstimated(k2)==1,
+                RandomEffectValuesTableCell{k+2,k2+3} = sprintf('%1.3g',allValues(k2));
+            else
+                if ~isnan(allValues(k2)),
+                    RandomEffectValuesTableCell{k+2,k2+3} = sprintf('%1.3g (FIX)',allValues(k2));
+                else
+                    RandomEffectValuesTableCell{k+2,k2+3} = '-';
+                end
+            end
+        end
+    end
+end
+RandomEffectValuesTableCell{end+1,1} = '<TF>';
+RandomEffectValuesTableCell{end,2}   = 'Omega (om) values correspond to standard deviations of the ETAs.';
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% RELATIVE STANDARD ERRORS of estimated FIXED EFFECT PARAMETERS and ERROR
+% MODEL PARAMETERS (IN PERCENT) 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ALLNAMES = [ALLfixEffectNames ALLerrorNames];
+FixedEffectRSETableCell = cell(1,3+length(ALLNAMES));
+FixedEffectRSETableCell(1,1:2) = {'<TT>' 'Relative standard errors of estimated fixed effect and error model parameters'};
+FixedEffectRSETableCell(end+1,:) = {'<TH>' 'MODEL' ['round(' order ')'] ALLNAMES{:}};
+FixedEffectRSETableCell(2,1:3) = {'<TH>' 'MODEL' ['round(' order ')']};
+for k=1:length(ALLNAMES),
+    FixedEffectRSETableCell{2,3+k} = ['rse(' ALLNAMES{k} ')'];
+end
+for k=1:length(RESULTS),
+    if ~isempty(RESULTS(k).rawParameterInfo),
+        % Get model specific parameter names and values
+        modelNAMES              = [RESULTS(k).rawParameterInfo.fixedEffects.names       RESULTS(k).rawParameterInfo.errorParameter.names];
+        modelVALUES             = [RESULTS(k).rawParameterInfo.fixedEffects.rse         RESULTS(k).rawParameterInfo.errorParameter.rse];
+        modelESTIMATED          = [RESULTS(k).rawParameterInfo.fixedEffects.estimated   RESULTS(k).rawParameterInfo.errorParameter.estimated];
+        % Sort the parameter values into the correct location
+        allValues               = NaN(1,length(ALLNAMES));
+        allEstimated            = zeros(1,length(ALLNAMES));
+        for kx=1:length(modelNAMES),
+            ix                  = strmatchIQM(modelNAMES{kx},ALLNAMES,'exact');
+            allValues(ix)       = modelVALUES(kx);
+            allEstimated(ix)    = modelESTIMATED(kx);            
+        end
+        % Create table row for current model
+        FixedEffectRSETableCell{k+2,1} = '<TR>';
+        FixedEffectRSETableCell{k+2,2} = RESULTS(k).model;
+        FixedEffectRSETableCell{k+2,3} = round(RESULTS(k).(order));
+        for k2=1:length(ALLNAMES),
+            if allEstimated(k2),
+                FixedEffectRSETableCell{k+2,k2+3} = sprintf('%1.3g',allValues(k2));
+            else
+                if ~isnan(allValues(k2)),
+                    FixedEffectRSETableCell{k+2,k2+3} = sprintf('%1.3g (FIX)',allValues(k2));
+                else
+                    FixedEffectRSETableCell{k+2,k2+3} = '-';
+                end
+            end
+        end
+    end
+end
+FixedEffectRSETableCell{end+1,1} = '<TF>';
+FixedEffectRSETableCell{end,2}   = sprintf('Relative standard errors in percent.\nStandard errors for fixed effects in NONMEM models approximated by sampling - since MU referencing used.');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Generate RANDOM EFFECTS REL STDERRORS Table
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ALLNAMES = [ALLfixEffectNames];
+RandomEffectRSETableCell = cell(1,3+length(ALLNAMES));
+RandomEffectRSETableCell(1,1:2) = {'<TT>' 'Relative standard errors of estimated random effect parameters'};
+RandomEffectRSETableCell(2,1:3) = {'<TH>' 'MODEL' ['round(' order ')']};
+for k=1:length(ALLNAMES),
+    RandomEffectRSETableCell{2,3+k} = ['rseom(' ALLNAMES{k} ')'];
+end
+for k=1:length(RESULTS),
+    if ~isempty(RESULTS(k).rawParameterInfo),
+        % Get model specific parameter names and values
+        modelNAMES              = RESULTS(k).rawParameterInfo.fixedEffects.names;
+        modelVALUES             = RESULTS(k).rawParameterInfo.randomEffects.rse;
+        modelESTIMATED          = RESULTS(k).rawParameterInfo.randomEffects.estimated;
+        % Sort the parameter values into the correct location
+        allValues               = NaN(1,length(ALLNAMES));
+        allEstimated            = zeros(1,length(ALLNAMES));
+        for kx=1:length(modelNAMES),
+            ix                  = strmatchIQM(modelNAMES{kx},ALLNAMES,'exact');
+            allValues(ix)       = modelVALUES(kx);
+            allEstimated(ix)    = modelESTIMATED(kx);            
+        end
+        % Create table row for current model
+        RandomEffectRSETableCell{k+2,1} = '<TR>';
+        RandomEffectRSETableCell{k+2,2} = RESULTS(k).model;
+        RandomEffectRSETableCell{k+2,3} = round(RESULTS(k).(order));
+        for k2=1:length(ALLNAMES),
+            if allEstimated(k2),
+                RandomEffectRSETableCell{k+2,k2+3} = sprintf('%1.3g',allValues(k2));
+            else
+                if ~isnan(allValues(k2)),
+                    RandomEffectRSETableCell{k+2,k2+3} = sprintf('%1.3g (FIX)',allValues(k2));
+                else
+                    RandomEffectRSETableCell{k+2,k2+3} = '-';
+                end
+            end
+        end
+    end
+end
+RandomEffectRSETableCell{end+1,1} = '<TF>';
+RandomEffectRSETableCell{end,2}   = 'Relative standard errors in percent.';
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Display results and save to file
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Convert to text and display text 
+textDisplay = IQMconvertCellTable2ReportTable(FixedEffectValuesTableCell,'text');
+disp(textDisplay);
+textDisplay = IQMconvertCellTable2ReportTable(RandomEffectValuesTableCell,'text');
+disp(textDisplay);
+textDisplay = IQMconvertCellTable2ReportTable(FixedEffectRSETableCell,'text');
+disp(textDisplay);
+textDisplay = IQMconvertCellTable2ReportTable(RandomEffectRSETableCell,'text');
+disp(textDisplay);
+
+% Convert to report text and export to file if filename defined
+text1 = IQMconvertCellTable2ReportTable(FixedEffectValuesTableCell,'report');     
+text2 = IQMconvertCellTable2ReportTable(RandomEffectValuesTableCell,'report');     
+text3 = IQMconvertCellTable2ReportTable(FixedEffectRSETableCell,'report');     
+text4 = IQMconvertCellTable2ReportTable(RandomEffectRSETableCell,'report');     
+text = sprintf('%s\r\n\r\n%s\r\n\r\n%s\r\n\r\n%s',text1,text2,text3,text4);
+IQMwriteText2File(text,[strrep(filename,'.txt','') '.txt']);
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/08-NLMEfitSummary/IQMfitsummaryTable.m b/IQMtools V1.2.2.2/IQMpro/tools/08-NLMEfitSummary/IQMfitsummaryTable.m
new file mode 100644
index 0000000000000000000000000000000000000000..175c7d0bb01011d3b571b1fbbae42a8f06fa38e4
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/08-NLMEfitSummary/IQMfitsummaryTable.m	
@@ -0,0 +1,385 @@
+function [tableCell] = IQMfitsummaryTable(projectPaths,filename)
+% This function creates a typical report-type NLME model parameter table.
+% "projectPaths" defines the NLME projects that are to be reported in this
+% table.
+%
+% [SYNTAX]
+% [tableCell] = IQMfitsummaryTable(projectPaths)
+% [tableCell] = IQMfitsummaryTable(projectPaths,filename)
+%
+% [INPUT]
+% projectPaths:     Cell-array with paths to NLME projects to create the
+%                   fit results table for. The table reports each model
+%                   result in a column. Columns ordered according to the
+%                   order in projectPaths.
+% filename:         Path and filename where to generate the output file.
+%                   default: '' (no file generated).
+%
+% [OUTPUT]
+% Table shown in command window and if desired also saved to file for
+% reporting purpose.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle variable input arguments
+if nargin<2,
+    filename = '';
+end
+
+% Handle cell-array thing
+if ischar(projectPaths),
+    projectPaths = {projectPaths};
+end
+
+% Check projects if NLME
+for k=1:length(projectPaths),
+    if ~isNLMEprojectIQM(projectPaths{k}),
+        error('Path "%s" does not contain an NLME project.',projectPaths{k});
+    end
+end
+
+% Load project results - do not reorder
+order   = '';
+RESULTS = parseSelectedProjectFolderResultsIQM(projectPaths,order);
+  
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Process the RESULT information somewhat
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Determine all available fixed effect parameters in the models
+ALLfixEffectNames = {};
+for k=1:length(RESULTS),
+    if ~isempty(RESULTS(k).rawParameterInfo),
+        fek = RESULTS(k).rawParameterInfo.fixedEffects.names;
+        ALLfixEffectNames = [ALLfixEffectNames fek];
+    end
+end
+ALLfixEffectNames = unique(ALLfixEffectNames);
+
+% Determine all available random effect parameters in the models
+ALLrandomEffectNames = {};
+for k=1:length(RESULTS),
+    if ~isempty(RESULTS(k).rawParameterInfo),
+        fek = RESULTS(k).rawParameterInfo.randomEffects.names;
+        ALLrandomEffectNames = [ALLrandomEffectNames fek];
+    end
+end
+ALLrandomEffectNames = unique(ALLrandomEffectNames);
+
+% Determine all available correlation parameters in the models
+ALLcorrelationNames = {};
+for k=1:length(RESULTS),
+    if ~isempty(RESULTS(k).rawParameterInfo),
+        fek = RESULTS(k).rawParameterInfo.correlation.names;
+        ALLcorrelationNames = [ALLcorrelationNames fek];
+    end
+end
+ALLcorrelationNames = unique(ALLcorrelationNames);
+
+% Determine all available covariate parameters in the models
+ALLcovariateNames = {};
+for k=1:length(RESULTS),
+    if ~isempty(RESULTS(k).rawParameterInfo),
+        fek = RESULTS(k).rawParameterInfo.covariate.names;
+        ALLcovariateNames = [ALLcovariateNames fek];
+    end
+end
+ALLcovariateNames = unique(ALLcovariateNames);
+
+% Determine all available covariate parameters in the models
+ALLerrorNames = {};
+for k=1:length(RESULTS),
+    if ~isempty(RESULTS(k).rawParameterInfo),
+        fek = RESULTS(k).rawParameterInfo.errorParameter.names;
+        ALLerrorNames = [ALLerrorNames fek];
+    end
+end
+ALLerrorNames = unique(ALLerrorNames);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Create the table
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Retain last name of model only
+modelsNames_Short = {RESULTS.model};
+for k=1:length(modelsNames_Short),
+    [~,f,e] = fileparts(modelsNames_Short{k});
+    modelsNames_Short{k} = [f e];
+end
+    
+
+
+tableCell                               = {'<TT>' 'Population parameter estimates for considered models'};
+tableCell(end+1,1:2+length(RESULTS))    = {'<TH>' ''          modelsNames_Short{:}};
+tableCell(end+1,1:2)                    = {'<TR>' 'Parameter'};
+for k=1:length(RESULTS),
+    tableCell(end,2+k) = {'Value      (RSE%)        (trans)'};
+end
+
+% FIXED EFFECTs - non-estimated get postfix (FIX).
+FLAG_FOOTER = 0;
+for k0=1:length(ALLfixEffectNames),
+    tableCell(end+1,1:2) = {'<TR>' ALLfixEffectNames{k0}};
+    for k=1:length(RESULTS),
+        % Check if parameter in model
+        ix = strmatchIQM(ALLfixEffectNames{k0},RESULTS(k).rawParameterInfo.fixedEffects.names,'exact');
+        if ~isempty(ix),
+            modelVALUES             = RESULTS(k).rawParameterInfo.fixedEffects.values(ix);
+            modelRSES               = RESULTS(k).rawParameterInfo.fixedEffects.rse(ix);
+            modelESTIMATED          = RESULTS(k).rawParameterInfo.fixedEffects.estimated(ix);
+            if modelESTIMATED,
+                value               = sprintf('%1.3g',modelVALUES);
+                if RESULTS(k).NONMEM,
+                    rse             = sprintf('(%1.3g%%*)',modelRSES);
+                    FLAG_FOOTER     = 1;
+                else
+                    rse                 = sprintf('(%1.3g%%)',modelRSES);
+                end
+                valuerse            = sprintf('%s %s',postFillCharIQM(value,10,' '),postFillCharIQM(rse,14,' '));
+            else
+                if ~isnan(modelVALUES),
+                    value           = sprintf('%1.3g',modelVALUES);
+                    rse             = sprintf('(FIX)');
+                    valuerse        = sprintf('%s %s',postFillCharIQM(value,10,' '),postFillCharIQM(rse,14,' '));
+                else
+                    valuerse        = '-';
+                end
+            end
+            % Get MU referencing transformation of fixed effect
+            modelTRANS              = RESULTS(k).rawParameterInfo.fixedEffects.distribution_info{ix};
+            if strcmp(modelTRANS,'(psi)'),
+                modelTRANS = '(norm)';
+            elseif strcmp(modelTRANS,'log(psi./(1-psi))'),
+                modelTRANS = '(logit)';
+            elseif strcmp(modelTRANS,'log(psi)'),
+                modelTRANS = '(log)';
+            else
+                error('Unknown transformation of fixed effect.');
+            end
+            % Add to text
+            valuerse = sprintf('%s%s',valuerse,modelTRANS);
+           
+        else
+            valuerse = '-';
+        end
+        % Add to table
+        tableCell(end,2+k) = {valuerse};
+    end
+end
+
+% Add footer if needed
+if FLAG_FOOTER,
+    tableCell(end+1,1:2) = {'<TF>' '* Standard errors for NONMEM models approximated by sampling due to MU-Referencing'};    
+end
+
+% Separator
+tableCell(end+1,1) = {'<HR>'};
+
+% RANDOM EFFECTs - non-estimated get postfix (FIX).
+for k0=1:length(ALLrandomEffectNames),
+    tableCell(end+1,1:2) = {'<TR>' ALLrandomEffectNames{k0}};
+    for k=1:length(RESULTS),
+        % Check if parameter in model
+        ix = strmatchIQM(ALLrandomEffectNames{k0},RESULTS(k).rawParameterInfo.randomEffects.names,'exact');
+        if ~isempty(ix),
+            modelVALUES             = RESULTS(k).rawParameterInfo.randomEffects.values(ix);
+            modelRSES               = RESULTS(k).rawParameterInfo.randomEffects.rse(ix);
+            modelESTIMATED          = RESULTS(k).rawParameterInfo.randomEffects.estimated(ix);
+            if modelESTIMATED==1,
+                value               = sprintf('%1.3g',modelVALUES);
+                rse                 = sprintf('(%1.3g%%)',modelRSES);
+                valuerse            = sprintf('%s %s',postFillCharIQM(value,10,' '),rse);
+            else
+                if ~isnan(modelVALUES),
+                    value           = sprintf('%1.3g',modelVALUES);
+                    rse             = sprintf('(FIX)',modelRSES);
+                    valuerse        = sprintf('%s %s',postFillCharIQM(value,10,' '),rse);
+                else
+                    valuerse        = '-';
+                end
+            end
+        else
+            valuerse = '-';
+        end
+        % Add to table
+        tableCell(end,2+k) = {valuerse};
+    end
+end
+      
+% Separator
+tableCell(end+1,1) = {'<HR>'};
+
+% CORRELATIONS - non-estimated get postfix (FIX).
+for k0=1:length(ALLcorrelationNames),
+    tableCell(end+1,1:2) = {'<TR>' ALLcorrelationNames{k0}};
+    for k=1:length(RESULTS),
+        % Check if parameter in model
+        ix = strmatchIQM(ALLcorrelationNames{k0},RESULTS(k).rawParameterInfo.correlation.names,'exact');
+        if ~isempty(ix),
+            modelVALUES             = RESULTS(k).rawParameterInfo.correlation.values(ix);
+            modelRSES               = RESULTS(k).rawParameterInfo.correlation.rse(ix);
+            modelESTIMATED          = RESULTS(k).rawParameterInfo.correlation.estimated(ix);
+            if modelESTIMATED,
+                value               = sprintf('%1.3g',modelVALUES);
+                rse                 = sprintf('(%1.3g%%)',modelRSES);
+                valuerse            = sprintf('%s %s',postFillCharIQM(value,10,' '),rse);
+            else
+                if ~isnan(modelVALUES),
+                    value           = sprintf('%1.3g',modelVALUES);
+                    rse             = sprintf('(FIX)',modelRSES);
+                    valuerse        = sprintf('%s %s',postFillCharIQM(value,10,' '),rse);
+                else
+                    valuerse        = '-';
+                end
+            end
+        else
+            valuerse = '-';
+        end
+        % Add to table
+        tableCell(end,2+k) = {valuerse};
+    end
+end
+      
+% Separator
+tableCell(end+1,1) = {'<HR>'};
+
+% COVARIATES - non-estimated get postfix (FIX).
+for k0=1:length(ALLcovariateNames),
+    tableCell(end+1,1:2) = {'<TR>' ALLcovariateNames{k0}};
+    for k=1:length(RESULTS),
+        % Check if parameter in model
+        ix = strmatchIQM(ALLcovariateNames{k0},RESULTS(k).rawParameterInfo.covariate.names,'exact');
+        if ~isempty(ix),
+            modelVALUES             = RESULTS(k).rawParameterInfo.covariate.values(ix);
+            modelRSES               = RESULTS(k).rawParameterInfo.covariate.rse(ix);
+            modelESTIMATED          = RESULTS(k).rawParameterInfo.covariate.estimated(ix);
+            if modelESTIMATED,
+                value               = sprintf('%1.3g',modelVALUES);
+                rse                 = sprintf('(%1.3g%%)',modelRSES);
+                valuerse            = sprintf('%s %s',postFillCharIQM(value,10,' '),postFillCharIQM(rse,14,' '));
+            else
+                if ~isnan(modelVALUES),
+                    value           = sprintf('%1.3g',modelVALUES);
+                    rse             = sprintf('(FIX)',modelRSES);
+                    valuerse        = sprintf('%s %s',postFillCharIQM(value,10,' '),postFillCharIQM(rse,14,' '));
+                else
+                    valuerse        = '-';
+                end
+            end
+            transinfo = getCovCatTransInfo(ALLcovariateNames{k0},RESULTS(k));
+            valuerse = sprintf('%s%s',valuerse,transinfo);
+        else
+            valuerse = '-';
+        end
+        % Add to table
+        tableCell(end,2+k) = {valuerse};
+    end
+end
+      
+% Separator
+tableCell(end+1,1) = {'<HR>'};
+
+% ERROR PARAMETERS - non-estimated get postfix (FIX).
+for k0=1:length(ALLerrorNames),
+    tableCell(end+1,1:2) = {'<TR>' ALLerrorNames{k0}};
+    for k=1:length(RESULTS),
+        % Check if parameter in model
+        ix = strmatchIQM(ALLerrorNames{k0},RESULTS(k).rawParameterInfo.errorParameter.names,'exact');
+        if ~isempty(ix),
+            modelVALUES             = RESULTS(k).rawParameterInfo.errorParameter.values(ix);
+            modelRSES               = RESULTS(k).rawParameterInfo.errorParameter.rse(ix);
+            modelESTIMATED          = RESULTS(k).rawParameterInfo.errorParameter.estimated(ix);
+            if modelESTIMATED,
+                value               = sprintf('%1.3g',modelVALUES);
+                rse                 = sprintf('(%1.3g%%)',modelRSES);
+                valuerse            = sprintf('%s %s',postFillCharIQM(value,10,' '),rse);
+            else
+                if ~isnan(modelVALUES),
+                    value           = sprintf('%1.3g',modelVALUES);
+                    rse             = sprintf('(FIX)',modelRSES);
+                    valuerse        = sprintf('%s %s',postFillCharIQM(value,10,' '),rse);
+                else
+                    valuerse        = '-';
+                end
+            end
+        else
+            valuerse = '-';
+        end
+        % Add to table
+        tableCell(end,2+k) = {valuerse};
+    end
+end
+      
+% Separator
+tableCell(end+1,1) = {'<HR>'};
+
+% OBJ, AIC, BIC
+tableCell(end+1,:) = {'<TR>' 'OBJ' RESULTS.OBJ};
+tableCell(end+1,:) = {'<TR>' 'AIC' RESULTS.AIC};
+tableCell(end+1,:) = {'<TR>' 'BIC' RESULTS.BIC};
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Display results and save to file
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Convert to text and display text 
+textDisplay = IQMconvertCellTable2ReportTable(tableCell,'text');
+disp(textDisplay);
+
+% Convert to report text and export to file if filename defined
+IQMconvertCellTable2ReportTable(tableCell,'report',filename);     
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Function to generate transformation and reference value information for
+% covariates ...
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [transinfo] = getCovCatTransInfo(ALLcovariateNamesK0,RESULTS)
+COVNAMES            = RESULTS.projectHeader.COVNAMES;
+CATNAMES            = RESULTS.projectHeader.CATNAMES;
+BETACOVNAMES        = RESULTS.projectHeader.BETACOVNAMES;
+BETACOVTRANS        = RESULTS.projectHeader.BETACOVTRANS;
+BETACATNAMES        = RESULTS.projectHeader.BETACATNAMES;
+BETACATREFERENCE    = RESULTS.projectHeader.BETACATREFERENCE;
+
+% Process covariate name to get parameter and covariate name
+name    = strrep(ALLcovariateNamesK0,'beta_','');
+name    = strrep(name,')','');
+name    = strrep(name,'(',',');
+terms   = explodePCIQM(name);
+pn      = terms{1};
+cn      = terms{2};
+% Check if categorical or continuous
+ctypecont = NaN;
+ix = strmatchIQM(cn,COVNAMES,'exact');
+if ~isempty(ix),
+    ctypecont = 1;
+    cc = '';
+else
+    terms   = explodePCIQM(cn,'_');
+    cn = terms{1};
+    cc = terms{2};
+    ix = strmatchIQM(cn,CATNAMES,'exact');
+    if ~isempty(ix),
+        ctypecont = 0;
+    end
+end
+if isnan(ctypecont),
+    error('Difficulty to decide covariate type.');
+end
+% Handle continuous covariate
+if ctypecont,
+    % Only need to get the covariate transformation
+    ix = strmatchIQM(ALLcovariateNamesK0,BETACOVNAMES,'exact');
+    trans = BETACOVTRANS{ix};
+    trans = strrep(trans,'cov',cn);
+%     transinfo = strrep(sprintf('(%s)',trans),'.','');
+    transinfo = sprintf('(%s)',trans);
+else
+    % Need to get reference category
+    test = sprintf('beta_%s(%s)',pn,cn);
+    ix = strmatchIQM(test,BETACATNAMES,'exact');
+    trans = BETACATREFERENCE{ix};
+    transinfo = sprintf('(Ref: %s)',trans);
+end
+return
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/08-NLMEfitSummary/IQMfitsummaryTableSingle.m b/IQMtools V1.2.2.2/IQMpro/tools/08-NLMEfitSummary/IQMfitsummaryTableSingle.m
new file mode 100644
index 0000000000000000000000000000000000000000..9bd8575bceecfac3c423f21376d8ecd36f1c633a
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/08-NLMEfitSummary/IQMfitsummaryTableSingle.m	
@@ -0,0 +1,420 @@
+function [tableCell] = IQMfitsummaryTableSingle(projectPath,filename)
+% This function creates a typical report-type NLME model parameter table.
+% "projectPaths" defines the NLME projects that are to be reported in this
+% table. In contrast to IQMfitsummaryTable this function creates a single
+% table with dedicated columns for value, RSE and trans.
+%
+% [SYNTAX]
+% [tableCell] = IQMfitsummaryTableSingle(projectPath)
+% [tableCell] = IQMfitsummaryTableSingle(projectPath,filename)
+%
+% [INPUT]
+% projectPath:      String with path to NLME project to create the
+%                   fit results table for.
+% filename:         Path and filename where to generate the output file.
+%                   default: '' (no file generated).
+%
+% [OUTPUT]
+% Table shown in command window and if desired also saved to file for
+% reporting purpose.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle variable input arguments
+if nargin<2,
+    filename = '';
+end
+
+% Handle cell-array thing
+if ischar(projectPath),
+    projectPath = {projectPath};
+end
+
+% Check projects if NLME
+for k=1:length(projectPath),
+    if ~isNLMEprojectIQM(projectPath{k}),
+        error('Path "%s" does not contain an NLME project.',projectPath{k});
+    end
+end
+
+% Load project results - do not reorder
+order   = '';
+RESULTS = parseSelectedProjectFolderResultsIQM(projectPath,order);
+  
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Process the RESULT information somewhat
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Determine all available fixed effect parameters in the models
+ALLfixEffectNames = {};
+for k=1:length(RESULTS),
+    if ~isempty(RESULTS(k).rawParameterInfo),
+        fek = RESULTS(k).rawParameterInfo.fixedEffects.names;
+        ALLfixEffectNames = [ALLfixEffectNames fek];
+    end
+end
+ALLfixEffectNames = unique(ALLfixEffectNames);
+
+% Determine all available random effect parameters in the models
+ALLrandomEffectNames = {};
+for k=1:length(RESULTS),
+    if ~isempty(RESULTS(k).rawParameterInfo),
+        fek = RESULTS(k).rawParameterInfo.randomEffects.names;
+        ALLrandomEffectNames = [ALLrandomEffectNames fek];
+    end
+end
+ALLrandomEffectNames = unique(ALLrandomEffectNames);
+
+% Determine all available correlation parameters in the models
+ALLcorrelationNames = {};
+for k=1:length(RESULTS),
+    if ~isempty(RESULTS(k).rawParameterInfo),
+        fek = RESULTS(k).rawParameterInfo.correlation.names;
+        ALLcorrelationNames = [ALLcorrelationNames fek];
+    end
+end
+ALLcorrelationNames = unique(ALLcorrelationNames);
+
+% Determine all available covariate parameters in the models
+ALLcovariateNames = {};
+for k=1:length(RESULTS),
+    if ~isempty(RESULTS(k).rawParameterInfo),
+        fek = RESULTS(k).rawParameterInfo.covariate.names;
+        ALLcovariateNames = [ALLcovariateNames fek];
+    end
+end
+ALLcovariateNames = unique(ALLcovariateNames);
+
+% Determine all available covariate parameters in the models
+ALLerrorNames = {};
+for k=1:length(RESULTS),
+    if ~isempty(RESULTS(k).rawParameterInfo),
+        fek = RESULTS(k).rawParameterInfo.errorParameter.names;
+        ALLerrorNames = [ALLerrorNames fek];
+    end
+end
+ALLerrorNames = unique(ALLerrorNames);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Calculate shrinkage
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[shOMEGAnames,sheta_shrinkage_percent] = IQMfitanalysisShrinkage(projectPath{1});
+
+% Need to order sheta_shrinkage_percent according to ALLrandomEffectNames
+eta_shrinkage_ordered = [];
+for k=1:length(ALLrandomEffectNames),
+    xxx = strrep(strrep(ALLrandomEffectNames{k},')',''),'omega(','');
+    % find index in ALLrandomEffectNames
+    ix = strmatchIQM(xxx,shOMEGAnames,'exact');
+    if isempty(ix),
+        error('Check!');
+    end
+    eta_shrinkage_ordered(k) = sheta_shrinkage_percent(ix);    
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Create the table
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Retain last name of model only
+modelsNames_Short = {RESULTS.model};
+for k=1:length(modelsNames_Short),
+    [~,f,e] = fileparts(modelsNames_Short{k});
+    modelsNames_Short{k} = [f e];
+end
+    
+
+
+tableCell                               = {'<TT>' 'Population parameter estimates for considered model' '' '' '' ''};
+tableCell(end+1,:)                      = {'<TH>' 'Parameter' 'Value' 'RSE (%)' 'Transformation' 'Shrinkage (%)'};
+
+
+% FIXED EFFECTs - non-estimated get postfix (FIX).
+FLAG_FOOTER = 0;
+for k0=1:length(ALLfixEffectNames),
+    tableCell(end+1,1:2) = {'<TR>' ALLfixEffectNames{k0}};
+    for k=1:length(RESULTS),
+        % Check if parameter in model
+        ix = strmatchIQM(ALLfixEffectNames{k0},RESULTS(k).rawParameterInfo.fixedEffects.names,'exact');
+        if ~isempty(ix),
+            modelVALUES             = RESULTS(k).rawParameterInfo.fixedEffects.values(ix);
+            modelRSES               = RESULTS(k).rawParameterInfo.fixedEffects.rse(ix);
+            modelESTIMATED          = RESULTS(k).rawParameterInfo.fixedEffects.estimated(ix);
+            if modelESTIMATED,
+                value               = sprintf('%1.3g',modelVALUES);
+                if RESULTS(k).NONMEM,
+                    rse             = sprintf('%1.3g%%*',modelRSES);
+                    FLAG_FOOTER     = 1;
+                else
+                    rse             = sprintf('%1.3g%%',modelRSES);
+                end
+            else
+                if ~isnan(modelVALUES),
+                    value           = sprintf('%1.3g',modelVALUES);
+                    rse             = sprintf('(FIX)');
+                    valuerse        = sprintf('%s %s',postFillCharIQM(value,10,' '),postFillCharIQM(rse,14,' '));
+                else
+                    value           = NaN;
+                    rse             = NaN;
+                end
+            end
+            % Get MU referencing transformation of fixed effect
+            modelTRANS              = RESULTS(k).rawParameterInfo.fixedEffects.distribution_info{ix};
+            if strcmp(modelTRANS,'(psi)'),
+                modelTRANS = 'normal';
+            elseif strcmp(modelTRANS,'log(psi./(1-psi))'),
+                modelTRANS = 'logitnormal';
+            elseif strcmp(modelTRANS,'log(psi)'),
+                modelTRANS = 'lognormal';
+            else
+                error('Unknown transformation of fixed effect.');
+            end
+        else
+            valuerse = '-';
+            value = '-';
+            rse = '-';
+            modelTRANS = '-';
+        end
+        % Add to table
+        tableCell(end,2+k) = {value};
+        tableCell(end,2+k+1) = {rse};
+        tableCell(end,2+k+2) = {modelTRANS};
+    end
+end
+
+% % Add footer if needed
+% if FLAG_FOOTER,
+%     tableCell(end+1,1:2) = {'<TF>' '* Standard errors for NONMEM models approximated by sampling due to MU-Referencing'};    
+% end
+
+% Separator
+tableCell(end+1,1) = {'<TR>'};
+
+% RANDOM EFFECTs - non-estimated get postfix (FIX).
+for k0=1:length(ALLrandomEffectNames),
+    tableCell(end+1,1:2) = {'<TR>' ALLrandomEffectNames{k0}};
+    for k=1:length(RESULTS),
+        % Check if parameter in model
+        ix = strmatchIQM(ALLrandomEffectNames{k0},RESULTS(k).rawParameterInfo.randomEffects.names,'exact');
+        if ~isempty(ix),
+            modelVALUES             = RESULTS(k).rawParameterInfo.randomEffects.values(ix);
+            modelRSES               = RESULTS(k).rawParameterInfo.randomEffects.rse(ix);
+            modelESTIMATED          = RESULTS(k).rawParameterInfo.randomEffects.estimated(ix);
+            if modelESTIMATED==1,
+                value               = sprintf('%1.3g',modelVALUES);
+                rse                 = sprintf('%1.3g%%',modelRSES);
+                valuerse            = sprintf('%s %s',postFillCharIQM(value,10,' '),rse);
+            else
+                if ~isnan(modelVALUES),
+                    value           = sprintf('%1.3g',modelVALUES);
+                    rse             = sprintf('(FIX)',modelRSES);
+                    valuerse        = sprintf('%s %s',postFillCharIQM(value,10,' '),rse);
+                else
+                    value           = NaN;
+                    rse             = NaN;
+                end
+            end
+        else
+            value = '-';
+            rse = '-';
+        end
+        % Add to table
+        tableCell(end,2+k) = {value};
+        tableCell(end,2+k+1) = {rse};
+        % Add shrinkage
+        if isnan(eta_shrinkage_ordered(k0)),
+            tableCell(end,2+k+3) = {'-'};
+        else
+            tableCell{end,2+k+3} = round(eta_shrinkage_ordered(k0),1);
+        end        
+    end
+end
+      
+% Separator
+tableCell(end+1,1) = {'<TR>'};
+
+% CORRELATIONS - non-estimated get postfix (FIX).
+for k0=1:length(ALLcorrelationNames),
+    tableCell(end+1,1:2) = {'<TR>' ALLcorrelationNames{k0}};
+    for k=1:length(RESULTS),
+        % Check if parameter in model
+        ix = strmatchIQM(ALLcorrelationNames{k0},RESULTS(k).rawParameterInfo.correlation.names,'exact');
+        if ~isempty(ix),
+            modelVALUES             = RESULTS(k).rawParameterInfo.correlation.values(ix);
+            modelRSES               = RESULTS(k).rawParameterInfo.correlation.rse(ix);
+            modelESTIMATED          = RESULTS(k).rawParameterInfo.correlation.estimated(ix);
+            if modelESTIMATED,
+                value               = sprintf('%1.3g',modelVALUES);
+                rse                 = sprintf('%1.3g%%',modelRSES);
+                valuerse            = sprintf('%s %s',postFillCharIQM(value,10,' '),rse);
+            else
+                if ~isnan(modelVALUES),
+                    value           = sprintf('%1.3g',modelVALUES);
+                    rse             = sprintf('(FIX)',modelRSES);
+                    valuerse        = sprintf('%s %s',postFillCharIQM(value,10,' '),rse);
+                else
+                    value           = NaN;
+                    rse             = NaN;
+                end
+            end
+        else
+            value = '-';
+            rse = '-';
+        end
+        % Add to table
+        tableCell(end,2+k) = {value};
+        tableCell(end,2+k+1) = {rse};
+    end
+end
+      
+% Separator
+tableCell(end+1,1) = {'<TR>'};
+
+% COVARIATES - non-estimated get postfix (FIX).
+for k0=1:length(ALLcovariateNames),
+    tableCell(end+1,1:2) = {'<TR>' ALLcovariateNames{k0}};
+    for k=1:length(RESULTS),
+        % Check if parameter in model
+        ix = strmatchIQM(ALLcovariateNames{k0},RESULTS(k).rawParameterInfo.covariate.names,'exact');
+        if ~isempty(ix),
+            modelVALUES             = RESULTS(k).rawParameterInfo.covariate.values(ix);
+            modelRSES               = RESULTS(k).rawParameterInfo.covariate.rse(ix);
+            modelESTIMATED          = RESULTS(k).rawParameterInfo.covariate.estimated(ix);
+            if modelESTIMATED,
+                value               = sprintf('%1.3g',modelVALUES);
+                rse                 = sprintf('(%1.3g%%)',modelRSES);
+                valuerse            = sprintf('%s %s',postFillCharIQM(value,10,' '),postFillCharIQM(rse,14,' '));
+            else
+                if ~isnan(modelVALUES),
+                    value           = sprintf('%1.3g',modelVALUES);
+                    rse             = sprintf('(FIX)',modelRSES);
+                    valuerse        = sprintf('%s %s',postFillCharIQM(value,10,' '),postFillCharIQM(rse,14,' '));
+                else
+                    value           = NaN;
+                    rse             = NaN;
+                end
+            end
+            transinfo = getCovCatTransInfo(ALLcovariateNames{k0},RESULTS(k));
+            valuerse = sprintf('%s%s',valuerse,transinfo);
+        else
+            value = '-';
+            rse = '-';
+            transinfo = '-';
+        end
+        % Add to table
+        tableCell(end,2+k) = {value};
+        tableCell(end,2+k+1) = {rse};
+        tableCell(end,2+k+2) = {transinfo};
+    end
+end
+      
+% Separator
+tableCell(end+1,1) = {'<TR>'};
+
+% ERROR PARAMETERS - non-estimated get postfix (FIX).
+for k0=1:length(ALLerrorNames),
+    tableCell(end+1,1:2) = {'<TR>' ALLerrorNames{k0}};
+    for k=1:length(RESULTS),
+        % Check if parameter in model
+        ix = strmatchIQM(ALLerrorNames{k0},RESULTS(k).rawParameterInfo.errorParameter.names,'exact');
+        if ~isempty(ix),
+            modelVALUES             = RESULTS(k).rawParameterInfo.errorParameter.values(ix);
+            modelRSES               = RESULTS(k).rawParameterInfo.errorParameter.rse(ix);
+            modelESTIMATED          = RESULTS(k).rawParameterInfo.errorParameter.estimated(ix);
+            if modelESTIMATED,
+                value               = sprintf('%1.3g',modelVALUES);
+                rse                 = sprintf('(%1.3g%%)',modelRSES);
+                valuerse            = sprintf('%s %s',postFillCharIQM(value,10,' '),rse);
+            else
+                if ~isnan(modelVALUES),
+                    value           = sprintf('%1.3g',modelVALUES);
+                    rse             = sprintf('(FIX)',modelRSES);
+                    valuerse        = sprintf('%s %s',postFillCharIQM(value,10,' '),rse);
+                else
+                    value           = NaN;
+                    rse             = NaN;
+                end
+            end
+        else
+            value = '-';
+            rse = '-';
+        end
+        % Add to table
+        tableCell(end,2+k) = {value};
+        tableCell(end,2+k+1) = {rse};
+    end
+end
+      
+% Separator
+tableCell(end+1,1) = {'<TR>'};
+
+% OBJ, AIC, BIC
+tableCell(end+1,1:3) = {'<TR>' 'OBJ' round(RESULTS.OBJ,2)};
+tableCell(end+1,1:3) = {'<TR>' 'AIC' round(RESULTS.AIC,2)};
+tableCell(end+1,1:3) = {'<TR>' 'BIC' round(RESULTS.BIC,2)};
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Display results and save to file
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Convert to text and display text 
+textDisplay = IQMconvertCellTable2ReportTable(tableCell,'text');
+disp(textDisplay);
+
+% Convert to report text and export to file if filename defined
+IQMconvertCellTable2ReportTable(tableCell,'report',filename);     
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Function to generate transformation and reference value information for
+% covariates ...
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [transinfo] = getCovCatTransInfo(ALLcovariateNamesK0,RESULTS)
+COVNAMES            = RESULTS.projectHeader.COVNAMES;
+CATNAMES            = RESULTS.projectHeader.CATNAMES;
+BETACOVNAMES        = RESULTS.projectHeader.BETACOVNAMES;
+BETACOVTRANS        = RESULTS.projectHeader.BETACOVTRANS;
+BETACATNAMES        = RESULTS.projectHeader.BETACATNAMES;
+BETACATREFERENCE    = RESULTS.projectHeader.BETACATREFERENCE;
+
+% Process covariate name to get parameter and covariate name
+name    = strrep(ALLcovariateNamesK0,'beta_','');
+name    = strrep(name,')','');
+name    = strrep(name,'(',',');
+terms   = explodePCIQM(name);
+pn      = terms{1};
+cn      = terms{2};
+% Check if categorical or continuous
+ctypecont = NaN;
+ix = strmatchIQM(cn,COVNAMES,'exact');
+if ~isempty(ix),
+    ctypecont = 1;
+    cc = '';
+else
+    terms   = explodePCIQM(cn,'_');
+    cn = terms{1};
+    cc = terms{2};
+    ix = strmatchIQM(cn,CATNAMES,'exact');
+    if ~isempty(ix),
+        ctypecont = 0;
+    end
+end
+if isnan(ctypecont),
+    error('Difficulty to decide covariate type.');
+end
+% Handle continuous covariate
+if ctypecont,
+    % Only need to get the covariate transformation
+    ix = strmatchIQM(ALLcovariateNamesK0,BETACOVNAMES,'exact');
+    trans = BETACOVTRANS{ix};
+    trans = strrep(trans,'cov',cn);
+%     transinfo = strrep(sprintf('(%s)',trans),'.','');
+    transinfo = sprintf('%s',trans);
+else
+    % Need to get reference category
+    test = sprintf('beta_%s(%s)',pn,cn);
+    ix = strmatchIQM(test,BETACATNAMES,'exact');
+    trans = BETACATREFERENCE{ix};
+    transinfo = sprintf('Reference group: %s',trans);
+end
+return
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/08-NLMEfitSummary/auxiliary/parseProjectFolderResultsIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/08-NLMEfitSummary/auxiliary/parseProjectFolderResultsIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..23c363b47190b9ebdc2876e1a97084fe0e29ff26
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/08-NLMEfitSummary/auxiliary/parseProjectFolderResultsIQM.m	
@@ -0,0 +1,106 @@
+function [RESULTS] = parseProjectFolderResultsIQM(modelProjectsFolder,order)
+% This function parses information from all NLME models that are present
+% within the specified folder and returns the information in a structure.
+% The optional argument "order" can be used to order the results according
+% to AIC, BIC or the objective function value.
+% 
+% [SYNTAX]
+% [RESULTS] = parseProjectFolderResultsIQM(modelProjectsFolder)
+% [RESULTS] = parseProjectFolderResultsIQM(modelProjectsFolder,order)
+%
+% [INPUT]
+% modelProjectsFolder:      Path to a folder with MONOLIX or NONMEM project folders
+%                           to generate the result tables for.
+% order:                    'AIC', 'BIC', or 'OBJ'. The results are then
+%                           ordered according to these values. 
+%                           If '' then no ordering is done. (default:
+%                           '').
+%
+% [OUTPUT]
+% RESULTS:                  MATLAB structure with the following content:
+%         RESULTS.model         
+%         RESULTS.OBJ           
+%         RESULTS.AIC           
+%         RESULTS.BIC                            
+%         RESULTS.parameternames                 
+%         RESULTS.parametervalues                
+%         RESULTS.stderrors                      
+%         RESULTS.correlationmatrixRandomEffects   
+%         RESULTS.rawParameterInfo                 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle variable input arguments
+if nargin<2,
+    order = ''; % do not order by default
+end
+
+% Handle optional arguments
+if ~ismember(upper(order),{'AIC','BIC','OBJ',''}),
+    error('Ordering selector "%s" not recognized.',order);
+end
+
+% Get the NLME projects in the defined folder
+projects = dir([modelProjectsFolder '/*']);
+% Remove . and ..
+ix_dot = strmatchIQM('.',{projects.name});
+projects(ix_dot) = [];
+% Remove files
+projects(find(~[projects.isdir])) = [];
+
+% Read the estimation results
+RESULTS = [];
+for k=1:length(projects),
+    try
+        if isMONOLIXprojectIQM([modelProjectsFolder '/' projects(k).name]),
+            x = parseMONOLIXresultsIQM([modelProjectsFolder '/' projects(k).name]);
+            y = sampleMONOLIXpopulationParametersIQM(x,0,1);
+            RESULTS(k).NONMEM = 0;
+            termination_info = '';
+        elseif isNONMEMprojectIQM([modelProjectsFolder '/' projects(k).name]),
+            % Do request back transformed parameter and standard error
+            % values for the rawparameters fixed effects and the
+            % parameters.values.
+            transformFlag = 1;
+            x = parseNONMEMresultsIQM([modelProjectsFolder '/' projects(k).name],transformFlag);
+            y = sampleNONMEMpopulationParametersIQM(x,0,1);
+            RESULTS(k).NONMEM = 1;
+            termination_info = x.termination_info{1};
+        else
+            error('Unknown project type.');
+        end
+        
+        % Collect results
+        RESULTS(k).model                            = projects(k).name;
+        RESULTS(k).OBJ                              = x.objectivefunction.OBJ;
+        RESULTS(k).AIC                              = x.objectivefunction.AIC;
+        RESULTS(k).BIC                              = x.objectivefunction.BIC;
+        RESULTS(k).parameternames                   = x.parameters.names;
+        RESULTS(k).parametervalues                  = x.parameters.values;
+        RESULTS(k).stderrors                        = x.parameters.stderrors;
+        RESULTS(k).correlationmatrixRandomEffects   = y.randomEffects.correlationmatrix;
+        RESULTS(k).rawParameterInfo                 = x.rawParameterInfo;
+        RESULTS(k).termination_info                 = termination_info;
+    catch
+        % It might happen that some model was not run ...
+        % Collect results
+        RESULTS(k).model                            = projects(k).name;
+        RESULTS(k).OBJ                              = NaN;
+        RESULTS(k).AIC                              = NaN;
+        RESULTS(k).BIC                              = NaN;
+        RESULTS(k).parameternames                   = {};
+        RESULTS(k).parametervalues                  = [];
+        RESULTS(k).stderrors                        = NaN;
+        RESULTS(k).correlationmatrixRandomEffects   = [];
+        RESULTS(k).rawParameterInfo                 = [];
+        RESULTS(k).termination_info                 = 'Crashed';        
+    end
+end
+
+if ~isempty(order),
+    % Sort the estimation results after the BIC
+    ranking_var = sortrows([[1:length(projects)]' [RESULTS.(order)]'],2); %#ok<*NBRAK>
+    RANKING = ranking_var(:,1);
+    % Reorder the results
+    RESULTS = RESULTS(RANKING);
+end
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/08-NLMEfitSummary/auxiliary/parseSelectedProjectFolderResultsIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/08-NLMEfitSummary/auxiliary/parseSelectedProjectFolderResultsIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..49567fa89d828cc7ec0d99e46f3d8d337140954d
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/08-NLMEfitSummary/auxiliary/parseSelectedProjectFolderResultsIQM.m	
@@ -0,0 +1,104 @@
+function [RESULTS] = parseSelectedProjectFolderResultsIQM(projectPaths,order)
+% This function parses information from the NLME models defined by the
+% projectPaths (cell-array) argument. The optional argument "order" can be
+% used to order the results according to AIC, BIC or the objective function
+% value. It order not provided, then the RESULTS are not re-ordered but
+% kept in the order defined by projectPaths.
+% 
+% [SYNTAX]
+% [RESULTS] = parseSelectedProjectFolderResultsIQM(projectPaths)
+% [RESULTS] = parseSelectedProjectFolderResultsIQM(projectPaths,order)
+%
+% [INPUT]
+% projectPaths:     Cell-array with paths to NLME projects for which to
+%                   return the results.
+% order:            'AIC', 'BIC', or 'OBJ'. The results
+%                   are ordered according to these values. 
+%                   If kept empty ('') then no re-ordering is done
+%                   (default: '')
+%
+% [OUTPUT]
+% RESULTS:                  MATLAB structure with the following content:
+%         RESULTS.model         
+%         RESULTS.OBJ           
+%         RESULTS.AIC           
+%         RESULTS.BIC                            
+%         RESULTS.parameternames                 
+%         RESULTS.parametervalues                
+%         RESULTS.stderrors                      
+%         RESULTS.correlationmatrixRandomEffects   
+%         RESULTS.rawParameterInfo      
+%         RESULTS.projectHeader
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle variable input arguments
+if nargin<2,
+    order = '';
+end
+
+% Handle optional arguments
+if ~ismember(upper(order),{'AIC','BIC','OBJ',''}),
+    error('Ordering selector "%s" not recognized.',order);
+end
+
+% Handle cell-array thing
+if ischar(projectPaths),
+    projectPaths = {projectPaths};
+end
+
+% Read the estimation results
+RESULTS = [];
+for k=1:length(projectPaths),
+    try
+        if isMONOLIXprojectIQM(projectPaths{k}),
+            x = parseMONOLIXresultsIQM(projectPaths{k});
+            y = sampleMONOLIXpopulationParametersIQM(x,0,1);
+            RESULTS(k).NONMEM = 0;
+        elseif isNONMEMprojectIQM(projectPaths{k}),
+            % Do request back transformed parameter and standard error
+            % values for the rawparameters fixed effects and the
+            % parameters.values.
+            transformFlag = 1;
+            x = parseNONMEMresultsIQM(projectPaths{k},transformFlag);
+            y = sampleNONMEMpopulationParametersIQM(x,0,1);
+            RESULTS(k).NONMEM = 1;
+        else
+            error('Unknown project type.');
+        end
+        
+        % Collect results
+        RESULTS(k).model                            = projectPaths{k};
+        RESULTS(k).OBJ                              = x.objectivefunction.OBJ;
+        RESULTS(k).AIC                              = x.objectivefunction.AIC;
+        RESULTS(k).BIC                              = x.objectivefunction.BIC;
+        RESULTS(k).parameternames                   = x.parameters.names;
+        RESULTS(k).parametervalues                  = x.parameters.values;
+        RESULTS(k).stderrors                        = x.parameters.stderrors;
+        RESULTS(k).correlationmatrixRandomEffects   = y.randomEffects.correlationmatrix;
+        RESULTS(k).rawParameterInfo                 = x.rawParameterInfo;
+        RESULTS(k).projectHeader                    = parseNLMEprojectHeaderIQM(projectPaths{k});
+    catch
+        % It might happen that some model was not run ...
+        % Collect results
+        RESULTS(k).model                            = projectPaths{k};
+        RESULTS(k).OBJ                              = NaN;
+        RESULTS(k).AIC                              = NaN;
+        RESULTS(k).BIC                              = NaN;
+        RESULTS(k).parameternames                   = {};
+        RESULTS(k).parametervalues                  = [];
+        RESULTS(k).stderrors                        = NaN;
+        RESULTS(k).correlationmatrixRandomEffects   = [];
+        RESULTS(k).rawParameterInfo                 = [];
+        RESULTS(k).projectHeader                    = [];        
+    end
+end
+
+% Re-order desired
+if ~isempty(order),
+    % Sort the estimation results after the BIC
+    ranking_var = sortrows([[1:length(projectPaths)]' [RESULTS.(order)]'],2); %#ok<*NBRAK>
+    RANKING = ranking_var(:,1);
+    % Reorder the results
+    RESULTS = RESULTS(RANKING);
+end
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/09-NLMEtools/IQMassessInformationContent.m b/IQMtools V1.2.2.2/IQMpro/tools/09-NLMEtools/IQMassessInformationContent.m
new file mode 100644
index 0000000000000000000000000000000000000000..e53429d8df42d06829e91169739c4a6447c57513
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/09-NLMEtools/IQMassessInformationContent.m	
@@ -0,0 +1,247 @@
+function [] = IQMassessInformationContent(projectFolder,model,output,dosings,obsTimes,options)
+% This function allows to predict the information content in data of (a)
+% future studies, given the planned dosing and observation schedule.
+%
+% It is simply based on sensitivity analysis wrt to changes in the model
+% parameters and correlation of the sensitivity trajectories.
+%
+% Assessed will be the impact of changes in single model parameters on the
+% readout at given observation times. The mean of these predicted
+% observations will be calculated and normalized sensitivities plotted as
+% barplot. Additionally, the correlation matrix of the normalized
+% sensitivities will be plotted for the parameters that have an impact on
+% the readout of more than a user definable threshold.
+%
+% What is this function good for?
+% If you have densly sampled data from Phase II studies and get a load of
+% sparsly sampled Phase III data in. Then this function might support you
+% in the selection of the parameters that you want to consider for
+% refitting on all data together. 
+%
+% Covariates, random effects, residual errors are NOT taken into account!
+% Population mean estimates of parameters are used!
+%
+% [SYNTAX]
+% [] = IQMassessInformationContent(projectFolder,model,output,dosings,obsTimes)
+% [] = IQMassessInformationContent(projectFolder,model,output,dosings,obsTimes,options)
+%
+% [INPUT]
+% projectFolder:    String with the name of the NLME(NONMEM or MONOLIX) project folder for
+%                   which to do the analysis. Needs to include the path to the 
+% 					project folder
+% model:            Structural model fitting to the NLME(NONMEM or MONOLIX) fits to use for
+%                   the simulation - or path to this model
+% output:           Cell-array with measured output names (model variables)
+% dosings:          Cell-array with dosing schemes to simulate the model for
+%                   This allows to consider more than one future study - or
+%                   paths to these dosings.
+% obsTimes:         Cell-array with Observation times to compare the models
+%                   at. Each entry in the cell-array corresponds to the
+%                   same entry in the "dosings" argument. Thus dosings and
+%                   obsTimes cell-arrays should have the same length
+% options:          Matlab structure with optional information
+%       options.pertSize            Relative parameter perturbations are
+%                                   used. (default: 10%)
+%       options.sensThreshold       Sensitivity threshold to select the
+%                                   parameters that have a significant
+%                                   impact on the output for subsequent
+%                                   correlation analysis. Default is 10%.
+%                                   As example, 10% means that when
+%                                   perturbing a parameter by x%, a
+%                                   significant perturbation of the output
+%                                   is considered to be a change of more
+%                                   than x/10 percent (plus or minus).
+%       options.optionsIntegrator   options for the integration.
+%                                   By default: abstol=1e-6, reltol=1e-6
+%       options.filename            Path and filename for export of figures
+%                                   to PS (Windows) or PDF (Unix). If not
+%                                   defined or empty, the figures will only
+%                                   be plotted 
+%
+% [OUTPUT]
+% Plots - which also can be exported to PDF if desired.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle options
+try optionsIntegrator           = options.optionsIntegrator;        catch, optionsIntegrator    = [];               end
+try pertSize                    = options.pertSize;                 catch, pertSize             = 10;               end
+try sensThreshold               = options.sensThreshold;            catch, sensThreshold        = 10;               end
+try filename                    = options.filename;                 catch, filename             = '';               end
+try optionsIntegrator.abstol    = optionsIntegrator.abstol;         catch, optionsIntegrator.abstol = 1e-6;         end
+try optionsIntegrator.reltol    = optionsIntegrator.reltol;         catch, optionsIntegrator.reltol = 1e-6;         end
+
+% Handle multiple dosings / obsTimes
+if ischar(model),
+    model = IQMmodel(model);
+end
+if ~iscell(dosings),
+    dosings = {dosings};
+end
+for k=1:length(dosings),
+    if ischar(dosings{k}),
+        dosings{k} = IQMdosing(dosings{k});
+    end
+end
+if ~iscell(obsTimes),
+    obsTimes = {obsTimes};
+end
+if length(dosings) ~= length(obsTimes),
+    error('Number of provided dosing scenarios and number of provided observation time vectors need to match.');
+end
+if ~iscell(output),
+    output = {output};
+end
+
+% Generate moddos and MEX model
+% Use one dosing ... need to be the same structure, only different times
+% and doses are allowed
+moddos      = mergemoddosIQM(model,dosings{1});
+mexModel    = IQMmakeTempMEXmodel(moddos);
+
+% Get population parameters for model
+parameters = IQMsampleNLMEfitParam(projectFolder,0,0);
+paramNames  = parameters.parameterNames;
+paramValues = parameters.parameterValuesPopulation;
+
+% Check that parameters in all fits are available in the model
+modelparamnames = IQMparameters(moddos);
+for k2=1:length(paramNames),
+    ix = strmatchIQM(paramNames{k2}, modelparamnames, 'exact');
+    if isempty(ix),
+        error('IQMassessInformationContent: Parameters provided in the fit results ("projectFolder") need to be present in the structural model ("model").');
+    end
+end
+
+% Simulate nominal PK parameters for all provided dosing schemes and 
+% concatenate results 
+output_nominal = [];
+for k=1:length(dosings),
+    % Search for Tinfinput and Tlaginput parameter names and if 0 then exchange to 1e-10
+    % Otherwise numerical problems!
+    ixxx                    = strmatchIQM('Tk0input',paramNames);
+    for kxxx=1:length(ixxx),
+        xxx = paramValues(:,ixxx(kxxx));
+        xxx(xxx<=2e-10) = 1e-10;
+        paramValues(:,ixxx(kxxx)) = xxx;
+    end
+    ixxx                    = strmatchIQM('Tinfinput',paramNames);
+    for kxxx=1:length(ixxx),
+        xxx = paramValues(:,ixxx(kxxx));
+        xxx(xxx<=2e-10) = 1e-10;
+        paramValues(:,ixxx(kxxx)) = xxx;
+    end
+    ix = strmatchIQM('Tlag',paramNames);
+    for klag=1:length(ix),
+        if paramValues(ix(klag)) < 1e-10,
+            paramValues(ix(klag)) = 0;
+        end
+    end    
+    y = IQMsimdosing(mexModel,dosings{k},obsTimes{k},[],paramNames,paramValues,optionsIntegrator);
+    for k2=1:length(output),
+        output_nominal_k = y.variablevalues(:,variableindexIQM(moddos,output{k2}));
+        output_nominal = [output_nominal(:); output_nominal_k(:)];
+    end
+end
+
+% Simulate single perturbed parameters (use all parameters in the model)
+% for all provided dosing schemes and concatenate results 
+output_pert    = [];
+for k=1:length(paramNames),
+    % Get parameter to perturb and new value
+    paramName               = paramNames{k};
+    paramValuePert          = paramValues(k)*(1+pertSize/100);
+    % Construct new full perturbed parameter vector
+    paramValues_Pert        = paramValues;
+    paramValues_Pert(k)     = paramValuePert;
+    
+    % Simulate all dosing scenarios
+    output_pert_k = [];
+    for k2=1:length(dosings),
+        % Search for Tinfinput and Tlaginput parameter names and if 0 then exchange to 1e-10
+        % Otherwise numerical problems!
+        ixxx                    = strmatchIQM('Tk0input',paramNames);
+        for kxxx=1:length(ixxx),
+            xxx = paramValues(:,ixxx(kxxx));
+            xxx(xxx<=2e-10) = 1e-10;
+            paramValues(:,ixxx(kxxx)) = xxx;
+        end
+        ixxx                    = strmatchIQM('Tinfinput',paramNames);
+        for kxxx=1:length(ixxx),
+            xxx = paramValues(:,ixxx(kxxx));
+            xxx(xxx<=2e-10) = 1e-10;
+            paramValues(:,ixxx(kxxx)) = xxx;
+        end
+        ix = strmatchIQM('Tlag',paramNames);
+        for klag=1:length(ix),
+            if paramValues(ix(klag)) < 1e-10,
+                paramValues(ix(klag)) = 0;
+            end
+        end
+        y                   = IQMsimdosing(mexModel,dosings{k2},obsTimes{k2},[],paramNames,paramValues_Pert,optionsIntegrator);
+        for k3=1:length(output),
+            output_pert_k2      = y.variablevalues(:,variableindexIQM(moddos,output{k3}));
+            output_pert_k       = [output_pert_k(:); output_pert_k2(:)];
+        end
+    end
+
+    % Collect output
+    output_pert             = [output_pert output_pert_k];
+end
+
+% Calculate sensitivity trajectories
+% Normalize by perturbation size
+% Expand output_nominal
+output_nominal_expanded = output_nominal(:,ones(1,length(paramNames)));
+% Normalized sensitivity
+Sn = 100*(output_pert - output_nominal_expanded)./output_nominal_expanded/pertSize*100;
+
+% Calculate metric
+meanSensitivity   = nanmeanIQM(abs(Sn));
+
+% Prepare output to file if needed
+IQMstartNewPrintFigure(filename);
+
+% Display sensitivities
+figure(1); clf
+bar([1:length(meanSensitivity)],meanSensitivity);
+paramNamesPlot = paramNames;
+set(gca,'XTickLabel',paramNamesPlot)
+grid on;
+set(gca,'FontSize',12)
+xlabel('Parameters','FontSize',14);
+ylabel('Normalized sensitivities [%]','FontSize',14);
+IQMprintFigure(gcf,filename)
+
+% Assess correlation of the most important parameters
+ix_important        = find(abs(meanSensitivity) >= sensThreshold);
+param_corr_Names    = paramNames(ix_important);
+X = [];
+for k=1:length(param_corr_Names),
+    ix = strmatchIQM(param_corr_Names{k},paramNames,'exact');
+    X(:,k) = Sn(:,ix);
+end
+% Remove rows in which NaNs appear
+[rowNaN,colNaN] = find(isnan(X));
+X(rowNaN,:) = [];
+corr_param = abs(corrcoef(X));
+
+% Plot results
+figure(2); clf;
+pcolor([corr_param zeros(length(corr_param),1); zeros(1,length(corr_param)) 0])
+axis square;
+colorbar('EastOutside');
+set(gca,'XTick',[1.5:length(param_corr_Names)+0.5]);
+set(gca,'XTickLabel',param_corr_Names);
+set(gca,'YTick',[1.5:length(param_corr_Names)+0.5]);
+set(gca,'YTickLabel',param_corr_Names);
+colormap('Bone');
+set(gca,'FontSize',12)
+title('Predicted correlations of parameters with significant impact','FontSize',14,'Interpreter','none');
+IQMprintFigure(gcf,filename)
+
+% Close export to file
+IQMconvert2pdf(filename);
+if ~isempty(filename),
+    close all
+end
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/09-NLMEtools/IQMbootstrap.m b/IQMtools V1.2.2.2/IQMpro/tools/09-NLMEtools/IQMbootstrap.m
new file mode 100644
index 0000000000000000000000000000000000000000..5718972395e7ab5cac99cd2c60380645616ec8aa
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/09-NLMEtools/IQMbootstrap.m	
@@ -0,0 +1,354 @@
+function [] = IQMbootstrap(projectPath,options)
+% IQMbootstrap: runs a bootstrap analysis on the provided NLME project folder.
+% The provided NLME fit is used as the reference. NSAMPLES bootstrap fits
+% are generated and run. Stratification for dataset resampling is possible
+% along a single column in the dataset.
+%
+% The results are plotted and stored as a PDF. 95% confidence intervals and
+% medians are shown for the bootstrap results. For the reference model the
+% point estimate and its 95% confidence interval are shown.
+%
+% Additionally to the plots a text file with tabular information is
+% generated.
+%
+% The names for the output files can not be chosen. They are
+% "bootstrap_results.pdf" and "bootstrap_results.txt" and are stored in the
+% output path (see optional arguments below).
+%
+% Fits that lead to an objective function of NaN are assumed to be "crashed
+% fits" and are excluded from the bootstrap result generation.
+%
+% [SYNTAX]
+% [] = IQMbootstrap(projectPath)
+% [] = IQMbootstrap(projectPath,options)
+%
+% [INPUT]
+% projectPath:      Path to the NONMEM or MONOLIX project that should be bootstrapped
+% options:          Matlab structure with optional information
+%   options.NO_RUNNING            =1: does not re-run the parameter
+%                                 estimation but assumes that bootstrap
+%                                 models already have been executed and
+%                                 only produces the output. (default: 0 =>
+%                                 create and run the bootstrap models)
+%   options.path                  Path where to store the bootstrap
+%                                 projects (default: './BOOTSTRAPPATH')
+%   options.outputpath            Path for storage of results - PDF and
+%                                 Text files (default: './BOOTSTRAPPATH')  
+%   options.NSAMPLES              Number of bootstrap samples (default: 200)
+%   options.GROUP                 String with group name to use for
+%                                 stratification (some column name in the
+%                                 dataset that contains categorical
+%                                 information). Can be set to '' (empty) if
+%                                 stratification not desired (default: '')   
+%   options.N_PROCESSORS_PAR:     Number of parallel model runs (default: as specified in SETUP_PATHS_TOOLS_IQMPRO)
+%   options.N_PROCESSORS_SINGLE:  Number of processors to parallelize
+%                                 single run (if NLME tool capable to do
+%                                 so) (default: 1)
+%
+% [OUTPUT]
+% Graphical output in PDF. Additionally, a text file with tabular
+% information.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle variable input arguments
+if nargin<2,
+    options = [];
+end
+
+% Handle bootstrap settings
+try NO_RUNNING              = options.NO_RUNNING;             catch, NO_RUNNING            = 0;                    end
+try bootstrappath           = options.path;                   catch, bootstrappath         = './BOOTSTRAPPATH';    end
+try NSAMPLES                = options.NSAMPLES;               catch, NSAMPLES              = 200;                  end
+try GROUP                   = options.GROUP;                  catch, GROUP                 = '';                   end
+try outputpath              = options.outputpath;             catch, outputpath            = bootstrappath;        end
+try N_PROCESSORS_PAR        = options.N_PROCESSORS_PAR;       catch, N_PROCESSORS_PAR      = getN_PROCESSORS_PARIQM();                    end
+try N_PROCESSORS_SINGLE     = options.N_PROCESSORS_SINGLE;    catch, N_PROCESSORS_SINGLE   = 1;                    end
+
+% Parse project header
+if isNLMEprojectIQM(projectPath),
+    projectHeader   = parseNLMEprojectHeaderIQM(projectPath);
+    TOOL            = projectHeader.TOOL;
+    projectfile     = projectHeader.projectFile;
+else
+    error('Given project path does not point to an NLME project.');
+end
+
+% Only do the following if NO_RUNNING==0
+if NO_RUNNING==0,
+    % Create bootstrap project folder
+    oldpath = pwd;
+    try, rmdir(bootstrappath,'s'); catch, end
+    mkdir(bootstrappath);
+    
+    % Create TEMPLATE project in bootstrappath
+    % - Copying the projectPath without RESULTS
+    mkdir([bootstrappath '/TEMPLATE']);
+    copyfile(projectPath,[bootstrappath '/TEMPLATE'])
+    try rmdir([bootstrappath '/TEMPLATE/RESULTS'],'s'); catch end
+    mkdir([bootstrappath '/TEMPLATE/RESULTS']);
+    
+    % Updating template project file with new data path and filename
+    oldpath = pwd();
+    cd([bootstrappath '/TEMPLATE']);
+    content = fileread(projectfile);
+    % Replace the data path with './data.csv'
+    content = strrep(content,projectHeader.DATA{1},'./data.csv');
+    
+    % Handle monolix thing extra
+    if isMONOLIXprojectIQM(projectPath),
+        [p,f,e] = fileparts(projectHeader.DATA{1});
+        content = strrep(content,[p '/'],'.');
+        content = strrep(content,p,'.');
+        content = strrep(content,[f e],'data.csv');
+    end
+    
+    % Write out new control file
+    fid     = fopen(projectfile,'w');
+    fprintf(fid,'%s',content);
+    fclose(fid);
+    cd(oldpath);
+    
+    % Loading the original data
+    oldpath = pwd(); cd(projectPath);
+    dataCSV = IQMloadCSVdataset(projectHeader.DATA{1});
+    cd(oldpath);
+    
+    % Check that 'ID' and 'GROUP' present as columns in the data
+    varNames = dataCSV.Properties.VariableNames;
+    ix = strmatchIQM('ID',varNames,'exact');
+    if isempty(ix),
+        error('No ID column present in the dataset.');
+    end
+    if ~isempty(GROUP),
+        ix = strmatchIQM(GROUP,varNames,'exact');
+        if isempty(ix),
+            error('The specified GROUP is not present as column in the dataset.');
+        end
+    end
+    
+    % Create all bootstrap models
+    % Get processors
+    N_PROCESSORS_NEEDED = min(N_PROCESSORS_PAR,NSAMPLES);
+    killMATLABpool = startParallelIQM(N_PROCESSORS_NEEDED);
+    
+    % Create models
+    parfor k=1:NSAMPLES,
+        % Define path for model
+        modelpath = [bootstrappath sprintf('/MODEL_%s',preFillCharIQM(k,length(num2str(NSAMPLES)),'0'))];
+        % Copy the template
+        copyfile([bootstrappath '/TEMPLATE'],modelpath);
+        % Resample the dataset
+        dataCSV_resampled = IQMresampleDataset(dataCSV,'ID',GROUP);
+        % Export resampled dataset to folder
+        IQMexportCSVdataset(dataCSV_resampled,[modelpath '/data.csv']);
+    end
+    % Release processors
+    stopParallelIQM(killMATLABpool);
+    
+    % Remove TEMPLATE folder
+    try rmdir([bootstrappath '/TEMPLATE'],'s'); catch end
+    
+    % Run all the models
+    % Do not produce GoF Plots for all fits!
+    IQMrunNLMEprojectFolder(bootstrappath,N_PROCESSORS_PAR,N_PROCESSORS_SINGLE,1);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get results from original model (reference model)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+REFERENCE           = parseNLMEprojectResults(projectPath);
+
+% Get all parameter names (same in reference and bootstrap models)
+fef_names           = REFERENCE.rawParameterInfo.fixedEffects.names;
+ref_names           = REFERENCE.rawParameterInfo.randomEffects.names;
+cor_names           = REFERENCE.rawParameterInfo.correlation.names;
+cov_names           = REFERENCE.rawParameterInfo.covariate.names;
+err_names           = REFERENCE.rawParameterInfo.errorParameter.names;
+
+% Get reference values (called nominal values)
+fef_value_nominal   = REFERENCE.rawParameterInfo.fixedEffects.values;
+ref_value_nominal   = REFERENCE.rawParameterInfo.randomEffects.values;
+cor_value_nominal   = REFERENCE.rawParameterInfo.correlation.values;
+cov_value_nominal   = REFERENCE.rawParameterInfo.covariate.values;
+err_value_nominal   = REFERENCE.rawParameterInfo.errorParameter.values;
+
+% Get reference standard errors (called nominal values)
+fef_stderr_nominal  = REFERENCE.rawParameterInfo.fixedEffects.stderr;
+ref_stderr_nominal  = REFERENCE.rawParameterInfo.randomEffects.stderr;
+cor_stderr_nominal  = REFERENCE.rawParameterInfo.correlation.stderr;
+cov_stderr_nominal  = REFERENCE.rawParameterInfo.covariate.stderr;
+err_stderr_nominal  = REFERENCE.rawParameterInfo.errorParameter.stderr;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get results from bootstrap models
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Parse results
+RESULTS             = parseProjectFolderResultsIQM(bootstrappath);
+
+% Get bootstrap resulting values
+fef_value_resampled = NaN(length(RESULTS),length(fef_value_nominal));
+ref_value_resampled = NaN(length(RESULTS),length(ref_value_nominal));
+cor_value_resampled = NaN(length(RESULTS),length(cor_value_nominal));
+cov_value_resampled = NaN(length(RESULTS),length(cov_value_nominal));
+err_value_resampled = NaN(length(RESULTS),length(err_value_nominal));
+
+for k=1:length(RESULTS),
+    if ~isempty(RESULTS(k).rawParameterInfo),
+        if ~isempty(RESULTS(k).rawParameterInfo.fixedEffects.values),
+            fef_value_resampled(k,:) = RESULTS(k).rawParameterInfo.fixedEffects.values;
+        end
+        if ~isempty(RESULTS(k).rawParameterInfo.randomEffects.values),
+            ref_value_resampled(k,:) = RESULTS(k).rawParameterInfo.randomEffects.values;
+        end
+        if ~isempty(RESULTS(k).rawParameterInfo.correlation.values),
+            cor_value_resampled(k,:) = RESULTS(k).rawParameterInfo.correlation.values;
+        end
+        if ~isempty(RESULTS(k).rawParameterInfo.covariate.values),
+            cov_value_resampled(k,:) = RESULTS(k).rawParameterInfo.covariate.values;
+        end
+        if ~isempty(RESULTS(k).rawParameterInfo.errorParameter.values),
+            err_value_resampled(k,:) = RESULTS(k).rawParameterInfo.errorParameter.values;
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Remove all crashed fits (defined by NaN)
+% Nominal fit not allowed to be crashed
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ix_crashed                          = find(isnan([RESULTS.OBJ]));
+fef_value_resampled(ix_crashed,:)   = [];
+ref_value_resampled(ix_crashed,:)   = [];
+cor_value_resampled(ix_crashed,:)   = [];
+cov_value_resampled(ix_crashed,:)   = [];
+err_value_resampled(ix_crashed,:)   = [];
+NSAMPLES_NOT_CRASHED                = size(fef_value_resampled,1);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Generate output for results
+% A figure with subplots will be done for each category.
+%  - Plotting histogram
+%  - Highlighting the 5% and 95% CI based on bootstraps
+%  - Plotting nominal point estimate and 5%/95% of CI
+%  - Textual representation of RSE based on nominal and bootstrap
+% Additionall a table is produced with the same information
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Prepare output file
+filename = [outputpath '/bootstrap_results'];
+
+% Get colors
+colors   = IQMgetcolors();
+
+% Initialize figure
+IQMstartNewPrintFigure(filename);
+
+% Initialize table
+tableText            = cell(1,6);
+tableText(end+1,1:2) = {'<TT>' sprintf('Bootstrap results')};
+tableText(end+1,:)   = {'<TH>' 'Parameter' 'Model estimate' 'Bootstrap median' 'Model 95% CI' 'Bootstrap 95% CI'};
+
+type_all            = {'Fixed Effects'     'Random Effects'        'Correlations'          'Covariates'            'Error Model'        };
+names_all           = {fef_names,           ref_names,              cor_names,              cov_names,              err_names           };
+value_nominal_all   = {fef_value_nominal,   ref_value_nominal,      cor_value_nominal,      cov_value_nominal,      err_value_nominal   };
+stderr_nominal_all  = {fef_stderr_nominal,  ref_stderr_nominal,     cor_stderr_nominal,     cov_stderr_nominal,     err_stderr_nominal  };
+value_resampled_all = {fef_value_resampled, ref_value_resampled,    cor_value_resampled,    cov_value_resampled,    err_value_resampled };
+
+for kk=1:length(names_all),
+    
+    names           = names_all{kk};
+    value_nominal   = value_nominal_all{kk};
+    stderr_nominal  = stderr_nominal_all{kk};
+    value_resampled = value_resampled_all{kk};
+    
+    % Define number of bins
+    NBINS           = ceil(max(NSAMPLES_NOT_CRASHED/50,10));
+    
+    if length(names) > 0,
+        % Remove parameters with stderr=0 (not estimated)
+        ix                      = find(stderr_nominal==0);
+        names(ix)               = [];
+        value_nominal(ix)       = [];
+        stderr_nominal(ix)      = [];
+        value_resampled(:,ix)   = [];
+        
+        figure(kk); clf
+        ncols                   = ceil(sqrt(length(names)));
+        nrows                   = ceil(length(names)/ncols);
+        for k=1:length(names),
+            subplot(nrows,ncols,k);
+            % Plot histogram
+            [n,x]               = hist(value_resampled(:,k),NBINS);
+            hh                  = bar(x,n/NSAMPLES_NOT_CRASHED); hold on
+            set(hh,'FaceColor',colors(1,:));
+            
+            % Set YLim to be fixed
+            YLim = get(gca,'YLim');
+            set(gca,'YLim',YLim);
+            
+            % Plot median based on bootstrap
+            q = quantileIQM(value_resampled(:,k),[0.025,0.5,0.975]);
+            plot(q(2)*[1 1],YLim,'-','LineWidth',3,'color',colors(2,:))
+            
+            % Plot median based on nominal fit
+            plot(value_nominal(k)*[1 1],YLim,'r--','LineWidth',3,'color',[0 0 0]);
+
+            % Plot 95% CI for bootstrap results
+            plot(q(1)*[1 1],YLim,'-','LineWidth',2,'color',colors(2,:))
+            plot(q(3)*[1 1],YLim,'-','LineWidth',2,'color',colors(2,:))
+
+            % Plot 95% CI for nominal fit results
+            plot((value_nominal(k)-1.96*stderr_nominal(k))*[1 1],YLim,'r--','LineWidth',2,'color',[0 0 0])
+            plot((value_nominal(k)+1.96*stderr_nominal(k))*[1 1],YLim,'r--','LineWidth',2,'color',[0 0 0])
+                    
+            % Update table
+            tableText(end+1,:)   = {'<TR>' names{k} sprintf('%10.4g',value_nominal(k)) sprintf('%10.4g',q(2)) sprintf('[%10.4g, %10.4g]',(value_nominal(k)-1.96*stderr_nominal(k)),(value_nominal(k)+1.96*stderr_nominal(k))) sprintf('[%10.4g, %10.4g]',q(1),q(3))};
+            
+            % Increase YLim by 30%
+            YLim = [0 YLim(2)*1.3];
+            set(gca,'YLim',YLim);
+            
+            XLim = get(gca,'XLim');
+            set(gca,'XLim',XLim);            
+
+            % Title
+            title(sprintf('%s',names{k}),'FontSize',14,'Interpreter','none');
+            % Determine CI for nominal and bootstrap
+            CI_nominal  = [(value_nominal(k)-1.96*stderr_nominal(k)) (value_nominal(k)+1.96*stderr_nominal(k))];
+            textInfo    = sprintf('Value, [95%% CI]:\nBT: %1.3g,[%1.3g,%1.3g]\nEST: %1.3g,[%1.3g,%1.3g]',q(2),q(1),q(3),value_nominal(k),CI_nominal(1),CI_nominal(2));
+            text(XLim(2),YLim(2),textInfo,'FontSize',10,'VerticalAlign','top','HorizontalAlign','right','Interpreter','none');
+            if k==1,
+                hh = legend(sprintf('Distribution (N=%d)',NSAMPLES_NOT_CRASHED),'Bootstrap median, 95% CI','Model estimate, 95% CI','Location','SouthEast');
+                set(hh,'FontSize',10);
+            end
+            grid off;
+            set(gca,'FontSize',12)
+        end
+        if kk < length(names_all),
+            tableText(end+1,1) = {'<HR>'};
+        end
+        IQMprintFigure(gcf,filename);
+    end
+end
+% Table footer
+tableText(end+1,1:2) = {'<TF>' sprintf('N=%d bootstrap samples were evaluable (objective function different from NaN).',NSAMPLES_NOT_CRASHED)};
+
+IQMconvert2pdf(filename)
+if ~isempty(filename),
+    close all
+end
+
+% Convert to text and display text 
+textDisplay = IQMconvertCellTable2ReportTable(tableText,'text');     
+disp(textDisplay);
+
+% Convert to report text and export to file if filename defined
+textReport = IQMconvertCellTable2ReportTable(tableText,'report');     
+IQMwriteText2File(textReport,[strrep(filename,'.txt','') '.txt']);
+
+
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/09-NLMEtools/IQMcompareModels.m b/IQMtools V1.2.2.2/IQMpro/tools/09-NLMEtools/IQMcompareModels.m
new file mode 100644
index 0000000000000000000000000000000000000000..46b17f6b9457b57878c12b9556f71b10dad72f1b
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/09-NLMEtools/IQMcompareModels.m	
@@ -0,0 +1,379 @@
+function [] = IQMcompareModels(projectFolders,models,output,dosings,obsTimes,options,covNames,catNames,data)
+% This function allows to compare the structural models for different
+% estimation results from NLME(NONMEM or MONOLIX). Useful for model selection when GOF
+% plots and other assessments suggest models are behaving very similar.
+%
+% The same structural model can be compared to several fits where this
+% model has been used. Alternatively, different structural model and
+% respective fits can be compared. In this case as many structural models
+% need to be defined as NLME(NONMEM or MONOLIX) project folders. Same order.
+%
+% It is not a VPC. The user just provides the structural model and the
+% dosing scheme to simulate. Along with parameter fits (all parameters need
+% to be in the fit but can be switched off by setting them to 0 etc.)
+%
+% Additionally, the user needs to provide a time vector for the
+% observations, the variable name in the model to compare. Etc.
+% 
+% A plot is returned, comparing the models.
+%
+% Idea: use clinically relevant dosing schedule and observation points. If
+% models do look similar, then no clinically relevant difference might be
+% present. Not only PK but also PD might be of interest! It's just a
+% supporting function and does not mean that the user can switch of the
+% brain ;-)
+%
+% [SYNTAX]
+% [] = IQMcompareModels(projectFolders,models,output,dosings,obsTimes)
+% [] = IQMcompareModels(projectFolders,models,output,dosings,obsTimes,options)
+% [] = IQMcompareModels(projectFolders,models,output,dosings,obsTimes,options,covNames,catNames,data)
+%
+% [INPUT]
+% projectFolders:   Cell-array with the names of the NLME(NONMEM or MONOLIX) project
+%                   folders for which to compare the models. The elements
+%                   need to include the full/relative path to the models
+% models:           Either a single structural model fitting to all the
+%                   NLME(NONMEM or MONOLIX) fits, defined in the projectFolders argument.
+%                   Or a cell-array with as many IQMmodels as entries in the
+%                   projectFolders argument. In this case each model will
+%                   be paired with the corresponding NLME(NONMEM or MONOLIX) project. Same
+%                   order needs to be used.
+% output:           String with the name of the model variable to compare
+%                   In the case of multiple models the same output name
+%                   needs to be present.
+% dosings:          Dosing scheme to simulate the model for or cell-array. If cell-array then 
+%                   each entry will be paired with each project
+% obsTimes:         Observation times to compare the models at
+% covNames:         Cell-array with continous covariate names to take into
+%                   account (only done if the modelfit uses these)
+% catNames:         Cell-array with categorical covariate names to take into
+%                   account (only done if the modelfit uses these)
+% data:             MATLAB dataset which was used for model fitting. Standard
+%                   IQM dataset is assumed. The columns with the
+%                   specified covariate names have to exist
+%                   Alternatively, the path to the datafile can be
+%                   specified
+%
+% options:          Matlab structure with optional information
+%       options.N_PROCESSORS:       Number of processors for parallel computation (default: as specified in SETUP_PATHS_TOOLS_IQMPRO)
+%
+%                                   If N_PROCESSORS>1 then parallel nodes are requested via the matlabpool
+%                                   command. N_PROCESSORS models will then be run in parallel.
+%
+%
+%       options.Nsim                Number of samples from IIV
+%                                   distributions (default: 500). If
+%                                   Nsim=1 it will be set to Nsim=2 - that
+%                                   small values anyway dont really make
+%                                   sense but Nsim=1 would be messy and
+%                                   lead to an error
+%       options.quantiles           Vector with quantiles to compute for
+%                                   comparison (does only make sense if
+%                                   Nsim reasonably large) (default: [0.05 0.95])
+%       options.logY                =1: log Y axis, =0: linear Y axis
+%       options.minY                Lower limit for Y-axis, e.g. LLOQ for PK
+%       options.plotData            =0 no (by default); =1 yes
+%       options.optionsIntegrator   options for the integration.
+%                                   By default: abstol=1e-6, reltol=1e-6
+%
+% [OUTPUT]
+% Plots - comparing the models.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle variable input arguments
+if nargin<7,
+    options = [];
+end
+if nargin<7,
+    covNames = {};
+end
+if nargin<8,
+    catNames = {};
+end
+if nargin<9,
+    data = table();
+end
+
+% Handle options
+try Nsim                        = options.Nsim;                 catch, Nsim                     = 500;              end
+try quantiles                   = options.quantiles;            catch, quantiles                = [0.05 0.95];      end
+try logY                        = options.logY;                 catch, logY                     = 1;                end
+try minY                        = options.minY;                 catch, minY                     = [];               end
+try plotData                    = options.plotData;             catch, plotData                 = 0;                end
+try optionsIntegrator           = options.optionsIntegrator;    catch, optionsIntegrator        = [];               end
+try optionsIntegrator.abstol    = optionsIntegrator.abstol;     catch, optionsIntegrator.abstol = 1e-6;             end
+try optionsIntegrator.reltol    = optionsIntegrator.reltol;     catch, optionsIntegrator.reltol = 1e-6;             end
+try N_PROCESSORS                = options.N_PROCESSORS;         catch, N_PROCESSORS             = getN_PROCESSORS_PARIQM();                end
+
+% Handle single/multiple models
+if ~iscell(models),
+    % Create models variable as cell-array with as many entries as projectFolders
+    model = models;
+    models = {};
+    for k=1:length(projectFolders),
+        models{k} = model;
+    end
+    MULTIPLE_STRUCTURAL_MODELS = 0;
+else
+    % Check that same number of models and projects
+    if length(models) ~= length(projectFolders),
+        error('Number of provided models (if more than 1) need to be the same as number of NLME(NONMEM or MONOLIX) fits in projectFolders.');
+    end
+    MULTIPLE_STRUCTURAL_MODELS = 1;
+end
+
+% Handle single/multiple dosing
+if ~iscell(dosings),
+    % Create models variable as cell-array with as many entries as projectFolders
+    dosing = dosings;
+    dosings = {};
+    for k=1:length(projectFolders),
+        dosings{k} = dosing;
+    end
+else
+    % Check that same number of models and projects
+    if length(dosings) ~= length(projectFolders),
+        error('Number of provided dosings (if more than 1) need to be the same as number of NLME(NONMEM or MONOLIX) fits in projectFolders.');
+    end
+end
+
+
+% Check if IQMmodels or chars - and convert if needed
+modeldefs = models;
+models = {};
+for k=1:length(modeldefs),
+    if ischar(modeldefs{k}),
+        models{k} = IQMmodel(modeldefs{k});
+    elseif isIQMmodel(modeldefs{k}),
+        models{k} = modeldefs{k};
+    else
+        error('Unknown model definition.');
+    end
+end
+
+% Handle data
+if ischar(data),
+    % If not provided as dataset, then load it
+    data = IQMloadCSVdataset(data);
+end
+
+% Handle dosing
+for k=1:length(dosings),
+    if ischar(dosings{k}),
+        % If not provided as dataset, then load it
+        dosings{k} = IQMdosing(dosings{k});
+    end
+end
+
+% Adjust Nsim if needed
+if Nsim==1,
+    Nsim = 2;
+end
+
+% Handle logY
+if logY==1,
+    plotType = 'semilogy';
+else
+    plotType = 'plot';
+end
+
+% Get colors
+[colors,lines]  = IQMgetcolors();
+
+% Merge model and create MEX model
+moddos = {};
+mexMODEL = {};
+for k=1:length(models),
+    moddos{k} = mergemoddosIQM(models{k},dosings{k});
+    IQMmakeMEXmodel(moddos{k},['mexModel_' num2str(k)]);
+    mexMODEL{k} = ['mexModel_' num2str(k)];
+end
+
+% Check cov / cat / data
+if ~isempty(covNames) && isempty(data),
+    error('Continuous covariate names provided but no data to get the covariates from.');
+end
+if ~isempty(catNames) && isempty(data),
+    error('Categorical covariate names provided but no data to get the covariates from.');
+end
+if isempty(catNames) && isempty(covNames) && ~isempty(data),
+    error('Data for covariates was provided but no covariate names.');
+end
+
+% If data and covariates provided, sample from the covariates
+if ~isempty(data),
+    dataCOV = table();
+    dataCAT = table();
+    allID = unique(data.ID);
+    firstRowData = table();
+    for k=1:length(allID),
+        datak = data(data.ID==allID(k),:);
+        firstRowData = [firstRowData; datak(1,:)];
+    end
+    for k=1:length(covNames),
+        dataCOV.(covNames{k}) = firstRowData.(covNames{k});
+    end
+    for k=1:length(catNames),
+        dataCAT.(catNames{k}) = firstRowData.(catNames{k});
+    end
+    NdataSubjects = height(dataCOV);
+    sampleCovariateDosingIX = ceil(NdataSubjects*rand(1,Nsim));
+    if ~isempty(dataCOV),
+        COVvaluesSampled = table2array(dataCOV(sampleCovariateDosingIX,:));
+    else
+        COVvaluesSampled = [];
+        covNames = {};
+    end
+    if ~isempty(dataCAT),
+        CATvaluesSampled = table2array(dataCAT(sampleCovariateDosingIX,:));
+    else
+        CATvaluesSampled = [];
+        catNames = {};
+    end        
+end
+
+% Sample parameters for all models
+parametersALL   = {};
+% If no data is provided
+if isempty(data),
+    % Data was not provided, do not consider covariates!
+    for k=1:length(projectFolders),
+        parametersALL{k} = IQMsampleNLMEfitParam(projectFolders{k},0,Nsim);
+    end
+else
+    % Data was provided! Do consider covariates
+    for k=1:length(projectFolders),
+        parametersALL{k} = IQMsampleNLMEfitParam(projectFolders{k},0,Nsim, covNames, COVvaluesSampled, catNames, CATvaluesSampled );
+    end
+end
+
+% Check that parameters in all fits are available in the models
+if MULTIPLE_STRUCTURAL_MODELS == 0,
+    % single model, multiple fits
+    modelparamnames = IQMparameters(moddos{1});
+    for k=1:length(parametersALL),
+        paramNamesFit = parametersALL{k}.parameterNames;
+        for k2=1:length(paramNamesFit),
+            ix = strmatchIQM(paramNamesFit{k2}, modelparamnames, 'exact');
+            if isempty(ix),
+                error('IQMcompareModels: Parameters provided in the fit results ("projectFolders") need to be present in the structural model ("model").');
+            end
+        end
+    end
+else
+    % multiple models, multiple fits
+    for k0=1:length(moddos),
+        modelparamnames = IQMparameters(moddos{k0});
+        paramNamesFit   = parametersALL{k0}.parameterNames;
+        for k2=1:length(paramNamesFit),
+            ix = strmatchIQM(paramNamesFit{k2}, modelparamnames, 'exact');
+            if isempty(ix),
+                error('IQMcompareModels: Parameters provided in the fit results ("projectFolders") need to be present in the structural model ("model").');
+            end
+        end
+    end
+end
+
+% Request processors
+killMATLABpool = startParallelIQM(N_PROCESSORS);
+
+% Simulate all models for all samples
+quantileInfoALL_sampled = {};
+medianInfoALL_sampled = {};
+for k=1:length(projectFolders),
+    disp(sprintf('Simulating individual parameters for model %d from %d ...',k,length(projectFolders)));
+    parameters = parametersALL{k};
+    paramNames = parameters.parameterNames;
+    % Get space for simulation results
+    outputALL  = NaN(length(obsTimes),Nsim);
+    parfor k2=1:Nsim,
+        paramValuesIndiv = parameters.parameterValuesIndividual(k2,:);
+        % Need to adjust the TlaginputX parameter in case it is 1e-10 => set to 0
+        ix = strmatchIQM('Tlaginput',paramNames);
+        for kkk=1:length(ix),
+            if paramValuesIndiv(ix(kkk)) < 2e-10,
+                paramValuesIndiv(ix(kkk)) = 1e-10;
+            end   
+        end
+        ix = strmatchIQM('Tk0input',paramNames);
+        for kkk=1:length(ix),
+            if paramValuesIndiv(ix(kkk)) < 2e-10,
+                paramValuesIndiv(ix(kkk)) = 1e-10;
+            end   
+        end
+        % Simulate the model
+        simres = IQMsimdosing(mexMODEL{k},dosings{k},obsTimes,[],paramNames,paramValuesIndiv,optionsIntegrator);    
+        % Get output
+        outputALL(:,k2) = simres.variablevalues(:,variableindexIQM(moddos{k},output));
+    end
+    % Get the statistics
+    quantileInfoALL_sampled{k} = quantileIQM(outputALL',quantiles);
+    medianInfoALL_sampled{k} = quantileIQM(outputALL',0.5);
+end
+
+% Release processors
+stopParallelIQM(killMATLABpool);
+
+% Remove mexModel
+clear mex
+for k=1:length(mexMODEL),
+    warning off;
+    delete([mexMODEL{k} '.' mexext]);
+    warning on;
+end
+
+% Plot the results
+figure(1); clf;
+legendText = {};
+for k=1:length(projectFolders),
+    % Plot population mean
+    x = obsTimes;
+    y = medianInfoALL_sampled{k};
+    if logY,
+        ix = find(y<0);
+        x(ix) = [];
+        y(ix) = [];
+    end
+    feval(plotType,x,y,lines{k},'Color',colors(k,:),'LineWidth',3); hold on
+    % create legend text
+    legendText{end+1} = sprintf('%s, Median',projectFolders{k});
+
+    % Plot sampled results
+    quantileInfo = quantileInfoALL_sampled{k};
+    for k2=1:length(quantiles),
+        x = obsTimes;
+        y = quantileInfo(k2,:);
+        if logY,
+            ix = find(y<0);
+            x(ix) = [];
+            y(ix) = [];
+        end
+        
+        % Plot quantiles for sampling
+        feval(plotType,x,y,lines{k},'Color',colors(k,:)); hold on
+        % create legend text
+        legendText{end+1} = sprintf('%s, Quantile: %g',projectFolders{k},quantiles(k2));
+    end
+end
+legend(legendText,'Location','best','Interpreter','none');
+set(gca,'FontSize',12);
+grid on;
+xlabel('Time','FontSize',14);
+ylabel(output,'FontSize',14,'Interpreter','none');
+title('Comparison of different models','FontSize',14,'Interpreter','none');
+
+% Overlay the data
+if plotData,
+    plot(data.TIME,data.DV,'o','MarkerFaceColor','k'); hold on
+end
+
+% Pre-specified limits for Y-axis
+YLim = get(gca,'YLim');
+if ~isempty(minY),
+    axis([min(obsTimes) max(obsTimes) minY YLim(2)]);
+else
+    axis([min(obsTimes) max(obsTimes) get(gca,'YLim')]);
+end
+
+legend(legendText,'Location','Best','Interpreter','none');
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/09-NLMEtools/IQMcovariateAssessmentUncertainty.m b/IQMtools V1.2.2.2/IQMpro/tools/09-NLMEtools/IQMcovariateAssessmentUncertainty.m
new file mode 100644
index 0000000000000000000000000000000000000000..686278a8e3b79626e1cfce4f5a902922af6f1d6d
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/09-NLMEtools/IQMcovariateAssessmentUncertainty.m	
@@ -0,0 +1,553 @@
+function [] = IQMcovariateAssessmentUncertainty(pathNLMEproject,filename,options)
+% This function assesses the changes that a covariates introduces on the
+% model parameters, relative to a reference individual. Uncertainty in the
+% estimated fixed effect parameters and covariate coefficients is
+% considered.
+%
+% Per model parameter that is changed by covariates, one plot is done.
+% Showing the uncertainty range for the parameter and the impact of the
+% covariates on this parameter. The horizontal lines correspond to the 95%
+% confidence intervals.
+%
+% [SYNTAX]
+% [] = IQMcovariateAssessmentUncertainty(pathNLMEproject)
+% [] = IQMcovariateAssessmentUncertainty(pathNLMEproject,filename)
+% [] = IQMcovariateAssessmentUncertainty(pathNLMEproject,filename,options)
+%
+% [INPUT]
+% pathNLMEproject:   Relative path to the NONMEM or MONOLIX project
+%                    folder for which to assess the covariates.
+% filename:          Filename to where to export the results (PDF). If
+%                    empty ('') then no PDF is created. Additionally a text
+%                    file is created with the information as a table.
+% options:           Matlab structure with optional information
+%       options.Nsamples:           How many samples should be taken from
+%                                   the uncertainty distributions. This
+%                                   number should be much larger than the
+%                                   number of individuals in the analysis
+%                                   dataset, so the covariate information
+%                                   in the dataset is well sampled.
+%                                   (default: 100000)
+%       options.ClinicalRelevanceLow:  Lower boundary of a grey box around 1 (default: 0.8)
+%       options.ClinicalRelevanceHigh: Upper boundary of a grey box around 1 (default: 1.25)
+%                                   This grey box is drawn around the nominal value of 1 and 
+%                                   allows a visual feedback of potential clinical relevance.
+%                                   
+% [OUTPUT]
+% Output of one figure per parameter.
+% If filename specified, then output written to file PDF file and as a text
+% file with tabular information.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle variable input arguments
+if nargin<2,
+    filename = '';
+end
+if nargin<3,
+    options = [];
+end
+
+% Handle optional arguments
+try ClinicalRelevanceLow        = options.ClinicalRelevanceLow;     catch, ClinicalRelevanceLow         = 0.8;              end
+try ClinicalRelevanceHigh       = options.ClinicalRelevanceHigh;    catch, ClinicalRelevanceHigh        = 1.25;             end
+try Nsamples                    = options.Nsamples;                 catch, Nsamples                     = 100000;           end
+
+% Get analysis dataset
+header          = parseNLMEprojectHeaderIQM(pathNLMEproject);
+analysisDataset = header.DATA{1};
+oldpath         = pwd(); 
+cd(pathNLMEproject);
+data            = IQMloadCSVdataset(analysisDataset);
+cd(oldpath);
+    
+% Load info from NLME fit to get covariate information
+if isMONOLIXprojectIQM(pathNLMEproject),
+    x = parseMONOLIXresultsIQM(pathNLMEproject);
+    % Remove the non-estimated covariates
+    ix_remove = find(x.rawParameterInfo.covariate.estimated == 0);
+    x.rawParameterInfo.covariate.estimated(ix_remove) = [];
+    x.rawParameterInfo.covariate.names(ix_remove) = [];
+    x.rawParameterInfo.covariate.rse(ix_remove) = [];
+    x.rawParameterInfo.covariate.stderr(ix_remove) = [];
+    x.rawParameterInfo.covariate.values(ix_remove) = [];    
+    y = sampleMONOLIXpopulationParametersIQM(x,0,0);
+elseif isNONMEMprojectIQM(pathNLMEproject),
+    transformFLAG = 1;
+    x = parseNONMEMresultsIQM(pathNLMEproject,transformFLAG);
+    % Remove the non-estimated covariates
+    ix_remove = find(x.rawParameterInfo.covariate.estimated == 0);
+    x.rawParameterInfo.covariate.estimated(ix_remove) = [];
+    x.rawParameterInfo.covariate.names(ix_remove) = [];
+    x.rawParameterInfo.covariate.rse(ix_remove) = [];
+    x.rawParameterInfo.covariate.stderr(ix_remove) = [];
+    x.rawParameterInfo.covariate.values(ix_remove) = [];
+    y = sampleNONMEMpopulationParametersIQM(x,0,0);
+else
+    error('Unknown project type.');
+end
+
+% Get covariate estimates and standard errors to compute the 5%/95% CI
+info                            = x.rawParameterInfo.covariate;
+covariateInfo                   = [];
+covariateInfo.Names             = {};
+covariateInfo.ParameterName     = {};
+covariateInfo.CovariateName     = {};
+covariateInfo.betaValue         = []; 
+covariateInfo.betaStderror      = []; 
+
+for k2=1:length(info.names),
+    % Get parametername and covariate name for the parameter estimate
+    xx = strrep(info.names{k2},'beta_','');
+    xx = strrep(xx,')','');
+    xx = explodePCIQM(xx,'(','#','$');
+    covariateInfo.Names{k2}             = info.names{k2};
+    covariateInfo.ParameterName{k2}     = xx{1};
+    covariateInfo.CovariateName{k2}     = xx{2};
+    covariateInfo.betaValue(k2)         = info.values(k2);
+    covariateInfo.betaStderror(k2)      = info.stderr(k2);
+end
+
+% Get parameter names and values
+parameterInfo           = [];
+parameterInfo.Names     = x.rawParameterInfo.fixedEffects.names;
+parameterInfo.Values    = x.rawParameterInfo.fixedEffects.values;
+parameterInfo.Stderror  = x.rawParameterInfo.fixedEffects.stderr;
+
+% Get expanded and matched THETA values
+covariateInfo.ParameterValues = [];
+for k=1:length(covariateInfo.ParameterName),
+    ix = strmatchIQM(covariateInfo.ParameterName{k},parameterInfo.Names,'exact');
+    covariateInfo.ParameterValues(k) = parameterInfo.Values(ix);
+    covariateInfo.ParameterStderror(k) = parameterInfo.Stderror(ix);
+end
+
+% Determine the covariates names
+covNames = {};
+for k=1:length(y.covariates.continuous),
+	covNames = [covNames y.covariates.continuous(k).covariates];
+end
+covNames = unique(covNames);
+catNames = {};
+for k=1:length(y.covariates.categorical),
+	catNames = [catNames y.covariates.categorical(k).covariates];
+end
+catNames = unique(catNames);
+
+% Get info vector defining cov or cat
+covariateInfo.TypeCov = [];
+for k=1:length(covariateInfo.CovariateName),
+    ix = strmatchIQM(covariateInfo.CovariateName{k},covNames,'exact');
+    if ~isempty(ix),
+        covariateInfo.TypeCov(k) = 1;
+    else
+        covariateInfo.TypeCov(k) = 0;
+    end
+end
+
+% Get transformation functions for parameters
+covariateInfo.IndivTransF = {};
+covariateInfo.IndivTransFinv = {};
+for k=1:length(covariateInfo.ParameterName),
+    ix = strmatchIQM(covariateInfo.ParameterName{k},y.randomEffects.names,'exact');
+    covariateInfo.IndivTransF{k} = y.randomEffects.transformation{ix};
+    covariateInfo.IndivTransFinv{k} = y.randomEffects.inv_transformation{ix};
+end
+
+% Get transformation functions for covariates
+covariateInfo.COVtrans = {};
+aaa = [y.covariates.continuous.covariates];
+bbb = [y.covariates.continuous.formula];
+for k=1:length(covariateInfo.CovariateName),
+    if covariateInfo.TypeCov(k) == 0,
+        % Categorical
+        covariateInfo.COVtrans{k} = [];
+    else
+        % Continuous
+        ix = strmatch(covariateInfo.CovariateName{k},aaa,'exact');
+        covariateInfo.COVtrans{k} = bbb{ix(1)};
+    end
+end
+
+% Get info from dataset about continuous and categorical covariates
+allID = unique(data.ID);
+covValuesALL = [];
+catValuesALL = [];
+for k=1:length(allID),
+    datak = data(data.ID==allID(k),:);
+    row = datak(1,:);
+    covValuesRow = [];
+    for k2=1:length(covNames),
+        covValuesRow(k2) = row.(covNames{k2});
+    end
+    covValuesALL = [covValuesALL; covValuesRow];
+    catValuesRow = [];
+    for k2=1:length(catNames),
+        catValuesRow(k2) = row.(catNames{k2});
+    end
+    catValuesALL = [catValuesALL; catValuesRow];
+end
+
+% Get info about the 5 and 95% quantiles of the continuous covariates
+quantileCOV_05 = quantileIQM(covValuesALL,0.05);
+quantileCOV_95 = quantileIQM(covValuesALL,0.95);
+covariateInfo.covQuantile_05 = NaN(1,length(covariateInfo.CovariateName));
+covariateInfo.covQuantile_95 = NaN(1,length(covariateInfo.CovariateName));
+% Add these info into covariateInfo structure
+for k=1:length(covariateInfo.CovariateName),
+    for k2=1:length(covNames),
+        % Find covname in structure - positions
+        ix = strmatchIQM(covNames{k2},covariateInfo.CovariateName,'exact');
+        covariateInfo.covQuantile_05(ix) = quantileCOV_05(k2);
+        covariateInfo.covQuantile_95(ix) = quantileCOV_95(k2);
+    end
+end
+
+% Determine median for cov and unique elements for cat
+if ~isempty(covValuesALL),
+    medianCov = nanmedianIQM(covValuesALL);
+else
+    medianCov = NaN;
+end
+catElements = {};
+for k=1:length(catNames),
+    catElements{k} = unique(catValuesALL(:,k));
+end
+
+% Determine reference subjects properties
+referenceSubject = [];
+referenceSubject.covNames = covNames;
+referenceSubject.covValues = medianCov;
+referenceSubject.catNames = catNames;
+referenceSubject.catValues = [];
+for k=1:length(catNames),
+    dummy = unique(covariateInfo.CovariateName);
+    ix = strmatchIQM(catNames{k},dummy);
+    number = [];
+    for k2=1:length(ix),
+        % find last occurrence of "_" then take the things behind that
+        ix2 = strfind(dummy{ix(k2)},'_');
+        number(k2) = str2num(dummy{ix(k2)}(ix2(end)+1:end));
+    end
+    % Get reference element
+    referenceSubject.catValues(k) = setdiff(catElements{k},number);
+end
+
+% Sample parameters from uncertainty distribution (assume normal distribution)
+% No need to consider correlations because each parameter is considered
+% independently of the others
+covariateInfo.ParameterSampled = [];
+covariateInfo.ParameterSampledNormalized = [];
+for k=1:length(covariateInfo.ParameterValues),
+    covariateInfo.ParameterSampled(:,k) = covariateInfo.ParameterValues(ones(1,Nsamples),k)+covariateInfo.ParameterStderror(k)*randn(Nsamples,1);
+    covariateInfo.ParameterSampledNormalized(:,k) = covariateInfo.ParameterSampled(:,k)/covariateInfo.ParameterValues(k);
+end
+
+% Sample betas from uncertainty distribution (assume normal distribution)
+covariateInfo.betaSampled = [];
+for k=1:length(covariateInfo.betaValue),
+    covariateInfo.betaSampled(:,k) = covariateInfo.betaValue(ones(1,Nsamples),k)+covariateInfo.betaStderror(k)*randn(Nsamples,1);
+end
+
+% Transform the covariates in the dataset - all values - continuous only
+covariateInfo.covariateDataTransformed = NaN(Nsamples,length(covariateInfo.CovariateName));
+covariateInfo.covariateData = NaN(Nsamples,length(covariateInfo.CovariateName));
+for k=1:length(covariateInfo.CovariateName),
+    if covariateInfo.TypeCov(k) == 1,
+        % Continuous
+        ix = strmatch(covariateInfo.CovariateName{k},covNames,'exact');
+        covValuesk = covValuesALL(:,ix);
+        covValuesTransformedk = eval(strrep(covariateInfo.COVtrans{k},'cov','covValuesk'));
+        % Sample Nsamples from the covValuesTransformedk data - uniform sampling
+        ix2 = ceil(length(covValuesTransformedk)*rand(1,Nsamples));
+        covariateInfo.covariateDataTransformed(:,k) = covValuesTransformedk(ix2);
+        covariateInfo.covariateData(:,k) = covValuesk(ix2);
+    end 
+end    
+
+% Transform the 5% and 95% quantiles of the continuous covariates
+covariateInfo.covQuantile_05_Transformed = NaN(1,length(covariateInfo.CovariateName));
+covariateInfo.covQuantile_95_Transformed = NaN(1,length(covariateInfo.CovariateName));
+for k=1:length(covariateInfo.CovariateName),
+    if covariateInfo.TypeCov(k) == 1,
+        % Continuous
+        covariateInfo.covQuantile_05_Transformed(k) = eval(strrep(covariateInfo.COVtrans{k},'cov','covariateInfo.covQuantile_05(k)'));
+        covariateInfo.covQuantile_95_Transformed(k) = eval(strrep(covariateInfo.COVtrans{k},'cov','covariateInfo.covQuantile_95(k)'));
+    end 
+end    
+
+% Calculate mu - same for all - for sampled parameters
+covariateInfo.mu = [];
+for k=1:length(covariateInfo.ParameterName),
+    covariateInfo.mu(:,k) = eval(strrep(covariateInfo.IndivTransFinv{k},'psi','covariateInfo.ParameterSampled(:,k)'));
+end
+
+% Handle covariates to determine the range of the parameters when using the sampling, normalized by the point
+% estimate for the reference subject (population mean)
+covariateInfo.ParamValueRangeNormalized = NaN(Nsamples,length(covariateInfo.TypeCov));
+for k=1:length(covariateInfo.TypeCov),
+    if covariateInfo.TypeCov(k) == 0,
+        covariatePHIcategorical = covariateInfo.mu(:,k)+covariateInfo.betaSampled(:,k);
+        covariatePSIcategorical = eval(strrep(covariateInfo.IndivTransF{k},'phi','covariatePHIcategorical'));
+        covariateInfo.ParamValueRangeNormalized(:,k) = covariatePSIcategorical/covariateInfo.ParameterValues(k);
+    else
+        covariatePHIcontinuous = covariateInfo.mu(:,k) + covariateInfo.betaSampled(:,k).*covariateInfo.covariateDataTransformed(:,k);
+        covariatePSIcontinuous = eval(strrep(covariateInfo.IndivTransF{k},'phi','covariatePHIcontinuous'));
+        covariateInfo.ParamValueRangeNormalized(:,k) = covariatePSIcontinuous/covariateInfo.ParameterValues(k);
+    end
+end
+
+% Determine the range of the parameters for 5/95% quantiles of continuous covariates
+% estimate for the reference subject (population mean)
+covariateInfo.ParamValueRangeNormalized_05 = NaN(Nsamples,length(covariateInfo.TypeCov));
+covariateInfo.ParamValueRangeNormalized_95 = NaN(Nsamples,length(covariateInfo.TypeCov));
+for k=1:length(covariateInfo.TypeCov),
+    if covariateInfo.TypeCov(k) == 1,
+        % Only for continuous covariates
+        covariatePHIcontinuous_05 = covariateInfo.mu(:,k) + covariateInfo.betaSampled(:,k).*covariateInfo.covQuantile_05_Transformed(:,k);
+        covariatePHIcontinuous_95 = covariateInfo.mu(:,k) + covariateInfo.betaSampled(:,k).*covariateInfo.covQuantile_95_Transformed(:,k);
+        covariatePSIcontinuous_05 = eval(strrep(covariateInfo.IndivTransF{k},'phi','covariatePHIcontinuous_05'));
+        covariatePSIcontinuous_95 = eval(strrep(covariateInfo.IndivTransF{k},'phi','covariatePHIcontinuous_95'));
+        covariateInfo.ParamValueRangeNormalized_05(:,k) = covariatePSIcontinuous_05/covariateInfo.ParameterValues(k);
+        covariateInfo.ParamValueRangeNormalized_95(:,k) = covariatePSIcontinuous_95/covariateInfo.ParameterValues(k);
+    end
+end
+
+% Prepare output to file
+IQMstartNewPrintFigure(filename);
+
+% Plot the results
+% Do one figure per parameter
+parametersPlot = unique(covariateInfo.ParameterName);
+for k=1:length(parametersPlot),
+    parameter = parametersPlot{k};
+    % Get indices which to handle
+    ix = strmatchIQM(parameter,covariateInfo.ParameterName,'exact');
+    % Open figure
+    handle = figure(k); clf;
+    % Create the data to plot
+    % Start with handling the sampled parameter - but use only first samples (ix(1))...
+    plotData = covariateInfo.ParameterSampledNormalized(:,ix(1));
+    plotData = plotData(:);
+    groupData = ones(length(plotData),1);
+    colorData = ones(length(plotData),1);
+    PlotData_changeWhiskers = plotData(:);
+    
+    % Now handle all the covariate data on this parameter
+    count = 1;
+    for k2=1:length(ix),
+        
+        % If continuous then also add the 05/95% quantileIQM information
+        if covariateInfo.TypeCov(ix(k2)) == 1,
+            % Whole covariate range
+            plotData  = [plotData; covariateInfo.ParamValueRangeNormalized(:,ix(k2))];
+            groupData = [groupData; (count+1)*ones(length(covariateInfo.ParamValueRangeNormalized(:,ix(k2))),1)];
+            colorData = [colorData; 2*ones(length(covariateInfo.ParamValueRangeNormalized(:,ix(k2))),1)];
+            PlotData_changeWhiskers = [PlotData_changeWhiskers covariateInfo.ParamValueRangeNormalized(:,ix(k2))];
+            count     = count+1;
+
+            % 5% quantileIQM
+            plotData  = [plotData; covariateInfo.ParamValueRangeNormalized_05(:,ix(k2))];
+            groupData = [groupData; (count+1)*ones(length(covariateInfo.ParamValueRangeNormalized_05(:,ix(k2))),1)];
+            colorData = [colorData; 3*ones(length(covariateInfo.ParamValueRangeNormalized_05(:,ix(k2))),1)];
+            PlotData_changeWhiskers = [PlotData_changeWhiskers covariateInfo.ParamValueRangeNormalized_05(:,ix(k2))];
+            count     = count+1;
+    
+            % 95% quantileIQM
+            plotData  = [plotData; covariateInfo.ParamValueRangeNormalized_95(:,ix(k2))];
+            groupData = [groupData; (count+1)*ones(length(covariateInfo.ParamValueRangeNormalized_95(:,ix(k2))),1)];
+            colorData = [colorData; 3*ones(length(covariateInfo.ParamValueRangeNormalized_95(:,ix(k2))),1)];
+            PlotData_changeWhiskers = [PlotData_changeWhiskers covariateInfo.ParamValueRangeNormalized_95(:,ix(k2))];
+            count     = count+1;
+        else
+            % Categorical covariate element
+            plotData  = [plotData; covariateInfo.ParamValueRangeNormalized(:,ix(k2))];
+            groupData = [groupData; (count+1)*ones(length(covariateInfo.ParamValueRangeNormalized(:,ix(k2))),1)];
+            colorData = [colorData; 4*ones(length(covariateInfo.ParamValueRangeNormalized(:,ix(k2))),1)];
+            PlotData_changeWhiskers = [PlotData_changeWhiskers covariateInfo.ParamValueRangeNormalized(:,ix(k2))];
+            count     = count+1;
+        end
+    end
+    
+    % Add 20% box
+    YLimMin = 0.5;
+    YLimMax = 0.5+length(unique(groupData));
+    IQMplotfill([ClinicalRelevanceLow ClinicalRelevanceHigh],YLimMin*[1 1],YLimMax*[1 1],0.9*[1 1 1],1); hold on;
+    
+    % Plot data
+    optionsBoxplot                      = [];
+    optionsBoxplot.verticalFlag         = 0;
+    optionsBoxplot.outliers             = 0;
+    optionsBoxplot.boxWidth             = 0.05;
+    optionsBoxplot.filled               = 1;
+    optionsBoxplot.whiskerPercentiles   = [2.5 97.5];
+    optionsBoxplot.axisij               = 1;
+    boxplotIQM(plotData,groupData,optionsBoxplot);
+    
+    % Need to define before boxplot to place the ticks correctly
+    axis square;
+    axis ij;
+
+    % Add line at X=1
+    hold on;
+    YLim = get(gca,'YLim');
+    plot([1 1],YLim,'k--');
+   
+    % Set Ylabels
+    ylabeltext = {};
+    % Parameter
+    ylabeltext{1} = ['Typical ' parameter];
+    
+    % Covariates
+    count = 1;
+    for k2=1:length(ix),
+        if covariateInfo.TypeCov(ix(k2)) == 1,
+            % Handle continuous covariate
+            % Get min and max values for covariate
+            minCov = min(covariateInfo.covariateData(:,ix(k2)));
+            maxCov = max(covariateInfo.covariateData(:,ix(k2)));
+            % Overall cov range effect on parameter
+            ylabeltext{1+count} = sprintf('%s (min-max: %g-%g)',covariateInfo.CovariateName{ix(k2)},minCov,maxCov);
+            count = count + 1;
+            
+            % 5% cov quantileIQM effect on parameter
+            ylabeltext{1+count} = sprintf('%s (5%%: %g)',covariateInfo.CovariateName{ix(k2)},covariateInfo.covQuantile_05(ix(k2)));
+            count = count + 1;
+
+            % 95% cov quantileIQM effect on parameter
+            ylabeltext{1+count} = sprintf('%s (95%%: %g)',covariateInfo.CovariateName{ix(k2)},covariateInfo.covQuantile_95(ix(k2)));
+            count = count + 1;
+        else
+            % Handle categorical covariate
+            ix2 = strfind(covariateInfo.CovariateName{ix(k2)},'_');
+            covcatName  = covariateInfo.CovariateName{ix(k2)}(1:ix2(end)-1);
+            covcatGroup = covariateInfo.CovariateName{ix(k2)}(ix2(end)+1:end);
+            ylabeltext{1+count} = sprintf('%s = %s',covcatName,covcatGroup);
+            count = count + 1;
+        end
+    end
+    
+    % Add yticklabeltext
+    set(gca,'YTick',[1:count+1]);
+    set(gca,'YTickLabel',ylabeltext);
+    set(gca,'YGrid','on')
+    
+    % Add xlabel etc.
+    xlabel('Change in parameter relative to reference individual','FontSize',12);
+    set(gca,'FontSize',12)
+    % Add title text with reference individual
+    titleText = sprintf('Covariate effects on parameter %s\nTypical individual:\n',parameter);
+    xxtext = '';
+    for k2=1:length(referenceSubject.covNames),
+        xxtext = sprintf('%s%s=%g, ',xxtext,referenceSubject.covNames{k2},referenceSubject.covValues(k2));
+    end
+    titleText = sprintf('%s%s, ',titleText,xxtext(1:end-2));
+    xxtext = '';
+    for k2=1:length(referenceSubject.catNames),
+        xxtext = sprintf('%s%s=%g, ',xxtext,referenceSubject.catNames{k2},referenceSubject.catValues(k2));
+    end
+    if ~isempty(referenceSubject.catNames),
+        titleText = sprintf('%s%s',titleText,xxtext(1:end-2));
+    else 
+        titleText = titleText(1:end-2);
+    end
+    title(titleText,'FontSize',12,'FontWeight','bold','Interpreter','none');
+    
+%     ylabel(sprintf('Covariate distribution in dataset (min/max, 5%%/95%%) & Nominal\n \n '),'FontSize',12);
+    
+    % Export to figure if wanted
+    if ~isempty(filename),
+        IQMprintFigure(gcf,filename);
+        close(handle);
+    end
+end
+
+% Stop figure export
+IQMconvert2pdf(filename);
+
+
+%%%%%%%%%%%%%%%%%%%%%%
+% Create Table
+%%%%%%%%%%%%%%%%%%%%%%
+PARAM = unique(covariateInfo.ParameterName);
+% Header and range of parameter values
+titleText = '';
+xxtext = '';
+for k2=1:length(referenceSubject.covNames),
+    xxtext = sprintf('%s%s=%g, ',xxtext,referenceSubject.covNames{k2},referenceSubject.covValues(k2));
+end
+titleText = sprintf('%s%s, ',titleText,xxtext(1:end-2));
+xxtext = '';
+for k2=1:length(referenceSubject.catNames),
+    xxtext = sprintf('%s%s=%g, ',xxtext,referenceSubject.catNames{k2},referenceSubject.catValues(k2));
+end
+if ~isempty(referenceSubject.catNames),
+    titleText = sprintf('%s%s',titleText,xxtext(1:end-2));
+else
+    titleText = titleText(1:end-2);
+end
+
+tableText = cell(1,2+length(PARAM));
+tableText(1,1:2) = {'<TT>' sprintf('Results of analysis of covariate impact on parameters relative to typical individual:\n%s',titleText)};
+tableText(2,:) = {'<TH>' '' PARAM{:}};
+tableText(3,1:2) = {'<TR>' ''};
+tableText(3,3:end) = {'2.5% / median / 97.5%'};
+tableText(4,1) = {'<HR>'};
+tableText(5,1) = {'<TR>'};
+tableText{5,2} = sprintf('Non-normalized value');
+for k=1:length(PARAM),
+    ix = strmatchIQM(PARAM{k},covariateInfo.ParameterName,'exact');
+    x  = covariateInfo.ParameterSampled(:,ix(1));
+    tableText{5,2+k} = sprintf('%1.4g / %1.4g / %1.4g*',quantileIQM(x,0.025),quantileIQM(x,0.5),quantileIQM(x,0.975));
+end
+tableText(6,1) = {'<HR>'};
+
+% Now add the normalized covariate things
+for k=1:length(covariateInfo.ParameterName),
+    % Find column to add
+    ixCol = strmatchIQM(covariateInfo.ParameterName{k},PARAM,'exact')+2;
+    
+    if covariateInfo.TypeCov(k) == 1,
+        % Continuous covariate
+        % Get text for first column
+        text05 = sprintf('%s (5%%: %g)',covariateInfo.CovariateName{k},covariateInfo.covQuantile_05(k));
+        text95 = sprintf('%s (95%%: %g)',covariateInfo.CovariateName{k},covariateInfo.covQuantile_95(k));
+        % Get row numbers
+        ixRow05 = strmatchIQM(text05,tableText(:,2),'exact');
+        ixRow95 = strmatchIQM(text95,tableText(:,2),'exact');        
+        if isempty(ixRow05),
+            ixRow05 = size(tableText,1)+1;
+            ixRow95 = size(tableText,1)+2;
+        end
+        x05 = covariateInfo.ParamValueRangeNormalized_05(:,k);
+        x95 = covariateInfo.ParamValueRangeNormalized_95(:,k);
+        tableText{ixRow05,1} = '<TR>';
+        tableText{ixRow95,1} = '<TR>';
+        tableText{ixRow05,2} = text05;
+        tableText{ixRow95,2} = text95;
+        tableText{ixRow05,ixCol} = sprintf('%1.4g / %1.4g / %1.4g**',quantileIQM(x05,0.025),quantileIQM(x05,0.5),quantileIQM(x05,0.975));
+        tableText{ixRow95,ixCol} = sprintf('%1.4g / %1.4g / %1.4g**',quantileIQM(x95,0.025),quantileIQM(x95,0.5),quantileIQM(x95,0.975));
+    else
+        % Categorical covariate
+        % Get text for first column
+        text = sprintf('%s',covariateInfo.CovariateName{k});
+        % Get row number
+        ixRow = strmatchIQM(text,tableText(:,2),'exact');
+        if isempty(ixRow),
+            ixRow = size(tableText,1)+1;
+        end
+        tableText{ixRow,1} = '<TR>';
+        tableText{ixRow,2} = text;
+        x = covariateInfo.ParamValueRangeNormalized(:,k);
+        tableText{ixRow,ixCol} = sprintf('%1.4g / %1.4g / %1.4g**',quantileIQM(x,0.025),quantileIQM(x,0.5),quantileIQM(x,0.975));
+    end
+end
+tableText(end+1,1:2) = {'<TF>' sprintf('*Parameter value and 95 percent uncertainty range for reference subject.\n**Values have been normalized by the median of the non-normalized value (reference subject).')};
+
+% Convert to text and display text 
+textDisplay = IQMconvertCellTable2ReportTable(tableText,'text');
+disp(textDisplay);
+%%
+% Convert to report text and export to file if filename defined
+IQMconvertCellTable2ReportTable(tableText,'report',filename);     
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/09-NLMEtools/IQMcreateVPC.m b/IQMtools V1.2.2.2/IQMpro/tools/09-NLMEtools/IQMcreateVPC.m
new file mode 100644
index 0000000000000000000000000000000000000000..487dc8c67fa97cf8e25e8ca058eed291af5fb667
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/09-NLMEtools/IQMcreateVPC.m	
@@ -0,0 +1,438 @@
+function [input_plot_VPC] = IQMcreateVPC(NLMEproject,model,data,outputsModel,outputsData,filename,options)
+% This function generates a VPC for a given NLMEproject. It requires the
+% additional input arguments "model", which is the structural model as an
+% IQMmodel object, used for generation of the NLMEproject file.
+% Additionally, a "data" set to determine observations and dosings for the
+% VPC. "outputModels" defines the names of states or variables in the model
+% for which VPCs should be generated. "outputsData" defines the NAMEs of
+% the events in the dataset that should be matched with outputModels.
+% "options" allows to define a range of optional arguments for both
+% plotting and simulation.
+%
+% This VPC function is intended for a single treatment group. Optionally,
+% it allows to create a dose normalized VPC, which only makes sense (in
+% most cases) for linear PK models when subjects have received the same
+% regimen and single dose levels. However, it will generate the VPC for any
+% data and included treatment groups. The user needs to know what (s)he
+% would like to do!
+%
+% This function handles also sequential 0th/1st order absorption. But
+% requires that the function isSequentialAbsorptionPopPKIQM can detect the
+% sequential thing. For this 1st order abs needs to be given as a bolus
+% with INPUT1 and 0th order as INPUT3. For the popPK workflow all is in
+% order ... when using it manually, then the user needs to take care.
+%
+% [SYNTAX]
+% [input_plot_VPC] = IQMcreateVPC(NLMEproject,model,data)
+% [input_plot_VPC] = IQMcreateVPC(NLMEproject,model,data,outputsModel,outputsData)
+% [input_plot_VPC] = IQMcreateVPC(NLMEproject,model,data,outputsModel,outputsData,filename)
+% [input_plot_VPC] = IQMcreateVPC(NLMEproject,model,data,outputsModel,outputsData,filename,options)
+%
+% [INPUT]
+% NLMEproject:      String with the name of the NLME project folder for
+%                   which to generate this VPC. 
+%                   Needs to include the absolute or relative path to the
+%                   folder. 
+% model:            Structural IQMmodel used for generation of the NLME
+%                   model (at least parameter names, regression parameters
+%                   and structure need to fit, additional variables can be
+%                   added.  
+% data:             Dataset for the VPC - covariates, regression parameters
+%                   and individual dosing schedules will be determined from
+%                   this dataset. For the simulation the correlation of
+%                   dosing schemes, covariates, and regression parameters
+%                   will be kept.
+% outputsModel:     String or cell-array of strings with outputs in the
+%                   model to consider for VPC generation. If left empty
+%                   ([]), then the outputs are determined from the NLME
+%                   project. However, if for PD the relative PD is to be
+%                   plotted and the absolute was fitted, then it is useful
+%                   if the names can be provided. 
+% outputsData:      String or cell-array of strings with outputs in the
+%                   data (NAME column) to match with the corresponding
+%                   outputsModel entries. 
+% filename:         If a filename is provided, the VPC results are exported
+%                   to a PDF file with this name (and path).
+%
+% options:          Matlab structure with optional information
+%           options.userDosing          If 0 order absorption present in
+%                                       model and the model not generated from the popPK workflow, then
+%                                       the user needs to provide an own dosing scheme here in this field.
+% 
+%       * General
+%           options.N_PROCESSORS_PAR    Number or processors (requires parallel toolbox) (default: as defined in SETUP_PATHS_TOOLS_IQMPRO) 
+%           options.NTRIALS             Number of TRIALS to simulate to determine simulation quantiles and confidence intervals. (default: 200) 
+%           options.QUANTILES           Vector with quantiles to compute for simulation and data (default: [0.05 0.95]) (90% variability)
+%           options.QUANTILES_CI        Vector with quantiles for the uncertainty of the QUANTILES (default: [0.025 0.975]) (95% CI)
+%           options.useNOMINAL_TIME     =0: Use actual observation and dose times 
+%                                       =1: Use nominal observation and dose times (default: 1)
+%                                       (for simulations observation and dosing times, and for plotting of observed data points)
+%
+%       * Simulation time point information
+%           options.nTimePoints         Number time points to simulate - spaced equidistantly. If set to empty ([]) then observation times are used. (default: 500) 
+%
+%       * Plot content
+%           options.doPlot              =0: no plot, =1: plot (default: 1)
+%           options.titleText           String with title text (default: '') (number of trials and subjects simulated will be added in second row in title)
+%           options.doseNormalized      =0: Do not do dose normalization (default: 0)
+%                                       =1: Do dose normalization (will divide DV with DOSE column and set AMT to 1. 
+%                                           TRT set to -1 and TRTNAME to 'DOSE NORMALIZED (across all treatment groups in the data)')  
+%                                       Mainly useful for linear PK model VPCs and same regimen across all treatment groups - with only different dose levels. 
+%           options.showLabels          =1: Shows subject IDs as data, =0: shows dots as data (default: 1)
+%           options.plotIndivLines      =1: Connect individual data points with lines (default: 0)
+%           options.showDataQuantiles   =1: Show lines for the observation quantiles (default: 0)
+%
+%       * Axes information
+%           options.logY                =1: log Y axis, =0: linear Y axis (default: 0)
+%           options.minX                Numeric value for lower value of X axis (default: not used)
+%           options.maxX                Numeric value for upper value of X axis (default: not used)
+%           options.minY                Numeric value for lower value of Y axis (default: not used)
+%           options.maxY                Numeric value for upper value of Y axis (default: not used)
+%
+%       * Binning information
+%           options.bins_mean           Vector with center values of bins to calculate data quantiles. If not 
+%                                       defined ([]), then bins_mean=NT of observations (default: [])
+%           options.bins_lookaround     Vector with values for positive and negative "lookaround" for quantile calculation 
+%                                       If not provided it is set to:
+%                                               bins_lookaround = diff(bins_mean) 
+%                                               bins_lookaround = [bins_lookaround(1); bins_lookaround(:)]/2
+%
+%       * Color settings
+%           options.colorMedianRange        Default: [1 0.9 0.8]
+%           options.colorQuantilesRange     Default: [0.8 1 0.8]
+%           options.colorData               Default: 0.2*[1 1 1]
+%           options.colorMedian             Default: [1 0.2 0]
+%
+%       * Integrator information
+%           options.optionsIntegrator   Options for the integration (See IQMmakeMEXmodel).
+%
+% [OUTPUT]
+% A MATLAB figure with the VPC - if desired exported to PDF.
+% input_plot_VPC: MATLAB structure, which can be used as input to the
+%                 function "IQMcreateVPCplot".
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle variable input arguments
+if nargin == 4,
+    error('When defining outputsModel also outputsData needs to be given as input argument.');
+end
+if nargin<4,
+    outputsModel = {};
+end
+if nargin<5,
+    outputsData = [];
+end
+if nargin<6,
+    filename = '';
+end
+if nargin<7,
+    options = [];
+end
+
+% Handle options
+try N_PROCESSORS_PAR    = options.N_PROCESSORS_PAR;     catch, N_PROCESSORS_PAR     = getN_PROCESSORS_PARIQM(); end 
+try NTRIALS         	= options.NTRIALS;              catch, NTRIALS              = 200;                      end 
+try QUANTILES           = options.QUANTILES;            catch, QUANTILES            = [0.05 0.95];              end 
+try QUANTILES_CI        = options.QUANTILES_CI;         catch, QUANTILES_CI         = [0.025 0.975];            end 
+try useNOMINAL_TIME     = options.useNOMINAL_TIME;      catch, useNOMINAL_TIME      = 1;                        end 
+try nTimePoints         = options.nTimePoints;          catch, nTimePoints          = 500;                      end 
+try doPlot              = options.doPlot;               catch, doPlot               = 1;                        end 
+try doseNormalized      = options.doseNormalized;       catch, doseNormalized       = 0;                        end 
+try optionsIntegrator   = options.optionsIntegrator;    catch, optionsIntegrator    = [];                       end 
+try titleText           = options.titleText;            catch, titleText            = '';                       end 
+try userDosing          = options.userDosing;           catch, userDosing           = [];                       end
+
+if length(QUANTILES)~=2,
+    error('QUANTILES option needs to have two values.');
+end
+if length(QUANTILES_CI)~=2,
+    error('QUANTILES_CI option needs to have two values.');
+end
+QUANTILES       = sort([QUANTILES 0.5]);
+QUANTILES_CI    = sort([QUANTILES_CI 0.5]);
+
+% Check data and return empty output argument if empty data or no
+% observations
+if isempty(data),
+    input_plot_VPC = titleText;
+    disp('Empty dataset provided to IQMcreateVPC function.');
+    return
+end
+
+if ischar(data),
+    data = IQMloadCSVdataset(data);
+end
+
+% Check if ADDL present and used - in this case: error
+showErrorADDL = 0;
+try
+    ADDL = data.ADDL;
+    % ADDL exists
+    if sum(ADDL>0) ~= 0,
+        showErrorADDL = 1;
+    end        
+catch
+    % ADDL does not exist - fine :) - so it does not need to be checked
+end
+if showErrorADDL,
+    error('ADDL column in dataset used to define additional doses. This is not handled in the VPC function.');
+end
+
+if ischar(userDosing),
+    userDosing = IQMdosing(userDosing);
+end
+
+if ischar(model),
+    model = IQMmodel(model);
+end
+
+if sum(data.MDV==0) == 0,
+    input_plot_VPC = titleText;
+    disp('Dataset provided to IQMcreateVPC function does not contain observations.');
+    return
+end    
+
+% Restore spaces in the dataset 
+data = restoreSpacesDataIQM(data);
+
+% Dose normalize the data if desired
+if doseNormalized,
+    if ~isempty(find(data.DOSE(data.EVID==0)==0)),
+        error('DOSE column contains 0 elements in observations. Dose normalization not done.');
+    end
+    data.DV                 = data.DV./data.DOSE;
+    data.AMT(data.EVID==1)  = 1;
+    data.TRT(1:end)         = -1;
+    data.TRTNAME(1:end)    = {'DOSE NORMALIZED (across all treatment groups in the data)'};
+end
+
+% % Check if multiple compounds present
+% if length(unique(data.NAME(data.EVID==1))) > 1,
+%     error('Multiple NAMEs for DOSES present in dataset. This is not allowed.');
+% end
+
+% Get the project header
+project_header          = parseNLMEprojectHeaderIQM(NLMEproject);
+
+% Handle outputs
+if isempty(outputsModel),
+    % Get outputs to simulate from the NLMEproject - if not defined by the user. 
+    outputsModel            = project_header.OUTPUTS;
+    ytypeData               = [1:length(outputsModel)];
+else
+    % Outputs defined by the user
+    % Fitting might be done on absolute PD, which is output of model for
+    % fitting but simulation might be done on relative PD, requiring user
+    % defined output.
+    
+    % Make cell of outputsModel if not a cell
+    if ~iscell(outputsModel),
+        outputsModel = {outputsModel};
+    end
+    % Make cell of outputsData if not a cell
+    if ~iscell(outputsData),
+        outputsData = {outputsData};
+    end    
+    % Checks and get ytypeData
+    if length(outputsData) ~= length(outputsModel),
+        error('Different numbers of entries for outputsData and outputsModel.');
+    end
+    ytypeData = [];
+    for k=1:length(outputsData),
+        ix = strmatchIQM(outputsData{k},data.NAME,'exact');
+        if isempty(ix),
+            error('outputData entry "%s" is not present in NAME column of dataset.',outputsData{k});
+        end
+        % Get YTYPE number
+        ytypeData(k) = data.YTYPE(ix(1));
+    end
+end
+
+% Get covariatenames (only the ones that have been used in the model)
+COVARIATESUSED          = project_header.COVARIATESUSED;    if length(COVARIATESUSED)==1 && isempty(COVARIATESUSED{1}), COVARIATESUSED  = {};       end
+COVNAMES                = project_header.COVNAMES;          if length(COVNAMES)==1 && isempty(COVNAMES{1}),             COVNAMES        = {};       end
+CATNAMES                = project_header.CATNAMES;          if length(CATNAMES)==1 && isempty(CATNAMES{1}),             CATNAMES        = {};       end
+covNames                = intersect(COVNAMES,COVARIATESUSED);
+catNames                = intersect(CATNAMES,COVARIATESUSED);
+
+% Get regression parameter names
+regNames                = project_header.REGRESSIONNAMES; if length(regNames)==1 && isempty(regNames{1}), regNames = {}; end
+
+% Get dosing types used in the model and mapping to ADM
+% Only allow BOLUS, INFUSION, and ABSORPTION0 for now
+DOSINGTYPES             = project_header.DOSINGTYPES;
+x                       = setdiff(DOSINGTYPES,{'BOLUS' 'INFUSION' 'ABSORPTION0'});
+if ~isempty(x),
+    error('Not supported dosing types used in the model. Supported: BOLUS, ABSORPTION0, and INFUSION.');
+end
+
+% In case that 0th order absorption is present, the user needs to provide
+% an own dosing scheme since it cannot automatically be decided if it is
+% sequential or parallel. If using the popPK VPC function then the correct
+% dosing scheme is already passed in the options.userDosing.
+useUserDosingScheme = 0;
+if ~isempty(strmatchIQM('ABSORPTION0',DOSINGTYPES,'exact')),
+    % Check if user provided a dosing scheme
+    if isempty(userDosing),
+        error('Your model contains 0th order absorption. You need to provide an own dosing scheme as options.userDosing!');
+    else
+        useUserDosingScheme = 1;
+    end
+end
+
+% Get first row of each subject
+allID = unique(data.USUBJID); firstRowData = table(); for k=1:length(allID), datak = data(ixdataIQM(data,'USUBJID',allID(k)),:); firstRowData = [firstRowData; datak(1,:)]; end
+
+% if regNames present then check if reg values change over time ... if yes then error
+if ~isempty(regNames),
+    for k=1:length(allID),
+        datak = data(ixdataIQM(data,'USUBJID',allID(k)),:);
+        for k2=1:length(regNames),
+            if length(unique(datak.(regNames{k2}))) ~= 1,
+                error('VPC function only handles non-time varying regression variables.');
+            end
+        end
+    end
+end
+
+% Determine covcatregdata for the simulation from firstRowData
+covcatregdata           = table(); covcatregnames = [{'USUBJID'} covNames catNames regNames]; 
+for k=1:length(covcatregnames), covcatregdata.(covcatregnames{k}) = firstRowData.(covcatregnames{k}); end
+
+% Get the dose data from the dataset:
+% Collect TIME, AMT, ADM and TINF information. If subject does not have a
+% dose, then set information to 0.
+% Use same allID as above to ensure same order of doses and covcatregdata
+dataDOSE    = data(data.EVID==1,:);
+dataDOSING  = [];
+for k=1:length(allID),
+    datak = dataDOSE(ixdataIQM(dataDOSE,'USUBJID',allID(k)),:);
+    if ~isempty(datak),
+        if useNOMINAL_TIME,
+            dataDOSING(k).TIME  = datak.NT; % Use nominal time
+            if ~isempty(find(isnan(datak.NT))),
+                error('Please check the nominal time information in your dataset - it might be missing (partly).\nAlternatively select the option "options.useNOMINAL_TIME=0".');
+            end
+        else
+            dataDOSING(k).TIME  = datak.TIME; % Use actual time
+        end
+        dataDOSING(k).DOSE  = datak.AMT;
+        dataDOSING(k).ADM   = datak.ADM;
+        dataDOSING(k).TINF  = datak.TINF;
+    else
+        dataDOSING(k).TIME  = 0;
+        dataDOSING(k).DOSE  = 0;
+        dataDOSING(k).ADM   = 1;
+        dataDOSING(k).TINF  = 1e-10; % Not 0 to avoid division by 0
+    end
+end
+
+% Determine the dosing schedules (order of dosing schedules matches the 
+% order of the covariates and for each dosing schedule the corresponding
+% set of covariates need to be used later in the simulation)
+
+% Cycle through dataDOSING and create dosing schemes
+dosings = {};
+for k=1:length(dataDOSING),
+    % Get empty dosing scheme with correct dosing types
+    if useUserDosingScheme,
+        ds = struct(userDosing);
+    else
+        ds = struct(IQMcreateDOSING(DOSINGTYPES));
+    end
+    
+    % Cycle through the inputs and fill them with content
+    for k2=1:length(DOSINGTYPES),
+        % Find the ADM doses in individual dosing information (k2
+        % corresponds to ADM in the dataset)
+        ix = find(dataDOSING(k).ADM==k2);
+        % Add the information into the dosing object
+        if ~isempty(ix),
+            ds.inputs(k2).time = dataDOSING(k).TIME(ix)';
+            ds.inputs(k2).D    = dataDOSING(k).DOSE(ix)';            
+        end
+        
+        if ~useUserDosingScheme,
+            ds.inputs(k2).Tlag = 0;
+        end
+        
+        % Parameters type dependent
+        if strcmp(DOSINGTYPES{k2},'BOLUS') && ~isempty(ix),
+            ds.inputs(k2).parameters = [];
+            % Check if potentially a sequential 0/1 order absorption
+            % This works fine with the popPK workflow.
+            if isSequentialAbsorptionPopPKIQM(NLMEproject),
+                ds.inputs(k2).Tlag = 'Tk0input3';
+            end
+        elseif strcmp(DOSINGTYPES{k2},'INFUSION') && ~isempty(ix),
+            TINF = dataDOSING(k).TINF(ix)';
+            TINF(TINF==0) = 0.0001; % Use small value similar to BOLUS if TINF=0 to avoid division by zero
+            ds.inputs(k2).parameters.value = TINF;
+        elseif strcmp(DOSINGTYPES{k2},'ABSORPTION0') && ~isempty(ix),
+            Tk0 = 0.0001; % Use small value similar to BOLUS if Tk0=0 to avoid division by zero
+            ds.inputs(k2).parameters.value = Tk0*ones(1,length(ds.inputs(k2).time));
+        elseif ~isempty(ix)
+            error('INPUT type "%s", provided in dosing scheme, not yet handled.',DOSINGTYPES{k2})
+        end
+    end
+    % Get dosing object
+    dosings{k} = IQMdosing(ds);
+end
+
+% Get observation data of interest only
+dataOBS = data(data.EVID==0,:);
+% Remove MDV=1
+dataOBS(dataOBS.MDV==1,:) = [];
+% Remove YTYPEs that are not in ytypeData
+remove_YTYPE = setdiff(unique(dataOBS.YTYPE),ytypeData);
+for k=1:length(remove_YTYPE),
+    dataOBS(dataOBS.YTYPE==remove_YTYPE(k),:) = [];
+end
+
+% Create observation time vector depending on settings
+if isempty(nTimePoints),
+    if useNOMINAL_TIME, 
+        obsTimes_simulation = unique(dataOBS.NT);
+    else
+        obsTimes_simulation = unique(dataOBS.TIME);
+    end
+else
+    if useNOMINAL_TIME, 
+        obsTimes_simulation = linspace(min(dataOBS.NT),max(dataOBS.NT),nTimePoints);
+    else
+        obsTimes_simulation = linspace(min(dataOBS.TIME),max(dataOBS.TIME),nTimePoints);
+    end
+end
+
+% Produce simulation results
+optionsSimulation                       = [];
+optionsSimulation.optionsIntegrator     = optionsIntegrator;
+optionsSimulation.NTRIALS               = NTRIALS;
+optionsSimulation.QUANTILESDATA         = QUANTILES;
+optionsSimulation.QUANTILESUNCERTAINTY  = QUANTILES_CI;
+optionsSimulation.KEEP_TRIAL_INDIVDATA  = 0;
+optionsSimulation.N_PROCESSORS_PAR      = N_PROCESSORS_PAR;
+optionsSimulation.NSUBJECTS             = length(dosings);
+simulation_result                       = IQMtrialGroupSimulation(model,dosings,NLMEproject,obsTimes_simulation,outputsModel,covcatregdata,optionsSimulation);
+
+% Construct VPC plot info
+input_plot_VPC                          = [];
+input_plot_VPC.simulation_result        = simulation_result;
+input_plot_VPC.data                     = data;
+input_plot_VPC.ytypeData                = ytypeData;
+if ~isempty(dataDOSE),
+    input_plot_VPC.doseUnit             = dataDOSE.UNIT{1};
+else
+    input_plot_VPC.doseUnit             = 'undefined';
+end
+input_plot_VPC.useNOMINAL_TIME          = useNOMINAL_TIME;
+input_plot_VPC.doseNormalized           = doseNormalized;
+input_plot_VPC.options                  = options;
+input_plot_VPC.titleText                = titleText;
+
+if doPlot,
+    % Call plotting function for VPC
+    IQMcreateVPCplot(input_plot_VPC,filename);
+end
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/09-NLMEtools/IQMcreateVPCplot.m b/IQMtools V1.2.2.2/IQMpro/tools/09-NLMEtools/IQMcreateVPCplot.m
new file mode 100644
index 0000000000000000000000000000000000000000..522208cbed58280c6780afa9830ab27f07836d9a
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/09-NLMEtools/IQMcreateVPCplot.m	
@@ -0,0 +1,251 @@
+function [] = IQMcreateVPCplot(input_plot_VPC,filename,options)
+% This function plots a VPC without the need to re-run the simulations. It
+% takes as input argument "input_plot_VPC", which is the output argument of
+% the IQMcreateVPC function and optional settings in "options".
+%
+% If the second input argument is not defined, options will be used from
+% the call to IQMcreateVPC. If options is provided the options stored in
+% the output of IQMcreateVPC are not used.
+%
+% [SYNTAX]
+% [] = IQMcreateVPCplot(input_plot_VPC)
+% [] = IQMcreateVPCplot(input_plot_VPC,filename)
+% [] = IQMcreateVPCplot(input_plot_VPC,filename,options)
+%
+% [INPUT]
+% input_plot_VPC:   Output argument of the IQMcreateVPC function. It can
+%                   also be a cell-array of the output arguments of
+%                   IQMcreateVPC. In this case all plots will be generated.
+%                   If options provided, they will be applied to all
+%                   elements in the cell-array.
+% filename:         If a filename is provided, the VPC results are exported
+%                   to a PDF file with this name (and path).
+% options:          Matlab structure with optional information
+%       * Plot content
+%           options.titleText           String with title text (default: '') (number of trials and subjects simulated will be added in second row in title)
+%           options.showLabels          =1: Shows subject IDs as data, =0: shows dots as data (default: 1)
+%           options.plotIndivLines      =1: Connect individual data points with lines (default: 0)
+%           options.showDataQuantiles   =1: Show lines for the observation quantiles (default: 0)
+%
+%       * Axes information
+%           options.logY                =1: log Y axis, =0: linear Y axis (default: 0)
+%           options.minX                Numeric value for lower value of X axis (default: not used)
+%           options.maxX                Numeric value for upper value of X axis (default: not used)
+%           options.minY                Numeric value for lower value of Y axis (default: not used)
+%           options.maxY                Numeric value for upper value of Y axis (default: not used)
+%
+%       * Binning information
+%           options.bins_mean           Vector with center values of bins to calculate data quantiles. If not 
+%                                       defined ([]), then bins_mean=NT of observations (default: [])
+%           options.bins_lookaround     Vector with values for positive and negative "lookaround" for quantile calculation 
+%                                       If not provided it is set to:
+%                                               bins_lookaround = diff(bins_mean) 
+%                                               bins_lookaround = [bins_lookaround(1); bins_lookaround(:)]/2
+%
+%       * Color settings
+%           options.colorMedianRange        Default: [1 0.9 0.8]
+%           options.colorQuantilesRange     Default: [0.8 1 0.8]
+%           options.colorData               Default: 0.2*[1 1 1]
+%           options.colorMedian             Default: [1 0.2 0]
+%
+% [OUTPUT]
+% A MATLAB figure with the VPC - if desired exported to PDF.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle main input
+if ~iscell(input_plot_VPC),
+    input_plot_VPC = {input_plot_VPC};
+end
+
+% Handle variable input arguments
+if nargin<2,
+    filename = '';
+end
+
+% Start new output file
+IQMstartNewPrintFigure(filename);
+
+% Loop through the things to plot
+for kInput=1:length(input_plot_VPC),
+    input_plot_VPC_k = input_plot_VPC{kInput};
+    
+    if ischar(input_plot_VPC_k),
+        figure();
+        title(sprintf('%s\nNo VPC produced, since either no data or no observations present in data.',input_plot_VPC_k),'Interpreter','none');
+        % Handle printing of figure
+        IQMprintFigure(gcf,filename)
+        if ~isempty(filename),
+            close(gcf);
+        end
+    else
+        
+        simulation_result       = input_plot_VPC_k.simulation_result;
+        data                    = input_plot_VPC_k.data;
+        ytypeData               = input_plot_VPC_k.ytypeData;
+        doseUnit                = input_plot_VPC_k.doseUnit;
+        useNOMINAL_TIME         = input_plot_VPC_k.useNOMINAL_TIME;
+        doseNormalized          = input_plot_VPC_k.doseNormalized;
+        titleText               = input_plot_VPC_k.titleText;
+        NTRIALS                 = simulation_result.NTRIALS;
+        NSUBJECTS               = simulation_result.NSUBJECTS;
+        NOUTPUTS                = length(simulation_result);
+        
+        % Handle variabe input arguments
+        if nargin<3,
+            options = input_plot_VPC_k.options;
+        end
+        
+        % Handle options
+        try showLabels          = options.showLabels;           catch, showLabels           = 1;                        end
+        try plotIndivLines      = options.plotIndivLines;       catch, plotIndivLines       = 0;                        end
+        try showDataQuantiles   = options.showDataQuantiles;    catch, showDataQuantiles    = 0;                        end
+        try logY                = options.logY;                 catch, logY                 = 0;                        end
+        try minX                = options.minX;                 catch, minX                 = [];                       end
+        try maxX                = options.maxX;                 catch, maxX                 = [];                       end
+        try minY                = options.minY;                 catch, minY                 = [];                       end
+        try maxY                = options.maxY;                 catch, maxY                 = [];                       end
+        try bins_mean           = options.bins_mean;            catch, bins_mean            = [];                       end
+        try bins_lookaround     = options.bins_lookaround;      catch, bins_lookaround      = [];                       end
+        try colorMedianRange    = options.colorMedianRange;     catch, colorMedianRange     = [1 0.9 0.8];              end
+        try colorQuantilesRange = options.colorQuantilesRange;  catch, colorQuantilesRange  = [0.8 1 0.8];              end
+        try colorData           = options.colorData;            catch, colorData            = 0.2*[1 1 1];              end
+        try colorMedian         = options.colorMedian;          catch, colorMedian          = [1 0.2 0];                end
+        
+        % Loop through the outputs
+        for kOUT=1:NOUTPUTS,
+            
+            % Initialize legend
+            legendText = {};
+            
+            % Create new figure for each output
+            figure();
+            
+            % Set Y axis transformation
+            if logY, set(gca,'YScale','log'); else set(gca,'YScale','linear'); end
+            
+            % Get simulated data
+            sim_output = simulation_result(kOUT);
+            
+            % Plot simulation results
+            IQMplotfill(sim_output.time,sim_output.quantilesData_uncertainty{1}(:,1),sim_output.quantilesData_uncertainty{1}(:,3),colorQuantilesRange,1); hold on;
+            legendText{end+1} = sprintf('Simulation - %1.3g Quantile [%g-%g]%%CI ',sim_output.QUANTILESDATA(1),100*sim_output.QUANTILESUNCERTAINTY(1),100*sim_output.QUANTILESUNCERTAINTY(3));
+            
+            IQMplotfill(sim_output.time,sim_output.quantilesData_uncertainty{3}(:,1),sim_output.quantilesData_uncertainty{3}(:,3),colorQuantilesRange,1); hold on;
+            legendText{end+1} = sprintf('Simulation - %1.3g Quantile [%g-%g]%%CI ',sim_output.QUANTILESDATA(3),100*sim_output.QUANTILESUNCERTAINTY(1),100*sim_output.QUANTILESUNCERTAINTY(3));
+            
+            IQMplotfill(sim_output.time,sim_output.quantilesData_uncertainty{2}(:,1),sim_output.quantilesData_uncertainty{2}(:,3),colorMedianRange,1); hold on;
+            legendText{end+1} = sprintf('Simulation - Median [%g-%g]%%CI ',100*sim_output.QUANTILESUNCERTAINTY(1),100*sim_output.QUANTILESUNCERTAINTY(3));
+            
+            plot(sim_output.time,sim_output.quantilesData_uncertainty{2}(:,2),'-','Color',colorMedian,'LineWidth',2); hold on
+            legendText{end+1} = sprintf('Simulation - Median');
+            
+            % Get observed data
+            data_output = data(data.EVID==0 & data.MDV==0 & data.YTYPE==ytypeData(kOUT),{'USUBJID','ID','TIME','NT','DV','TRT','TRTNAME','NAME','UNIT','TIMEUNIT'});
+            
+            % Handle useNOMINAL_TIME flag
+            if useNOMINAL_TIME,
+                data_output.TIME_PLOT   = data_output.NT;
+            else
+                data_output.TIME_PLOT   = data_output.TIME;
+            end
+            
+            % Plot the observed data - either as ID text or as dots.
+            if showLabels,
+                text(data_output.TIME_PLOT, data_output.DV, cellstr( num2str(data_output.ID, '%d') ),'Color',colorData, 'VerticalAlignment','middle', 'HorizontalAlignment','center', 'FontSize', 8);
+                plot(-100000,0,'.','MarkerSize',10,'Color',colorData);
+                legendText{end+1} = '(Subject ID) Observed data';
+            else
+                plot(data_output.TIME_PLOT, data_output.DV, '.','MarkerSize',20,'Color',colorData);
+                legendText{end+1} = 'Observed data';
+            end
+            
+            % Determine and plot data quantiles
+            if showDataQuantiles,
+                
+                % Define bins_mean if bins_mean not defined by the user
+                if isempty(bins_mean),
+                    % Set bins_mean to the nominal observation times
+                    bins_mean           = unique(data_output.NT);
+                    if ~isempty(find(isnan(data_output.NT))),
+                        error('Please check the nominal time information in your dataset - it might be missing (partly).\nAlternatively provide "options.bins_mean" and "options.bins_lookaround" information.');
+                    end
+                end
+                
+                % If bins_lookaround not defined
+                if isempty(bins_lookaround),
+                    bins_lookaround = diff(bins_mean);
+                    bins_lookaround = [bins_lookaround(1); bins_lookaround(:)]/2;
+                end
+                
+                % Median
+                [xbin_median,ybin_median] = binnedquantilesIQM(data_output.TIME_PLOT,data_output.DV,0.5,{bins_mean,bins_lookaround});
+                plot(xbin_median, ybin_median, 'ko--','LineWidth',2,'MarkerFace','k','MarkerSize',4);
+                legendText{end+1} = 'Observed data - Median';
+                
+                % Defined quantiles - only first and last (third)
+                for k=1:2:length(sim_output.QUANTILESDATA),
+                    [xbin,ybin] = binnedquantilesIQM(data_output.TIME_PLOT,data_output.DV,sim_output.QUANTILESDATA(k),{bins_mean,bins_lookaround});
+                    plot(xbin, ybin, 'ko--','LineWidth',1,'MarkerFace','k','MarkerSize',4);
+                    legendText{end+1} = sprintf('Observed data - Quantile: %g', sim_output.QUANTILESDATA(k));
+                end
+            end
+            
+            % Plot individual data lines
+            if plotIndivLines,
+                allID = unique(data.ID);
+                for k=1:length(allID),
+                    datak = data_output(data_output.ID==allID(k),:);
+                    plot(datak.TIME, datak.DV,'--','Color',0.7*[1 1 1]);
+                end
+            end
+            
+            % Set axes to default values
+            xtimes = [sim_output.time(:);data_output.TIME_PLOT];
+            set(gca,'XLim',[min(xtimes) max(xtimes)]);
+            
+            % Set axes if defined
+            XLim = get(gca,'XLim');
+            if ~isempty(minX), XLim(1) = minX; end
+            if ~isempty(maxX), XLim(2) = maxX; end
+            set(gca,'XLim',XLim);
+            YLim = get(gca,'YLim');
+            if ~isempty(minY), YLim(1) = minY; end
+            if ~isempty(maxY), YLim(2) = maxY; end
+            set(gca,'YLim',YLim);
+            
+            % Annotate plot
+            h = legend(legendText,'Location','best','Interpreter','none');
+            set(h,'FontSize',10);
+            set(gca,'FontSize',12);
+            grid on;
+            if ~useNOMINAL_TIME,
+                xlabel(['Time [' strrep(data_output.TIMEUNIT{1},':::',' ') ']'],'FontSize',14,'Interpreter','none');
+            else
+                xlabel(['NOMINAL Time [' strrep(data_output.TIMEUNIT{1},':::',' ') ']'],'FontSize',14,'Interpreter','none');
+            end
+            
+            if ~doseNormalized,
+                ylabel([strrep(data_output.NAME{1},':::',' ') ' [' strrep(data_output.UNIT{1},':::',' ') ']'],'FontSize',14,'Interpreter','none');
+            else
+                ylabel(['Dose normalized ' strrep(data_output.NAME{1},':::',' ') ' [' strrep(data_output.UNIT{1},':::',' ') '/' doseUnit ']'],'FontSize',14,'Interpreter','none');
+            end
+            
+            if isempty(titleText),
+                title(sprintf('NTRIALS: %d, NSUBJECTS: %d',NTRIALS,NSUBJECTS),'FontSize',16,'Interpreter','none');
+            else
+                title(sprintf('%s\n(NTRIALS: %d, NSUBJECTS: %d)',titleText,NTRIALS,NSUBJECTS),'FontSize',16,'Interpreter','none');
+            end
+            
+            % Handle printing of figure
+            IQMprintFigure(gcf,filename)
+            if ~isempty(filename),
+                close(gcf);
+            end
+        end
+    end
+end
+
+IQMconvert2pdf(filename);
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/09-NLMEtools/IQMcreateVPCstratified.m b/IQMtools V1.2.2.2/IQMpro/tools/09-NLMEtools/IQMcreateVPCstratified.m
new file mode 100644
index 0000000000000000000000000000000000000000..b5bb3737338d67f65ab4d87bcd09a7e6f33ba776
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/09-NLMEtools/IQMcreateVPCstratified.m	
@@ -0,0 +1,191 @@
+function [allVPCresults] = IQMcreateVPCstratified(GROUP,NLMEproject,model,data,outputsModel,outputsData,filename,options)
+% This function generates a stratified VPC for a given NLMEproject.
+% Stratification is done by the "GROUP" argument, which needs to be the
+% name of a column in the dataset to stratify along.
+% It requires otherwise the same input arguments as IQMcreateVPC:
+% "model", which is the structural model as an
+% IQMmodel object, used for generation of the NLMEproject file.
+% Additionally, a "data" set to determine observations and dosings for the
+% VPC. "outputModels" defines the names of states or variables in the model
+% for which VPCs should be generated. "outputsData" defines the NAMEs of
+% the events in the dataset that should be matched with outputModels.
+% "options" allows to define a range of optional arguments for both
+% plotting and simulation.
+%
+% [SYNTAX]
+% [allVPCresults] = IQMcreateVPCstratified(GROUP,NLMEproject,model,data)
+% [allVPCresults] = IQMcreateVPCstratified(GROUP,NLMEproject,model,data,outputsModel,outputsData)
+% [allVPCresults] = IQMcreateVPCstratified(GROUP,NLMEproject,model,data,outputsModel,outputsData,filename)
+% [allVPCresults] = IQMcreateVPCstratified(GROUP,NLMEproject,model,data,outputsModel,outputsData,filename,options)
+%
+% [INPUT]
+% GROUP:            String with the name of the column in the data to use
+%                   for stratification.
+% NLMEproject:      String with the name of the NLME project folder for
+%                   which to generate this VPC. 
+%                   Needs to include the absolute or relative path to the
+%                   folder. 
+% model:            Structural IQMmodel used for generation of the NLME
+%                   model (at least parameter names, regression parameters
+%                   and structure need to fit, additional variables can be
+%                   added.  
+% data:             Dataset for the VPC - covariates, regression parameters
+%                   and individual dosing schedules will be determined from
+%                   this dataset. For the simulation the correlation of
+%                   dosing schemes, covariates, and regression parameters
+%                   will be kept.
+% outputsModel:     String or cell-array of strings with outputs in the
+%                   model to consider for VPC generation. If left empty
+%                   ([]), then the outputs are determined from the NLME
+%                   project. However, if for PD the relative PD is to be
+%                   plotted and the absolute was fitted, then it is useful
+%                   if the names can be provided. 
+% outputsData:      String or cell-array of strings with outputs in the
+%                   data (NAME column) to match with the corresponding
+%                   outputsModel entries. 
+% filename:         If a filename is provided, the VPC results are exported
+%                   to a PDF file with this name (and path). Default:
+%                   'VPC.pdf')
+%
+% options:          Matlab structure with optional information
+%           options.userDosing          If 0 order absorption present in
+%                                       model and the model not generated from the popPK workflow, then
+%                                       the user needs to provide an own dosing scheme here in this field.
+% 
+%       * General
+%           options.N_PROCESSORS_PAR    Number or processors (requires parallel toolbox) (default: as defined in SETUP_PATHS_TOOLS_IQMPRO) 
+%           options.NTRIALS             Number of TRIALS to simulate to determine simulation quantiles and confidence intervals. (default: 200) 
+%           options.QUANTILES           Vector with quantiles to compute for simulation and data (default: [0.05 0.95]) (90% variability)
+%           options.QUANTILES_CI        Vector with quantiles for the uncertainty of the QUANTILES (default: [0.025 0.975]) (95% CI)
+%           options.useNOMINAL_TIME     =0: Use actual observation and dose times 
+%                                       =1: Use nominal observation and dose times (default: 1)
+%                                       (for simulations observation and dosing times, and for plotting of observed data points)
+%
+%       * Simulation time point information
+%           options.nTimePoints         Number time points to simulate - spaced equidistantly. If set to empty ([]) then observation times are used. (default: 500) 
+%
+%       * Plot content
+%           options.showLabels          =1: Shows subject IDs as data, =0: shows dots as data (default: 1)
+%           options.plotIndivLines      =1: Connect individual data points with lines (default: 0)
+%           options.showDataQuantiles   =1: Show lines for the observation quantiles (default: 0)
+%
+%       * Axes information
+%           options.logY                =1: log Y axis, =0: linear Y axis (default: 0)
+%           options.minX                Numeric value for lower value of X axis (default: not used)
+%           options.maxX                Numeric value for upper value of X axis (default: not used)
+%           options.minY                Numeric value for lower value of Y axis (default: not used)
+%           options.maxY                Numeric value for upper value of Y axis (default: not used)
+%
+%       * Binning information
+%           options.bins_mean           Vector with center values of bins to calculate data quantiles. If not 
+%                                       defined ([]), then bins_mean=NT of observations (default: [])
+%           options.bins_lookaround     Vector with values for positive and negative "lookaround" for quantile calculation 
+%                                       If not provided it is set to:
+%                                               bins_lookaround = diff(bins_mean) 
+%                                               bins_lookaround = [bins_lookaround(1); bins_lookaround(:)]/2
+%
+%       * Color settings
+%           options.colorMedianRange        Default: [1 0.9 0.8]
+%           options.colorQuantilesRange     Default: [0.8 1 0.8]
+%           options.colorData               Default: 0.2*[1 1 1]
+%           options.colorMedian             Default: [1 0.2 0]
+%
+%       * Integrator information
+%           options.optionsIntegrator   Options for the integration (See IQMmakeMEXmodel).
+%
+% [OUTPUT]
+% VPCs in MATLAB figures or exported to PDF (default: PDF as VPC.pdf)
+% allVPCresults: Cell-array of outputs to IQMcreateVPC. Possible to use
+%                directly as input argument to IQMcreateVPCplot
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle variable input arguments
+if nargin == 5,
+    error('When defining outputsModel also outputsData needs to be given as input argument.');
+end
+if nargin<5,
+    outputsModel = {};
+end
+if nargin<6,
+    outputsData = [];
+end
+if nargin<7,
+    filename = 'VPC.pdf';
+end
+if nargin<8,
+    options = [];
+end
+
+% Set some fixed options for the stratified VPC
+options.doPlot          = 0;
+options.doseNormalized  = 0;
+
+% Handle data, model, dosing
+if ischar(data),
+    data = IQMloadCSVdataset(data);
+end
+if ischar(model),
+    model = IQMmodel(model);
+end
+
+% Check if ADDL present and used - in this case: error
+showErrorADDL = 0;
+try
+    ADDL = data.ADDL;
+    % ADDL exists
+    if sum(ADDL>0) ~= 0,
+        showErrorADDL = 1;
+    end        
+catch
+    % ADDL does not exist - fine :) - so it does not need to be checked
+end
+if showErrorADDL,
+    error('ADDL column in dataset used to define additional doses. This is not handled in the VPC function.');
+end
+
+% Check GROUP
+checkDataColumnsIQM(data,GROUP);
+
+% Restore spaces in data
+data = restoreSpacesDataIQM(data);
+
+% Handle options
+try N_PROCESSORS_PAR    = options.N_PROCESSORS_PAR;      catch, N_PROCESSORS_PAR     = getN_PROCESSORS_PARIQM();        end
+
+% Check presence TINF column
+if isempty(strmatchIQM('TINF',data.Properties.VariableNames,'exact')),
+    error('Please ensure that a TINF column is present in the VPC data.');
+end
+
+% Request processors
+killMATLABpool = startParallelIQM(N_PROCESSORS_PAR);
+
+% Get groups for stratification
+allGroups = unique(data.(GROUP));
+
+% Cycle through the groups
+allVPCresults = cell(1,length(allGroups));
+for k=1:length(allGroups),
+    disp(allGroups(k))
+ 
+    % Stratify by provided groupName
+    dataStratified = data(ixdataIQM(data,GROUP,allGroups(k)),:);
+    
+    % Set titleText
+    if isnumeric(allGroups),
+        options.titleText = sprintf('%s: %d',GROUP,allGroups(k));
+    else
+        options.titleText = sprintf('%s: %s',GROUP,allGroups{k});
+    end
+    
+    % Generate VPC data (no plotting)
+    allVPCresults{k}    = IQMcreateVPC(NLMEproject,model,dataStratified,outputsModel,outputsData,filename,options);
+end
+
+% Release processors
+stopParallelIQM(killMATLABpool);
+
+% Plot results
+IQMcreateVPCplot(allVPCresults,filename)
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/09-NLMEtools/IQMduplicateNLMEmodel.m b/IQMtools V1.2.2.2/IQMpro/tools/09-NLMEtools/IQMduplicateNLMEmodel.m
new file mode 100644
index 0000000000000000000000000000000000000000..76bd99e237cc89c04907952d003ded5e134af7a3
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/09-NLMEtools/IQMduplicateNLMEmodel.m	
@@ -0,0 +1,121 @@
+function [] = IQMduplicateNLMEmodel(modelSource,modelDestination,relPathData,reRunModel,N_PROCESSORS)
+% This function duplicates a NLME model, specified by the path to its
+% project folder (modelSource) to a new path (modelDestination). Important
+% is that the model should still be executable and therefore the relative
+% path from the modelDestination location to the dataset for the model
+% needs to be provided. It is checked in this function that the path is
+% correct and the dataset accessibe.
+%
+% On request the model can be re-run or just copied.
+%
+% [SYNTAX]
+% [] = IQMduplicateNLMEmodel(modelSource,modelDestination,relPathData)
+% [] = IQMduplicateNLMEmodel(modelSource,modelDestination,relPathData,reRunModel)
+% [] = IQMduplicateNLMEmodel(modelSource,modelDestination,relPathData,reRunModel,N_PROCESSORS)
+%
+% [INPUT]
+% modelSource:          Relative path to the NLME project folder to be copied
+% modelDestination:     Relative path to where to copy it
+% relPathData:          Relative path from copied NLME project to the
+%                       dataset for the model (without data filename) 
+% reRunModel:           =0: do not rerun, =1: rerun (default: 0)
+% N_PROCESSORS          Number of processors if use if parallel (default: 1)
+%
+% [OUTPUT]
+% Duplicated model at modelDestination location.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle variable input arguments
+if nargin<3 || nargin>5,
+    error('Incorrect number of input arguments.');
+end
+if nargin<4,
+    reRunModel = 0;
+end
+if nargin<5,
+    N_PROCESSORS = 1;
+end
+
+% Handle the relative path to the data
+relPathData         = strrep(relPathData,'\','/');
+if relPathData(end)~='/',
+    relPathData = [relPathData '/'];
+end
+
+% Remove the destination folder if present
+try
+    rmdir(modelDestination,'s');
+end
+
+% Copy the source project
+try
+    copyfile(modelSource,modelDestination,'f');
+catch
+    error('Check if source NLME project folder exists.');
+end
+
+% Change into destination project folder
+oldpath = pwd();
+cd(modelDestination)
+
+if isMONOLIXprojectIQM('.'),
+    % Get model file
+    content     = fileread('project.mlxtran');
+    
+    % Get name of dataset
+    dataName    = regexp(content,'; DATA                = ''([^\n]+)''\r\n','tokens');
+    [~,f,e]     = fileparts(dataName{1}{1});
+    
+    % Get path to dataset to check if it exists
+    dataPathCheck = [relPathData f e];
+    
+    % Exchange data path in the header
+    content = regexprep(content,'; DATA                = [^\n]+\r\n',sprintf('; DATA                = ''%s%s%s''\r\n',relPathData,f,e));
+    
+    % Exchange data path in the DATA section
+    content = regexprep(content,'path = [^\n]+\r\n',sprintf('path = "%%MLXPROJECT%%/%s",\r\n',relPathData));
+
+    % Write out project file
+    fid = fopen('project.mlxtran','w');
+    fwrite(fid,content);
+    fclose(fid);
+elseif isNONMEMprojectIQM('.'),
+    % Get model file
+    content     = fileread('project.nmctl');
+    
+    % Get name of dataset
+    dataName    = regexp(content,'; DATA                = ''([^\n]+)''\r\n','tokens');
+    [~,f,e]     = fileparts(dataName{1}{1});
+    
+    % Get path to dataset to check if it exists
+    dataPathCheck = [relPathData f e];
+    
+    % Exchange data path in the header
+    content = regexprep(content,'; DATA                = [^\n]+\r\n',sprintf('; DATA                = ''%s%s%s''\r\n',relPathData,f,e));
+    
+    % Exchange data path in the DATA section
+    content = regexprep(content,'\$DATA [^\n]+\r\n',sprintf('$DATA %s%s%s\r\n',relPathData,f,e));
+
+    % Write out project file
+    fid = fopen('project.nmctl','w');
+    fwrite(fid,content);
+    fclose(fid);
+else
+    error('Unknown NLME project.');
+end
+
+% Check if data file with the new path exists
+if exist(dataPathCheck,'file')~=2,
+    error(sprintf('The dataset the duplicated model uses is not available with the provided relative path. Please check.\nAlso please check if in the NLME project a dataset is located. In this case IQM Tools has created it there,\nfor example to handle certain special cases. In this case use ''.'' as relPathData input argument.'));
+end
+
+% Change to original folder
+cd(oldpath);
+
+% Rerun the model if desired
+if reRunModel,
+    IQMrunNLMEproject(modelDestination,N_PROCESSORS);
+end
+
+fclose('all');
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/09-NLMEtools/IQMscm.m b/IQMtools V1.2.2.2/IQMpro/tools/09-NLMEtools/IQMscm.m
new file mode 100644
index 0000000000000000000000000000000000000000..143c9bb0d9ba19b4a8905acbe1d529078a5a8954
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/09-NLMEtools/IQMscm.m	
@@ -0,0 +1,854 @@
+function [] = IQMscm(TOOL,projectPathSCM,optionsSCM,model,dosing,data,options)
+% IQMscm: Stepwise covariate search, using forward inclusion / backward
+% elimination. Decision fotr inclusion or exclusion based on objective
+% function value.
+%
+% Although the algorithm is in principle applicable to categorical
+% covariates with more than 2 categories, it does not really make sense and
+% might introduce to many parameters that are not significant. A better
+% approach is to get the modeler to think a little more and reduce the
+% number of categories to 2. Covariates with multiple categories can be
+% assessed after the SCM has been done by adding them one at a time.
+%
+% This function here will only allow for categorical covariates with 2
+% categories - not more.
+%
+% Centering for continuous covariates is fixed at the median of the
+% covariates for SCM. Structural covariates can be centered as desired.
+%
+% [SYNTAX]
+% [] = IQMscm(TOOL,projectPathSCM,optionsSCM,model,dosing,data,options)
+%
+% [INPUT]
+% Input arguments model, dosing, data, options are identical to the ones
+% documented in IQMcreateNONMEMproject, IQMcreateMONOLIXproject, and
+% IQMcreateNLMEproject and are not repeated here.
+%
+% TOOL:             'NONMEM' or 'MONOLIX'
+% projectPathSCM:   Path to which all the generated NLME projects will be saved
+% optionsSCM:       Structure with optional settings for the covariate search.
+%   optionsSCM.outputPath:              Path where to store the log file (default: projectPathSCM)
+%   optionsSCM.N_PROCESSORS_PAR:        Number of parallel model runs (default: as specified in SETUP_PATHS_TOOLS_IQMPRO)
+%   optionsSCM.N_PROCESSORS_SINGLE:     Number of processors to parallelize single run (if NONMEM and MONOLIX allow for it) (default: 1)
+%   optionsSCM.p_forward:               p-value for forward inclusion step (default: 0.05)
+%   optionsSCM.p_backward:              p-value for forward inclusion step (default: 0.001)
+%   optionsSCM.covariateTests:          Cell-array with parameter/covariate combinations to test
+%                                       First element in each sub-array is the parameter name,
+%                                       following are the covariates to test.
+%
+%                                       Example:
+%                                          {
+%                                             {'EMAX','WT0','SEX','HT0','ETHN'}
+%                                             {'EC50','WT0','SEX','HT0','ETHN'}
+%                                             {'fS'  ,'WT0','SEX','HT0','ETHN'}
+%                                           }
+%
+%                                       If not specified or empty, then all covariates will be
+%                                       tested on all parameters.
+%
+% If "covariateModels" is defined in modeltest, then these covariates are
+% included by default and are not subject to the SCM algorithm.
+%
+% [OUTPUT]
+% The output is in the form of a logfile that is stored in the selected
+% output folder.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Check TOOL definition
+if ~strcmpi(TOOL,'nonmem') && ~strcmpi(TOOL,'monolix'),
+    error('Please select as first input argument either ''NONMEM'' or ''MONOLIX''');
+end
+
+% Handle optionsSCM
+try p_forward               = optionsSCM.p_forward;                 catch, p_forward                = 0.05;                     end
+try p_backward              = optionsSCM.p_backward;                catch, p_backward               = 0.001;                    end
+try covariateTests          = optionsSCM.covariateTests;            catch, covariateTests           = {};                       end
+try outputPath              = optionsSCM.outputPath;                catch, outputPath               = projectPathSCM;           end
+try N_PROCESSORS_PAR        = optionsSCM.N_PROCESSORS_PAR;          catch, N_PROCESSORS_PAR         = getN_PROCESSORS_PARIQM(); end
+try N_PROCESSORS_SINGLE     = optionsSCM.N_PROCESSORS_SINGLE;       catch, N_PROCESSORS_SINGLE      = 1;                        end
+
+% Get previously defined covariate model (fixed covariate model)
+try covariateModel          = options.covariateModel;               catch, covariateModel           = '';                       end
+try covariateModelValues    = options.covariateModelValues;         catch, covariateModelValues     = {};                       end
+try COVestimate             = options.COVestimate;                  catch, COVestimate              = {};                       end
+
+% Check if NONMEM and SAEM ... then show error
+if strcmpi(TOOL,'NONMEM') && strcmpi(options.algorithm.METHOD,'SAEM'),
+    error('Stepwise covariate search with NONMEM SAEM is not a good idea. Please use FO(CE(I)) or MONOLIX.');
+end
+
+% Create the projectFolder
+try rmdir(projectPathSCM,'s'); catch end
+warning off
+mkdir(projectPathSCM);
+warning on
+
+% Load dataset to assess number of categorical elements
+oldpath = pwd();
+cd(projectPathSCM);
+dataContents = IQMloadCSVdataset([data.dataRelPathFromProject '/' data.dataFileName]);
+cd(oldpath);
+
+% Change data path to match the nested model folder structure
+data.dataRelPathFromProject = ['../' data.dataRelPathFromProject];
+
+% If NONMEM used then check if IMP set to 1
+if strcmpi(TOOL,'nonmem') && strcmpi(options.algorithm.METHOD,'saem') && options.algorithm.IMPORTANCESAMPLING == 0,
+    error('When using NONMEM/SAEM, please set the options.algorithm.IMPORTANCESAMPLING=1.');
+end
+
+% Create the BASE model (MODEL_BASE) and load header
+BASEmodelFolder     = [projectPathSCM '/MODEL_BASE'];
+IQMcreateNLMEproject(TOOL,model,dosing,data,BASEmodelFolder,options);
+projectInfo         = parseNLMEprojectHeaderIQM(BASEmodelFolder);
+
+% Get parameter names, continuous and categorical covariate names from the
+% models header
+parNames            = projectInfo.PARAMNAMES;
+covNames            = projectInfo.COVNAMES;
+catNames            = projectInfo.CATNAMES;
+covcatNames         = [covNames catNames];
+
+% If list of covariates empty then generate it - to include all covariates
+% on all parameters
+if isempty(covariateTests)
+    covariateTests = cell(length(parNames),1);
+    for k1=1:length(parNames),
+        cTk{1} = parNames{k1};
+        for k2=1:length(covcatNames),
+            cTk{k2+1} = covcatNames{k2};
+        end
+        covariateTests{k1} = cTk(:)';
+    end
+end
+
+% Expand the covariat settings to matching lists for parameters and covariate names
+covSearch                   = [];
+covSearch.paramNamesTest    = {};
+covSearch.covcatNamesTest   = {};
+for k1=1:length(covariateTests),
+    for k2=2:length(covariateTests{k1}),
+        covSearch.paramNamesTest{end+1}  = covariateTests{k1}{1};
+        covSearch.covcatNamesTest{end+1} = covariateTests{k1}{k2};
+    end
+end
+
+% Check lists if selected covariates and parameters present in model and dataset
+for k=1:length(covSearch.paramNamesTest),
+    ix = strmatchIQM(covSearch.paramNamesTest{k},parNames,'exact');
+    if isempty(ix),
+        error('Parameter %s is not estimated in the model.',covSearch.paramNamesTest{k});
+    end
+end
+
+for k=1:length(covSearch.covcatNamesTest),
+    ix = strmatchIQM(covSearch.covcatNamesTest{k},covcatNames,'exact');
+    if isempty(ix),
+        error('Covariate %s is not present in the dataset.',covSearch.covcatNamesTest{k});
+    end
+end
+
+% Determine structural covariate information (structural covariates are
+% covariates that already are in the model by options.covariateModel)
+covStructural               = [];
+covStructural.paramNames    = {};
+covStructural.covcatNames   = {};
+covStructural.value         = [];
+covStructural.estimate      = [];
+terms = strrep(strrep(explodePCIQM(covariateModel,',','{','}'),'{',''),'}','');
+for k=1:length(terms),
+    x = explodePCIQM(terms{k});
+    for k2=2:length(x),
+        covStructural.paramNames{end+1} = x{1};
+        covStructural.covcatNames{end+1} = x{k2};
+        if isempty(covariateModelValues),
+            covStructural.value(end+1) = 0.1;
+        else
+            covStructural.value(end+1) = covariateModelValues{k}(k2-1);
+        end
+        if isempty(COVestimate),
+            covStructural.estimate(end+1) = 1;
+        else
+            covStructural.estimate(end+1) = COVestimate{k}(k2-1);
+        end
+    end
+    
+end
+
+% Remove structural covariates from covSearch - since these are already in
+% the model
+ix_remove = [];
+for k=1:length(covStructural.paramNames),
+    par = covStructural.paramNames{k};
+    cov = covStructural.covcatNames{k};
+    ix1 = strmatchIQM(par,covSearch.paramNamesTest,'exact');
+    ix2 = strmatchIQM(cov,covSearch.covcatNamesTest,'exact');
+    if ~isempty(intersect(ix1,ix2)),
+        ix_remove(end+1) = intersect(ix1,ix2);
+    end
+end
+if ~isempty(ix_remove),
+    covSearch.paramNamesTest(ix_remove) = [];
+    covSearch.covcatNamesTest(ix_remove) = [];
+end
+
+% Determine delta Objective functions required for covariates
+% DF: 1 for continuous, N-1 for categorical - since N=2 for categorical ...
+% it is the same.
+for k=1:length(covSearch.covcatNamesTest),
+    % Check if categorical
+    if ~isempty(strmatchIQM(covSearch.covcatNamesTest{k},covNames,'exact')),
+        % Continuous covariate
+        N_DF = 1;
+    else
+        % Categorical covariate
+        N_categories = length(unique(dataContents.(covSearch.covcatNamesTest{k})));
+        if N_categories > 2,
+            error('Categorical covariate "%s" has more than 2 categories - this is not allowed.',covSearch.covcatNamesTest{k});
+        end
+        if N_categories < 2,
+            error('Categorical covariate "%s" has less than 2 categories - this is not allowed.',covSearch.covcatNamesTest{k});
+        end
+        N_DF = 1;        
+    end
+    covSearch.delta_forward(k)   = chi2invIQM(1-p_forward,N_DF);
+    covSearch.delta_backward(k)  = chi2invIQM(1-p_backward,N_DF);
+end
+
+% Save information for later
+covSearchBackUp = covSearch;
+
+% Open report file
+warning off
+mkdir(outputPath);
+warning on
+fid = fopen([outputPath '/SCMlogfile.txt'],'w');
+
+fprintf(fid,'****************************************************************************\n');
+fprintf(fid,'* Covariate search using forward inclusion and backward elimination method *\n');
+fprintf(fid,'****************************************************************************\n');
+fprintf(fid,'Username: %s\n',usernameIQM());
+fprintf(fid,'Date:     %s\n',datestr(now,'yyyy-mmm-DD HH:MM'));
+fprintf(fid,'****************************************************************************\n');
+fprintf(fid,'\n');
+fprintf(fid,'p-value forward:      %g\n',p_forward);
+fprintf(fid,'p-value backward:     %g\n',p_backward);
+fprintf(fid,'\n');
+fprintf(fid,'Decisions based on delta objective function.\n');
+fprintf(fid,'\n');
+
+fprintf(fid,'************************************\n');
+fprintf(fid,'* RUNNING BASE MODEL (MODEL_BASE)  *\n');
+fprintf(fid,'************************************\n');
+fprintf(fid,'\n');
+
+% Run the BASE model (MODEL_BASE)
+BASEmodelFolder = [projectPathSCM '/MODEL_BASE'];
+IQMrunNLMEproject(BASEmodelFolder,N_PROCESSORS_SINGLE);
+RESULTS         = parseNLMEprojectResults(BASEmodelFolder);
+close all; drawnow();
+
+% Get OFV and optimal parameters for BASE model
+BASE_OFV            = RESULTS.objectivefunction.OBJ;
+
+% Report OFV for BASE model
+fprintf(fid,'Objective function value for BASE model: %g\n',BASE_OFV);
+if strcmpi(TOOL,'NONMEM'),
+    fprintf(fid,'\n');
+    fprintf(fid,'%s\n',RESULTS.termination_info{1});
+end
+fprintf(fid,'\n');
+
+% Update model options with optimal BASE model parameters
+options.POPvalues0  = RESULTS.rawParameterInfo.fixedEffects.values;
+options.IIVvalues0  = RESULTS.rawParameterInfo.randomEffects.values;
+options.errorParam0 = RESULTS.rawParameterInfo.errorParameter.values;
+
+% Update data path again for the level models
+data.dataRelPathFromProject = ['../' data.dataRelPathFromProject];
+
+% Forward inclusion
+fprintf(fid,'************************************\n');
+fprintf(fid,'* FORWARD INCLUSION                *\n');
+fprintf(fid,'************************************\n');
+fprintf(fid,'\n');
+
+OLD_OFV                     = BASE_OFV;
+covariatesForward           = {};
+covariateModelValuesForward = {};
+COVestimateForward          = {};
+countModel                  = 1;
+Nmaxmodels                  = (length(covSearch.covcatNamesTest)^2-length(covSearch.covcatNamesTest))/2+length(covSearch.covcatNamesTest);
+continueForwardSearch       = 1;
+levelCount                  = 1;
+levelModel                  = '';
+ForwardModelName            = BASEmodelFolder;
+ModelNameAll                = {};
+
+while continueForwardSearch,
+    
+    % Run through remaining parameter/covariate combinations
+    % Generate all models first and then run all at once
+    covariatesTestForward           = {};
+    covariateModelValuesTESTForward = {};
+    COVestimateTESTForward          = {};
+    covariateModelAll               = {};
+    
+    for k1=1:length(covSearch.paramNamesTest),
+        
+        % Reset covariate setting to previous level
+        covariatesTest          = covariatesForward;
+        covariateModelValues    = covariateModelValuesForward;
+        COVestimate             = COVestimateForward;
+        
+        % Get new parameter/covariate combination to test
+        param = covSearch.paramNamesTest{k1};
+        cov   = covSearch.covcatNamesTest{k1};
+        delta = covSearch.delta_forward(k1);
+        value = 0.1; % Setting default value to 0.1 (NONMEM does not allow 0)
+        
+        % Build covariate test structure and covariateModelValues and COVestimate
+        ix = [];
+        for k2=1:length(covariatesTest),
+            if strcmp(covariatesTest{k2}{1},param),
+                ix = k2;
+            end
+        end
+        if isempty(ix),
+            covariatesTest{end+1}{1}        = param;
+            covariatesTest{end}{2}          = cov;
+            covariateModelValues{end+1}     = value;
+            COVestimate{end+1}              = 1;
+        else
+            covariatesTest{ix}{end+1}       = cov;
+            covariateModelValues{ix}(end+1) = value;
+            COVestimate{ix}(end+1)          = 1;
+        end
+        covariatesTest                      = covariatesTest(:);
+        
+        % Save for later
+        covariatesTestForward{k1}           = covariatesTest;
+        covariateModelValuesTESTForward{k1} = covariateModelValues;
+        COVestimateTESTForward{k1}          = COVestimate;
+        
+        % Convert to required format
+        covariateModel                      = '';
+        for k3=1:size(covariatesTest,1),
+            if ~isempty(covariatesTest{k3}),
+                text                        = sprintf('%s,',covariatesTest{k3}{:});
+                covariateModel              = [covariateModel '{' text(1:end-1) '},'];
+            end
+        end
+        covariateModel                      = covariateModel(1:end-1);
+        covariateModelAll{k1}               = covariateModel;
+        
+        % Determine COVestimate and covariateModelValues
+        COVestimate = {};
+        covariateModelValues = {};
+        for k3=1:size(covariatesTest,1),
+            COVestimate{k3}                 = ones(1,length(covariatesTest{k3})-1);
+            covariateModelValues{k3}        = 0.1*ones(1,length(covariatesTest{k3})-1);
+        end
+        
+        % Add structural covariates to covariate model
+        for k3=1:length(covStructural.paramNames),
+            param    = covStructural.paramNames{k3};
+            cov      = covStructural.covcatNames{k3};
+            value    = covStructural.value(k3);
+            estimate = covStructural.estimate(k3);
+            % Find where to add
+            ix = [];
+            for k4=1:size(covariatesTest,1),
+                if strcmp(param,covariatesTest{k4}{1}),
+                    ix = k4;
+                    break;
+                end
+            end
+            if ~isempty(ix),
+                % add info
+                covariatesTest{ix}{end+1} = cov;
+                covariateModelValues{ix}(end+1) = value;
+                COVestimate{ix}(end+1) = estimate;
+            else
+                % new param
+                covariatesTest{end+1}{1} = param;
+                covariatesTest{end}{2} = cov;
+                covariateModelValues{end+1}(1) = value;
+                COVestimate{end+1}(1) = estimate;
+            end
+            covariatesTest = covariatesTest(:);
+        end
+        
+        % Convert to required format for the search things
+        covariateModel                      = '';
+        for k3=1:size(covariatesTest,1),
+            if ~isempty(covariatesTest{k3}),
+                text                        = sprintf('%s,',covariatesTest{k3}{:});
+                covariateModel              = [covariateModel '{' text(1:end-1) '},'];
+            end
+        end
+        covariateModel                      = covariateModel(1:end-1);
+        
+        % Set covariateModel
+        options.covariateModel              = covariateModel;
+        options.covariateModelValues        = covariateModelValues;
+        options.COVestimate                 = COVestimate;
+        
+        % Create model
+        ModelName                           = sprintf('MODEL_%s',preFillCharIQM(countModel,length(num2str(Nmaxmodels)),'0'));
+        FolderName                          = [projectPathSCM sprintf('/FW_LEVEL_%d',levelCount)];
+        ModelFolder                         = [FolderName '/' ModelName];
+        ModelNameAll{k1}                    = ModelFolder;
+        
+        IQMcreateNLMEproject(TOOL,model,dosing,data,ModelFolder,options);
+
+        countModel                          = countModel + 1;
+    end
+    
+    % Run the level models - do not create GoF plots
+    IQMrunNLMEprojectFolder(FolderName,N_PROCESSORS_PAR,N_PROCESSORS_SINGLE,1);
+    
+    % Read the results 
+    NLME_ORDER_CRITERION    = ''; % Do not order them
+    LEVEL_RESULTS           = parseProjectFolderResultsIQM(FolderName,NLME_ORDER_CRITERION);
+    IQMfitsummaryAll(FolderName,FolderName,NLME_ORDER_CRITERION);
+    
+    % Determine significance 
+    LEVEL_SIGNIFICANCE      = [];
+    % Get OBJ
+    LEVEL_OBJ               = [LEVEL_RESULTS.OBJ];
+    
+    % Create a table with output information    
+    if strcmpi(TOOL,'NONMEM'),
+        tableText               = cell(1,10);
+        tableText(1,1:2)        = {'<TT>' sprintf('Level %d: %s',levelCount,levelModel)};
+        tableText(2,:)          = {'<TH>','Model','Covariate tested','OBJ(cov)','OBJ(prev)','OBJ(prev)-OBJ(cov)','Significance','MINIMIZATION SUCCESSFUL','MINIMIZATION TERMINATED','PROBLEMS'};
+    else
+        tableText               = cell(1,7);
+        tableText(1,1:2)        = {'<TT>' sprintf('Level %d: %s',levelCount,levelModel)};
+        tableText(2,:)          = {'<TH>','Model','Covariate tested','OBJ(cov)','OBJ(prev)','OBJ(prev)-OBJ(cov)','Significance'};
+    end
+    for k1=1:length(covSearch.paramNamesTest),
+        tableText{k1+2,1}   = '<TR>';
+        tableText{k1+2,2}   = LEVEL_RESULTS(k1).model;
+        tableText{k1+2,3}   = sprintf('%s on %s',covSearch.covcatNamesTest{k1},covSearch.paramNamesTest{k1});
+        tableText{k1+2,4}   = round(100*LEVEL_OBJ(k1))/100;
+        tableText{k1+2,5}   = round(100*OLD_OFV)/100;
+        tableText{k1+2,6}   = round(100*(OLD_OFV-LEVEL_OBJ(k1)))/100;
+        if OLD_OFV-LEVEL_OBJ(k1) >= covSearch.delta_forward(k1),
+            LEVEL_SIGNIFICANCE(k1) = 1;
+            tableText{k1+2,7}   = 'YES';
+        else
+            LEVEL_SIGNIFICANCE(k1) = 0;
+            tableText{k1+2,7}   = '-';
+        end
+        if strcmpi(TOOL,'NONMEM'),
+            if ~isempty(strfind(LEVEL_RESULTS(k1).termination_info,'MINIMIZATION SUCCESSFUL')),
+                tableText{k1+2,8} = 'YES';
+            else
+                tableText{k1+2,8} = '-';
+            end            
+            if ~isempty(strfind(LEVEL_RESULTS(k1).termination_info,'MINIMIZATION TERMINATED')),
+                tableText{k1+2,9} = 'YES';
+            else
+                tableText{k1+2,9} = '-';
+            end     
+            if ~isempty(strfind(LEVEL_RESULTS(k1).termination_info,'PROBLEMS')),
+                tableText{k1+2,10} = 'YES';
+            else
+                tableText{k1+2,10} = '-';
+            end            
+        end
+    end        
+    
+    % Determine which covariate leads to the largest drop in OBJ
+    [~,ixBEST] = max(OLD_OFV-LEVEL_OBJ);
+    
+    % If none significant then stop forward inclusion here
+    if sum(LEVEL_SIGNIFICANCE) == 0,
+        % Nothing significant anymore - stop forward search
+        continueForwardSearch = 0;
+        
+        % Finalize table for this level by adding footer
+        tableText(end+1,1:2) = {'<TF>' 'No significant decrease in objective function => End of forward inclusion.'};
+    else
+        % Finalize table for this level by adding footer
+        tableText(end+1,1:2) = {'<TF>' sprintf('Retained covariate model for next level: %s (%s on %s)\n',LEVEL_RESULTS(ixBEST).model,covSearch.covcatNamesTest{ixBEST},covSearch.paramNamesTest{ixBEST})};
+
+        % Setup for new level
+        % -------------------
+        
+        OLD_OFV                             = LEVEL_OBJ(ixBEST);
+        
+        % Update options with optimal model parameters from last run
+        options.POPvalues0                  = LEVEL_RESULTS(ixBEST).rawParameterInfo.fixedEffects.values;
+        options.IIVvalues0                  = LEVEL_RESULTS(ixBEST).rawParameterInfo.randomEffects.values;
+        options.errorParam0                 = LEVEL_RESULTS(ixBEST).rawParameterInfo.errorParameter.values;
+        
+        % Remove covariate from search
+        covSearch.covcatNamesTest(ixBEST)   = [];
+        covSearch.delta_forward(ixBEST)     = [];
+        covSearch.delta_backward(ixBEST)    = [];
+        covSearch.paramNamesTest(ixBEST)    = [];
+        
+        % Set new base covariates
+        covariatesForward                   = covariatesTestForward{ixBEST};
+        covariateModelValuesForward         = covariateModelValuesTESTForward{ixBEST};
+        COVestimateForward                  = COVestimateTESTForward{ixBEST};
+        
+        % Update estimated covariate coefficient for next level - with all new estimates!
+        covInfo = LEVEL_RESULTS(ixBEST).rawParameterInfo.covariate;
+        
+        for k1x = 1:length(covariatesForward),
+            paramUpdate = covariatesForward{k1x}{1};
+            for k2x = 2:length(covariatesForward{k1x}),
+                covUpdate = covariatesForward{k1x}{k2x};
+                % Find parameter and covariate
+                matchIX = [];
+                for kkkx=1:length(covInfo.names),
+                    ixParam = strfind(covInfo.names{kkkx},paramUpdate);
+                    ixCov = strfind(covInfo.names{kkkx},covUpdate);
+                    if ~isempty(ixParam) && ~isempty(ixCov),
+                        matchIX(end+1) = kkkx;
+                    end
+                end
+                if length(matchIX) ~= 1,
+                    error('Problem with getting covariate coefficient value.');
+                end
+                % Get the estimated value
+                value = covInfo.values(matchIX);
+                % Add value to covariateModelValuesForward
+                ix = [];
+                for k2=1:length(covariatesForward),
+                    if strcmp(covariatesForward{k2}{1},paramUpdate),
+                        ix = k2;
+                    end
+                end
+                covariateModelValuesForward{ix}(strmatchIQM(covUpdate,covariatesForward{ix},'exact')-1) = value;
+            end
+        end
+        
+        levelModel          = covariateModelAll{ixBEST};
+        ForwardModelName    = ModelNameAll{ixBEST};
+        levelCount          = levelCount+1;
+    end
+    
+    % Export table for the level into the log file
+    textDisplay = IQMconvertCellTable2ReportTable(tableText,'text');
+    fprintf(fid,'%s\n',textDisplay);
+end
+
+% Get forward results
+FORWARD_OFV = OLD_OFV;
+forwardModel = levelModel;
+
+% Report forward model
+fprintf(fid,'************************************\n');
+fprintf(fid,'* FORWARD MODEL RESULTS            *\n');
+fprintf(fid,'************************************\n');
+fprintf(fid,'\n');
+
+fprintf(fid,'Forward model:             %s\n',ForwardModelName);
+fprintf(fid,'Covariates:                %s\n',forwardModel);
+fprintf(fid,'Objective function value:  %g\n',FORWARD_OFV);
+fprintf(fid,'\n');
+
+
+% Backward elimination
+fprintf(fid,'************************************\n');
+fprintf(fid,'* BACKWARD ELIMINATION             *\n');
+fprintf(fid,'************************************\n');
+fprintf(fid,'\n');
+
+% Create covSearch structure for backward search
+covSearchBackward = covSearchBackUp;
+ix_keep = [];
+for k1=1:size(covariatesForward),
+    param = covariatesForward{k1}{1};
+    for k2=2:length(covariatesForward{k1}),
+        cov = covariatesForward{k1}{k2};
+        ix_keep(end+1) = intersect(strmatchIQM(param,covSearchBackward.paramNamesTest,'exact'),strmatchIQM(cov,covSearchBackward.covcatNamesTest,'exact'));
+    end
+end
+covSearchBackward.covcatNamesTest = covSearchBackward.covcatNamesTest(ix_keep);
+covSearchBackward.paramNamesTest = covSearchBackward.paramNamesTest(ix_keep);
+covSearchBackward.delta_forward = covSearchBackward.delta_forward(ix_keep);
+covSearchBackward.delta_backward = covSearchBackward.delta_backward(ix_keep);
+
+% Add parameter values
+for k1=1:length(covSearchBackward.paramNamesTest),
+    paramName = covSearchBackward.paramNamesTest{k1};
+    covName   = covSearchBackward.covcatNamesTest{k1};
+    for k2=1:size(covariatesForward),
+        if strcmp(paramName,covariatesForward{k2}{1}),
+            ix = k2;
+            break;
+        end
+    end
+    ix2 = strmatchIQM(covName,covariatesForward{ix}(2:end),'exact');
+    value = covariateModelValuesForward{ix}(ix2);
+    covSearchBackward.value(k1) = value;
+end
+
+% Do the search
+covariateModelAll  = {};
+levelCount         = 1;
+countModel         = 1;
+BackwardModelName  = ForwardModelName;
+ModelNameAll       = {};
+
+% Check if backward search needed
+if ~isempty(covariatesForward),
+    continueBackwardSearch = 1;
+else
+    continueBackwardSearch = 0;
+end
+
+% OBJ:  Start with FORWARD_OFV and remove one by one ... until deltaOFV>... for
+while continueBackwardSearch,
+    
+    % Run through remaining parameter/covariate combinations
+    % Generate all models first and then run all at once
+    
+    for k1=1:length(covSearchBackward.paramNamesTest),
+        
+        % Reset covariate setting to previous level
+        covariatesTest  = covSearchBackward;
+        
+        % Remove parameter to test
+        param                   = covariatesTest.paramNamesTest;
+        cov                     = covariatesTest.covcatNamesTest;
+        value                   = covariatesTest.value;
+        param(k1)               = [];
+        cov(k1)                 = [];
+        value(k1)               = [];
+        
+        % Build covariate test structure
+        x                       = unique(param);
+        covTestStructure        = {};
+        covariateModelValues    = cell(1,length(x));
+        COVestimate             = cell(1,length(x));
+        
+        for k2=1:length(x),
+            covTestStructure{k2}{1}         = x{k2};
+        end
+        covTestStructure                    = covTestStructure(:);
+        for k2=1:length(param),
+            ix = strmatchIQM(param{k2},x,'exact');
+            covTestStructure{ix}{end+1} 	= cov{k2};
+            covariateModelValues{ix}(end+1) = value(k2);
+            COVestimate{ix}(end+1)          = 1;
+        end
+        
+        % Convert to required format
+        covariateModel                      = '';
+        for k3=1:size(covTestStructure,1),
+            if ~isempty(covTestStructure{k3}),
+                text                        = sprintf('%s,',covTestStructure{k3}{:});
+                covariateModel              = [covariateModel '{' text(1:end-1) '},'];
+            end
+        end
+        covariateModel                      = covariateModel(1:end-1);
+        covariateModelAll{k1}               = covariateModel;
+        
+        % Add structural covariates to covariate model
+        for k3=1:length(covStructural.paramNames),
+            param                           = covStructural.paramNames{k3};
+            cov                             = covStructural.covcatNames{k3};
+            value                           = covStructural.value(k3);
+            estimate                        = covStructural.estimate(k3);
+            % Find where to add
+            ix = [];
+            for k4=1:size(covTestStructure,1),
+                if strcmp(param,covTestStructure{k4}{1}),
+                    ix = k4;
+                    break;
+                end
+            end
+            if ~isempty(ix),
+                % add info
+                covTestStructure{ix}{end+1}         = cov;
+                covariateModelValues{ix}(end+1)     = value;
+                COVestimate{ix}(end+1)              = estimate;
+            else
+                % new param
+                covTestStructure{end+1}{1}          = param;
+                covTestStructure{end}{2}            = cov;
+                covariateModelValues{end+1}(1)      = value;
+                COVestimate{end+1}(1)               = estimate;
+            end
+            covTestStructure                        = covTestStructure(:);
+        end
+        
+        % Convert to required format for the search things
+        covariateModel                      = '';
+        for k3=1:size(covTestStructure,1),
+            if ~isempty(covTestStructure{k3}),
+                text                        = sprintf('%s,',covTestStructure{k3}{:});
+                covariateModel              = [covariateModel '{' text(1:end-1) '},'];
+            end
+        end
+        covariateModel                      = covariateModel(1:end-1);
+        
+        % Set covariateModel
+        options.covariateModel              = covariateModel;
+        options.covariateModelValues        = covariateModelValues;
+        options.COVestimate                 = COVestimate;
+        
+        % Create model
+        ModelName                           = sprintf('MODEL_%s',preFillCharIQM(countModel,length(num2str(Nmaxmodels)),'0'));
+        FolderName                          = [projectPathSCM sprintf('/BW_LEVEL_%d',levelCount)];
+        ModelFolder                         = [FolderName '/' ModelName];
+        ModelNameAll{k1}                    = ModelFolder;
+        
+        IQMcreateNLMEproject(TOOL,model,dosing,data,ModelFolder,options);
+
+        countModel                          = countModel + 1;
+    end
+    
+    % Run the level models - do not create GoF plots
+    IQMrunNLMEprojectFolder(FolderName,N_PROCESSORS_PAR,N_PROCESSORS_SINGLE,1);
+    
+    % Read the results
+    NLME_ORDER_CRITERION = ''; % Do not order them
+    LEVEL_RESULTS = parseProjectFolderResultsIQM(FolderName,NLME_ORDER_CRITERION);
+    IQMfitsummaryAll(FolderName,FolderName,NLME_ORDER_CRITERION);
+    
+    % Determine significance 
+    LEVEL_SIGNIFICANCE = [];
+    LEVEL_OBJ = [LEVEL_RESULTS.OBJ];
+    
+    
+    % Create a table with output information    
+    if strcmpi(TOOL,'NONMEM'),
+        tableText               = cell(1,10);
+        tableText(1,1:2)        = {'<TT>' sprintf('Level %d: %s',levelCount,levelModel)};
+        tableText(2,:)          = {'<TH>','Model','Covariate removed','OBJ(cov)','OBJ(prev)','OBJ(prev)-OBJ(cov)','Significance','MINIMIZATION SUCCESSFUL','MINIMIZATION TERMINATED','PROBLEMS'};
+    else
+        tableText               = cell(1,7);
+        tableText(1,1:2)        = {'<TT>' sprintf('Level %d: %s',levelCount,levelModel)};
+        tableText(2,:)          = {'<TH>','Model','Covariate tested','OBJ(cov)','OBJ(prev)','OBJ(prev)-OBJ(cov)','Significance'};
+    end
+    for k1=1:length(covSearchBackward.paramNamesTest),
+        tableText{k1+2,1}   = '<TR>';
+        tableText{k1+2,2}   = LEVEL_RESULTS(k1).model;
+        tableText{k1+2,3}   = sprintf('%s on %s',covSearchBackward.covcatNamesTest{k1},covSearchBackward.paramNamesTest{k1});
+        tableText{k1+2,4}   = round(100*LEVEL_OBJ(k1))/100;
+        tableText{k1+2,5}   = round(100*OLD_OFV)/100;
+        tableText{k1+2,6}   = round(100*(-OLD_OFV+LEVEL_OBJ(k1)))/100;
+        if -OLD_OFV+LEVEL_OBJ(k1) >= covSearchBackward.delta_backward(k1),
+            LEVEL_SIGNIFICANCE(k1) = 1;
+            tableText{k1+2,7}   = 'YES';
+        else
+            LEVEL_SIGNIFICANCE(k1) = 0;
+            tableText{k1+2,7}   = '-';
+        end
+        if strcmpi(TOOL,'NONMEM'),
+            if ~isempty(strfind(LEVEL_RESULTS(k1).termination_info,'MINIMIZATION SUCCESSFUL')),
+                tableText{k1+2,8} = 'YES';
+            else
+                tableText{k1+2,8} = '-';
+            end            
+            if ~isempty(strfind(LEVEL_RESULTS(k1).termination_info,'MINIMIZATION TERMINATED')),
+                tableText{k1+2,9} = 'YES';
+            else
+                tableText{k1+2,9} = '-';
+            end     
+            if ~isempty(strfind(LEVEL_RESULTS(k1).termination_info,'PROBLEMS')),
+                tableText{k1+2,10} = 'YES';
+            else
+                tableText{k1+2,10} = '-';
+            end            
+        end
+    end        
+    
+    % Determine which covariate leads to the largest increase in OBJ
+    [~,ixBEST] = min(-OLD_OFV+LEVEL_OBJ);
+    
+    % If all significant then stop backward elimination here
+    if sum(LEVEL_SIGNIFICANCE~=1) == 0,
+        continueBackwardSearch = 0;
+        % Finalize table for this level by adding footer
+        tableText(end+1,1:2) = {'<TF>' 'No insignificant increase in objective function => End of backward elimination.'};
+    else
+        % Finalize table for this level by adding footer
+        tableText(end+1,1:2) = {'<TF>' sprintf('Removed covariate model for next level: %s (%s on %s)\n',LEVEL_RESULTS(ixBEST).model,covSearchBackward.covcatNamesTest{ixBEST},covSearchBackward.paramNamesTest{ixBEST})};
+        
+        % Setup for new level
+        
+        OLD_OFV                                     = LEVEL_OBJ(ixBEST);
+        
+        % Update options with optimal model parameters from last run
+        options.POPvalues0                          = LEVEL_RESULTS(ixBEST).rawParameterInfo.fixedEffects.values;
+        options.IIVvalues0                          = LEVEL_RESULTS(ixBEST).rawParameterInfo.randomEffects.values;
+        options.errorParam0                         = LEVEL_RESULTS(ixBEST).rawParameterInfo.errorParameter.values;
+        
+        % Remove covariate from search
+        covSearchBackward.covcatNamesTest(ixBEST)   = [];
+        covSearchBackward.delta_forward(ixBEST)     = [];
+        covSearchBackward.delta_backward(ixBEST)    = [];
+        covSearchBackward.paramNamesTest(ixBEST)    = [];
+        covSearchBackward.value                     = NaN(1,length(covSearchBackward.paramNamesTest));
+        
+        levelModel                                  = covariateModelAll{ixBEST};
+        levelCount                                  = levelCount+1;
+        BackwardModelName                           = ModelNameAll{ixBEST};
+        
+        % Update values in covSearchBackward to estimated ones in best model
+        covInfo                                     = LEVEL_RESULTS(ixBEST).rawParameterInfo.covariate;
+        
+        for k1x = 1:length(covSearchBackward.paramNamesTest),
+            paramUpdate = covSearchBackward.paramNamesTest{k1x};
+            covUpdate   = covSearchBackward.covcatNamesTest{k1x};
+            
+            % Find parameter and covariate
+            matchIX = [];
+            for kkkx=1:length(covInfo.names),
+                ixParam = strfind(covInfo.names{kkkx},paramUpdate);
+                ixCov = strfind(covInfo.names{kkkx},covUpdate);
+                if ~isempty(ixParam) && ~isempty(ixCov),
+                    matchIX(end+1) = kkkx;
+                end
+            end
+            if length(matchIX) ~= 1,
+                error('Problem with getting covariate coefficient value.');
+            end
+            
+            % Add value to covSearchBackward
+            covSearchBackward.value(k1x) = covInfo.values(matchIX);
+        end
+    end
+    
+    if  isempty(covSearchBackward.paramNamesTest),
+        continueBackwardSearch = 0;
+        % Finalize table for this level by adding footer
+        tableText(end,1:2) = {'<TF>' 'All candidate covariates removed in backward elimination.'};
+    end
+    
+    % Export table for the level into the log file
+    textDisplay = IQMconvertCellTable2ReportTable(tableText,'text');
+    fprintf(fid,'%s\n',textDisplay);
+end
+
+% Get backward results
+BACKWARD_OFV = OLD_OFV;
+backwardModel = levelModel;
+
+% Report backward model
+fprintf(fid,'************************************\n');
+fprintf(fid,'* BACKWARD MODEL RESULTS           *\n');
+fprintf(fid,'************************************\n');
+fprintf(fid,'\n');
+
+fprintf(fid,'Backward model:            %s\n',BackwardModelName);
+if ~isempty(backwardModel),
+    fprintf(fid,'Covariates:                "%s"\n',backwardModel);
+else
+    fprintf(fid,'Covariates:                "NONE"\n');
+end    
+fprintf(fid,'Objective function value:  %g\n',BACKWARD_OFV);
+fprintf(fid,'\n');
+
+% Close report file
+fclose(fid);
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/09-NLMEtools/IQMtrialGroupSimulation.m b/IQMtools V1.2.2.2/IQMpro/tools/09-NLMEtools/IQMtrialGroupSimulation.m
new file mode 100644
index 0000000000000000000000000000000000000000..2f51a4a2b1317e816910f7017867085b0880eae9
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/09-NLMEtools/IQMtrialGroupSimulation.m	
@@ -0,0 +1,350 @@
+function [output] = IQMtrialGroupSimulation(model,dosing,NLMEproject,OBSTIME,outputs,covcatregdata,options)
+% This function performs a trial simulation for a single treatment arm,
+% defined by a dosing object and "OBSTIME". "NTRIALS" are simulated with each
+% "NSUBJECTS" subjects. The specified "model" and "dosing" scheme are used
+% for the simulation. Model parameters are sampled from the NLME
+% project in "NLMEproject". Covariates can be taken into account and will be
+% identified from the NLME project. Possible values for covariates need to
+% be provided as a MATLAB table in "covcatregdata". Columns need to have
+% the names of the covariates. Additionally, regression parameters can be
+% provided, if present in the "model". These as well should be present as
+% columns in "covcatregdata". In each simulated trial "NSAMPLES" rows of
+% "covcatregdata" are sampled, allowing to keep the correlations between
+% the covariates and the regression parameters.
+% 
+% The "dosing" input can contain a single dosing object. In this case the
+% same dosing is applied in each simulation. For VPCs or weight based
+% dosing, etc. this is not sufficient. Therefore, it is possible to provide
+% a cell-array of dosing objects as "dosing". This cell-array has to have
+% the same length as "covcatregdata". Then each n-th element of this
+% cell-array is used as a dosing for the covariate/regression parameter
+% combination in the n-th row of "covcatregdata". If "covcatregdata" is
+% empty or does contain a single row then multiple dosings are possible -
+% with same covcatregdata.
+% 
+% The simulation results consist of customizable quantiles of the data and
+% their uncertainty. If desired, additionally all simulated individual data
+% is returned (for each trial).
+%
+% [SYNTAX]
+% [output] = IQMtrialGroupSimulation(model,dosing,NLMEproject,OBSTIME)
+% [output] = IQMtrialGroupSimulation(model,dosing,NLMEproject,OBSTIME,outputs)
+% [output] = IQMtrialGroupSimulation(model,dosing,NLMEproject,OBSTIME,outputs,covcatregdata)
+% [output] = IQMtrialGroupSimulation(model,dosing,NLMEproject,OBSTIME,outputs,covcatregdata,options)
+%
+% [INPUT]
+% model:            IQMmodel object (merged with dosing or not) or string
+%                   with name of the mexmodel that has been prepared
+%                   previously for simulation (already merged with dosing
+%                   scheme)
+% dosing:           Dosing scheme to be simulated. Can be a cell-array with
+%                   as many dosings as number of parameter sets. Then for
+%                   each covariate and regression parameter set the
+%                   corresponding dosing is simulated. In this case the
+%                   dosings need to have all the same structure (inputs and
+%                   input types). 
+% NLMEproject:      Path to the NLME project to sample parameters from.
+%                   For each trial population parameters are sampled from
+%                   the uncertainty distribution. Then NSAMPLES individual
+%                   sets of parameters are sampled.
+% OBSTIME:          Observation times to read out the outputs.
+% outputs:          String with the name of the model variable report as
+%                   output. Or cell-array with model outputs. Only states
+%                   and variables can be used as outputs. If not provided
+%                   or kept empty ([] or '' or {}) then the outputs are
+%                   used which are stored in the NLME project.
+% covcatregdata:    MATLAB table with covariate (continuous and
+%                   categorical) and regression parameter information in
+%                   the columns. Typically this information will come from
+%                   the dataset that has been used for fitting the model
+%                   but own values can be provided. For each subject to
+%                   sample from one row needs to be present. The names of
+%                   the columns need to match the covariate and regression
+%                   parameter names, used in the model. If kept empty, then
+%                   no covariates are considered for simulation. If kept
+%                   empty and the model contains regression parameters, an
+%                   error will be shown. If not provided then it is set to
+%                   empty ([]).
+%
+% options:          Matlab structure with additional information
+%       options.optionsIntegrator:      Integrator options (see IQMmakeMEXmodel)      
+%       options.N_PROCESSORS_PAR:       Number of processors to simulate in parallel (requires parallel toolbox) (default: as specified in SETUP_PATHS_TOOLS_IQMPRO)
+%       options.NSUBJECTS:              Number of subjects per trial (default: 100) 
+%       options.NTRIALS:                Number of trials (default: 100)      
+%       options.QUANTILESDATA:          Vector with quantiles to compute from the data for each trial (default: [0.05 0.5 0.95])    
+%       options.QUANTILESUNCERTAINTY:   Vector with quantiles to compute for each trial quantiles for all trials (uncertainty of data quantiles) (default: [0.05 0.5 0.95])          
+%       options.KEEP_TRIAL_INDIVDATA:   =0: Do not keep individual data in the output (saves memory), =1: keep it (default: 0)
+%
+% [OUTPUT]
+% output: Matlab structure with results
+%       output.name:                        String with output name
+%       output.time:                        Timevector of the simulation
+%       output.QUANTILESDATA:               options.QUANTILESDATA
+%       output.QUANTILESUNCERTAINTY:        options.QUANTILESUNCERTAINTY
+%       output.quantilesData_uncertainty:   Cell-array with as many entries
+%                                           and entries in QUANTILESDATA.
+%                                           Each element contains the
+%                                           uncertainty quantiles for each
+%                                           data quantile. 
+%       output.data_individual_per_trial:   Cell-array with each element
+%                                           containing individual data for
+%                                           each trial. Columns:
+%                                           individuals, Rows: OBSTIME
+%                                           timepoints.       
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle cell
+if ischar(model),
+    model = IQMmodel(model);
+end
+if ischar(dosing),
+    dosing = IQMdosing(dosing);
+end
+
+% Handle variable input arguments
+if nargin<5,
+    outputs             = {};
+end
+if nargin<6,
+    covcatregdata       = [];
+end
+if nargin<7,
+    options             = [];
+end
+
+% Handle options
+try optionsIntegrator           = options.optionsIntegrator;    catch,  optionsIntegrator       = [];                       end
+try N_PROCESSORS_PAR            = options.N_PROCESSORS_PAR;     catch,  N_PROCESSORS_PAR        = getN_PROCESSORS_PARIQM(); end
+try NSUBJECTS                   = options.NSUBJECTS;            catch,  NSUBJECTS               = 100;                      end
+try NTRIALS                     = options.NTRIALS;              catch,  NTRIALS                 = 100;                      end
+try QUANTILESDATA               = options.QUANTILESDATA;        catch,  QUANTILESDATA           = [0.05 0.5 0.95];          end
+try QUANTILESUNCERTAINTY        = options.QUANTILESUNCERTAINTY; catch,  QUANTILESUNCERTAINTY    = [0.05 0.5 0.95];          end
+try KEEP_TRIAL_INDIVDATA        = options.KEEP_TRIAL_INDIVDATA; catch,  KEEP_TRIAL_INDIVDATA    = 0;                        end    
+    
+% If NSUBJECTS=1 then set to NSUBJECTS = 2
+if NSUBJECTS==1,
+    NSUBJECTS=2;
+end
+
+% Handle cell things
+if ~iscell(outputs),
+    outputs = {outputs};
+end
+if ~iscell(dosing),
+    dosing = {dosing};
+end
+
+% Get the project header
+project_header          = parseNLMEprojectHeaderIQM(NLMEproject);
+
+% Get outputs to simulate from the NLMEproject - if not defined by the
+% user. Fitting might be done on absolute PD, which is output of model for
+% fitting but simulation might be done on relative PD, requiring user
+% defined output.
+if isempty(outputs),
+    outputs             = project_header.OUTPUTS;
+end
+
+% Get covariatenames (only the ones that have been used in the model)
+COVARIATESUSED          = project_header.COVARIATESUSED;    if length(COVARIATESUSED)==1 && isempty(COVARIATESUSED{1}), COVARIATESUSED  = {};       end
+COVNAMES                = project_header.COVNAMES;          if length(COVNAMES)==1 && isempty(COVNAMES{1}),             COVNAMES        = {};       end
+CATNAMES                = project_header.CATNAMES;          if length(CATNAMES)==1 && isempty(CATNAMES{1}),             CATNAMES        = {};       end
+covNames                = intersect(COVNAMES,COVARIATESUSED);
+catNames                = intersect(CATNAMES,COVARIATESUSED);
+
+% Get regression parameter names
+regNames                = project_header.REGRESSIONNAMES; if length(regNames)==1 && isempty(regNames{1}), regNames = {}; end
+
+% If regression parameters are present in the model but no covcatregdata then an error will be shown
+if isempty(covcatregdata) && ~isempty(regNames),
+    error('Model contains regression parameters but no "covcatregdata" provided as input.');
+end
+
+% Handle empty covcatregdata - then do not use covariate information - but warn the user!
+if isempty(covcatregdata),
+    covcatregdata = table();
+    % If these data are not provided, covariates in the model are going to be neglected.
+    if ~isempty(covNames) || ~isempty(catNames),
+        disp('No covariate parameter data defined, but present in the model.');
+        disp('=> Covariates will not be considered in the model.');
+        covNames = {};
+        catNames = {};
+    end
+else
+    % If covcatregdata not empty then remove covariates that are not
+    % present in the covcatregdata
+    covNames_reduced    = intersect(covNames,covcatregdata.Properties.VariableNames);
+    catNames_reduced    = intersect(catNames,covcatregdata.Properties.VariableNames);
+    % Warn the user
+    covcatNames_missing = [setdiff(covNames,covNames_reduced) setdiff(catNames,catNames_reduced)];
+    if ~isempty(covcatNames_missing),
+        disp('The following covariates are in the model but have not been provided in covcatregdata:');
+        disp(covcatNames_missing);
+        % Update cov cat names
+        covNames            = covNames_reduced;
+        catNames            = catNames_reduced;
+    end
+end
+
+% Check if reg names in the provided covcatregdata
+checkDataColumnsIQM(covcatregdata,regNames);
+
+% Handle the interplay between dosing and covcatregdata
+%   The "dosing" input can contain a single dosing object. In this case the
+%   same dosing is applied in each simulation. For VPCs or weight based
+%   dosing, etc. this is not sufficient. Therefore, it is possible to provide
+%   a cell-array of dosing objects as "dosing". This cell-array has to have
+%   the same length as "covcatregdata". Then each n-th element of this
+%   cell-array is used as a dosing for the covariate/regression parameter
+%   combination in the n-th row of "covcatregdata". If "covcatregdata" is
+%   empty or does contain a single row then multiple dosings are possible -
+%   with same covcatregdata.
+if length(dosing)==1 && height(covcatregdata)>1,
+    % Allowed, expand dosing to match height of covcatregdata
+    temp = cell(height(covcatregdata),1); temp(1:end) = dosing; dosing = temp;
+elseif length(dosing)>1 && height(covcatregdata) == 1,
+    % Allowed, expand covcatregdata to match length of dosing
+    covcatregdata = covcatregdata(ones(1,length(dosing)),:);
+elseif isempty(covcatregdata),
+    % Allowed => do not change anything in dosing ... keep it
+elseif length(dosing) == height(covcatregdata),
+    % Allowed => do nothing
+else
+    % All other cases not allowed
+    error('Length of dosing not compatible with height of covcatregdata.');
+end
+
+% Check if model needs to be merged and compiled - if model given as string
+% then assume MEX file name provided (already merged with dosing)
+if ~ischar(model),
+    try
+        moddos      = mergemoddosIQM(model,dosing{1});
+        % Will lead to an error if already merged ...
+    catch
+        moddos      = model;
+    end
+    % Create mex model temp file name
+    [~,mexModel]    = fileparts(tempname);
+    IQMmakeMEXmodel(moddos,mexModel);
+    removeMexModel  = 1;
+else
+    mexModel = model;
+    removeMexModel  = 0;
+end
+
+% Get parallel nodes
+killMATLABpool = startParallelIQM(N_PROCESSORS_PAR);
+
+% Initialize output
+collect_output = [];
+
+% Loop the trials
+for kTRIAL=1:NTRIALS,
+
+    % Sample NSUBJECTS row wise from covcatregdata and dosing (keeping correlations of covValues, catValues, regValues, and dosing the same)
+    % covcatregdata might be empty, dosing is not, so use length of dosing to sample indices
+    ix_samples              = ceil(length(dosing)*rand(NSUBJECTS,1));
+    dosing_sampled          = dosing(ix_samples);
+    if ~isempty(covcatregdata),
+        covcatregdata_sampled   = covcatregdata(ix_samples,:);
+    else
+        covcatregdata_sampled   = [];
+    end
+
+    % Get sampled cov, cat, regvalues
+    covValues               = []; for k=1:length(covNames), covValues(:,k) = covcatregdata_sampled.(covNames{k}); end
+    catValues               = []; for k=1:length(catNames), catValues(:,k) = covcatregdata_sampled.(catNames{k}); end
+    regValues               = []; for k=1:length(regNames), regValues(:,k) = covcatregdata_sampled.(regNames{k}); end
+    
+    % Sample individual parameters from NLMEproject after sampling population
+    % parameters from uncertainty distribution
+    paramFIT                = IQMsampleNLMEfitParam(NLMEproject,1,NSUBJECTS,covNames,covValues,catNames,catValues);
+      
+    % Combine FIT and REGRESSION parameters to simulation parameters
+    paramNames              = [paramFIT.parameterNames regNames];
+    paramValues             = [paramFIT.parameterValuesIndividual regValues];
+    
+    % Search for Tinfinput and Tlaginput parameter names and if 0 then exchange to 1e-10
+    % Otherwise numerical problems!
+    ixxx                    = strmatchIQM('Tk0input',paramNames);
+    for kxxx=1:length(ixxx),
+        xxx = paramValues(:,ixxx(kxxx));
+        xxx(xxx<=2e-10) = 1e-10;
+        paramValues(:,ixxx(kxxx)) = xxx;
+    end
+    ixxx                    = strmatchIQM('Tinfinput',paramNames);
+    for kxxx=1:length(ixxx),
+        xxx = paramValues(:,ixxx(kxxx));
+        xxx(xxx<=2e-10) = 1e-10;
+        paramValues(:,ixxx(kxxx)) = xxx;
+    end
+    
+    % Simulate the group
+    warning off;
+    factorDose              = []; % Assume all doses in dosing objects absolute with no need to scale (e.g. by bodyweight)
+    result_trial            = simulateGroupIQM(mexModel,dosing_sampled,outputs,OBSTIME,paramNames,paramValues,[],optionsIntegrator);
+    warning on;
+    
+    % Store output
+    collect_output(kTRIAL).trial                            = kTRIAL;
+    for kOUT=1:length(result_trial),
+        collect_output(kTRIAL).data(kOUT).name              =  result_trial(kOUT).name;
+        collect_output(kTRIAL).data(kOUT).quantiles         = QUANTILESDATA;
+        collect_output(kTRIAL).data(kOUT).quantilesData     = quantileIQM(result_trial(kOUT).values',[0.05 0.5 0.95])';
+        if KEEP_TRIAL_INDIVDATA,
+            collect_output(kTRIAL).data(kOUT).values        = result_trial(kOUT).values;
+        end
+    end
+end
+
+% Stop parallel nodes
+stopParallelIQM(killMATLABpool);
+
+% Remove mexModel
+clear mex
+if removeMexModel
+    delete([mexModel '.' mexext]);
+end
+
+% Collect all data quantile information for the trials
+qDATA_TRIAL = cell(length(collect_output(kTRIAL).data),length(QUANTILESDATA));
+for kTRIAL=1:length(collect_output),
+    for kOUT=1:length(collect_output(kTRIAL).data),
+        q = collect_output(kTRIAL).data(kOUT).quantilesData;
+        for kq=1:size(q,2),
+            qDATA_TRIAL{kOUT,kq} = [qDATA_TRIAL{kOUT,kq} q(:,kq)];
+        end
+    end
+end
+% qDATA_TRIAL each row contains results for one output
+% qDATA_TRIAL each column contains results for one QUANTILEDATA
+% qDATA_TRIAL each element contains results for all trials (colums: trial, rows: OBSTIME timepoints)
+
+% Determine uncertainties for the data quantiles
+qDATAUNCERTAINTY = cell(size(qDATA_TRIAL));
+for kOUT=1:size(qDATA_TRIAL,1),
+    for kQD=1:size(qDATA_TRIAL,2),
+        qDATAUNCERTAINTY{kOUT,kQD} = quantileIQM(qDATA_TRIAL{kOUT,kQD}',QUANTILESUNCERTAINTY)';
+    end
+end
+% qDATAUNCERTAINTY: each row corresponds to an output, each column to a
+% data quantile. Each elements contains the uncertainty quantiles over time.
+
+% Construct the output
+output                                  = [];
+for k=1:length(outputs),
+    output(k).name                      = outputs{k};
+    output(k).time                      = OBSTIME;
+    output(k).NTRIALS                   = NTRIALS;
+    output(k).NSUBJECTS                 = NSUBJECTS;    
+    output(k).QUANTILESDATA             = QUANTILESDATA;
+    output(k).QUANTILESUNCERTAINTY      = QUANTILESUNCERTAINTY;
+    output(k).quantilesData_uncertainty = qDATAUNCERTAINTY(k,:);
+    if KEEP_TRIAL_INDIVDATA,
+        output(k).data_individual_per_trial = {};
+        for k2=1:length(collect_output),
+            output(k).data_individual_per_trial{k2} = collect_output(k2).data(k).values;
+        end
+    end
+end
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/09-NLMEtools/auxiliary/simulateGroupIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/09-NLMEtools/auxiliary/simulateGroupIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..bd005c1292eda9542e7b2bba59209118dd428e19
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/09-NLMEtools/auxiliary/simulateGroupIQM.m	
@@ -0,0 +1,241 @@
+function [output] = simulateGroupIQM(model,dosing,outputs,OBSTIME,paramNames,paramValues,factorDose,options)
+% This function simulates a given model for (a) given dosing scheme(s), returns
+% the selected outputs at times OBSTIME. Simulations are done for each row
+% in the paramValues input argument. 
+%
+% If dosing has a single element then the same dosing is used for each
+% simulation. If it is a cell-array then this array has to have the length
+% of the number of parameter sets to be simulated and for each parameter
+% set the corresponding dosing is used. 
+%
+% The factorDose argument needs to contain as many columns as INPUT
+% definitions in the dosing scheme(s). The value in each column is
+% multiplied with the corresponding dose input in the dosing scheme. If
+% factorDose contains only a single row then the same factors are used for
+% all simulations. If it contains as many rows as paramValues (and maybe
+% dosing has elements - if not scalar) then different factors can be
+% applied for each individual simulation.
+%
+% [SYNTAX]
+% [output] = simulateGroupIQM(model,dosing,outputs,OBSTIME,paramNames,paramValues)
+% [output] = simulateGroupIQM(model,dosing,outputs,OBSTIME,paramNames,paramValues,factorDose)
+% [output] = simulateGroupIQM(model,dosing,outputs,OBSTIME,paramNames,paramValues,factorDose,options)
+%
+% [INPUT]
+% model:            IQMmodel object (merged with dosing or not) or string
+%                   with name of the mexmodel that has been prepared
+%                   previously for simulation (already merged with dosing
+%                   scheme)
+% dosing:           Dosing scheme to be simulated. Can be a cell-array with
+%                   as many dosings as number of parameter sets. Then for
+%                   each parameter set the corresponding dosing is
+%                   simulated. In this case the dosings need to have all
+%                   the same structure (inputs and input types).
+% outputs:          String with the name of the model variable report as
+%                   output. Or cell-array with model outputs. Only states
+%                   and variables can be used as outputs.
+% OBSTIME:          Observation times to read out the outputs
+% paramNames:       Cell-array with names of parameters to change in the
+%                   model.
+% paramValues:      Matrix parameter values to be changed in the model -
+%                   same order as paramNames (in columns). Each row a
+%                   different set of parameters to be simulated.  
+% factorDose:       Scalar, matrix, or vector. As many columns as dosing
+%                   object has inputs. Either single row or as many rows as
+%                   paramValues. Each column value multiplied to the
+%                   dose of the corresponding input in dosing scheme.
+%                   Default: no scaling of dose.
+%
+% options:          Matlab structure with integrator options
+%       OPTIONS.method:             'stiff' or 'nonstiff' (default: 'stiff')
+%       OPTIONS.abstol:             abs tolerance (default: 1e-6)
+%       OPTIONS.reltol:             rel tolerance (default: 1e-6)
+%       OPTIONS.minstep:            min step-size integrator (default: 0)
+%       OPTIONS.maxstep:            max step-size integrator (default: inf)
+%       OPTIONS.maxnumsteps:        max number of steps between two output
+%                                   points (default: 100000)
+%       OPTIONS.maxerrtestfails:    maximum number of error test failures
+%                                   permitted in attempting one step
+%                                   (default: 50)
+%       OPTIONS.maxorder:           maximum order of the linear multistep
+%                                   method (default: 5 BDF, 12 ADAMS)
+%       OPTIONS.maxconvfails:       maximum number of nonlinear solver convergence 
+%                                   failures permitted during one step
+%                                   (default: 10)
+%       OPTIONS.initstep:           initial step size to be attempted
+%                                   (default: 0)
+%       OPTIONS.maxnonlineariter:   maximum number of nonlinear solver
+%                                   iterations permitted per step 
+%                                   (default: 3)
+%
+% [OUTPUT]
+% output: Matlab structure with simulation results
+%       output.name:                String with entries in outputs
+%       output.values:              Matrix with as many columns as
+%                                   paramValues has rows
+%                                   and as many rows and OBSTIME
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle variable input arguments
+if nargin<7,
+    factorDose = [];
+end
+if nargin<8,
+    options = [];
+end
+
+% Handle cells
+if ~iscell(dosing),
+    dosing = {dosing};
+end
+if ~iscell(outputs),
+    outputs = {outputs};
+end
+
+% Determine numbers 
+NR_SIM      = size(paramValues,1); % Parameters set (simulations)
+ds = struct(dosing{1});
+NR_INPUTS   = length(ds.inputs); % Number dosing inputs
+
+% Expand if needed
+if length(dosing) == 1,
+    temp        = cell(NR_SIM,1);
+    temp(1:end) = dosing;
+    dosing      = temp; 
+end
+if isempty(factorDose),
+    factorDose = ones(1,NR_INPUTS);
+end
+if size(factorDose,1) == 1,
+    factorDose = factorDose(ones(1,NR_SIM),:);
+end
+
+% Check size of dosing, paramValues and factorDose
+if length(dosing) ~= size(paramValues,1),
+    error('Different number of dosing and paramValues.');
+end
+if length(dosing) ~= size(factorDose,1),
+    error('Different number of dosing and factorDose or factorDose and paramValues.');
+end
+
+% Check size paramNames and paramValues
+if length(paramNames) ~= size(paramValues,2),
+    error('Different number of paramNames and columns in paramValues.');
+end
+
+% Check if model contains outputs
+errorText = '';
+for k=1:length(outputs),
+    ix = strmatchIQM(outputs{k},[IQMstates(model)' IQMvariables(model)'],'exact');
+    if isempty(ix),
+        errorText = sprintf('%sOutput "%s" is not present in the model as state or variable.',errorText,outputs{k});
+    end
+end
+if ~isempty(errorText),
+    error(errorText);
+end
+
+% Check if model needs to be merged and compiled - if model given as string
+% then assume MEX file name provided (already merged with dosing)
+if ~ischar(model),
+    try
+        moddos = mergemoddosIQM(model,dosing{1});
+        % Will lead to an error if already merged ...
+    catch
+        moddos = model;
+    end
+    % Create mex model temp file name
+    [~,mexModel] = fileparts(tempname);
+    IQMmakeMEXmodel(moddos,mexModel);
+    removeMexModel = 1;
+else
+    mexModel = model;
+    removeMexModel = 0;
+end
+
+% Check if model contains parameters
+errorText = '';
+for k=1:length(paramNames),
+    ix = strmatchIQM(paramNames{k},IQMparameters(mexModel),'exact');
+    if isempty(ix),
+        errorText = sprintf('%sParameters "%s" is not present in the model.',errorText,paramNames{k});
+    end
+end
+if ~isempty(errorText),
+    error(errorText);
+end
+
+% Update dosing schemes with factorDose
+for k=1:length(dosing),
+    ds = struct(dosing{k});
+    for k2=1:length(ds.inputs),
+        ds.inputs(k2).D = factorDose(k,k2)*ds.inputs(k2).D;
+    end
+    dosing{k} = IQMdosing(ds);
+end
+
+% Initialize output structure
+output = [];
+for k=1:length(outputs),
+    output(k).name      = outputs{k};
+    output(k).values    = [];
+end
+
+% Initialize collection variable for parfor loop
+values = [];
+
+% Force stiff method due to some strange thing...
+options.METHOD = 'stiff';
+
+% Simulate 
+parfor k=1:NR_SIM,
+    paramSimValues = paramValues(k,:);
+    
+    % Need to adjust the Tlag parameters in case it is 1e-10 => set to 0
+    % Mainly for popPK workflow. Will not impact anything else at all ...
+    % 1e-10 is so small that it does not make a difference.
+    ix = strmatchIQM('Tlag',paramNames);
+    for klag=1:length(ix),
+        if paramSimValues(ix(klag)) < 1e-10,
+            paramSimValues(ix(klag)) = 0;
+        end
+    end
+
+    % Simulate
+    try
+        simres = IQMsimdosing(mexModel,dosing{k},OBSTIME,[],paramNames,paramSimValues,options);
+
+        % Get outputs
+        output_values = [];
+        for k2=1:length(outputs),
+            si = stateindexIQM(mexModel,outputs{k2});
+            if ~isempty(si),
+                output_values(:,k2) = simres.statevalues(:,si)';
+            end
+            vi = variableindexIQM(mexModel,outputs{k2});
+            if ~isempty(vi),
+                output_values(:,k2) = simres.variablevalues(:,vi)';
+            end
+        end
+    catch
+        output_values = NaN(length(OBSTIME),length(outputs));
+        disp(lasterr);
+    end
+    
+    % Collect output values
+    values = [values output_values];
+end
+
+% Split values to output
+for k=1:length(outputs),
+    output(k).values = values(:,k:length(outputs):end);
+end
+
+% Remove mexModel
+clear mex
+if removeMexModel
+    delete([mexModel '.' mexext]);
+end
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/IQMbuildPopPKModelSpace.m b/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/IQMbuildPopPKModelSpace.m
new file mode 100644
index 0000000000000000000000000000000000000000..a91ceaeb3f8e9a3325705af1949da26aa5721ca8
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/IQMbuildPopPKModelSpace.m	
@@ -0,0 +1,270 @@
+function [] = IQMbuildPopPKModelSpace(nameSpace, modeltest, analysisDatasetFile, dataheaderNLME, optionsNLME, optionsModelSpace)
+% This functions allows to assess a user defined popPK model subspace.
+% Models within this subspace will be created / run / results will be
+% imported / fitness assessments will be generated / table to compare
+% different models will also be generated.
+% 
+% Even if this function is quite comprehensive, it is impossible to handle
+% ALL possible PK model structures. The goal is to handle the most common
+% ones. Applying the Pareto principle.
+%
+% Currently covered are:
+%  1,2,3 compartmental models
+%  IV bolus and/or infusion
+%  Zero-order, first-order, and mixed absorption models (parallel and sequential)
+%  Linear, saturable, and linear+saturable clearance
+%  Lagtime on 0th and 1st order absorption
+%
+% Use of NONMEM or MONOLIX. NONMEM is often faster, MONOLIX typically is more robust and
+% does not have the numerical issues observed with the far older software NONMEM.
+%
+% Assumptions:
+% - Covariates always log transformed and centered by the median
+% - All individual parameters assumed log normally distributed
+%
+% [SYNTAX]
+% [] = IQMbuildPopPKModelSpace(nameSpace, modeltest, analysisDatasetFile, dataheaderNLME)
+% [] = IQMbuildPopPKModelSpace(nameSpace, modeltest, analysisDatasetFile, dataheaderNLME, optionsNLME)
+% [] = IQMbuildPopPKModelSpace(nameSpace, modeltest, analysisDatasetFile, dataheaderNLME, optionsNLME, optionsModelSpace)
+%
+% [INPUT]
+% nameSpace:                                Unique identifier for giving the output folders and files a name
+% modeltest:                                MATLAB structure with model space information
+% analysisDatasetFile:                      Relative path including filename to the popPK dataset from where this function is called 
+% dataheaderNLME:                           Data set header definition for Monolix and NONMEM (see IQMgetNLMEdataHeader)
+%
+%    DEFINITIONS REQUIRED FOR:
+%    -------------------------          
+%       modeltest.numberCompartments        Vector, defining the number of compartments to test. Example: = [1 2 3]  or [1 2] or 3
+%       modeltest.errorModels               Cell-array, defining the residual error models to test. Example: {'const','prop','comb1'}
+%       modeltest.errorParam0:              Cell-array with as many elements as outputs in the error models to be tested. Each 
+%                                           element is a vector with initial guesses for a and b of the error model parameters. 
+%                                           Example: {[0.5] [0.3] [0.5 0.3]}  'const': a, 'prop': b, 'comb1': a,b
+%       modeltest.saturableClearance        Vector with elements 0 and or 1.
+%       modeltest.FACTOR_UNITS              Conversion factor for dose and concentration units
+%       modeltest.POPvalues0                Vector with starting guesses for fixed effect parameters 
+%                                                      CL    Vc    Q1    Vp1    Q2    Vp2    Fiv    Fabs1    ka    TlagAbs1   Fabs0   Tk0   TlagAbs0   Frel0   VMAX   KM
+%                                           Example: [ 5     50    10    500    10    500    1      1        1     0.5        1       1     0.5        0.5     1e-10   10];
+%                                           This can also be a cell-array with multiple vectors for initial guesses
+%       modeltest.POPestimate               Vector with flags defining if fixed effects estimated or kept fix on initial guess   
+%                                                      CL    Vc    Q1    Vp1    Q2    Vp2    Fiv    Fabs1    ka    TlagAbs1   Fabs0   Tk0   TlagAbs0   Frel0   VMAX   KM
+%                                           Example: [ 1     1     1     1      1     1      0      0        1     1          0       1     1          1       1       1];
+%                                           This can also be a cell-array with multiple vectors for estimation definitions
+%       modeltest.IIVestimate               Vector with flags defining if random effects estimated or kept fixed on initial guess, or set to fixed 0   
+%                                                      CL    Vc    Q1    Vp1    Q2    Vp2    Fiv    Fabs1    ka    TlagAbs1   Fabs0   Tk0   TlagAbs0   Frel0   VMAX   KM
+%                                           Example:  [1     1     1     1      1     1      0      0        1     1          0       1     1          1       1       2]
+%  			                                    0: IIV not estimated (IIVvalues0 not used) 
+%           			                        1: IIV estimated (IIVvalues0 as starting guesses)
+%                       		                2: IIV not estimated but fixed on IIVvalues0 value
+%                                             This can also be a cell-array with multiple vectors for estimation definitions
+%
+%    DEFINITIONS OPTIONAL FOR:
+%    -------------------------
+%       modeltest.absorptionModel           Vector with elements: 1 (first order) 0 (zero order) 2 (mixed first and 
+%                                           zero order (parallel) absorption) and/or 3 (mixed 0/1 sequential). This is an optional definition, since 
+%                                           only needed when absorption data (1st or 0 order present). By default only
+%                                           first order absorption is considered. Default value: 1.
+%       modeltest.lagTime                   Vector with elements 0 and or 1.
+%                                           This is an optional definition, since only needed when absorption data 
+%                                           (1st or 0 order present). By default no lag time is considered. 
+%                                           Default value: 0.
+%
+%       modeltest.IIVvalues0                Vector with starting guesses for random effect parameters 
+%                                                     CL    Vc    Q1    Vp1    Q2    Vp2    Fiv    Fabs1    ka    TlagAbs1   Fabs0   Tk0   TlagAbs0   Frel0   VMAX   KM
+%                                           Example: [0.5   0.5   0.5   0.5    0.5   0.5    0.5    0.5      0.5   0.5        0.5     0.5   0.5        0.5     0.5     0.5];
+%                                           This can also be a cell-array with multiple vectors for initial guesses
+%                                           By default the intial guesses for random effect are 0.5.
+%       modeltest.covarianceModels          String with covariance settings for random effects.
+%                                           Example: '{CL,Vc,Vp2},{Q1,ka,VMAX}'
+%                                               This will estimate the covariances between the random effect of the parameters in the curly brackets.
+%                                           Default is '', which is a diagonal covariance matrix. 
+%                                           Can be a cell-array of strings - all definitions will be combined with all others
+%       modeltest.covariateModels           String defining the covariate model
+%                                           Example: '{CL,WT0,AGE0,SEX},{Vc,WT0}'
+%                                               This will add WT0, AGE0 and SEX as covariates on CL and WT0 on Vc.
+%                                               For each parameter and covariate a separate covariate coefficient is estimated.
+%                                               The covariate relationship is obtained by the distribution of the individual parameters for a parameter
+%                                               and the transformation of the covariate. By default the continuous covariates are centered by the data median
+%                                               and then log transformed.
+%                                           Can be a cell-array - all definitions will be combined with all others
+%                                           >>>Covariates can be added to all parameters for which not both IIVestimate and POPestimate are 0.
+%       modeltest.covariateModelValues      Cell-array with vector entries, defining the starting guesses for covariate coefficients
+%                                           Example: { [0.75 0.6 0.2], [1]} - matching the "covariateModels" example above.
+%                                           If undefined, values start at 0 (or for NONMEM more at 0.1)
+%                                           If covariateModels is a cell array this has also to be grouped into a cell-array with same length.
+%                                           For categorical covariates with multiple categories only the same value (1 value can be set)
+%       modeltest.COVestimate               Cell-array with vector entries, defining if covariate coefficients will be estimated (1) or not (0) 
+%                                           Example: { [0 1 1], [0]} - matching the "covariateModels" example above.
+%                                           If undefined, all covariate coefficients are estimated.
+%                                           If covariateModels is a cell array this has also to be grouped into a cell-array with same length.
+%       modeltest.COVcentering.covs:        Cell-array with covariates that should be centered around a custom value. (default: {})
+%       modeltest.COVcentering.values:      Vector with centering values (default: [] - median)
+%
+%       modeltest.covariateModelsTV:        String with comma-separated names of time dependent covariates. These are defined normally, using the
+%                                           covariateModels, etc. fields and here only need to be named. Only needed when using SAEM!
+%
+% optionsNLME: Options for NLME algorithm settings
+%   General 
+%   -------
+%       optionsNLME.parameterEstimationTool:        Define to use NONMEM or MONOLIX. 'NONMEM' or 'MONOLIX' (default) as entries. 
+%
+%       optionsNLME.N_PROCESSORS_PAR:               Number of parallel model runs (default: as specified in SETUP_PATHS_TOOLS_IQMPRO)
+%       optionsNLME.N_PROCESSORS_SINGLE:            Number of processors to parallelize single run (if NONMEM and MONOLIX allow for it) (default: 1)
+%
+%       optionsNLME.algorithm.SEED:                 Seed setting. Defualt: 123456
+%       optionsNLME.algorithm.K1:                   First iterations. Default: 500
+%       optionsNLME.algorithm.K2:                   Final iterations. Default: 200
+%       optionsNLME.algorithm.K1_AUTO:              Automatic first iteration number (0: off, 1: on). Default: 0
+%       optionsNLME.algorithm.K2_AUTO:              Automatic final iteration number (0: off, 1: on). Default: 0
+%       optionsNLME.algorithm.NRCHAINS:             Number of parallel chains. Default: 1
+%
+%	NONMEM specific
+%	---------------
+%       optionsNLME.algorithm.METHOD:               'FO','FOCE','FOCEI','SAEM' (default: SAEM)
+%       optionsNLME.algorithm.MAXEVAL:              Default: 9999
+%       optioptionsNLMEons.algorithm.SIGDIGITS:     Default: 3
+%       optionsNLME.algorithm.PRINT:                Default: 1
+%       optionsNLME.algorithm.M4:                   Default: 0 (default: M3 method if dataset formated with CENS column and non-zero entries in it.)
+%       optionsNLME.algorithm.ITS:                  Allow to run an ITS method as first method befor all other methods (METHOD)
+%       optionsNLME.algorithm.ITS_ITERATIONS:       Number of iterations for ITS (default: 10)
+%       optionsNLME.algorithm.IMPORTANCESAMPLING:   Allow determination of the OFV - only accepted after SAEM
+%       optionsNLME.algorithm.IMP_ITERATIONS:       Number of iterations for importance sampling (default: 5)
+%
+%   Monolix specific
+%   ----------------
+%       optionsNLME.algorithm.LLsetting:                'linearization' (default) or 'importantsampling'
+%       optionsNLME.algorithm.FIMsetting:               'linearization' (default) or 'stochasticApproximation'
+%       optionsNLME.algorithm.INDIVparametersetting:    'conditionalMode' (default) ... others not considered for now. 
+%
+% optionsModelSpace:            Structure with additional optional information
+%       optionsModelSpace.buildModelsOnly:          =0 (default): build models and run them. =1: build models only, but to not run them
+%       optionsModelSpace.Ntests:                   Number of tests to perform (default=1)
+%       optionsModelSpace.std_noise_setting:        Standard deviation to use to add noise to the initial parameter guesses (default=0.5 (50%CV))
+%                                                       Normal:         Parameter_guess + std_noise_setting*Parameter_guess*randomNumbers(0-1)
+%                                                       Lognormal:      Parameter_guess * exp(std_noise_setting*randomNumbers(0-1))
+%                                                       Logitnormal:    Similar and between 0-1
+%
+% [OUTPUT]
+% - All PK models are created in the ['../Models/' nameSpace] folder 
+% - A modelInfo.txt file is written into the ['../Models/' nameSpace] folder, detailing what the different models contain
+% - Text results for parameters are produced in the ['../Models/' nameSpace] folder 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Define parameternames in ODE and ANALYTIC models. NONLINEAR parameters need to be at the end.
+% Its the required order ... checks for ODE models will be done. MONOLIX works with an analytic template. 
+% For NONMEM no analytic template can be used, since numerics horribly bad. Individual ADVANs will be
+% generated automatically instead.
+TemplateModels = [];
+TemplateModels.ParameterNames.ODE       = {'CL', 'Vc', 'Q1', 'Vp1', 'Q2', 'Vp2', 'Fiv', 'Fabs1', 'ka', 'Tlaginput1', 'Fabs0', 'Tk0input3', 'Tlaginput3', 'Frel0', 'VMAX', 'KM'};
+TemplateModels.IIVdistribution.ODE      = { 'L',  'L',  'L',   'L',  'L',   'L',   'L',     'L',  'L',          'L',     'L',         'L',          'L',     'L',    'L',  'L'};
+TemplateModels.ParameterNames.ANALYTIC  = {'CL', 'Vc', 'Q1', 'Vp1', 'Q2', 'Vp2', 'Fiv', 'Fabs1', 'ka', 'Tlaginput1', 'Fabs0', 'Tk0input3', 'Tlaginput3', 'Frel0'};
+TemplateModels.IIVdistribution.ANALYTIC = { 'L',  'L',  'L',   'L',  'L',   'L',   'L',     'L',  'L',          'L',     'L',         'L',          'L',     'L'};
+TemplateModels.Model.MONOLIX.ANALYTIC            = 'template_popPK_model_ANALYTIC_MLXTRAN.txt';
+TemplateModels.Model.MONOLIX.ANALYTIC_SEQ01ABS   = 'template_popPK_model_ANALYTIC_SEQ01ABS_MLXTRAN.txt';
+TemplateModels.Model.ODE                = 'template_popPK_model.txt';
+TemplateModels.Model.DOSING             = 'template_popPK_dosing.dos';
+TemplateModels.Model.DOSING_SEQ01ABS    = 'template_popPK_dosing_SEQ01ABS.dos';
+% % Define parameters that need to be renamed - to make a better match between them - mainly for display reasons.
+% TemplateModels.ODEparamNamesOld         = {'Tlaginput1', 'Tlaginput3', 'Tk0input3'};
+% TemplateModels.ODEparamNamesNew         = {'TlagAbs1',   'TlagAbs0',   'Tk0'};
+
+% Handle some optional things
+try buildModelsOnly         = optionsModelSpace.buildModelsOnly;        catch, buildModelsOnly          = 0;           end
+try Ntests                  = optionsModelSpace.Ntests;                 catch, Ntests                   = 1;           end
+try std_noise_setting       = optionsModelSpace.std_noise_setting;      catch, std_noise_setting        = 0.5;         end
+try parameterEstimationTool = optionsNLME.parameterEstimationTool;      catch, parameterEstimationTool  = 'MONOLIX';   end
+try N_PROCESSORS_PAR        = optionsNLME.N_PROCESSORS_PAR;             catch, N_PROCESSORS_PAR      = getN_PROCESSORS_PARIQM(); end
+try N_PROCESSORS_SINGLE     = optionsNLME.N_PROCESSORS_SINGLE;          catch, N_PROCESSORS_SINGLE      = 1;           end
+
+% Check NLME tool to be used
+if strcmp(lower(parameterEstimationTool),'monolix'),
+    FLAG_NONMEM = 0;
+elseif strcmp(lower(parameterEstimationTool),'nonmem'),
+    FLAG_NONMEM = 1;
+else
+    error('Unknown NLMETOOL input argument.');
+end
+    
+% Define output location and project name settings
+modelProjectsFolder             = ['../Models/' nameSpace];
+dataRelPathFromProjectPath      = '../../../Data';
+PROJECT_PREFIX                  = ['FIT' nameSpace '_'];
+
+% Handle robustness analysis settings 
+% Allow perturbation only of fixed effects that are also estimated.
+if Ntests > 1,
+    
+    % Repeated fits from different initial guesses desired
+    popvalues0  = modeltest.POPvalues0;
+    popestimate = modeltest.POPestimate;
+    iivestimate = modeltest.IIVestimate;
+    
+    % Check possible errors
+    if ~isvector(popvalues0),
+        error('The repeated fit setting using "optionsModelSpace.Ntests>1" can only be used if "modeltest.POPvalues0" given as a single vector.');
+    end
+    if ~isvector(popestimate),
+        error('The repeated fit setting using "optionsModelSpace.Ntests>1" can only be used if "modeltest.POPestimate" given as a single vector, not as a cell-array!');
+    end
+    if ~isvector(iivestimate),
+        error('The repeated fit setting using "optionsModelSpace.Ntests>1" can only be used if "modeltest.IIVestimate" given as a single vector, not as a cell-array!');
+    end
+    
+    % Get info about parameters where perturbation allowed
+    randomize_parameters = popestimate;
+    
+    % Do sample log-normally distributed parameters 
+    popvaluesnew = {};
+    
+    for k=1:Ntests,
+        POPvalues0_sampled                          = popvalues0;
+
+        % Handle normal distributions
+        ix_normal_sampled                           = find(strcmp(TemplateModels.IIVdistribution.ODE,'N').*randomize_parameters);
+        MU                                          = popvalues0(ix_normal_sampled);
+        XXX                                         = MU.*(1 + std_noise_setting.*randn(1,length(ix_normal_sampled)));
+        POPvalues0_sampled(ix_normal_sampled)       = XXX;
+
+        % Handle log-normal distributions
+        ix_lognormal_sampled                        = find(strcmp(TemplateModels.IIVdistribution.ODE,'L').*randomize_parameters);
+        MU                                          = log(popvalues0(ix_lognormal_sampled));
+        XXX                                         = MU + std_noise_setting.*randn(1,length(ix_lognormal_sampled));
+        POPvalues0_sampled(ix_lognormal_sampled)    = exp(XXX);
+        
+        % Handle logit-normal distributions
+        ix_logitnormal_sampled                      = find(strcmp(TemplateModels.IIVdistribution.ODE,'G').*randomize_parameters);
+        MU                                          = log(popvalues0(ix_logitnormal_sampled)./(1-popvalues0(ix_logitnormal_sampled)));
+        XXX                                         = MU + std_noise_setting.*randn(1,length(ix_logitnormal_sampled));
+        POPvalues0_sampled(ix_logitnormal_sampled)  = exp(XXX)./(1+exp(XXX));
+        
+        % Save sampled starting guesses in cell-array
+        popvaluesnew{k}                             = POPvalues0_sampled;
+    end
+    
+    % Update modeltest structure with sampled starting guesses
+    modeltest.POPvalues0 = popvaluesnew;  
+end
+
+% Create the popPK model projects 
+table_MODEL_INFO = buildPKmodelSpaceIQM(FLAG_NONMEM,TemplateModels,modelProjectsFolder, dataRelPathFromProjectPath, PROJECT_PREFIX,...
+                                       analysisDatasetFile, dataheaderNLME, modeltest, optionsNLME);
+
+% Display the table
+IQMconvertCellTable2ReportTable(table_MODEL_INFO,'text')
+                                   
+% Export table
+IQMconvertCellTable2ReportTable(table_MODEL_INFO,'report',[modelProjectsFolder '/modelInfo.txt']);
+
+% Return if only building models desired
+if buildModelsOnly,
+    return
+end
+
+% Run the popPK model projects
+IQMrunNLMEprojectFolder(modelProjectsFolder,N_PROCESSORS_PAR,N_PROCESSORS_SINGLE);
+
+% Create model comparison tables 
+SETUP_PATHS_TOOLS_IQMPRO
+IQMfitsummaryAll(modelProjectsFolder,modelProjectsFolder,NLME_ORDER_CRITERION);
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/IQMcleanPopPKdataWrapper.m b/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/IQMcleanPopPKdataWrapper.m
new file mode 100644
index 0000000000000000000000000000000000000000..007ef61d7fecbff91f2dd98695784977afa833e7
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/IQMcleanPopPKdataWrapper.m	
@@ -0,0 +1,169 @@
+function [dataCleaned] = IQMcleanPopPKdataWrapper(data,DOSENAME,OBSNAME,covNames,catNames,removeSUBJECT,removeREC,outputPath,catImputationValues)
+% This function is a wrapper for different cleaning functions for standard
+% popPK datasets. Standard here means single compound and single PK
+% readout.
+% 
+% The following "cleaning" functions are called in sequence:
+% 
+% 1) IQMcleanRemoveRecordsSUBJECTs - removes manually selected records and subjects
+%
+% 2) IQMselectDataEvents - keeps only selected dose and observation
+%
+% 3) IQMcleanRemovePlaceboSubjects - removes placebo subjects
+% 
+% 4) IQMcleanRemoveSubjectsNoObservations - removes subjects without PK observations
+% 
+% 5) IQMcleanRemoveZeroDoses - removes doses with 0 amount
+%
+% 6) IQMcleanImputeCovariates - imputes covariates - continuous to the median, categorical to 99 or to provided imputation values
+%
+% 7) Check if MDV=1 present for observations without a reason in IGNORE column.
+%    If yes, then throw an error.
+%
+% 8) Set all non-empty IGNORE observation records to MDV=1
+% 
+% [SYNTAX]
+% [dataCleaned] = IQMcleanPopPKdataWrapper(data,DOSENAME,OBSNAME,covNames,catNames)
+% [dataCleaned] = IQMcleanPopPKdataWrapper(data,DOSENAME,OBSNAME,covNames,catNames,removeSUBJECT,removeREC)
+% [dataCleaned] = IQMcleanPopPKdataWrapper(data,DOSENAME,OBSNAME,covNames,catNames,removeSUBJECT,removeREC,outputPath)
+% [dataCleaned] = IQMcleanPopPKdataWrapper(data,DOSENAME,OBSNAME,covNames,catNames,removeSUBJECT,removeREC,outputPath,catImputationValues)
+%
+% [INPUT]
+% data:           Dataset in task specific dataset format.
+% DOSENAME:       String with the NAME of the dosing event to consider.
+% OBSNAME:        String with the NAME of the observation event to consider.
+% covNames:       Cell-array with names of continuous covariates
+% catNames:       Cell-array with names of categorical covariates
+% removeSUBJECT:  Cell-matrix with 2 columns. First column contains the
+%                 USUBJID identifiers of the subjects to be removed
+%                 from the dataset. The second column contains strings,
+%                 which define the reason why this subject is removed.
+%                 Default: {} - nothing removed.
+% removeREC:      Cell-matrix with 2 columns. First column contains the indices
+%                 of the records to be removed from the dataset. The second
+%                 column contains strings, which define the reason why this
+%                 record is removed. The indices correspond to the number
+%                 of the row in the dataset (-1 due to the header). These
+%                 indices are also displayed as IX# in the individual plots
+%                 when using the IQMexplorePKdataWrapper function.
+%                 Default: {} - nothing removed.
+% outputPath:     Path where to store the cleaning log files
+%                 Default: '../Output/DataCleaning/';
+% catImputationValues: Vector with values for imputation of categorical
+%                 covariates. If not provided "99" will be used for all
+%                 imputed categorical covariates. Vector needs same order
+%                 and number of elements as catNames. 
+%
+% [OUTPUT]
+% dataCleaned:    Cleaned dataset 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle variable input arguments
+if nargin<5 || nargin>9,
+    error('Incorrect number of input arguments.');
+end
+if nargin<6,
+    removeSUBJECT = {};
+end
+if nargin<7,
+    removeREC = {};
+end
+if nargin<8,
+    outputPath = '../Output/DataCleaning/';
+end
+if nargin<9,
+    catImputationValues = [];
+end
+
+% Handle cell thing
+if ischar(covNames),
+    covNames = {covNames};
+end
+if ischar(catNames),
+    catNames = {catNames};
+end
+
+% Handle cell thingy
+if ischar(OBSNAME),
+    OBSNAME = {OBSNAME};
+end
+if length(OBSNAME) > 1,
+    error('OBSNAME can only contain one NAME.');
+end
+OBSNAME = OBSNAME{1};
+
+if ischar(DOSENAME),
+    DOSENAME = {DOSENAME};
+end
+if length(DOSENAME) > 1,
+    error('DOSENAME can only contain one NAME.');
+end
+DOSENAME = DOSENAME{1};
+
+% Remove manually selected records and subjects 
+% Records are not actually removed ... the IGNORE entries are set to the
+% provided reason instead. And MDV is set to 1.
+% It is checked that this is only done on observation records (EVID=0). If
+% done on dose records an error is thrown.
+% Subjects are removed completely from the dataset, as this involves also
+% removing doses and to be not tool specific (e.g. MONOLIX does not know an
+% IGNORE statement) we need to ask the user to 
+% either accept removal completely or handle it outside this function.
+filename = [outputPath '/01_Manually_Selected_Records_and_Subjects'];
+datax = IQMcleanRemoveRecordsSUBJECTs(data,removeSUBJECT,removeREC,filename);
+
+% Keep only selected dose and observation
+datax = IQMselectDataEvents(datax,{DOSENAME OBSNAME}); 
+
+% Remove placebo subjects
+filename = [outputPath '/02_PLACEBO_subjects'];
+datax = IQMcleanRemovePlaceboSubjects(datax,filename);
+
+% Remove subjects without PK observations
+filename = [outputPath '/03_Subjects_without_observations'];
+datax = IQMcleanRemoveSubjectsNoObservations(datax,filename);
+
+% Remove doses with 0 amount
+filename = [outputPath '/04_Dose_Records_zero_amount'];
+datax = IQMcleanRemoveZeroDoses(datax,filename);
+
+% Covariate imputation
+filename = [outputPath '/05_Covariate_Imputation'];
+if isempty(catImputationValues),
+    catImputationValues = 99*ones(1,length(catNames));
+end
+datax = IQMcleanImputeCovariates(datax,covNames,catNames,catImputationValues,filename);
+
+% Check if MDV=1 present for observations without a reason in IGNORE column.
+% If yes, then throw an error.
+ix_MDV_IGNORE_test = find(datax.EVID==0 & datax.MDV==1 & strcmp(datax.IGNORE,''));
+if ~isempty(ix_MDV_IGNORE_test),
+    error('MDV=1 observations present that do not have an IGNORE reason.');
+end
+
+% Set all non-empty IGNORE observation records to MDV=1
+ix_IGNORE = find(datax.EVID==0 & ~strcmp(datax.IGNORE,''));
+datax.MDV(ix_IGNORE) = 1;
+
+% Assign output
+dataCleaned = datax;
+
+% Check length of original data with cleaned dataset. When the compliance
+% mode is on all removals should have been handled before (e.g. by using
+% the IGNORE column) and adequate specification of the data set spec.
+% Meaning that nothing should actually be really removed from the data.
+SETUP_PATHS_TOOLS_IQMLITE  % Get compliance mode setting
+if height(data) ~= height(dataCleaned),
+    text = sprintf('The IQMcleanPopPKdataWrapper function removed some rows in the dataset.\n');
+    text = sprintf('%sThis is perfectly normal and it is supposed to do that (see help text for this function).\n',text);
+    text = sprintf('%sBut if you would like to keep track of removed records in clinical projects for compliance\n',text);
+    text = sprintf('%sreasons, then this is not acceptable and removals of single records should be handled using\n',text);
+    text = sprintf('%sthe IGNORE column. Removal of subjects should be handled prior to the call to IQMcleanPopPKdataWrapper.\n',text);
+    text = sprintf('%sThis message appears as a warning is compliance mode is "OFF" and as an error if it is "ON".\n',text);
+    if COMPLIANCE_OUTPUT_MODE == 1,
+        error(text);
+    else
+        warning(text);
+    end
+end
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/IQMcomparePopPKmodels.m b/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/IQMcomparePopPKmodels.m
new file mode 100644
index 0000000000000000000000000000000000000000..08f9d3975cf71e6efb808a93c38bae77cbc3d2d4
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/IQMcomparePopPKmodels.m	
@@ -0,0 +1,176 @@
+function [] = IQMcomparePopPKmodels(projectFolders,FACTOR_UNITS,dosing_abs,dosing_iv,obsTimes,options,covNames,catNames,data)
+% This function allows to compare different popPK models created with the
+% popPK workflow in IQM Tools. Useful for model selection when GOF
+% plots and other assessments suggest models are behaving very similar.
+%
+% Covariates can be taken into account. For that the relevant information
+% need to be provided. Sampling is done from the covariates in the modeling
+% dataset. The user has to make sure that a reasonable number of
+% simulations (options.Nsim) is done.
+%
+% [SYNTAX]
+% [] = IQMcomparePopPKmodels(projectFolders,FACTOR_UNITS,dosing_abs,dosing_iv,obsTimes)
+% [] = IQMcomparePopPKmodels(projectFolders,FACTOR_UNITS,dosing_abs,dosing_iv,obsTimes,options)
+% [] = IQMcomparePopPKmodels(projectFolders,FACTOR_UNITS,dosing_abs,dosing_iv,obsTimes,options,covNames,catNames,data)
+%
+% [INPUT]
+% projectFolders:   Cell-array with the names of the Monolix project
+%                   folders for which to compare the models. The elements
+%                   need to include the full/relative path to the models
+% FACTOR_UNITS:     The FACTOR_UNITS value used for popPK model fitting.
+% dosing_abs:       MATLAB structure with 3 fields defining possible dosing
+%                   with absorption, covering 1st order, 0th order and mixed 
+%                   order absorption - dependent on the model.
+%       dosing_abs.TIME:        Vector with dosing times
+%       dosing_abs.DOSE:        Scalar or vector with doses (if vector then same length as dosing time vector) 
+% dosing_iv:        MATLAB structure with 4 fields defining possible dosing
+%                   with IV administration
+%       dosing_iv.TIME:         Vector with dosing times
+%       dosing_iv.DOSE:         Scalar or vector with doses (if vector then same length as dosing time vector) 
+%       dosing_iv.TINF:         Scalar or vector with infusion time (if vector then same length as dosing time vector) 
+% obsTimes:         Observation times to compare the models at
+% covNames:         Cell-array with continous covariate names to take into
+%                   account (only done if the modelfit uses these)
+% catNames:         Cell-array with categorical covariate names to take into
+%                   account (only done if the modelfit uses these)
+% data:             MATLAB dataset which was used for model fitting. Standard
+%                   IQM Tools dataset is assumed. The columns with the
+%                   specified covariate names have to exist
+%                   Alternatively, the path to the datafile can be
+%                   specified
+% options:          Matlab structure with optional information
+%       options.filename            Filename (with path) for export of resulting figure as PNG. If undefined or empty then not exported (default: '')
+%       options.N_PROCESSORS:       Number of processors for parallel computation (default: as specified in SETUP_PATHS_TOOLS_IQMPRO)
+%       options.Nsim                Number of samples from IIV distributions (default: 100)
+%       options.quantiles           Vector with quantiles to compute for comparison (does only make sense if Nsim reasonably large) (default: [0.05 0.95])
+%       options.logY                =1: log Y axis, =0: linear Y axis
+%       options.minY                Lower limit for Y-axis, e.g. LLOQ for PK
+%       options.plotData            =0 no (by default); =1 yes
+%       options.optionsIntegrator   options for the integration. By default: abstol=1e-6, reltol=1e-6
+%
+% [OUTPUT]
+% The figure with the comparison is stored in the filename file (PNG) or if not
+% defined, then just shown
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle variable input arguments
+if nargin<6,
+    options = [];
+end
+if nargin<7,
+    covNames = {};
+end
+if nargin<8,
+    catNames = {};
+end
+if nargin<9,
+    data = table();
+end
+
+% Handle optional input arguments
+try filename        = options.filename;         catch, filename     = '';   end
+try Nsim            = options.Nsim;             catch, Nsim         = 100;  end
+try N_PROCESSORS    = options.N_PROCESSORS;     catch, N_PROCESSORS = getN_PROCESSORS_PARIQM(); end
+try logY            = options.logY;             catch, logY         = 1;    end
+try minY            = options.minY;             catch, minY         = [];   end
+try plotData        = options.plotData;         catch, plotData     = 0;    end
+
+% Handle data
+if ischar(data),
+    % If not provided as dataset, then load it
+    data = IQMloadCSVdataset(data);
+end
+
+%% Handle DOSING INFORMATION
+% Interface inputs
+DOSING_TIME_ABS             = [];
+DOSING_DOSE_ABS             = [];
+try
+    DOSING_TIME_ABS         = dosing_abs.TIME;
+end
+try
+    DOSING_DOSE_ABS         = dosing_abs.DOSE;
+end
+
+DOSING_TIME_IV             = [];
+DOSING_DOSE_IV             = [];
+DOSING_TINF_IV             = [];
+try
+    DOSING_TIME_IV         = dosing_iv.TIME;
+end
+try
+    DOSING_DOSE_IV         = dosing_iv.DOSE;
+end
+try
+    DOSING_TINF_IV         = dosing_iv.TINF;
+end
+
+% Handle empty inputs
+if isempty(DOSING_TIME_ABS),
+    DOSING_TIME_ABS = 0;
+end
+if isempty(DOSING_DOSE_ABS),
+    DOSING_DOSE_ABS = 0;
+end
+
+if isempty(DOSING_TIME_IV),
+    DOSING_TIME_IV = 0;
+end
+if isempty(DOSING_DOSE_IV),
+    DOSING_DOSE_IV = 0;
+end
+if isempty(DOSING_TINF_IV),
+    DOSING_TINF_IV = 0.0001;
+end
+
+% Check inputs
+if (length(DOSING_TIME_ABS)~=1 && length(DOSING_DOSE_ABS)~=1)  && (length(DOSING_TIME_ABS) ~= length(DOSING_DOSE_ABS)),
+    error('DOSING_TIME_ABS and DOSING_DOSE_ABS need to have same length. Or one needs to be a scalar.');
+end
+
+% Check inputs
+if (length(DOSING_TIME_IV)~=1 && length(DOSING_DOSE_IV)~=1)  && (length(DOSING_TIME_IV) ~= length(DOSING_DOSE_IV)),
+    error('DOSING_TIME_IV and DOSING_DOSE_IV need to have same length. Or one needs to be a scalar.');
+end
+if length(DOSING_TINF_IV)~=1,
+    error('DOSING_TINF_IV needs to be a scalar.');
+end  
+    
+% Define dosings
+% Abs doses can be added to input 1 and input 3. Model parameterization
+% adequate to switch on or off 1st and 0th order absorption
+dosings = {};
+for k=1:length(projectFolders),
+    DOSING_INFO = {DOSING_DOSE_ABS DOSING_DOSE_IV DOSING_DOSE_ABS};
+    DOSTIM_INFO = {DOSING_TIME_ABS DOSING_TIME_IV DOSING_TIME_ABS};
+    if isSequentialAbsorptionPopPKIQM(projectFolders{k}),
+        % If sequential 0/1 order absorption then set Tlaginput1 to 'Tk0input3'
+        dosing = IQMcreateDOSING({'BOLUS','INFUSION','ABSORPTION0'},DOSING_INFO,DOSTIM_INFO,{[] DOSING_TINF_IV 1e-10},{'Tk0input3' 0 0});
+    else
+        dosing = IQMcreateDOSING({'BOLUS','INFUSION','ABSORPTION0'},DOSING_INFO,DOSTIM_INFO,{[] DOSING_TINF_IV 1e-10},{0 0 0});
+    end
+    dosings{k} = dosing;
+end
+
+%% Handle interface to IQMcompareModels
+model                           = IQMmodel('template_popPK_model.txt');
+output                          = 'OUTPUT1';
+optionsComparison               = [];
+optionsComparison.Nsim          = Nsim;
+optionsComparison.N_PROCESSORS  = N_PROCESSORS;
+optionsComparison.logY          = logY;
+optionsComparison.minY          = minY;
+optionsComparison.plotData      = plotData;
+
+% Update model with needed parameter settings
+model                           = IQMparameters(model,'FACTOR_UNITS',FACTOR_UNITS);
+% Ensure VMAX and other param are 0 and only changed by the fit
+model                           = IQMparameters(model,{'CL','Q1','Q2','VMAX','ka'},[0 0 0 0 0]);
+
+% Run compare models
+IQMcompareModels(projectFolders,model,output,dosings,obsTimes,optionsComparison,covNames,catNames,data)
+
+% Export figure
+IQMprintFigure(gcf,filename,'png');
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/IQMcreatePopPKstratifiedVPC.m b/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/IQMcreatePopPKstratifiedVPC.m
new file mode 100644
index 0000000000000000000000000000000000000000..b5ce68f4331a89f7e9d4d36825ddda54509685b7
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/IQMcreatePopPKstratifiedVPC.m	
@@ -0,0 +1,175 @@
+function [allVPCresults] = IQMcreatePopPKstratifiedVPC(NLMEproject,FACTOR_UNITS,filename,options,data)
+% This function creates a stratified VPC for a given model on a given
+% dataset. Assumption is that the model has been built using the popPK
+% workflow functions within IQM Tools.
+% Stratification is done automatically using the TRT column. Also, the PK
+% is identified by "OUTPUT1" variable in the model and by TYPE==1.
+% The structural model is selected automatically.
+%
+% The doses and dosing schedule and the covariates are obtained from the
+% dataset.  
+%
+% Assumption: ADM=2: IV, ADM=1: 1st order absorption, ADM=3: oth order
+% absorption. If available, the dataset that is stored in the models
+% project folder will be used for VPC generation ... in this way 0th order
+% absorption and mixed order absorption can be handled. Last thing
+% remaining is to decide between parallel or sequential mixed order
+% absorption, which can be done based on function
+% IQMgetPopPKabsorptionType.
+%
+% [SYNTAX]
+% [allVPCresults] = IQMcreatePopPKstratifiedVPC(NLMEproject,FACTOR_UNITS)
+% [allVPCresults] = IQMcreatePopPKstratifiedVPC(NLMEproject,FACTOR_UNITS,filename)
+% [allVPCresults] = IQMcreatePopPKstratifiedVPC(NLMEproject,FACTOR_UNITS,filename,options)
+% [allVPCresults] = IQMcreatePopPKstratifiedVPC(NLMEproject,FACTOR_UNITS,filename,options,data)
+%
+% [INPUT]
+% NLMEproject:      String with the name of the NLME project folder for
+%                   which to generate this VPC. 
+%                   Needs to include the absolute or relative path to the
+%                   folder. 
+% FACTOR_UNITS:     The FACTOR_UNITS value used for popPK model fitting.
+% filename:         If a filename is provided, the VPC results are exported
+%                   to a PDF file with this name (and path). Default:
+%                   'VPC.pdf')
+% data:             Allows to pass a datafile for VPC generation (by
+%                   default the dataset is used that is stored in the
+%                   models metainformation.
+%
+% options:          Matlab structure with optional information
+%       * Grouping / Stratification
+%           options.GROUP:              String with the name of the column in the data to use
+%                                       for stratification (default: 'TRTNAME') 
+%           options.doseNormalized:     1: dose normalized VPC, 0: non-dose
+%                                       normalized (default: 0)
+% 
+%       * General
+%           options.N_PROCESSORS_PAR    Number or processors (requires parallel toolbox) (default: as defined in SETUP_PATHS_TOOLS_IQMPRO) 
+%           options.NTRIALS             Number of TRIALS to simulate to determine simulation quantiles and confidence intervals. (default: 100) 
+%           options.QUANTILES           Vector with quantiles to compute for simulation and data (default: [0.05 0.95]) (90% variability)
+%           options.QUANTILES_CI        Vector with quantiles for the uncertainty of the QUANTILES (default: [0.025 0.975]) (95% CI)
+%           options.useNOMINAL_TIME     =0: Use actual observation and dose times 
+%                                       =1: Use nominal observation and dose times (default: 1)
+%                                       (for simulations observation and dosing times, and for plotting of observed data points)
+%
+%       * Simulation time point information
+%           options.nTimePoints         Number time points to simulate - spaced equidistantly. If set to empty ([]) then observation times are used. (default: 500) 
+%
+%       * Plot content
+%           options.showLabels          =1: Shows subject IDs as data, =0: shows dots as data (default: 1)
+%           options.plotIndivLines      =1: Connect individual data points with lines (default: 0)
+%           options.showDataQuantiles   =1: Show lines for the observation quantiles (default: 0)
+%
+%       * Axes information
+%           options.logY                =1: log Y axis, =0: linear Y axis (default: 1)
+%           options.minX                Numeric value for lower value of X axis (default: not used)
+%           options.maxX                Numeric value for upper value of X axis (default: not used)
+%           options.minY                Numeric value for lower value of Y axis (default: not used)
+%           options.maxY                Numeric value for upper value of Y axis (default: not used)
+%
+%       * Binning information
+%           options.bins_mean           Vector with center values of bins to calculate data quantiles. If not 
+%                                       defined ([]), then bins_mean=NT of observations (default: [])
+%           options.bins_lookaround     Vector with values for positive and negative "lookaround" for quantile calculation 
+%                                       If not provided it is set to:
+%                                               bins_lookaround = diff(bins_mean) 
+%                                               bins_lookaround = [bins_lookaround(1); bins_lookaround(:)]/2
+%
+%       * Color settings
+%           options.colorMedianRange        Default: [1 0.9 0.8]
+%           options.colorQuantilesRange     Default: [0.8 1 0.8]
+%           options.colorData               Default: 0.2*[1 1 1]
+%           options.colorMedian             Default: [1 0.2 0]
+%
+%       * Integrator information
+%           options.optionsIntegrator   Options for the integration (See IQMmakeMEXmodel).
+%
+% [OUTPUT]
+% VPCs in MATLAB figures or exported to PDF (default: PDF as VPC.pdf)
+% allVPCresults: Cell-array of outputs to IQMcreateVPC. Possible to use
+%                directly as input argument to IQMcreateVPCplot
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle variable input arguments
+if nargin<3,
+    filename                = 'VPC.pdf';
+end
+if nargin<4,
+    options                 = [];
+end
+if nargin<5,
+    data                    = [];
+end
+
+% Handle option defaults different from IQMcreateVPCstratified
+try GROUP                   = options.GROUP;            catch, GROUP                    = 'TRTNAME';   end
+try logY                    = options.logY;             catch, options.logY             = 1;            end
+try NTRIALS                 = options.NTRIALS;          catch, options.NTRIALS          = 100;          end
+try doseNormalized          = options.doseNormalized;   catch, doseNormalized           = 0;            end
+
+% Get dataset from NLME project if data undefined by user
+if isempty(data),
+    project_header              = parseNLMEprojectHeaderIQM(NLMEproject);
+    oldpath = pwd();
+    cd(NLMEproject);
+    data                        = IQMloadCSVdataset(project_header.DATA{1});
+    cd(oldpath);
+end
+
+% Check data
+if ischar(data),
+    data = IQMloadCSVdataset(data);
+end
+
+% Handle dose normalization
+if doseNormalized,
+    % Normalize all DV and AMT by DOSE
+    data.DV                     = data.DV./data.DOSE;
+    data.AMT                    = data.AMT./data.DOSE;
+    % Set names
+    PKname                      = data.NAME(data.YTYPE==1);
+    data.NAME(data.YTYPE==1)    = {echangeSpacesDataIQM(sprintf('Dose normalized %s',PKname{1}))};
+    % Set units
+    PKunit                      = data.UNIT(data.YTYPE==1);
+    DOSEunit                    = data.UNIT(data.YTYPE==0);
+    data.UNIT(data.YTYPE==1)    = {echangeSpacesDataIQM(sprintf('%s/%s',PKunit{1},DOSEunit{1}))};    
+end
+
+% Handle options
+if isempty(GROUP),
+    GROUP = 'TRTNAME';
+end
+
+% Load template model
+model                       = IQMmodel('template_popPK_model.txt');
+
+% Parameterize model
+model                       = IQMparameters(model,'FACTOR_UNITS',FACTOR_UNITS);
+
+% Ensure VMAX and other param are 0 and only changed by the fit
+model                       = IQMparameters(model,{'CL','Q1','Q2','VMAX','ka'},[0 0 0 0 0]);
+
+% Get dosing scheme ... make distinction only for sequential absorption
+if isSequentialAbsorptionPopPKIQM(NLMEproject)
+    % Use special dosing ... since sequential 0th/1st order dosing
+    dosing                      = IQMdosing('template_popPK_dosing_SEQ01ABS.dos');
+else
+    % Use normal dosing ...
+    dosing                      = IQMdosing('template_popPK_dosing.dos');
+end
+
+% Assign correct dosing scheme to options:
+options.userDosing = dosing;
+
+% Define additional things known for popPK model
+outputsModel                = 'OUTPUT1';
+outputsData                 = unique(data.NAME(data.YTYPE==1));
+outputsData                 = restoreSpacesDataIQM(outputsData{1});
+regressionVariables         = {};
+ 
+% Run the VPC ...
+allVPCresults               = IQMcreateVPCstratified(GROUP,NLMEproject,model,data,outputsModel,outputsData,filename,options);
+
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/IQMscmPopPK.m b/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/IQMscmPopPK.m
new file mode 100644
index 0000000000000000000000000000000000000000..72ec46269761f86cb7a58a3a805d1a7c9e982664
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/IQMscmPopPK.m	
@@ -0,0 +1,1104 @@
+function [] = IQMscmPopPK(nameSpace, modeltest, modelingDatasetFile, dataheaderNLME, optionsNLME, optionsSCM)
+% IQMscm: Stepwise covariate search, using forward inclusion / backward
+% elimination. Decision fotr inclusion or exclusion based on objective
+% function value. This function takes input arguments that are used by the
+% PopPK modeling workflow and thus allows to run analytic versions of
+% linear PK models. 
+%
+% Although the algorithm is in principle applicable to categorical
+% covariates with more than 2 categories, it does not really make sense and
+% might introduce to many parameters that are not significant. A better
+% approach is to get the modeler to think a little more and reduce the
+% number of categories to 2. Covariates with multiple categories can be
+% assessed after the SCM has been done by adding them one at a time.
+%
+% This function here will only allow for categorical covariates with 2
+% categories - not more.
+%
+% Centering for continuous covariates is fixed at the median of the
+% covariates for SCM. Structural covariates can be centered as desired.
+%
+% [SYNTAX]
+% [] = IQMscmPopPK(nameSpace, modeltest, modelingDatasetFile, dataheaderNLME, optionsNLME, optionsSCM)
+%
+% [INPUT]
+% Input arguments nameSpace, modeltest, modelingDatasetFile, dataheaderNLME,
+% optionsNLME are identical to the ones used and documented in
+% IQMbuildPopPKModelSpace and are not repeated here. 
+% 
+% However, instead of a model space, only a single model is allowed to be
+% defined. This is checked and an error is returned if multiple models are
+% defined.
+%
+% optionsSCM:       Structure with optional settings for the covariate search.
+%   optionsSCM.outputPath:              Path where to store the log file (default: projectPathSCM)
+%   optionsSCM.N_PROCESSORS_PAR:        Number of parallel model runs (default: as specified in SETUP_PATHS_TOOLS_IQMPRO)
+%   optionsSCM.N_PROCESSORS_SINGLE:     Number of processors to parallelize single run (if NONMEM and MONOLIX allow for it) (default: 1)
+%   optionsSCM.p_forward:               p-value for forward inclusion step (default: 0.05)
+%   optionsSCM.p_backward:              p-value for forward inclusion step (default: 0.001)
+%   optionsSCM.covariateTests:          Cell-array with parameter/covariate combinations to test
+%                                       First element in each sub-array is the parameter name,
+%                                       following are the covariates to test.
+%
+%                                       Example:
+%                                          {
+%                                             {'EMAX','WT0','SEX','HT0','ETHN'}
+%                                             {'EC50','WT0','SEX','HT0','ETHN'}
+%                                             {'fS'  ,'WT0','SEX','HT0','ETHN'}
+%                                           }
+%
+%                                       If not specified or empty, then all covariates will be
+%                                       tested on all parameters.
+%
+% If "covariateModels" is defined in modeltest, then these covariates are
+% included by default and are not subject to the SCM algorithm.
+%
+% [OUTPUT]
+% The output is in the form of a logfile that is stored in the selected
+% output folder.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Same definitions as in IQMbuilPopPKModelSpace
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Define parameternames in ODE and ANALYTIC models. NONLINEAR parameters need to be at the end.
+% Its the required order ... checks for ODE models will be done. MONOLIX works with an analytic template. 
+% For NONMEM no analytic template can be used, since numerics horribly bad. Individual ADVANs will be
+% generated automatically instead.
+TemplateModels = [];
+TemplateModels.ParameterNames.ODE       = {'CL', 'Vc', 'Q1', 'Vp1', 'Q2', 'Vp2', 'Fiv', 'Fabs1', 'ka', 'Tlaginput1', 'Fabs0', 'Tk0input3', 'Tlaginput3', 'Frel0', 'VMAX', 'KM'};
+TemplateModels.IIVdistribution.ODE      = { 'L',  'L',  'L',   'L',  'L',   'L',   'L',     'L',  'L',          'L',     'L',         'L',          'L',     'L',    'L',  'L'};
+TemplateModels.ParameterNames.ANALYTIC  = {'CL', 'Vc', 'Q1', 'Vp1', 'Q2', 'Vp2', 'Fiv', 'Fabs1', 'ka', 'Tlaginput1', 'Fabs0', 'Tk0input3', 'Tlaginput3', 'Frel0'};
+TemplateModels.IIVdistribution.ANALYTIC = { 'L',  'L',  'L',   'L',  'L',   'L',   'L',     'L',  'L',          'L',     'L',         'L',          'L',     'L'};
+TemplateModels.Model.MONOLIX.ANALYTIC            = 'template_popPK_model_ANALYTIC_MLXTRAN.txt';
+TemplateModels.Model.MONOLIX.ANALYTIC_SEQ01ABS   = 'template_popPK_model_ANALYTIC_SEQ01ABS_MLXTRAN.txt';
+TemplateModels.Model.ODE                = 'template_popPK_model.txt';
+TemplateModels.Model.DOSING             = 'template_popPK_dosing.dos';
+TemplateModels.Model.DOSING_SEQ01ABS    = 'template_popPK_dosing_SEQ01ABS.dos';
+
+% TemplateModels = [];
+% TemplateModels.ParameterNames.ODE       = {'CL', 'Vc', 'Q1', 'Vp1', 'Q2', 'Vp2', 'Fiv', 'Fabs1', 'ka', 'Tlaginput1', 'Fabs0', 'Tk0input3', 'Tlaginput3', 'Frel0', 'VMAX', 'KM'};
+% TemplateModels.IIVdistribution.ODE      = { 'L',  'L',  'L',   'L',  'L',   'L',   'L',     'L',  'L',          'L',     'L',         'L',          'L',     'L',    'L',  'L'};
+% TemplateModels.ParameterNames.ANALYTIC  = {'CL', 'Vc', 'Q1', 'Vp1', 'Q2', 'Vp2', 'Fiv', 'Fabs1', 'ka', 'Tlaginput1', 'Fabs0', 'Tk0input3', 'Tlaginput3', 'Frel0'};
+% TemplateModels.IIVdistribution.ANALYTIC = { 'L',  'L',  'L',   'L',  'L',   'L',   'L',     'L',  'L',          'L',     'L',         'L',          'L',     'L'};
+% TemplateModels.Model.MONOLIX.ANALYTIC   = 'template_popPK_model_ANALYTIC_MLXTRAN.txt';
+% TemplateModels.Model.ODE                = 'template_popPK_model.txt';
+% TemplateModels.Model.DOSING             = 'template_popPK_dosing.dos';
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% First step: need to get all information to basically reuse IQMscm functionality
+% TOOL,projectPathSCM,optionsSCM,model,dosing,data,options
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Get modeltest elements
+try numberCompartments          = modeltest.numberCompartments;         catch, error('modeltest.numberCompartments undefined');                             end
+try errorModels                 = modeltest.errorModels;                catch, error('modeltest.errorModels undefined');                                    end
+try saturableClearance          = modeltest.saturableClearance;         catch, error('modeltest.saturableClearance undefined');                             end
+try FACTOR_UNITS                = modeltest.FACTOR_UNITS;               catch, error('modeltest.FACTOR_UNITS undefined');                                   end
+try POPvalues0                  = modeltest.POPvalues0;                 catch, error('modeltest.POPvalues0 undefined');                                     end
+try POPestimate                 = modeltest.POPestimate;                catch, error('modeltest.POPestimate undefined');                                    end
+try IIVestimate                 = modeltest.IIVestimate;                catch, error('modeltest.IIVestimate undefined');                                    end
+
+try absorptionModel             = modeltest.absorptionModel;            catch, absorptionModel = 1;                                                         end % default: 1st order absorption
+try lagTime                     = modeltest.lagTime;                    catch, lagTime = 0;                                                                 end % default: no lag time
+
+try IIVvalues0                  = modeltest.IIVvalues0;                 catch, IIVvalues0           = ones(1,length(TemplateModels.ParameterNames.ODE));    end
+try covarianceModel             = modeltest.covarianceModels;           catch, covarianceModel      = '';                          	                        end
+try IIVdistribution             = modeltest.IIVdistribution;            catch, IIVdistribution      = {};                          	                        end
+try errorParam0                 = modeltest.errorParam0;                catch, errorParam0          = [];                         	                        end
+try SILENT                      = optionsNLME.SILENT;                   catch, SILENT               = 1;                         	                        end
+try algorithm                   = optionsNLME.algorithm;                catch, algorithm            = [];                         	                        end
+try covariateModel              = modeltest.covariateModels;            catch, covariateModel       = '';                        	                        end
+try covariateModelValues        = modeltest.covariateModelValues;       catch, covariateModelValues = {};                                                   end
+try COVestimate                 = modeltest.COVestimate;                catch, COVestimate          = {};                                                   end
+try TOOL                        = optionsNLME.parameterEstimationTool; 	catch, TOOL                 = 'MONOLIX';                                            end
+
+try covariateModelTV            = modeltest.covariateModelsTV;          catch, covariateModelTV     = '';                                                   end
+
+% Check if model space is single model
+multiple = 0;
+if length(numberCompartments) > 1, multiple = 1; end
+if iscell(errorModels), if length(errorModels) > 1, multiple = 1; else errorModels = errorModels{1}; end; end
+if iscell(errorParam0), if length(errorParam0) > 1, multiple = 1; else errorParam0 = errorParam0{1}; end; end
+if length(saturableClearance) > 1, multiple = 1; end
+if length(absorptionModel) > 1, multiple = 1; end
+if length(lagTime) > 1, multiple = 1; end
+if iscell(POPvalues0), if length(POPvalues0)>1, multiple = 1; else POPvalues0 = POPvalues0{1}; end; end
+if iscell(POPestimate), if length(POPestimate)>1, multiple = 1; else POPestimate = POPestimate{1}; end; end
+if iscell(IIVestimate), if length(IIVestimate)>1, multiple = 1; else IIVestimate = IIVestimate{1}; end; end
+if iscell(IIVvalues0), if length(IIVvalues0)>1, multiple = 1; else IIVvalues0 = IIVvalues0{1}; end; end
+if iscell(covarianceModel), if length(covarianceModel)>1, multiple = 1; else covarianceModel = covarianceModel{1}; end; end
+if iscell(covariateModel), if length(covariateModel)>1, multiple = 1; else covariateModel = covariateModel{1}; end; end
+if multiple,
+    error('Modelspace is larger than a single model.');
+end
+
+% Get TOOL
+if strcmpi(TOOL,'nonmem'),
+    FLAG_NONMEM                 = 1;
+elseif strcmpi(TOOL,'monolix'),
+    FLAG_NONMEM                 = 0;
+else
+    error('Unknown definition of tool in optionsNLME.parameterEstimationTool.');
+end
+
+% Get projectPathSCM
+projectPathSCM              	= ['../Models/' nameSpace];
+
+% Get optionsSCM
+%   Already defined as input argument
+
+% Get model
+%   Not needed ... will be handled differently
+
+% Get dosing
+%   Not needed ... will be handled differently
+
+% Get data
+[xdummyx,f,e]                   = fileparts(modelingDatasetFile);
+data                            = [];
+data.dataFileName                = [f e];
+data.header                     = dataheaderNLME;
+data.dataRelPathFromProject     = '../../Data';
+
+% Get options for single model generation by copying
+options                         = [];
+options.POPestimate             = POPestimate;
+options.POPvalues0              = POPvalues0;
+options.IIVdistribution         = IIVdistribution;
+options.IIVestimate             = IIVestimate;
+options.IIVvalues0              = IIVvalues0;
+options.errorModels             = errorModels;
+options.errorParam0             = errorParam0;
+options.covarianceModel         = covarianceModel;
+options.SILENT                  = SILENT;
+options.algorithm               = algorithm;
+options.covariateModel          = covariateModel;
+options.covariateModelValues    = covariateModelValues;
+options.COVestimate             = COVestimate;
+
+options.covariateModelTV        = covariateModelTV;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Second step: Do this IQMscm but with different model generation
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Handle optionsSCM
+try p_forward               = optionsSCM.p_forward;                 catch, p_forward                = 0.05;                     end
+try p_backward              = optionsSCM.p_backward;                catch, p_backward               = 0.001;                    end
+try covariateTests          = optionsSCM.covariateTests;            catch, covariateTests           = {};                       end
+try outputPath              = optionsSCM.outputPath;                catch, outputPath               = projectPathSCM;           end
+try N_PROCESSORS_PAR        = optionsSCM.N_PROCESSORS_PAR;          catch, N_PROCESSORS_PAR         = getN_PROCESSORS_PARIQM(); end
+try N_PROCESSORS_SINGLE     = optionsSCM.N_PROCESSORS_SINGLE;       catch, N_PROCESSORS_SINGLE      = 1;                        end
+
+% Get previously defined covariate model (fixed covariate model)
+try covariateModel          = options.covariateModel;               catch, covariateModel           = '';                       end
+try covariateModelValues    = options.covariateModelValues;         catch, covariateModelValues     = {};                       end
+try COVestimate             = options.COVestimate;                  catch, COVestimate              = {};                       end
+
+% Check if NONMEM and SAEM ... then show error
+if strcmpi(TOOL,'NONMEM') && strcmpi(options.algorithm.METHOD,'SAEM'),
+    error('Stepwise covariate search with NONMEM SAEM is not a good idea. Please use FO(CE(I)) or MONOLIX.');
+end
+
+% Create the projectFolder
+try rmdir(projectPathSCM,'s'); catch end
+warning off
+mkdir(projectPathSCM);
+warning on
+
+% Load dataset to assess number of categorical elements
+oldpath = pwd();
+cd(projectPathSCM);
+dataContents = IQMloadCSVdataset([data.dataRelPathFromProject '/' data.dataFileName]);
+cd(oldpath);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Check unsupported administration routes
+% ADM=1 is covering 1st order, 0th order, and mixed absorption for the popPK
+% workflow. 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%       
+ADMunique = unique(dataContents.ADM);
+if sum(ADMunique>2)~=0,
+    error('Unknown/unsupported ADM entries in dataset. 0: observation, 1: 0th/1st/mixed order absorption, 2: IV (bolus or infusion).');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Check lag time and absorption model settings.
+% If no absorption doses (ADM=1) present in the dataset and lagTime and 
+% absorptionModel variables not on default values, then reset them to 
+% default values. 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%       
+% Check if absorption dose data present (ADM=1)
+FLAG_ABSORPTION_DATA_PRESENT = 1;
+if ~ismember(1,ADMunique),
+    FLAG_ABSORPTION_DATA_PRESENT = 0;
+    if sum(lagTime) ~= 0,
+        warning('Dataset does not contain absorption doses (ADM=1). Estimation of lag time not considered.');
+        lagTime = 0;
+    end
+    if sum(absorptionModel) ~= 0,
+        warning('Dataset does not contain absorption doses (ADM=1). No absorption model considered.');
+        absorptionModel = 1;
+    end
+end
+
+%% Intermediate step: Check NONMEM issue 
+% Fiv not possible to estimate with NONMEM since RATE not handled together
+% with bioavailability. In this case MONOLIX needs to be used.
+% Only needs to be checked if IV data present in the dataset.
+
+FLAG_NONMEM__RATE_BIOAVAILABILITY_ISSUE__OK = 1;
+
+if ~isempty(find(dataContents.ADM==2)),
+    % IV data present ... need to check
+    
+    % Get index Fiv
+    ix_Fiv = strmatchIQM('Fiv',TemplateModels.ParameterNames.ODE,'exact');
+    
+    % If Fiv initial guess not 1 then NONMEM not ok
+    if POPvalues0(ix_Fiv) ~= 1,
+        FLAG_NONMEM__RATE_BIOAVAILABILITY_ISSUE__OK = 0;
+    end
+    
+    % If Fiv estimated then NONMEM not ok
+    if POPestimate(ix_Fiv) ~= 0,
+        FLAG_NONMEM__RATE_BIOAVAILABILITY_ISSUE__OK = 0;
+    end
+    
+    % If FACTOR_UNITS not equal 1 then NONMEM not ok
+    if FACTOR_UNITS~=1,
+        FLAG_NONMEM__RATE_BIOAVAILABILITY_ISSUE__OK = 0;
+    end
+    
+    % Error message if needed
+    if FLAG_NONMEM && ~FLAG_NONMEM__RATE_BIOAVAILABILITY_ISSUE__OK,
+        error(sprintf('NONMEM can not be used with these settings (estimation of Fiv or non-unity initial guess for Fiv or FACTOR_UNITS not equal to 1).\nNONMEM is unable to combine bioavailability parameter with infusion RATE. Simple fix: For these model\nsettings, please use the more modern software MONOLIX, which can do this correctly without a lot of work-arounds.'));
+    end
+end
+
+%% Change data path to match the nested model folder structure
+data.dataRelPathFromProject = ['../' data.dataRelPathFromProject];
+
+% If NONMEM used then check if IMP set to 1
+if strcmpi(TOOL,'nonmem') && strcmpi(options.algorithm.METHOD,'saem') && options.algorithm.IMPORTANCESAMPLING == 0,
+    error('When using NONMEM/SAEM, please set the options.algorithm.IMPORTANCESAMPLING=1.');
+end
+
+% Create the BASE model (MODEL_BASE) and load header
+BASEmodelFolder             = [projectPathSCM '/MODEL_BASE'];
+dataRelPathFromProjectPath  = '../../../Data';
+createPopPK_NLMEproject_ODE_Analytic_IQM(FLAG_NONMEM,FLAG_ABSORPTION_DATA_PRESENT,'MODEL_BASE',TemplateModels,FACTOR_UNITS, ...
+            numberCompartments,saturableClearance, ...
+            absorptionModel,lagTime, ...
+            data,BASEmodelFolder,dataRelPathFromProjectPath,options, ...
+            FLAG_NONMEM__RATE_BIOAVAILABILITY_ISSUE__OK, dataContents);
+projectInfo                 = parseNLMEprojectHeaderIQM(BASEmodelFolder);
+                                       
+% Get parameter names, continuous and categorical covariate names from the
+% models header
+parNames            = projectInfo.PARAMNAMES;
+covNames            = projectInfo.COVNAMES;
+catNames            = projectInfo.CATNAMES;
+covcatNames         = [covNames catNames];
+
+% If list of covariates empty then generate it - to include all covariates
+% on all parameters
+if isempty(covariateTests)
+    covariateTests = cell(length(parNames),1);
+    for k1=1:length(parNames),
+        cTk{1} = parNames{k1};
+        for k2=1:length(covcatNames),
+            cTk{k2+1} = covcatNames{k2};
+        end
+        covariateTests{k1} = cTk(:)';
+    end
+end
+
+% Expand the covariat settings to matching lists for parameters and covariate names
+covSearch                   = [];
+covSearch.paramNamesTest    = {};
+covSearch.covcatNamesTest   = {};
+for k1=1:length(covariateTests),
+    for k2=2:length(covariateTests{k1}),
+        covSearch.paramNamesTest{end+1}  = covariateTests{k1}{1};
+        covSearch.covcatNamesTest{end+1} = covariateTests{k1}{k2};
+    end
+end
+
+% Check lists if selected covariates and parameters present in model and dataset
+for k=1:length(covSearch.paramNamesTest),
+    ix = strmatchIQM(covSearch.paramNamesTest{k},parNames,'exact');
+    if isempty(ix),
+        error('Parameter %s is not estimated in the model.',covSearch.paramNamesTest{k});
+    end
+end
+
+for k=1:length(covSearch.covcatNamesTest),
+    ix = strmatchIQM(covSearch.covcatNamesTest{k},covcatNames,'exact');
+    if isempty(ix),
+        error('Covariate %s is not present in the dataset.',covSearch.covcatNamesTest{k});
+    end
+end
+
+% Determine structural covariate information (structural covariates are
+% covariates that already are in the model by options.covariateModel)
+covStructural               = [];
+covStructural.paramNames    = {};
+covStructural.covcatNames   = {};
+covStructural.value         = [];
+covStructural.estimate      = [];
+terms = strrep(strrep(explodePCIQM(covariateModel,',','{','}'),'{',''),'}','');
+for k=1:length(terms),
+    x = explodePCIQM(terms{k});
+    for k2=2:length(x),
+        covStructural.paramNames{end+1} = x{1};
+        covStructural.covcatNames{end+1} = x{k2};
+        if isempty(covariateModelValues),
+            covStructural.value(end+1) = 0.1;
+        else
+            covStructural.value(end+1) = covariateModelValues{k}(k2-1);
+        end
+        if isempty(COVestimate),
+            covStructural.estimate(end+1) = 1;
+        else
+            covStructural.estimate(end+1) = COVestimate{k}(k2-1);
+        end
+    end
+    
+end
+
+% Remove structural covariates from covSearch - since these are already in
+% the model
+ix_remove = [];
+for k=1:length(covStructural.paramNames),
+    par = covStructural.paramNames{k};
+    cov = covStructural.covcatNames{k};
+    ix1 = strmatchIQM(par,covSearch.paramNamesTest,'exact');
+    ix2 = strmatchIQM(cov,covSearch.covcatNamesTest,'exact');
+    if ~isempty(intersect(ix1,ix2)),
+        ix_remove(end+1) = intersect(ix1,ix2);
+    end
+end
+if ~isempty(ix_remove),
+    covSearch.paramNamesTest(ix_remove) = [];
+    covSearch.covcatNamesTest(ix_remove) = [];
+end
+
+% Determine delta Objective functions required for covariates
+% DF: 1 for continuous, N-1 for categorical - since N=2 for categorical ...
+% it is the same.
+for k=1:length(covSearch.covcatNamesTest),
+    % Check if categorical
+    if ~isempty(strmatchIQM(covSearch.covcatNamesTest{k},covNames,'exact')),
+        % Continuous covariate
+        N_DF = 1;
+    else
+        % Categorical covariate
+        N_categories = length(unique(dataContents.(covSearch.covcatNamesTest{k})));
+        if N_categories > 2,
+            error('Categorical covariate "%s" has more than 2 categories - this is not allowed.',covSearch.covcatNamesTest{k});
+        end
+        if N_categories < 2,
+            error('Categorical covariate "%s" has less than 2 categories - this is not allowed.',covSearch.covcatNamesTest{k});
+        end
+        N_DF = 1;        
+    end
+    covSearch.delta_forward(k)   = chi2invIQM(1-p_forward,N_DF);
+    covSearch.delta_backward(k)  = chi2invIQM(1-p_backward,N_DF);
+end
+
+% Save information for later
+covSearchBackUp = covSearch;
+
+% Open report file
+warning off
+mkdir(outputPath);
+warning on
+fid = fopen([outputPath '/SCMlogfile.txt'],'w');
+
+fprintf(fid,'****************************************************************************\n');
+fprintf(fid,'* Covariate search using forward inclusion and backward elimination method *\n');
+fprintf(fid,'****************************************************************************\n');
+fprintf(fid,'Username: %s\n',usernameIQM());
+fprintf(fid,'Date:     %s\n',datestr(now,'yyyy-mmm-DD HH:MM'));
+fprintf(fid,'****************************************************************************\n');
+fprintf(fid,'\n');
+fprintf(fid,'p-value forward:      %g\n',p_forward);
+fprintf(fid,'p-value backward:     %g\n',p_backward);
+fprintf(fid,'\n');
+fprintf(fid,'Decisions based on delta objective function.\n');
+fprintf(fid,'\n');
+
+fprintf(fid,'************************************\n');
+fprintf(fid,'* RUNNING BASE MODEL (MODEL_BASE)  *\n');
+fprintf(fid,'************************************\n');
+fprintf(fid,'\n');
+
+% Run the BASE model (MODEL_BASE)
+BASEmodelFolder = [projectPathSCM '/MODEL_BASE'];
+IQMrunNLMEproject(BASEmodelFolder,N_PROCESSORS_SINGLE);
+RESULTS         = parseNLMEprojectResults(BASEmodelFolder);
+
+% Get OFV and optimal parameters for BASE model
+BASE_OFV            = RESULTS.objectivefunction.OBJ;
+
+% If NaN then fit crashed ... pbly NONMEM error
+if isnan(BASE_OFV),
+    error('Base model crashed ... ');
+end
+
+% Report OFV for BASE model
+fprintf(fid,'Objective function value for BASE model: %g\n',BASE_OFV);
+if strcmpi(TOOL,'NONMEM'),
+    fprintf(fid,'\n');
+    fprintf(fid,'%s\n',RESULTS.termination_info{1});
+end
+fprintf(fid,'\n');
+
+% Update model options with optimal BASE model parameters
+options.POPvalues0  = RESULTS.rawParameterInfo.fixedEffects.values;
+options.IIVvalues0  = RESULTS.rawParameterInfo.randomEffects.values;
+options.errorParam0 = RESULTS.rawParameterInfo.errorParameter.values;
+
+% If sequential 0/1 order absorption need to add Tlaginput 1 in between 
+if absorptionModel == 3,
+    POPvalues0 = NaN(1,length(options.POPvalues0)+1);
+    POPvalues0([1:9 11:end]) = options.POPvalues0;
+    options.POPvalues0 = POPvalues0;
+    
+    IIVvalues0 = NaN(1,length(options.IIVvalues0)+1);
+    IIVvalues0([1:9 11:end]) = options.IIVvalues0;
+    options.IIVvalues0 = IIVvalues0;
+end
+
+% Update data path again for the level models
+data.dataRelPathFromProject = ['../' data.dataRelPathFromProject];
+
+% Forward inclusion
+fprintf(fid,'************************************\n');
+fprintf(fid,'* FORWARD INCLUSION                *\n');
+fprintf(fid,'************************************\n');
+fprintf(fid,'\n');
+
+OLD_OFV                     = BASE_OFV;
+covariatesForward           = {};
+covariateModelValuesForward = {};
+COVestimateForward          = {};
+countModel                  = 1;
+Nmaxmodels                  = (length(covSearch.covcatNamesTest)^2-length(covSearch.covcatNamesTest))/2+length(covSearch.covcatNamesTest);
+continueForwardSearch       = 1;
+levelCount                  = 1;
+levelModel                  = '';
+ForwardModelName            = BASEmodelFolder;
+ModelNameAll                = {};
+
+while continueForwardSearch,
+    
+    % Run through remaining parameter/covariate combinations
+    % Generate all models first and then run all at once
+    covariatesTestForward           = {};
+    covariateModelValuesTESTForward = {};
+    COVestimateTESTForward          = {};
+    covariateModelAll               = {};
+    
+    for k1=1:length(covSearch.paramNamesTest),
+        
+        % Reset covariate setting to previous level
+        covariatesTest          = covariatesForward;
+        covariateModelValues    = covariateModelValuesForward;
+        COVestimate             = COVestimateForward;
+        
+        % Get new parameter/covariate combination to test
+        param = covSearch.paramNamesTest{k1};
+        cov   = covSearch.covcatNamesTest{k1};
+        delta = covSearch.delta_forward(k1);
+        value = 0.1; % Setting default value to 0.1 (NONMEM does not allow 0)
+        
+        % Build covariate test structure and covariateModelValues and COVestimate
+        ix = [];
+        for k2=1:length(covariatesTest),
+            if strcmp(covariatesTest{k2}{1},param),
+                ix = k2;
+            end
+        end
+        if isempty(ix),
+            covariatesTest{end+1}{1}        = param;
+            covariatesTest{end}{2}          = cov;
+            covariateModelValues{end+1}     = value;
+            COVestimate{end+1}              = 1;
+        else
+            covariatesTest{ix}{end+1}       = cov;
+            covariateModelValues{ix}(end+1) = value;
+            COVestimate{ix}(end+1)          = 1;
+        end
+        covariatesTest                      = covariatesTest(:);
+        
+        % Save for later
+        covariatesTestForward{k1}           = covariatesTest;
+        covariateModelValuesTESTForward{k1} = covariateModelValues;
+        COVestimateTESTForward{k1}          = COVestimate;
+        
+        % Convert to required format
+        covariateModel                      = '';
+        for k3=1:size(covariatesTest,1),
+            if ~isempty(covariatesTest{k3}),
+                text                        = sprintf('%s,',covariatesTest{k3}{:});
+                covariateModel              = [covariateModel '{' text(1:end-1) '},'];
+            end
+        end
+        covariateModel                      = covariateModel(1:end-1);
+        covariateModelAll{k1}               = covariateModel;
+        
+        % Determine COVestimate and covariateModelValues
+        COVestimate = {};
+        covariateModelValues = {};
+        for k3=1:size(covariatesTest,1),
+            COVestimate{k3}                 = ones(1,length(covariatesTest{k3})-1);
+            covariateModelValues{k3}        = 0.1*ones(1,length(covariatesTest{k3})-1);
+        end
+        
+        % Add structural covariates to covariate model
+        for k3=1:length(covStructural.paramNames),
+            param    = covStructural.paramNames{k3};
+            cov      = covStructural.covcatNames{k3};
+            value    = covStructural.value(k3);
+            estimate = covStructural.estimate(k3);
+            % Find where to add
+            ix = [];
+            for k4=1:size(covariatesTest,1),
+                if strcmp(param,covariatesTest{k4}{1}),
+                    ix = k4;
+                    break;
+                end
+            end
+            if ~isempty(ix),
+                % add info
+                covariatesTest{ix}{end+1} = cov;
+                covariateModelValues{ix}(end+1) = value;
+                COVestimate{ix}(end+1) = estimate;
+            else
+                % new param
+                covariatesTest{end+1}{1} = param;
+                covariatesTest{end}{2} = cov;
+                covariateModelValues{end+1}(1) = value;
+                COVestimate{end+1}(1) = estimate;
+            end
+            covariatesTest = covariatesTest(:);
+        end
+        
+        % Convert to required format for the search things
+        covariateModel                      = '';
+        for k3=1:size(covariatesTest,1),
+            if ~isempty(covariatesTest{k3}),
+                text                        = sprintf('%s,',covariatesTest{k3}{:});
+                covariateModel              = [covariateModel '{' text(1:end-1) '},'];
+            end
+        end
+        covariateModel                      = covariateModel(1:end-1);
+        
+        % Set covariateModel
+        options.covariateModel              = covariateModel;
+        options.covariateModelValues        = covariateModelValues;
+        options.COVestimate                 = COVestimate;
+        
+        % Create model
+        ModelName                           = sprintf('MODEL_%s',preFillCharIQM(countModel,length(num2str(Nmaxmodels)),'0'));
+        FolderName                          = [projectPathSCM sprintf('/FW_LEVEL_%d',levelCount)];
+        ModelFolder                         = [FolderName '/' ModelName];
+        ModelNameAll{k1}                    = ModelFolder;
+        
+        % For popPK all parameters need to be positive. 0 is not allowed due to L or maybe G transformation
+        % Here we fix 0 values to 1e-10 if present
+        options.POPvalues0(options.POPvalues0==0) = 1e-10;
+        
+        % Create project    
+        dataRelPathFromProjectPath = '../../../../Data';
+        createPopPK_NLMEproject_ODE_Analytic_IQM(FLAG_NONMEM,FLAG_ABSORPTION_DATA_PRESENT,ModelName,TemplateModels,FACTOR_UNITS, ...
+            numberCompartments,saturableClearance,...
+            absorptionModel,lagTime,...
+            data,ModelFolder,dataRelPathFromProjectPath,options,...
+            FLAG_NONMEM__RATE_BIOAVAILABILITY_ISSUE__OK, dataContents);
+        
+        countModel                          = countModel + 1;
+    end
+    
+    % Run the level models - do not create GoF plots
+    IQMrunNLMEprojectFolder(FolderName,N_PROCESSORS_PAR,N_PROCESSORS_SINGLE,1);
+    
+    % Read the results 
+    NLME_ORDER_CRITERION    = ''; % Do not order them
+    LEVEL_RESULTS           = parseProjectFolderResultsIQM(FolderName,NLME_ORDER_CRITERION);
+    IQMfitsummaryAll(FolderName,FolderName,NLME_ORDER_CRITERION);
+    
+    % Determine significance 
+    LEVEL_SIGNIFICANCE      = [];
+    % Get OBJ
+    LEVEL_OBJ               = [LEVEL_RESULTS.OBJ];
+    
+    % Create a table with output information    
+    if strcmpi(TOOL,'NONMEM'),
+        tableText               = cell(1,10);
+        tableText(1,1:2)        = {'<TT>' sprintf('Level %d: %s',levelCount,levelModel)};
+        tableText(2,:)          = {'<TH>','Model','Covariate tested','OBJ(cov)','OBJ(prev)','OBJ(prev)-OBJ(cov)','Significance','MINIMIZATION SUCCESSFUL','MINIMIZATION TERMINATED','PROBLEMS'};
+    else
+        tableText               = cell(1,7);
+        tableText(1,1:2)        = {'<TT>' sprintf('Level %d: %s',levelCount,levelModel)};
+        tableText(2,:)          = {'<TH>','Model','Covariate tested','OBJ(cov)','OBJ(prev)','OBJ(prev)-OBJ(cov)','Significance'};
+    end
+    for k1=1:length(covSearch.paramNamesTest),
+        tableText{k1+2,1}   = '<TR>';
+        tableText{k1+2,2}   = LEVEL_RESULTS(k1).model;
+        tableText{k1+2,3}   = sprintf('%s on %s',covSearch.covcatNamesTest{k1},covSearch.paramNamesTest{k1});
+        tableText{k1+2,4}   = round(100*LEVEL_OBJ(k1))/100;
+        tableText{k1+2,5}   = round(100*OLD_OFV)/100;
+        tableText{k1+2,6}   = round(100*(OLD_OFV-LEVEL_OBJ(k1)))/100;
+        if OLD_OFV-LEVEL_OBJ(k1) >= covSearch.delta_forward(k1),
+            LEVEL_SIGNIFICANCE(k1) = 1;
+            tableText{k1+2,7}   = 'YES';
+        else
+            LEVEL_SIGNIFICANCE(k1) = 0;
+            tableText{k1+2,7}   = '-';
+        end
+        if strcmpi(TOOL,'NONMEM'),
+            if ~isempty(strfind(LEVEL_RESULTS(k1).termination_info,'MINIMIZATION SUCCESSFUL')),
+                tableText{k1+2,8} = 'YES';
+            else
+                tableText{k1+2,8} = '-';
+            end            
+            if ~isempty(strfind(LEVEL_RESULTS(k1).termination_info,'MINIMIZATION TERMINATED')),
+                tableText{k1+2,9} = 'YES';
+            else
+                tableText{k1+2,9} = '-';
+            end     
+            if ~isempty(strfind(LEVEL_RESULTS(k1).termination_info,'PROBLEMS')),
+                tableText{k1+2,10} = 'YES';
+            else
+                tableText{k1+2,10} = '-';
+            end            
+        end
+    end        
+    
+    % Determine which covariate leads to the largest drop in OBJ
+    [~,ixBEST] = max(OLD_OFV-LEVEL_OBJ);
+    
+    % If none significant then stop forward inclusion here
+    if sum(LEVEL_SIGNIFICANCE) == 0,
+        % Nothing significant anymore - stop forward search
+        continueForwardSearch = 0;
+        
+        % Finalize table for this level by adding footer
+        tableText(end+1,1:2) = {'<TF>' 'No significant decrease in objective function => End of forward inclusion.'};
+    else
+        % Finalize table for this level by adding footer
+        tableText(end+1,1:2) = {'<TF>' sprintf('Retained covariate model for next level: %s (%s on %s)\n',LEVEL_RESULTS(ixBEST).model,covSearch.covcatNamesTest{ixBEST},covSearch.paramNamesTest{ixBEST})};
+
+        % Setup for new level
+        % -------------------
+        
+        OLD_OFV                             = LEVEL_OBJ(ixBEST);
+        
+        % Update options with optimal model parameters from last run
+        options.POPvalues0                  = LEVEL_RESULTS(ixBEST).rawParameterInfo.fixedEffects.values;
+        options.IIVvalues0                  = LEVEL_RESULTS(ixBEST).rawParameterInfo.randomEffects.values;
+        options.errorParam0                 = LEVEL_RESULTS(ixBEST).rawParameterInfo.errorParameter.values;
+
+        % If sequential 0/1 order absorption need to add Tlaginput 1 in between
+        if absorptionModel == 3,
+            POPvalues0 = NaN(1,length(options.POPvalues0)+1);
+            POPvalues0([1:9 11:end]) = options.POPvalues0;
+            options.POPvalues0 = POPvalues0;
+            
+            IIVvalues0 = NaN(1,length(options.IIVvalues0)+1);
+            IIVvalues0([1:9 11:end]) = options.IIVvalues0;
+            options.IIVvalues0 = IIVvalues0;
+        end
+           
+        % Remove covariate from search
+        covSearch.covcatNamesTest(ixBEST)   = [];
+        covSearch.delta_forward(ixBEST)     = [];
+        covSearch.delta_backward(ixBEST)    = [];
+        covSearch.paramNamesTest(ixBEST)    = [];
+        
+        % Set new base covariates
+        covariatesForward                   = covariatesTestForward{ixBEST};
+        covariateModelValuesForward         = covariateModelValuesTESTForward{ixBEST};
+        COVestimateForward                  = COVestimateTESTForward{ixBEST};
+        
+        % Update estimated covariate coefficient for next level - with all new estimates!
+        covInfo = LEVEL_RESULTS(ixBEST).rawParameterInfo.covariate;
+        
+        for k1x = 1:length(covariatesForward),
+            paramUpdate = covariatesForward{k1x}{1};
+            for k2x = 2:length(covariatesForward{k1x}),
+                covUpdate = covariatesForward{k1x}{k2x};
+                % Find parameter and covariate
+                matchIX = [];
+                for kkkx=1:length(covInfo.names),
+                    ixParam = strfind(covInfo.names{kkkx},paramUpdate);
+                    ixCov = strfind(covInfo.names{kkkx},covUpdate);
+                    if ~isempty(ixParam) && ~isempty(ixCov),
+                        matchIX(end+1) = kkkx;
+                    end
+                end
+                if length(matchIX) ~= 1,
+                    error('Problem with getting covariate coefficient value.');
+                end
+                % Get the estimated value
+                value = covInfo.values(matchIX);
+                % Add value to covariateModelValuesForward
+                ix = [];
+                for k2=1:length(covariatesForward),
+                    if strcmp(covariatesForward{k2}{1},paramUpdate),
+                        ix = k2;
+                    end
+                end
+                covariateModelValuesForward{ix}(strmatchIQM(covUpdate,covariatesForward{ix},'exact')-1) = value;
+            end
+        end
+        
+        levelModel          = covariateModelAll{ixBEST};
+        ForwardModelName    = ModelNameAll{ixBEST};
+        levelCount          = levelCount+1;
+    end
+    
+    % Export table for the level into the log file
+    textDisplay = IQMconvertCellTable2ReportTable(tableText,'text');
+    fprintf(fid,'%s\n',textDisplay);
+end
+
+% Get forward results
+FORWARD_OFV = OLD_OFV;
+forwardModel = levelModel;
+
+% Report forward model
+fprintf(fid,'************************************\n');
+fprintf(fid,'* FORWARD MODEL RESULTS            *\n');
+fprintf(fid,'************************************\n');
+fprintf(fid,'\n');
+
+fprintf(fid,'Forward model:             %s\n',ForwardModelName);
+fprintf(fid,'Covariates:                %s\n',forwardModel);
+fprintf(fid,'Objective function value:  %g\n',FORWARD_OFV);
+fprintf(fid,'\n');
+
+
+% Backward elimination
+fprintf(fid,'************************************\n');
+fprintf(fid,'* BACKWARD ELIMINATION             *\n');
+fprintf(fid,'************************************\n');
+fprintf(fid,'\n');
+
+% Create covSearch structure for backward search
+covSearchBackward = covSearchBackUp;
+ix_keep = [];
+for k1=1:size(covariatesForward),
+    param = covariatesForward{k1}{1};
+    for k2=2:length(covariatesForward{k1}),
+        cov = covariatesForward{k1}{k2};
+        ix_keep(end+1) = intersect(strmatchIQM(param,covSearchBackward.paramNamesTest,'exact'),strmatchIQM(cov,covSearchBackward.covcatNamesTest,'exact'));
+    end
+end
+covSearchBackward.covcatNamesTest = covSearchBackward.covcatNamesTest(ix_keep);
+covSearchBackward.paramNamesTest = covSearchBackward.paramNamesTest(ix_keep);
+covSearchBackward.delta_forward = covSearchBackward.delta_forward(ix_keep);
+covSearchBackward.delta_backward = covSearchBackward.delta_backward(ix_keep);
+
+% Add parameter values
+for k1=1:length(covSearchBackward.paramNamesTest),
+    paramName = covSearchBackward.paramNamesTest{k1};
+    covName   = covSearchBackward.covcatNamesTest{k1};
+    for k2=1:size(covariatesForward),
+        if strcmp(paramName,covariatesForward{k2}{1}),
+            ix = k2;
+            break;
+        end
+    end
+    ix2 = strmatchIQM(covName,covariatesForward{ix}(2:end),'exact');
+    value = covariateModelValuesForward{ix}(ix2);
+    covSearchBackward.value(k1) = value;
+end
+
+% Do the search
+covariateModelAll  = {};
+levelCount         = 1;
+countModel         = 1;
+BackwardModelName  = ForwardModelName;
+ModelNameAll       = {};
+
+% Check if backward search needed
+if ~isempty(covariatesForward),
+    continueBackwardSearch = 1;
+else
+    continueBackwardSearch = 0;
+end
+
+% OBJ:  Start with FORWARD_OFV and remove one by one ... until deltaOFV>... for
+while continueBackwardSearch,
+    
+    % Run through remaining parameter/covariate combinations
+    % Generate all models first and then run all at once
+    
+    for k1=1:length(covSearchBackward.paramNamesTest),
+        
+        % Reset covariate setting to previous level
+        covariatesTest  = covSearchBackward;
+        
+        % Remove parameter to test
+        param                   = covariatesTest.paramNamesTest;
+        cov                     = covariatesTest.covcatNamesTest;
+        value                   = covariatesTest.value;
+        param(k1)               = [];
+        cov(k1)                 = [];
+        value(k1)               = [];
+        
+        % Build covariate test structure
+        x                       = unique(param);
+        covTestStructure        = {};
+        covariateModelValues    = cell(1,length(x));
+        COVestimate             = cell(1,length(x));
+        
+        for k2=1:length(x),
+            covTestStructure{k2}{1}         = x{k2};
+        end
+        covTestStructure                    = covTestStructure(:);
+        for k2=1:length(param),
+            ix = strmatchIQM(param{k2},x,'exact');
+            covTestStructure{ix}{end+1} 	= cov{k2};
+            covariateModelValues{ix}(end+1) = value(k2);
+            COVestimate{ix}(end+1)          = 1;
+        end
+        
+        % Convert to required format
+        covariateModel                      = '';
+        for k3=1:size(covTestStructure,1),
+            if ~isempty(covTestStructure{k3}),
+                text                        = sprintf('%s,',covTestStructure{k3}{:});
+                covariateModel              = [covariateModel '{' text(1:end-1) '},'];
+            end
+        end
+        covariateModel                      = covariateModel(1:end-1);
+        covariateModelAll{k1}               = covariateModel;
+        
+        % Add structural covariates to covariate model
+        for k3=1:length(covStructural.paramNames),
+            param                           = covStructural.paramNames{k3};
+            cov                             = covStructural.covcatNames{k3};
+            value                           = covStructural.value(k3);
+            estimate                        = covStructural.estimate(k3);
+            % Find where to add
+            ix = [];
+            for k4=1:size(covTestStructure,1),
+                if strcmp(param,covTestStructure{k4}{1}),
+                    ix = k4;
+                    break;
+                end
+            end
+            if ~isempty(ix),
+                % add info
+                covTestStructure{ix}{end+1}         = cov;
+                covariateModelValues{ix}(end+1)     = value;
+                COVestimate{ix}(end+1)              = estimate;
+            else
+                % new param
+                covTestStructure{end+1}{1}          = param;
+                covTestStructure{end}{2}            = cov;
+                covariateModelValues{end+1}(1)      = value;
+                COVestimate{end+1}(1)               = estimate;
+            end
+            covTestStructure                        = covTestStructure(:);
+        end
+        
+        % Convert to required format for the search things
+        covariateModel                      = '';
+        for k3=1:size(covTestStructure,1),
+            if ~isempty(covTestStructure{k3}),
+                text                        = sprintf('%s,',covTestStructure{k3}{:});
+                covariateModel              = [covariateModel '{' text(1:end-1) '},'];
+            end
+        end
+        covariateModel                      = covariateModel(1:end-1);
+        
+        % Set covariateModel
+        options.covariateModel              = covariateModel;
+        options.covariateModelValues        = covariateModelValues;
+        options.COVestimate                 = COVestimate;
+        
+        % Create model
+        ModelName                           = sprintf('MODEL_%s',preFillCharIQM(countModel,length(num2str(Nmaxmodels)),'0'));
+        FolderName                          = [projectPathSCM sprintf('/BW_LEVEL_%d',levelCount)];
+        ModelFolder                         = [FolderName '/' ModelName];
+        ModelNameAll{k1}                    = ModelFolder;
+        
+        % For popPK all parameters need to be positive. 0 is not allowed due to L or maybe G transformation
+        % Here we fix 0 values to 1e-10 if present
+        options.POPvalues0(options.POPvalues0==0) = 1e-10;
+        
+        % Create project    
+        dataRelPathFromProjectPath = '../../../../Data';
+        createPopPK_NLMEproject_ODE_Analytic_IQM(FLAG_NONMEM,FLAG_ABSORPTION_DATA_PRESENT,ModelName,TemplateModels,FACTOR_UNITS,...
+            numberCompartments,saturableClearance,...
+            absorptionModel,lagTime,...
+            data,ModelFolder,dataRelPathFromProjectPath,options,...
+            FLAG_NONMEM__RATE_BIOAVAILABILITY_ISSUE__OK, dataContents);
+        
+        countModel                          = countModel + 1;
+    end
+    
+    % Run the level models - do not create GoF plots
+    IQMrunNLMEprojectFolder(FolderName,N_PROCESSORS_PAR,N_PROCESSORS_SINGLE,1);
+    
+    % Read the results
+    NLME_ORDER_CRITERION = ''; % Do not order them
+    LEVEL_RESULTS = parseProjectFolderResultsIQM(FolderName,NLME_ORDER_CRITERION);
+    IQMfitsummaryAll(FolderName,FolderName,NLME_ORDER_CRITERION);
+    
+    % Determine significance 
+    LEVEL_SIGNIFICANCE = [];
+    LEVEL_OBJ = [LEVEL_RESULTS.OBJ];
+    
+    
+    % Create a table with output information    
+    if strcmpi(TOOL,'NONMEM'),
+        tableText               = cell(1,10);
+        tableText(1,1:2)        = {'<TT>' sprintf('Level %d: %s',levelCount,levelModel)};
+        tableText(2,:)          = {'<TH>','Model','Covariate removed','OBJ(cov)','OBJ(prev)','OBJ(prev)-OBJ(cov)','Significance','MINIMIZATION SUCCESSFUL','MINIMIZATION TERMINATED','PROBLEMS'};
+    else
+        tableText               = cell(1,7);
+        tableText(1,1:2)        = {'<TT>' sprintf('Level %d: %s',levelCount,levelModel)};
+        tableText(2,:)          = {'<TH>','Model','Covariate tested','OBJ(cov)','OBJ(prev)','OBJ(prev)-OBJ(cov)','Significance'};
+    end
+    for k1=1:length(covSearchBackward.paramNamesTest),
+        tableText{k1+2,1}   = '<TR>';
+        tableText{k1+2,2}   = LEVEL_RESULTS(k1).model;
+        tableText{k1+2,3}   = sprintf('%s on %s',covSearchBackward.covcatNamesTest{k1},covSearchBackward.paramNamesTest{k1});
+        tableText{k1+2,4}   = round(100*LEVEL_OBJ(k1))/100;
+        tableText{k1+2,5}   = round(100*OLD_OFV)/100;
+        tableText{k1+2,6}   = round(100*(-OLD_OFV+LEVEL_OBJ(k1)))/100;
+        if -OLD_OFV+LEVEL_OBJ(k1) >= covSearchBackward.delta_backward(k1),
+            LEVEL_SIGNIFICANCE(k1) = 1;
+            tableText{k1+2,7}   = 'YES';
+        else
+            LEVEL_SIGNIFICANCE(k1) = 0;
+            tableText{k1+2,7}   = '-';
+        end
+        if strcmpi(TOOL,'NONMEM'),
+            if ~isempty(strfind(LEVEL_RESULTS(k1).termination_info,'MINIMIZATION SUCCESSFUL')),
+                tableText{k1+2,8} = 'YES';
+            else
+                tableText{k1+2,8} = '-';
+            end            
+            if ~isempty(strfind(LEVEL_RESULTS(k1).termination_info,'MINIMIZATION TERMINATED')),
+                tableText{k1+2,9} = 'YES';
+            else
+                tableText{k1+2,9} = '-';
+            end     
+            if ~isempty(strfind(LEVEL_RESULTS(k1).termination_info,'PROBLEMS')),
+                tableText{k1+2,10} = 'YES';
+            else
+                tableText{k1+2,10} = '-';
+            end            
+        end
+    end        
+    
+    % Determine which covariate leads to the largest increase in OBJ
+    [~,ixBEST] = min(-OLD_OFV+LEVEL_OBJ);
+    
+    % If all significant then stop backward elimination here
+    if sum(LEVEL_SIGNIFICANCE~=1) == 0,
+        continueBackwardSearch = 0;
+        % Finalize table for this level by adding footer
+        tableText(end+1,1:2) = {'<TF>' 'No insignificant increase in objective function => End of backward elimination.'};
+    else
+        % Finalize table for this level by adding footer
+        tableText(end+1,1:2) = {'<TF>' sprintf('Removed covariate model for next level: %s (%s on %s)\n',LEVEL_RESULTS(ixBEST).model,covSearchBackward.covcatNamesTest{ixBEST},covSearchBackward.paramNamesTest{ixBEST})};
+        
+        % Setup for new level
+        
+        OLD_OFV                                     = LEVEL_OBJ(ixBEST);
+        
+        % Update options with optimal model parameters from last run
+        options.POPvalues0                          = LEVEL_RESULTS(ixBEST).rawParameterInfo.fixedEffects.values;
+        options.IIVvalues0                          = LEVEL_RESULTS(ixBEST).rawParameterInfo.randomEffects.values;
+        options.errorParam0                         = LEVEL_RESULTS(ixBEST).rawParameterInfo.errorParameter.values;
+        
+        % If sequential 0/1 order absorption need to add Tlaginput 1 in between
+        if absorptionModel == 3,
+            POPvalues0 = NaN(1,length(options.POPvalues0)+1);
+            POPvalues0([1:9 11:end]) = options.POPvalues0;
+            options.POPvalues0 = POPvalues0;
+            
+            IIVvalues0 = NaN(1,length(options.IIVvalues0)+1);
+            IIVvalues0([1:9 11:end]) = options.IIVvalues0;
+            options.IIVvalues0 = IIVvalues0;
+        end
+
+        % Remove covariate from search
+        covSearchBackward.covcatNamesTest(ixBEST)   = [];
+        covSearchBackward.delta_forward(ixBEST)     = [];
+        covSearchBackward.delta_backward(ixBEST)    = [];
+        covSearchBackward.paramNamesTest(ixBEST)    = [];
+        covSearchBackward.value                     = NaN(1,length(covSearchBackward.paramNamesTest));
+        
+        levelModel                                  = covariateModelAll{ixBEST};
+        levelCount                                  = levelCount+1;
+        BackwardModelName                           = ModelNameAll{ixBEST};
+        
+        % Update values in covSearchBackward to estimated ones in best model
+        covInfo                                     = LEVEL_RESULTS(ixBEST).rawParameterInfo.covariate;
+        
+        for k1x = 1:length(covSearchBackward.paramNamesTest),
+            paramUpdate = covSearchBackward.paramNamesTest{k1x};
+            covUpdate   = covSearchBackward.covcatNamesTest{k1x};
+            
+            % Find parameter and covariate
+            matchIX = [];
+            for kkkx=1:length(covInfo.names),
+                ixParam = strfind(covInfo.names{kkkx},paramUpdate);
+                ixCov = strfind(covInfo.names{kkkx},covUpdate);
+                if ~isempty(ixParam) && ~isempty(ixCov),
+                    matchIX(end+1) = kkkx;
+                end
+            end
+            if length(matchIX) ~= 1,
+                error('Problem with getting covariate coefficient value.');
+            end
+            
+            % Add value to covSearchBackward
+            covSearchBackward.value(k1x) = covInfo.values(matchIX);
+        end
+    end
+    
+    if  isempty(covSearchBackward.paramNamesTest),
+        continueBackwardSearch = 0;
+        % Finalize table for this level by adding footer
+        tableText(end,1:2) = {'<TF>' 'All candidate covariates removed in backward elimination.'};
+    end
+    
+    % Export table for the level into the log file
+    textDisplay = IQMconvertCellTable2ReportTable(tableText,'text');
+    fprintf(fid,'%s\n',textDisplay);
+end
+
+% Get backward results
+BACKWARD_OFV = OLD_OFV;
+backwardModel = levelModel;
+
+% Report backward model
+fprintf(fid,'************************************\n');
+fprintf(fid,'* BACKWARD MODEL RESULTS           *\n');
+fprintf(fid,'************************************\n');
+fprintf(fid,'\n');
+
+fprintf(fid,'Backward model:            %s\n',BackwardModelName);
+if ~isempty(backwardModel),
+    fprintf(fid,'Covariates:                "%s"\n',backwardModel);
+else
+    fprintf(fid,'Covariates:                "NONE"\n');
+end    
+fprintf(fid,'Objective function value:  %g\n',BACKWARD_OFV);
+fprintf(fid,'\n');
+
+% Close report file
+fclose(fid);
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/IQMsimulatePopPKmodel.m b/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/IQMsimulatePopPKmodel.m
new file mode 100644
index 0000000000000000000000000000000000000000..d20db3483b45b22e4dc40157c69b65e7883dc309
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/IQMsimulatePopPKmodel.m	
@@ -0,0 +1,295 @@
+function [output] = IQMsimulatePopPKmodel(NLMEproject,FACTOR_UNITS,dosing_abs,dosing_iv,OBSTIME,COVARIATE_DATA,options)
+% This function allows to simulate PK models for user defined dosing
+% schemes. As input a popPK NLME project folder is expected that has been
+% generated with the popPK modeling workflow in IQM Tools. Dosings can be
+% defined as absorption (covering 1st order, 0th order and mixed order absorption) 
+% doses and IV doses (bolus and infusion). 
+%
+% [SYNTAX]
+% [output] = IQMsimulatePopPKmodel(NLMEproject,FACTOR_UNITS,dosing_abs,dosing_iv,OBSTIME)
+% [output] = IQMsimulatePopPKmodel(NLMEproject,FACTOR_UNITS,dosing_abs,dosing_iv,OBSTIME,COVARIATE_DATA)
+% [output] = IQMsimulatePopPKmodel(NLMEproject,FACTOR_UNITS,dosing_abs,dosing_iv,OBSTIME,COVARIATE_DATA,options)
+%
+% [INPUT]
+% NLMEproject:      Path to the NLME project to sample parameters from.
+%                   For each trial population parameters are sampled from
+%                   the uncertainty distribution. Then NSAMPLES individual
+%                   sets of parameters are sampled.
+% FACTOR_UNITS:     The FACTOR_UNITS value used for popPK model fitting.
+% dosing_abs:       MATLAB structure with 3 fields defining possible dosing
+%                   with absorption, covering 1st order, 0th order and mixed 
+%                   order absorption - dependent on the model.
+%       dosing_abs.TIME:        Vector with dosing times
+%       dosing_abs.DOSE:        Scalar or vector with doses (if vector then same length as dosing time vector) 
+%       dosing_abs.SCALING:     String with name of covariate to use for dose scaling. For example if 
+%                               weight is 'WT0' then defining this as scaling will enable weight based dosing.
+%                               If empty ('') then no dose scaling is done.
+% dosing_iv:        MATLAB structure with 4 fields defining possible dosing
+%                   with IV administration
+%       dosing_iv.TIME:         Vector with dosing times
+%       dosing_iv.DOSE:         Scalar or vector with doses (if vector then same length as dosing time vector) 
+%       dosing_iv.TINF:         Scalar or vector with infusion time (if vector then same length as dosing time vector) 
+%       dosing_iv.SCALING:      String with name of covariate to use for dose scaling. For example if 
+%                               weight is 'WT0' then defining this as scaling will enable weight based dosing.
+%                               If empty ('') then no dose scaling is done.
+% OBSTIME:          Observation times to read out the output.
+% COVARIATE_DATA:   MATLAB table with covariate data for simulation.
+%                   Column names should match the covariates that are used
+%                   in the model. The user can specify any number of rows
+%                   that define virtual subjects from which the covariates
+%                   are sampled for simulation. Additionally, if weight
+%                   based dosing (or any other scaling) should be done,
+%                   this scaling factor (e.g. 'WT0') should be present in
+%                   this table.
+%                   An alternative is to provide a full NLME modeling
+%                   dataset. If USUBJID is present the the covariates will
+%                   be extracted from the model and the covariates for each
+%                   subject will be taken from the dataset. 
+%                   It also can be the path to the NLME dataset.
+%                   If columns 'TIMEUNIT', 'UNIT', 'NAME', 'YTYPE' is
+%                   present in this table then the axes labeling will be
+%                   nicer.
+%
+% options:          Matlab structure with additional information
+%       options.filename:               Filename for PNG figure export (default: '' - no export)
+%       options.optionsIntegrator:      Integrator options (see IQMmakeMEXmodel)      
+%       options.N_PROCESSORS_PAR:       Number of processors to simulate in parallel (requires parallel toolbox) (default: as specified in SETUP_PATHS_TOOLS_IQMPRO)
+%       options.NSUBJECTS:              Number of subjects per trial (default: 100) 
+%       options.NTRIALS:                Number of trials (default: 100)      
+%       options.QUANTILESDATA:          Vector with quantiles to compute from the data for each trial (default: [0.05 0.5 0.95])    
+%       options.QUANTILESUNCERTAINTY:   Vector with quantiles to compute for each trial quantiles for all trials (uncertainty of data quantiles) (default: [0.05 0.5 0.95])          
+%       options.KEEP_TRIAL_INDIVDATA:   =0: Do not keep individual data in the output (saves memory), =1: keep it (default: 0)
+%       options.colorMedianRange        Default: [1 0.9 0.8]
+%       options.colorQuantilesRange     Default: [0.8 1 0.8]
+%       options.colorData               Default: 0.2*[1 1 1]
+%       options.colorMedian             Default: [1 0.2 0]
+%
+% [OUTPUT]
+% The simulation results are plotted and if desired the simulation is
+% exported to PNG.
+% output: Matlab structure with results
+%       output.name:                        String with output name
+%       output.time:                        Timevector of the simulation
+%       output.QUANTILESDATA:               options.QUANTILESDATA
+%       output.QUANTILESUNCERTAINTY:        options.QUANTILESUNCERTAINTY
+%       output.quantilesData_uncertainty:   Cell-array with as many entries
+%                                           and entries in QUANTILESDATA.
+%                                           Each element contains the
+%                                           uncertainty quantiles for each
+%                                           data quantile. 
+%       output.data_individual_per_trial:   Cell-array with each element
+%                                           containing individual data for
+%                                           each trial. Columns:
+%                                           individuals, Rows: OBSTIME
+%                                           timepoints.    
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle variable input arguments
+if nargin<5 || nargin>7,
+    error('Incorrect number of input arguments.');
+end
+if nargin<6,
+    COVARIATE_DATA          = [];
+end
+if nargin<7,
+    options                 = [];
+end
+
+% Handle options
+try filename                = options.filename;             catch, filename             = '';                       end
+try options.NSUBJECTS       = options.NSUBJECTS;            catch, options.NSUBJECTS    = 100;                      end
+try options.NTRIALS         = options.NTRIALS;              catch, options.NTRIALS      = 100;                      end
+try colorMedianRange        = options.colorMedianRange;     catch, colorMedianRange     = [1 0.9 0.8];              end
+try colorQuantilesRange     = options.colorQuantilesRange;  catch, colorQuantilesRange  = [0.8 1 0.8];              end
+try colorMedian             = options.colorMedian;          catch, colorMedian          = [1 0.2 0];                end
+
+% Interface inputs
+DOSING_TIME_ABS             = [];
+DOSING_DOSE_ABS             = [];
+DOSING_SCALING_ABS          = '';
+try
+    DOSING_TIME_ABS         = dosing_abs.TIME;
+end
+try
+    DOSING_DOSE_ABS         = dosing_abs.DOSE;
+end
+try
+    DOSING_SCALING_ABS      = dosing_abs.SCALING;
+end
+
+DOSING_TIME_IV             = [];
+DOSING_DOSE_IV             = [];
+DOSING_TINF_IV             = [];
+DOSING_SCALING_IV          = '';
+try
+    DOSING_TIME_IV         = dosing_iv.TIME;
+end
+try
+    DOSING_DOSE_IV         = dosing_iv.DOSE;
+end
+try
+    DOSING_TINF_IV         = dosing_iv.TINF;
+end
+try
+    DOSING_SCALING_IV      = dosing_iv.SCALING;
+end
+
+% Handle empty inputs
+if isempty(DOSING_TIME_ABS),
+    DOSING_TIME_ABS = 0;
+end
+if isempty(DOSING_DOSE_ABS),
+    DOSING_DOSE_ABS = 0;
+end
+
+if isempty(DOSING_TIME_IV),
+    DOSING_TIME_IV = 0;
+end
+if isempty(DOSING_DOSE_IV),
+    DOSING_DOSE_IV = 0;
+end
+if isempty(DOSING_TINF_IV),
+    DOSING_TINF_IV = 0.0001;
+end
+
+% Check inputs
+if (length(DOSING_TIME_ABS)~=1 && length(DOSING_DOSE_ABS)~=1)  && (length(DOSING_TIME_ABS) ~= length(DOSING_DOSE_ABS)),
+    error('DOSING_TIME_ABS and DOSING_DOSE_ABS need to have same length. Or one needs to be a scalar.');
+end
+
+% Check inputs
+if (length(DOSING_TIME_IV)~=1 && length(DOSING_DOSE_IV)~=1)  && (length(DOSING_TIME_IV) ~= length(DOSING_DOSE_IV)),
+    error('DOSING_TIME_IV and DOSING_DOSE_IV need to have same length. Or one needs to be a scalar.');
+end
+if length(DOSING_TINF_IV)~=1,
+    error('DOSING_TINF_IV needs to be a scalar.');
+end
+
+% Load data if needed
+if ~isempty(COVARIATE_DATA) && ischar(COVARIATE_DATA),
+    COVARIATE_DATA = IQMloadCSVdataset(COVARIATE_DATA);
+end
+
+% Get information for plotting if present
+% Define default infos for plotting
+TIMEUNIT   = 'unknown';
+OBSNAME     = 'Output';
+OBSUNIT     = 'unknown';
+% Check if YTYPE present
+try
+    readout     = COVARIATE_DATA(COVARIATE_DATA.YTYPE==1,:);
+    TIMEUNIT   = restoreSpacesDataIQM(readout.TIMEUNIT{1});
+    OBSNAME     = restoreSpacesDataIQM(readout.NAME{1});
+    OBSUNIT     = restoreSpacesDataIQM(readout.UNIT{1});
+end
+
+% If USUBJID present ... then filter out one row per subject
+if ~isempty(COVARIATE_DATA),
+    if ~isempty(strmatchIQM('USUBJID',COVARIATE_DATA.Properties.VariableNames,'exact')),
+        pinfo = parseNLMEprojectHeaderIQM(NLMEproject);
+        COVARIATE_DATA = unique(COVARIATE_DATA(:,[{'USUBJID'} pinfo.COVARIATESUSED]));
+    end
+end
+
+% If COVARIATE_DATA then non empty scaling settings lead to error and
+% scaling names need to be present in COVARIATE_DATA
+if isempty(COVARIATE_DATA),
+    if ~isempty(DOSING_SCALING_ABS) || ~isempty(DOSING_SCALING_IV),
+        error('Dosing scaling can only be used if COVARIATE_DATA contains the scaling values.');
+    end
+    COVARIATE_DATA = table();
+else
+    if ~istable(COVARIATE_DATA),
+        error('COVARIATE_DATA needs to be a MATLAB table.');
+    end
+    if ~isempty(DOSING_SCALING_ABS),
+        % Check if scaling name present
+        if isempty(strmatchIQM(DOSING_SCALING_ABS,COVARIATE_DATA.Properties.VariableNames,'exact')),
+            error('DOSING_SCALING_ABS entry not found in COVARIATE_DATA.');
+        end
+        SCALING_ABS = COVARIATE_DATA.(DOSING_SCALING_ABS);
+    else
+        SCALING_ABS = ones(height(COVARIATE_DATA),1);
+    end
+    if ~isempty(DOSING_SCALING_IV),
+        % Check if scaling name present
+        if isempty(strmatchIQM(DOSING_SCALING_IV,COVARIATE_DATA.Properties.VariableNames,'exact')),
+            error('DOSING_SCALING_ABS entry not found in COVARIATE_DATA.');
+        end
+        SCALING_IV = COVARIATE_DATA.(DOSING_SCALING_IV);
+    else
+        SCALING_IV = ones(height(COVARIATE_DATA),1);
+    end
+end
+
+% Create dosing scheme
+% Abs doses can be added to input 1 and input 3. Model parameterization
+% adequate to switch on or off 1st and 0th order absorption
+DOSING_INFO = {DOSING_DOSE_ABS DOSING_DOSE_IV DOSING_DOSE_ABS};
+DOSTIM_INFO = {DOSING_TIME_ABS DOSING_TIME_IV DOSING_TIME_ABS};
+if isSequentialAbsorptionPopPKIQM(NLMEproject),
+    % If sequential 0/1 order absorption then set Tlaginput1 to 'Tk0input3'
+    dosing = IQMcreateDOSING({'BOLUS','INFUSION','ABSORPTION0'},DOSING_INFO,DOSTIM_INFO,{[] DOSING_TINF_IV 1e-10},{'Tk0input3' 0 0});
+else
+    dosing = IQMcreateDOSING({'BOLUS','INFUSION','ABSORPTION0'},DOSING_INFO,DOSTIM_INFO,{[] DOSING_TINF_IV 1e-10},{0 0 0});
+end
+
+% Apply dosing scaling if desired
+if ~isempty(COVARIATE_DATA),
+    dosings                 = {};
+    for k=1:height(COVARIATE_DATA),
+        % Get structure of defined dosing
+        ds                  = struct(dosing);
+        % Apply SCALING_ABS 
+        ds.inputs(1).D      = ds.inputs(1).D*SCALING_ABS(k);
+        % Apply SCALING_IV 
+        ds.inputs(2).D      = ds.inputs(2).D*SCALING_IV(k);
+        % Collect dosings
+        dosings{k}          = IQMdosing(ds);
+    end
+else
+    % Just use the defined dosing for all simulated subjects
+    dosings                 = dosing;
+end
+
+% Load template model
+model                       = IQMmodel('template_popPK_model.txt');
+
+% Parameterize model
+model                       = IQMparameters(model,'FACTOR_UNITS',FACTOR_UNITS);
+
+% Ensure VMAX and other param are 0 and only changed by the fit
+model                       = IQMparameters(model,{'CL','Q1','Q2','VMAX','ka','Fiv','Fabs1','Fabs0','Frel0'},[0 0 0 0 0 0 0 0 0]);
+
+% Do the simulation
+output                      = IQMtrialGroupSimulation(model,dosings,NLMEproject,OBSTIME,'OUTPUT1',COVARIATE_DATA,options);
+
+% Do the plotting
+figure(); clf
+set(gca,'YScale','log')
+
+legendText = {};
+
+% Plot simulation results
+IQMplotfill(output.time,output.quantilesData_uncertainty{1}(:,1),output.quantilesData_uncertainty{1}(:,3),colorQuantilesRange,1); hold on;
+legendText{end+1} = sprintf('Simulation - %1.3g Quantile [%g-%g]%%CI ',output.QUANTILESDATA(1),100*output.QUANTILESUNCERTAINTY(1),100*output.QUANTILESUNCERTAINTY(3));
+
+IQMplotfill(output.time,output.quantilesData_uncertainty{3}(:,1),output.quantilesData_uncertainty{3}(:,3),colorQuantilesRange,1); hold on;
+legendText{end+1} = sprintf('Simulation - %1.3g Quantile [%g-%g]%%CI ',output.QUANTILESDATA(3),100*output.QUANTILESUNCERTAINTY(1),100*output.QUANTILESUNCERTAINTY(3));
+
+IQMplotfill(output.time,output.quantilesData_uncertainty{2}(:,1),output.quantilesData_uncertainty{2}(:,3),colorMedianRange,1); hold on;
+legendText{end+1} = sprintf('Simulation - Median [%g-%g]%%CI ',100*output.QUANTILESUNCERTAINTY(1),100*output.QUANTILESUNCERTAINTY(3));
+
+plot(output.time,output.quantilesData_uncertainty{2}(:,2),'-','Color',colorMedian,'LineWidth',2); hold on
+legendText{end+1} = sprintf('Simulation - Median');
+
+% Annotate
+grid on;
+xlabel(['Time [' TIMEUNIT ']'],'FontSize',14);
+ylabel([OBSNAME ' [' OBSUNIT ']'],'FontSize',14);
+title(sprintf('NTRIALS=%d, NSUBJECTS=%d',options.NTRIALS,options.NSUBJECTS),'FontSize',16);
+legend(legendText,'Location','best');
+
+% Export figure
+IQMprintFigure(gcf,filename,'png');
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/auxiliary/buildPKmodelSpaceIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/auxiliary/buildPKmodelSpaceIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..2c2fc95cc249f1d82916367eb5b1e73894d14cd7
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/auxiliary/buildPKmodelSpaceIQM.m	
@@ -0,0 +1,328 @@
+function [table_MODEL_INFO] = buildPKmodelSpaceIQM(FLAG_NONMEM,TemplateModels,modelProjectsFolder, dataRelPathFromProjectPath, PROJECT_PREFIX, ...
+                analysisDatasetFile, dataheaderNLME, modeltest, options)
+% buildPKmodelSpaceIQM: creates a subspace of popPK model projects for
+% Monlix, based on user settings.
+% Function called by IQMbuildPopPKModelSpace. 
+% Function not supposed to be called by a user.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle REQUIRED "modeltest" input arguments 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%       
+try numberCompartments      = modeltest.numberCompartments;      catch, error('Please specify "modeltest.numberCompartments".');    end %#ok<*CTCH>
+try errorModels             = modeltest.errorModels;             catch, error('Please specify "modeltest.errorModels".');           end
+try saturableClearance      = modeltest.saturableClearance;      catch, error('Please specify "modeltest.saturableClearance".');    end
+try FACTOR_UNITS            = modeltest.FACTOR_UNITS;            catch, error('Please specify "modeltest.FACTOR_UNITS".');          end
+try POPvalues0              = modeltest.POPvalues0;              catch, error('Please specify "modeltest.POPvalues0".');            end
+try POPestimate             = modeltest.POPestimate;             catch, error('Please specify "modeltest.POPestimate".');           end
+try IIVestimate             = modeltest.IIVestimate;             catch, error('Please specify "modeltest.IIVestimate".');           end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle OPTIONAL "modeltest" input arguments values
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%       
+try absorptionModel         = modeltest.absorptionModel;         catch, absorptionModel = 1;           end % default: 1st order absorption
+try lagTime                 = modeltest.lagTime;                 catch, lagTime = 0;                   end % default: no lag time
+
+try IIVvalues0              = modeltest.IIVvalues0;              catch, IIVvalues0             = 0.5*ones(1,length(TemplateModels.ParameterNames.ODE));   end
+try covarianceModels        = modeltest.covarianceModels;        catch, covarianceModels       = '';   end %#ok<*CTCH>
+try covariateModels         = modeltest.covariateModels;         catch, covariateModels        = '';   end
+try covariateModelValues    = modeltest.covariateModelValues;    catch, covariateModelValues   = {};   end %#ok<*CTCH>
+try COVestimate             = modeltest.COVestimate;             catch, COVestimate            = {};   end
+COVcentering = [];
+try COVcentering.covs       = modeltest.COVcentering.covs;       catch, COVcentering.covs      = {};   end
+try COVcentering.values     = modeltest.COVcentering.values;     catch, COVcentering.values    = [];   end
+
+try covariateModelsTV       = modeltest.covariateModelsTV;         catch, covariateModelsTV        = '';   end
+ 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Adjust potential strings to cell-arrays if required as cell-arrays
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%       
+if ischar(covarianceModels), covarianceModels = {covarianceModels}; end
+if ischar(covariateModels),  covariateModels  = {covariateModels};  end
+if ischar(errorModels),      errorModels      = {errorModels};      end
+if ~iscell(IIVestimate),     IIVestimate      = {IIVestimate};      end
+if ~iscell(POPestimate),     POPestimate      = {POPestimate};      end
+if ~iscell(POPvalues0),      POPvalues0       = {POPvalues0};       end
+
+if ischar(covariateModelsTV),  covariateModelsTV  = {covariateModelsTV};  end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% For now allow only a single time varying covariate model
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%       
+if length(covariateModelsTV) ~= 1,
+    error('Only single time varying covariate model allowed.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check if errorParam0 is defined and check if correctly
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%       
+try errorParam0             = modeltest.errorParam0;             catch, errorParam0 = cell(1,length(errorModels)); end
+if ~iscell(errorParam0),      errorParam0      = {errorParam0};      end
+if length(errorParam0) ~= length(errorModels),
+    error('Incorrect number of errorParam0 entries - need to match errorModels.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Adjust covariateModelValues and COVestimate
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%       
+if length(covariateModels) == 1 && length(covariateModelValues) ~= 1,
+    covariateModelValues ={covariateModelValues};
+end
+if length(covariateModels) == 1 && length(COVestimate) ~= 1,
+    COVestimate ={COVestimate};
+end
+
+if isempty(covariateModelValues),
+    covariateModelValues = cell(length(covariateModels),1);
+end
+if isempty(COVestimate),
+    COVestimate = cell(length(covariateModels),1);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check covariateModelValues and COVestimate
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%       
+if length(covariateModelValues) ~= length(covariateModels),
+    error('modeltest.covariateModelValues needs to have same length as modeltest.covariateModels.');
+end
+if length(COVestimate) ~= length(covariateModels),
+    error('modeltest.covariateModelValues needs to have same length as modeltest.covariateModels.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle Monolix/NONMEM default options
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%       
+optionsNLME                                     = options;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Load dataset, and check data format
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%       
+% Load dataset
+analysisDataset         = IQMloadCSVdataset(analysisDatasetFile);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check unsupported administration routes
+% ADM=1 is covering 1st order, 0th order, and mixed absorption for the popPK
+% workflow. 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%       
+ADMunique = unique(analysisDataset.ADM);
+if sum(ADMunique>2)~=0,
+    error('Unknown/unsupported ADM entries in dataset. 0: observation, 1: 0th/1st/mixed order absorption, 2: IV (bolus or infusion).');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check lag time and absorption model settings.
+% If no absorption doses (ADM=1) present in the dataset and lagTime and 
+% absorptionModel variables not on default values, then reset them to 
+% default values. 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%       
+% Check if absorption dose data present (ADM=1)
+FLAG_ABSORPTION_DATA_PRESENT = 1;
+if ~ismember(1,ADMunique),
+    FLAG_ABSORPTION_DATA_PRESENT = 0;
+    if sum(lagTime) ~= 0,
+        warning('Dataset does not contain absorption doses (ADM=1). Estimation of lag time not considered.');
+        lagTime = 0;
+    end
+    if sum(absorptionModel) ~= 0,
+        warning('Dataset does not contain absorption doses (ADM=1). No absorption model considered.');
+        absorptionModel = 1;
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check NONMEM issue 
+% Fiv not possible to estimate with NONMEM since RATE not handled together
+% with bioavailability. In this case MONOLIX needs to be used.
+%
+% Only needs to be checked if IV data present in the dataset.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%       
+
+FLAG_NONMEM__RATE_BIOAVAILABILITY_ISSUE__OK = 1;
+
+if ~isempty(find(analysisDataset.ADM==2)),
+    % IV data present ... need to check
+    
+    % Get index Fiv
+    ix_Fiv = strmatchIQM('Fiv',TemplateModels.ParameterNames.ODE,'exact');
+    
+    % If Fiv initial guess not 1 then NONMEM not ok
+    for k=1:length(POPvalues0),
+        if POPvalues0{k}(ix_Fiv) ~= 1,
+            FLAG_NONMEM__RATE_BIOAVAILABILITY_ISSUE__OK = 0;
+        end
+    end
+    
+    % If Fiv estimated then NONMEM not ok
+    for k=1:length(POPestimate),
+        if POPestimate{k}(ix_Fiv) ~= 0,
+            FLAG_NONMEM__RATE_BIOAVAILABILITY_ISSUE__OK = 0;
+        end
+    end
+    
+    % If FACTOR_UNITS not equal 1 then NONMEM not ok
+    if FACTOR_UNITS~=1,
+        FLAG_NONMEM__RATE_BIOAVAILABILITY_ISSUE__OK = 0;
+    end
+    
+    % Error message if needed
+    if FLAG_NONMEM && ~FLAG_NONMEM__RATE_BIOAVAILABILITY_ISSUE__OK,
+        error(sprintf('NONMEM can not be used with these settings (estimation of Fiv or non-unity initial guess for Fiv).\nNONMEM is unable to combine bioavailability parameter with infusion RATE. Simple fix: For these model\nsettings, please use the more modern software MONOLIX, which can do this correctly without a lot of work-arounds.'));
+    end
+end
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Remove and create the folder in which to create the NLME projets
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+warning off; %#ok<*WNOFF>
+try rmdir(modelProjectsFolder,'s'); catch, end; mkdir(modelProjectsFolder);
+warning on; %#ok<*WNON>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Open model Info Text file for output (create folder if non existent)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+table_MODEL_INFO = {'<TH>' 'Model' 'Nr Compartments' 'Error model' 'Clearance' 'Absorption Model' 'Absorption Lagtime' 'Type' 'POPestimate' 'IIVestimate' 'Covariance Model' 'Covariate Model' 'Initial guesses'};
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Build the defined model space
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+count               = 0;
+MODEL_INFO          = [];
+
+% Cycle through all covariate definitions
+for kcovariates = 1:length(covariateModels),
+    
+    % Cycle through all covariance definitions
+    for kcovariances = 1:length(covarianceModels),
+        
+        % Cycle through all compartment definitions
+        for kcompartments=1:length(numberCompartments),
+            
+            % Cycle through all error model definitions
+            for kerrormodels=1:length(errorModels),
+                errorParam0_k = errorParam0{kerrormodels};
+                
+                % Cycle through all clearance definitions
+                for kclearance=1:length(saturableClearance),
+                    
+                    % Cycle through all absorption models to consider
+                    for kabsorption=1:length(absorptionModel),
+                    
+                        % Cycle through all lagtime definitions
+                        for klagtime=1:length(lagTime),
+                            
+                            % Cycle through POPestimate
+                            for kpopestimate=1:length(POPestimate),
+                                
+                                % Cycle through IIVestimate
+                                for kiivestimate=1:length(IIVestimate),
+                                    
+                                    % Cycle through POPvalues0
+                                    for kpopvalues=1:length(POPvalues0),
+                                        
+                                        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+                                        % Create Project
+                                        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+                                        count                   = count+1;
+                                        % Get model name
+                                        modelName               = [PROJECT_PREFIX preFillCharIQM(count,3,'0')];
+                                        % Get project path
+                                        projectPath             = [modelProjectsFolder '/' modelName];
+                                        % Get data location and header information for monolix
+                                        [p,f,e]                 = fileparts(analysisDatasetFile);
+                                        data                    = [];
+                                        data.path               = p;
+                                        data.dataFileName       = [f e];
+                                        data.header             = dataheaderNLME;
+                                        % Define options
+                                        optionsProject.POPestimate          = POPestimate{kpopestimate};
+                                        optionsProject.POPvalues0           = POPvalues0{kpopvalues};
+                                        optionsProject.IIVdistribution      = {}; % use default => log-normal!
+                                        optionsProject.IIVestimate          = IIVestimate{kiivestimate};
+                                        optionsProject.IIVvalues0           = IIVvalues0;
+                                        optionsProject.errorModels          = errorModels{kerrormodels};
+                                        optionsProject.covarianceModel      = covarianceModels{kcovariances};
+                                        
+                                        optionsProject.covariateModel       = covariateModels{kcovariates};
+                                        optionsProject.covariateModelValues = covariateModelValues{kcovariates};
+                                        optionsProject.COVestimate          = COVestimate{kcovariates};
+                                        optionsProject.COVcentering.covs    = COVcentering.covs;
+                                        optionsProject.COVcentering.values  = COVcentering.values;
+                                        
+                                        optionsProject.covariateModelTV     = covariateModelsTV{1}; % Only one allowed
+                                        
+                                        optionsProject.algorithm             = optionsNLME.algorithm;
+                                        optionsProject.SILENT                = 1;
+                                        
+                                        optionsProject.errorParam0           = errorParam0_k;
+                                        
+                                        % Create the project after specification
+                                        [FLAGanalyticModel,MODEL_SETTINGS] = createPopPK_NLMEproject_ODE_Analytic_IQM(...
+                                            FLAG_NONMEM,FLAG_ABSORPTION_DATA_PRESENT,modelName,TemplateModels, FACTOR_UNITS,...
+                                            numberCompartments(kcompartments),saturableClearance(kclearance), ...
+                                            absorptionModel(kabsorption),lagTime(klagtime),...
+                                            data,projectPath,dataRelPathFromProjectPath,optionsProject, ...
+                                            FLAG_NONMEM__RATE_BIOAVAILABILITY_ISSUE__OK,analysisDataset);
+                                       
+                                        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+                                        % Get table with model information
+                                        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+                                        clearanceText = 'Linear';
+                                        if saturableClearance(kclearance)==1,
+                                            clearanceText = 'Linear+Saturable';
+                                        end
+                                        
+                                        if ~FLAG_ABSORPTION_DATA_PRESENT,
+                                            lagtimeText = '-';
+                                        else
+                                            lagtimeText   = '-';
+                                            if lagTime(klagtime)==1,
+                                                lagtimeText   = 'Yes';
+                                            end
+                                        end
+                                        
+                                        modelTypeText = 'ODE';
+                                        if FLAGanalyticModel,
+                                            modelTypeText = 'Analytic';
+                                        end
+                                        
+                                        if ~FLAG_ABSORPTION_DATA_PRESENT,
+                                            absorptionModelText = '-';
+                                        else
+                                            absorptionModelText = '1st order';
+                                            if absorptionModel(kabsorption) == 0,
+                                                absorptionModelText = '0th order';
+                                            elseif absorptionModel(kabsorption) == 2,
+                                                absorptionModelText = 'Mixed (parallel) 0th/1st order';
+                                            elseif absorptionModel(kabsorption) == 3,
+                                                absorptionModelText = 'Mixed (sequential) 0th/1st order';
+                                            end
+                                        end
+                                        
+                                        table_MODEL_INFO{end+1,1} = '<TR>';
+                                        table_MODEL_INFO{end,2}   = modelName;
+                                        table_MODEL_INFO{end,3}   = numberCompartments(kcompartments);
+                                        table_MODEL_INFO{end,4}   = errorModels{kerrormodels};
+                                        table_MODEL_INFO{end,5}   = clearanceText;
+                                        table_MODEL_INFO{end,6}   = absorptionModelText;
+                                        table_MODEL_INFO{end,7}   = lagtimeText;
+                                        table_MODEL_INFO{end,8}   = modelTypeText;
+                                        table_MODEL_INFO{end,9}   = strtrim(sprintf('%d ',POPestimate{kpopestimate}));
+                                        table_MODEL_INFO{end,10}   = strtrim(sprintf('%d ',IIVestimate{kiivestimate}));
+                                        table_MODEL_INFO{end,11}  = MODEL_SETTINGS.covarianceModel;
+                                        table_MODEL_INFO{end,12}  = MODEL_SETTINGS.covariateModel;
+                                        table_MODEL_INFO{end,13}  = strtrim(sprintf('%d ',POPvalues0{kpopvalues}));
+                                        
+                                    end % popvalues0
+                                end % iivestimate
+                            end % popestimate
+                        end % lagtime
+                    end % absorption
+                end % clearance
+            end % error models
+        end % compartments
+    end % covariances
+end % covariates
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/auxiliary/createPopPK_MONOLIXprojectIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/auxiliary/createPopPK_MONOLIXprojectIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..d3dd1ab66bbcf9aed07641fde922467113a4247e
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/auxiliary/createPopPK_MONOLIXprojectIQM.m	
@@ -0,0 +1,860 @@
+function createPopPK_MONOLIXprojectIQM(modelNameFIT,modelName,modelFile,parameterNames,FACTOR_UNITS,data,projectPath,options)
+
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Define Default Properties (Never changing)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+projectName            = 'project';
+resultsFolder          = 'RESULTS';
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check input
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try
+    dataRelPathFromProject = data.dataRelPathFromProject;
+    dataFileName           = data.dataFileName;
+    dataHeaderIdent        = data.dataHeaderIdent;
+    
+    % Removal of TIMEPOS in dataHeaderIdent
+    % TIMEPOS only needed for NONMEM ...
+    dataHeaderIdent         = strrep(dataHeaderIdent,',TIMEPOS,',',IGNORE,');    
+catch
+    error('data input argument not defined correctly.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle optional arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try POPestimate                     = options.POPestimate;              catch, POPestimate = [];                             end
+try POPvalues0                      = options.POPvalues0;               catch, POPvalues0 = [];                              end
+try IIVdistribution                 = options.IIVdistribution;          catch, IIVdistribution = {};                         end
+try IIVestimate                     = options.IIVestimate;              catch, IIVestimate = [];                             end
+try IIVvalues0                      = options.IIVvalues0;               catch, IIVvalues0 = [];                              end
+try errorModels                     = options.errorModels;              catch, errorModels = '';                             end
+try errorParam0                     = options.errorParam0;              catch, errorParam0 = [];                             end
+try covarianceModel                 = options.covarianceModel;          catch, covarianceModel = 'diagonal';                 end
+try covariateModel                  = options.covariateModel;           catch, covariateModel = '';                          end
+try covariateModelValues            = options.covariateModelValues;     catch, covariateModelValues = {};                    end
+try COVestimate                     = options.COVestimate;              catch, COVestimate = {};                             end
+
+try COVcentering_covs               = options.COVcentering.covs;        catch, COVcentering_covs = {};                       end
+try COVcentering_values             = options.COVcentering.values;      catch, COVcentering_values = [];                     end
+
+try SEED                            = options.algorithm.SEED;           catch, SEED = 123456;                                end
+try K1                              = options.algorithm.K1;             catch, K1 = 500;                                     end
+try K2                              = options.algorithm.K2;             catch, K2 = 200;                                     end
+try K1_AUTO                         = options.algorithm.K1_AUTO;        catch, K1_AUTO = 0;                                  end
+try K2_AUTO                         = options.algorithm.K2_AUTO;        catch, K2_AUTO = 0;                                  end
+try NRCHAINS                        = options.algorithm.NRCHAINS;       catch, NRCHAINS = 1;                                 end
+try SILENT                          = options.SILENT;                   catch, SILENT = 0;                                   end
+try INDIVparametersetting           = options.algorithm.INDIVparametersetting;    catch, INDIVparametersetting = 'conditionalMode';    end
+try LLsetting                       = options.algorithm.LLsetting;      catch, LLsetting = 'linearization';                  end
+try FIMsetting                      = options.algorithm.FIMsetting;     catch, FIMsetting = 'linearization';                 end
+
+try keepProjectFolder               = options.keepProjectFolder;                catch, keepProjectFolder = 0;                        end   
+
+if ~iscell(COVcentering_covs),
+    COVcentering_covs = {COVcentering_covs};
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Convert covariate model into different syntax
+% '{CL,BMI0}, {Fsubcut,WT0}, {Vc,SEX,BMI0}'
+% to
+% {{'CL','BMI0'}, {'Fsubcut','WT0'}, {'Vc','SEX','BMI0'}}
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(covariateModel),
+    terms = explodePCIQM(covariateModel,',','{','}');
+    y = {};
+    for k=1:length(terms),
+        x = strrep(strtrim(terms{k}),' ','');
+        x = strrep(x,'{','{''');
+        x = strrep(x,'}','''}');
+        x = strrep(x,',',''',''');
+        y{k} = eval(x);
+    end
+    covariateModel = y;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check covariateModelValues
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(covariateModel) && ~isempty(covariateModelValues),
+    error('If you define covariateModelValues, you also need to define the covariateModel.');
+end
+
+if isempty(covariateModelValues),
+    % Determine default covariateModelValues
+    covariateModelValues = {};
+    for k=1:length(covariateModel),
+        covariateModelValues{k} = zeros(1,length(covariateModel{k})-1);
+    end
+else
+    % Check correct length of covariateModelValues elements
+    if length(covariateModel) ~= length(covariateModelValues),
+        error('Number of elements in covariateModel and covariateModelValues needs to match.');
+    end
+    for k=1:length(covariateModel),
+        if length(covariateModel{k})-1 ~= length(covariateModelValues{k}),
+            error('Length of single elements in covariateModel and covariateModelValues needs to match (covariateModelValues elements being one shorter).');
+        end            
+    end    
+end
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check COVestimate
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(covariateModel) && ~isempty(COVestimate),
+    error('If you define COVestimate, you also need to define the covariateModel.');
+end
+
+if isempty(COVestimate),
+    % Determine default COVestimate - all are estimates
+    COVestimate = {};
+    for k=1:length(covariateModel),
+        COVestimate{k} = ones(1,length(covariateModel{k})-1);
+    end
+else
+    % Check correct length of COVestimate elements
+    if length(covariateModel) ~= length(COVestimate),
+        error('Number of elements in covariateModel and COVestimate needs to match.');
+    end
+    for k=1:length(covariateModel),
+        if length(covariateModel{k})-1 ~= length(COVestimate{k}),
+            error('Length of single elements in covariateModel and COVestimate needs to match (COVestimate elements being one shorter).');
+        end            
+    end    
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Create and change into project path
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+warning off
+oldpath = pwd;
+if ~keepProjectFolder,
+    try, rmdir(projectPath,'s'); catch, end
+end
+mkdir(projectPath); cd(projectPath)
+mkdir(resultsFolder);
+warning on
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check if datafile exists and csv file and load some information
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+dataFile = [dataRelPathFromProject '/' dataFileName];
+try
+    dataheader = IQMloadCSVdataset(dataFile,1);
+catch
+    cd(oldpath);
+    error('Please check if the data file "%s" exists.',dataFile)
+end
+% Check if length of header identical to dataHeaderIdent
+if length(explodePCIQM(dataHeaderIdent,',')) ~= length(dataheader),
+    cd(oldpath);
+    error('Please check: The data header identifiers do not have the same length as the number of columns in the dataset.')
+end
+% Determine continuous and categorical covariates
+IDs = explodePCIQM(dataHeaderIdent,',');
+covIDs = strmatchIQM('COV',upper(IDs));
+covNames = dataheader(covIDs);
+catIDs = strmatchIQM('CAT',upper(IDs));
+catNames = dataheader(catIDs);
+% No regression parameters to be expected!
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Loading dataset and determining medians for covariates
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Load dataset
+dataCSV = IQMloadCSVdataset(fullfile(dataRelPathFromProject,dataFileName));
+dataheader = dataCSV.Properties.VariableNames;
+% Determine index of COV columns and their names
+terms = explodePCIQM(dataHeaderIdent);
+ixCOVs = strmatchIQM('COV',terms,'exact');
+if ~isempty(ixCOVs),
+    dataheaderCOVs = dataheader(ixCOVs);
+    % Determine index of ID column and ID name
+    terms = explodePCIQM(dataHeaderIdent);
+    ixID = strmatchIQM('ID',terms,'exact');
+    dataheaderID = dataheader(ixID);
+    % Determine median values across ID column
+    allID = eval(sprintf('unique(dataCSV.%s);',dataheaderID{1}));
+    allCOVs = NaN(length(allID),length(ixCOVs));
+    for k=1:length(allID),
+        datak = eval(sprintf('dataCSV(dataCSV.%s==allID(k),ixCOVs);',dataheaderID{1}));
+        allCOVs(k,:) = table2array(datak(1,:));
+    end
+    covariateMedianValues = median(allCOVs);
+    covariateMedianNames = dataheaderCOVs;
+    
+    % Handle custom centering values
+    for k=1:length(COVcentering_covs),
+        ix = strmatchIQM(COVcentering_covs{k},covariateMedianNames,'exact');
+        covariateMedianValues(ix) = COVcentering_values(k);
+    end
+    
+    if ~SILENT, 
+        disp(' ')
+        disp('==================================================================');
+        disp('Analysis of dataset for covariates - determine the median values  ')
+        disp(' Results:');
+        for k=1:length(covariateMedianValues),
+            disp(sprintf('   median(%s) = %g',covariateMedianNames{k},covariateMedianValues(k)));
+        end
+        disp('These values will be used to center the continuous covariates')
+        disp('==================================================================');
+        disp(' ')
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check POPestimate thing
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(POPestimate),
+    POPestimate = ones(1,length(parameterNames));
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check POPvalues0 thing
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(POPvalues0),
+    POPvalues0 = ones(1,length(parameterNames));
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check IIV distribution things
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(IIVdistribution),
+    IIVdistribution = {};
+    for k=1:length(parameterNames),
+        IIVdistribution{k} = 'L';
+    end
+end
+
+% Check contents
+test = IIVdistribution;
+for k=1:length(IIVdistribution),
+    if ~ismember(test{k},{'L','N','G'}),
+        cd(oldpath);
+        error('Please make sure that only "N", "L", or "G" appear in the "IIVdistribution" variable.');
+    end
+end
+
+% Check length
+if length(IIVdistribution) ~= length(parameterNames),
+    cd(oldpath);
+    error('Please make sure that an equal number of IIVdistribution is defined as estimated parameters in the model.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check IIV estimation things
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(IIVestimate),
+    IIVestimate = ones(1,length(parameterNames));
+end
+% Check length
+if length(IIVestimate) ~= length(parameterNames),
+    cd(oldpath);
+    error('Please make sure that an equal number of IIVestimate is defined as estimated parameters in the model.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check IIVvalues0 thing
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(IIVvalues0),
+    IIVvalues0 = ones(1,length(parameterNames));
+end
+if length(parameterNames) ~= length(IIVvalues0),
+    cd(oldpath);
+    error('Please make sure IIVvalues0 is of same length as number of parameters to be estimated.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check residual error things
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(errorModels),
+    errorModels = 'comb1';
+end
+test = errorModels;
+test = strtrim(strrep(strrep(strrep(strrep(strrep(strrep(strrep(test,'const',''),'prop',''),'comb1',''),'exp',''),'band(0,100)',''),'logit',''),',',''));
+if ~isempty(test),
+    cd(oldpath);
+    error('Please make sure that only "const", "prop", "comb1", or "exp" appear in the "errorModels" variable.');
+end
+% Check length
+errors = explodePCIQM(errorModels,',');
+if length(errors) ~= 1,
+    cd(oldpath);
+    error('Please make sure that only one residual error model is defined.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle empty errorParam0
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(errorParam0),
+    terms = explodePCIQM(errorModels);
+    for k=1:length(terms),
+        if strcmp(lower(terms{k}),'const'),
+            errorParam0(end+1) = 1;
+        elseif strcmp(lower(terms{k}),'prop'),
+            errorParam0(end+1) = 0.3;
+        elseif strcmp(lower(terms{k}),'comb1'),
+            errorParam0(end+1) = 1;
+            errorParam0(end+1) = 0.3;          
+        elseif strcmp(lower(terms{k}),'exp'),
+            errorParam0(end+1) = 1;
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check errorParam0
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+terms = explodePCIQM(errorModels);
+nrneededelements = 0;
+for k=1:length(terms),
+    if strcmpi(terms{k},'const'),
+        nrneededelements = nrneededelements+1;
+    elseif strcmpi(terms{k},'prop'),
+        nrneededelements = nrneededelements+1;
+    elseif strcmpi(terms{k},'comb1'),
+        nrneededelements = nrneededelements+2;
+    elseif strcmpi(terms{k},'exp'),
+        nrneededelements = nrneededelements+1;
+    end
+end
+if length(errorParam0) ~= nrneededelements,
+    error('Incorrect number of elements in options.errorParam0.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check covariance model
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(covarianceModel),
+    covarianceModel = 'diagonal';
+elseif ~strcmp(covarianceModel,'diagonal'),
+    % Need to check that none of the parameters for which no IIV is estimated is used in the covarianceModel
+    param_est_noIIV = parameterNames(find(~IIVestimate));
+    for k=1:length(param_est_noIIV),
+        if ~isempty(regexp(covarianceModel,['\<' param_est_noIIV{k} '\>'])),
+            cd(oldpath);
+            error('Please make sure none of the parameters for which no IIV is estimated is used in the covarianceModel settings.');
+        end
+    end
+    % Check that all parameters in the covariance model actually are model parameters
+    param = {parameterNames};
+    test  = covarianceModel;
+    for k=1:length(param),
+        test = regexprep(test,['\<' param{k} '\>'],'');
+    end
+    test = strrep(test,'{','');
+    test = strrep(test,'}','');
+    test = strrep(test,',','');
+    if ~isempty(test),
+        cd(oldpath);
+        error('Please make sure that covarianceModel only contains parameter names in the model.');
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check LL setting
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(LLsetting),
+    LLsetting = 'both';
+end
+if isempty(strmatchIQM(LLsetting,{'linearization','importantSampling','both'})),
+    cd(oldpath);
+    error('Please make sure LLsetting has one of the following values: "linearization", "importantSampling", "both"=""');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check covariate model things
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% First check that all first elements are estimated parameters of the model
+for k=1:length(covariateModel),
+    param = covariateModel{k}{1};
+    if isempty(strmatchIQM(param,parameterNames,'exact')),
+        cd(oldpath);
+        error('Please make sure that all parameters for which covariates are defined are defined in the model.');
+    end
+end
+% Second check that all defined covariates actually are covariates
+covcatNames = [covNames catNames];
+for k=1:length(covariateModel),
+    for k2=2:length(covariateModel{k}),
+        cov = covariateModel{k}{k2};
+        if isempty(strmatchIQM(cov,covcatNames,'exact')),
+            cd(oldpath);
+            error('Please make sure that all covariates, defined in covariateModel, are defined in the dataset.');
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% OPEN File
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fid = fopen([projectName '.mlxtran'],'w');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INFO
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; MLXTRAN PROJECT, created using IQM Tools\r\n');
+fprintf(fid,'; Date: %s\r\n',datestr(now,'yyyy-mmm-DD HH:MM'));
+fprintf(fid,'; By:   %s\r\n',usernameIQM());
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Placeholder for project information
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; ==PROJECT HEADER START===================================================\r\n');
+fprintf(fid,'PROJECT_HEADER_PLACEHOLDER\r\n');
+fprintf(fid,'; ==PROJECT HEADER END=====================================================\r\n');
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DESCRIPTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; =============================================\r\n');
+fprintf(fid,'DESCRIPTION:\r\n');
+fprintf(fid,'; =============================================\r\n');
+fprintf(fid,'\t%s\r\n',modelNameFIT);
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DATA
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; =============================================\r\n');
+fprintf(fid,'DATA:\r\n');
+fprintf(fid,'; =============================================\r\n');
+fprintf(fid,'\tpath = "%%MLXPROJECT%%/%s/",\r\n',dataRelPathFromProject);
+fprintf(fid,'\tfile  ="%s",\r\n',dataFileName);
+fprintf(fid,'\theaders = {%s},\r\n',dataHeaderIdent);
+fprintf(fid,'\tcolumnDelimiter = ","\r\n');
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% VARIABLES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; =============================================\r\n');
+fprintf(fid,'VARIABLES:\r\n');
+fprintf(fid,'; =============================================\r\n');
+% Assume all covariates defined in dataset are used ...
+% Continuous are always log transformed and centered by median
+% Categorical are always kept as they are
+text = '';
+% Write out continuous first
+for k=1:length(covNames),
+    text = sprintf('%s\t%s,\r\n',text,covNames{k});
+    covname = covNames{k};
+    % Scale covariate by median value from dataset
+    ixmedian = strmatchIQM(covname,covariateMedianNames,'exact');
+    covname_weighted = sprintf('%s/%g',covname,covariateMedianValues(ixmedian));
+    text = sprintf('%s\tt_%s = log(%s) [use=cov],\r\n',text,covname,covname_weighted);
+end
+% Write out categorical
+for k=1:length(catNames),
+    text = sprintf('%s\t%s [use=cov, type=cat],\r\n',text,catNames{k});
+end
+% Remove last comma and write text to file
+fprintf(fid,text(1:end-3));
+fprintf(fid,'\r\n');
+fprintf(fid,'\r\n');
+
+% Create BETACOVNAMES and BETACOVTRANS information for header
+BETACOVNAMES = {};
+BETACOVTRANS = {};
+for k=1:length(covariateModel),
+    for k2=2:length(covariateModel{k}),
+        if ~isempty(strmatchIQM(covariateModel{k}{k2},covNames,'exact')),
+            BETACOVNAMES{end+1} = sprintf('beta_%s(%s)',covariateModel{k}{1},covariateModel{k}{k2});
+            ixmedian = strmatchIQM(covariateModel{k}{k2},covariateMedianNames,'exact');
+            BETACOVTRANS{end+1} = sprintf('log(cov/%g)',covariateMedianValues(ixmedian));
+        end
+    end
+end
+
+% Create BETACATNAMES and BETACATREFERENCE information for header
+BETACATNAMES        = {};
+BETACATREFERENCE    = [];
+for k=1:length(covariateModel),
+    for k2=2:length(covariateModel{k}),
+        if ~isempty(strmatchIQM(covariateModel{k}{k2},catNames,'exact')),
+            BETACATNAMES{end+1} = sprintf('beta_%s(%s)',covariateModel{k}{1},covariateModel{k}{k2});
+            BETACATREFERENCE(end+1) = min(unique(dataCSV.(covariateModel{k}{k2})));
+        end
+    end
+end
+
+% Determine all categories for categorical covariates and store them as
+% metadata in the header of the project.mlxtran file
+CAT_CATEGORIES = {};
+for k=1:length(catNames),
+    x = unique(dataCSV.(catNames{k}));
+    x = sprintf('%g,',x);
+    x = ['[' x(1:end-1) ']'];
+    CAT_CATEGORIES{k} = x;
+end
+CAT_CATEGORIES = sprintf('%s,',CAT_CATEGORIES{:});
+CAT_CATEGORIES = [CAT_CATEGORIES(1:end-1)];
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INDIVIDUAL
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; =============================================\r\n');
+fprintf(fid,'INDIVIDUAL:\r\n');
+fprintf(fid,'; =============================================\r\n');
+% Write out parameters to estimate. Assume iiv=yes on all of them by default. 
+% If no IIV desired then rather fix omega to 0.01.
+text = '';
+PARAM_TRANSNAME_STRING = {};
+PARAM_INVTRANSNAME_STRING = {};
+
+for k=1:length(parameterNames),
+    if IIVdistribution{k} == 'L', 
+        dtext = 'logNormal'; 
+        PARAM_INVTRANSNAME_STRING{k} = 'log(psi)';
+        PARAM_TRANSNAME_STRING{k} = 'exp(phi)';        
+    end
+    if IIVdistribution{k} == 'N', 
+        dtext = 'Normal';
+        PARAM_INVTRANSNAME_STRING{k} = '(psi)';
+        PARAM_TRANSNAME_STRING{k} = '(phi)';
+    end
+    if IIVdistribution{k} == 'G', 
+        dtext = 'logitNormal'; 
+        PARAM_INVTRANSNAME_STRING{k} = 'log(psi./(1-psi))';
+        PARAM_TRANSNAME_STRING{k} = 'exp(phi)./(1+exp(phi))';        
+    end
+    % check if IIV (not if both random effect and population value not estimated)
+    if IIVestimate(k) == 0,
+        iiv='no';
+    else
+        iiv='yes';
+    end
+    % check for covariates to use
+    param = parameterNames{k};
+    covs = {};
+    for k2=1:length(covariateModel),
+        if strcmp(param,covariateModel{k2}{1}),
+            covs = covariateModel{k2}(2:end);
+        end
+    end
+    % Attach "t_" to continuous covariate names, keep categorical covariate names same
+    for k2=1:length(covs),
+        if ~isempty(strmatchIQM(covs{k2},covNames,'exact')),
+            covs{k2} = ['t_' covs{k2}];
+        end
+    end
+    % Write it out
+    if isempty(covs),
+        text = sprintf('%s\t%s = {distribution=%s, iiv=%s},\r\n',text,param,dtext,iiv);
+    else
+        % Create cov text
+        covText = '';
+        for k2=1:length(covs),
+            covText = sprintf('%s%s,',covText,covs{k2});
+        end
+        covText = covText(1:end-1);
+        text = sprintf('%s\t%s = {distribution=%s, covariate={%s}, iiv=%s},\r\n',text,param,dtext,covText,iiv);
+    end        
+end
+% Remove last comma and write text to file
+fprintf(fid,text(1:end-3));
+fprintf(fid,'\r\n');
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CORRELATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~strcmp(covarianceModel,'diagonal'),
+    fprintf(fid,'; =============================================\r\n');
+    fprintf(fid,'CORRELATION:\r\n');
+    fprintf(fid,'; =============================================\r\n');
+    fprintf(fid,'\tcorrelationIIV = {%s}\r\n',covarianceModel);
+    fprintf(fid,'\r\n');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% STRUCTURAL_MODEL
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% copy model to project folder
+copyfile(modelFile,'.');
+% add FACTOR_UNITS
+contents = fileread(modelName);
+contents = strrep(contents,'FACTOR_UNITS = 1',sprintf('FACTOR_UNITS = %g',FACTOR_UNITS));
+fid2 = fopen(modelName,'w');
+fprintf(fid2,'%s',contents);
+fclose(fid2);
+fprintf(fid,'; =============================================\r\n');
+fprintf(fid,'STRUCTURAL_MODEL:\r\n');
+fprintf(fid,'; =============================================\r\n');
+fprintf(fid,'\tfile = "%s",\r\n',modelName);
+fprintf(fid,'\tpath = "%%MLXPROJECT%%/",\r\n');
+fprintf(fid,'\toutput = {Cc}');
+fprintf(fid,'\r\n');
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% OBSERVATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; =============================================\r\n');
+fprintf(fid,'OBSERVATIONS:\r\n');
+fprintf(fid,'; =============================================\r\n');
+% Only consider "continuous" observations with IQM Tools conversion 
+errors = explodePCIQM(errorModels,',');
+text = '';
+for k=1:length(errors),
+    if strcmp(errors{k},'const'), errorModel = 'constant'; end
+    if strcmp(errors{k},'prop'), errorModel = 'proportional'; end
+    if strcmp(errors{k},'comb1'), errorModel = 'combined1'; end
+    if strcmp(errors{k},'exp'), errorModel = 'exponential'; end
+    if strcmp(errors{k},'logit'), errorModel = 'logit'; end
+    if strcmp(errors{k},'band(0,100)'), errorModel = 'band(0,100)'; end
+    text = sprintf('%s\ty%d = {type=continuous, prediction=Cc, error=%s},\r\n',text,k,errorModel);
+end
+% Remove last comma and write text to file
+fprintf(fid,text(1:end-3));
+fprintf(fid,'\r\n');
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% TASKS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; =============================================\r\n');
+fprintf(fid,'TASKS:\r\n');
+fprintf(fid,'; =============================================\r\n');
+fprintf(fid,'\t; settings\r\n');
+fprintf(fid,'\tglobalSettings={\r\n');
+fprintf(fid,'\t\twithVariance=no,\r\n'); % Always estimate standard deviations of IIVs
+fprintf(fid,'\t\tsettingsGraphics="%%MLXPROJECT%%/project_graphics.xmlx",\r\n');
+fprintf(fid,'\t\tsettingsAlgorithms="%%MLXPROJECT%%/project_algorithms.xmlx",\r\n');
+fprintf(fid,'\t\tresultFolder="%%MLXPROJECT%%/%s"},\r\n',resultsFolder);
+fprintf(fid,'\t; workflow\r\n');
+fprintf(fid,'\testimatePopulationParameters(\r\n');
+fprintf(fid,'\t\tinitialValues={\r\n');
+% write out population parameter initial values
+for k=1:length(POPestimate),
+    method = '';
+    if POPestimate(k) == 0,
+        method = '[method=FIXED]';
+    end
+    fprintf(fid,'\t\t\tpop_{%s} = %g %s,\r\n',parameterNames{k},POPvalues0(k),method);
+end
+
+% write out covariate coefficient initial guesses
+for k1=1:length(covariateModel),
+    for k2=2:length(covariateModel{k1}),
+        covarvalue = covariateModelValues{k1}(k2-1);
+        if COVestimate{k1}(k2-1),
+            method = '';
+        else
+            method = '[method=FIXED]';
+        end
+        ix = strmatchIQM(covariateModel{k1}{k2},covNames,'exact');
+        if isempty(ix),
+            fprintf(fid,'\t\t\tbeta_{%s,%s} = %g %s,\r\n',covariateModel{k1}{1},covariateModel{k1}{k2},covarvalue,method);
+        else
+            fprintf(fid,'\t\t\tbeta_{%s,t_%s} = %g %s,\r\n',covariateModel{k1}{1},covariateModel{k1}{k2},covarvalue,method);
+        end
+    end
+end
+
+% write out residual error model
+errors = explodePCIQM(errorModels,',');
+count = 1;
+for k=1:length(errors),
+    if strcmp(errors{k},'const'), 
+        fprintf(fid,'\t\t\ta_y%d = %g,\r\n',k,errorParam0(count));
+        count = count + 1;
+    end
+    if strcmp(errors{k},'prop'), 
+        fprintf(fid,'\t\t\tb_y%d = %g,\r\n',k,errorParam0(count));
+        count = count + 1;
+    end
+    if strcmp(errors{k},'comb1'), 
+        fprintf(fid,'\t\t\ta_y%d = %g,\r\n',k,errorParam0(count));
+        count = count + 1;
+        fprintf(fid,'\t\t\tb_y%d = %g,\r\n',k,errorParam0(count));
+        count = count + 1;
+    end
+    if strcmp(errors{k},'exp'), 
+        fprintf(fid,'\t\t\ta_y%d = %g,\r\n',k,errorParam0(count));
+        count = count + 1;
+    end
+end
+
+% write out population parameter initial values
+text = '';
+for k=1:length(parameterNames),
+    if IIVestimate(k)==1,
+        value0 = IIVvalues0(k);
+        text = sprintf('%s\t\t\tomega_{%s} = %g,\r\n',text,parameterNames{k},value0);
+    elseif IIVestimate(k)==2,
+        value0 = IIVvalues0(k);
+        text = sprintf('%s\t\t\tomega_{%s} = %g [method=FIXED],\r\n',text,parameterNames{k},value0);
+    end
+end
+fprintf(fid,text(1:end-3));
+fprintf(fid,'\r\n');
+
+fprintf(fid,'\t\t} ),\r\n');
+if strcmp(FIMsetting,'linearization'),
+    fprintf(fid,'\testimateFisherInformationMatrix( method={linearization} ),\r\n');
+else
+    fprintf(fid,'\testimateFisherInformationMatrix( method={stochasticApproximation} ),\r\n');
+end
+fprintf(fid,'\testimateIndividualParameters( method={%s} ),\r\n',INDIVparametersetting);
+if strcmp(LLsetting,'linearization'),
+    fprintf(fid,'\testimateLogLikelihood(method={linearization}),\r\n');
+elseif strcmp(LLsetting,'importantSampling'),
+    fprintf(fid,'\testimateLogLikelihood(method={importantSampling}),\r\n');
+elseif strcmp(LLsetting,'both'),
+    fprintf(fid,'\testimateLogLikelihood(method={importantSampling,linearization}),\r\n');
+end
+fprintf(fid,'\tdisplayGraphics()');
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CLOSE File
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fclose(fid);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Create Project Header with Metadata
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+PROJECT_INFO_TEXT = '';
+
+% Data location
+DATA_info = sprintf('; DATA                = ''%s''\r\n',strrep(fullfile(dataRelPathFromProject,dataFileName),'\','/'));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,DATA_info);
+
+% DOSINGTYPES
+DOSINGTYPES = {'BOLUS' 'INFUSION' 'ABSORPTION0'};
+x = sprintf('%s,',DOSINGTYPES{:});
+DOSINGTYPES_info = sprintf('; DOSINGTYPES         = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,DOSINGTYPES_info);
+
+% covNames
+x = sprintf('%s,',covNames{:});
+COVNAMES_info = sprintf('; COVNAMES            = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,COVNAMES_info);
+
+% catNames
+x = sprintf('%s,',catNames{:});
+CATNAMES_info = sprintf('; CATNAMES            = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,CATNAMES_info);
+
+% CATCATEGORIES
+CATCATEGORIES_info = sprintf('; CATCATEGORIES       = ''%s''\r\n',CAT_CATEGORIES);
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,CATCATEGORIES_info);
+
+% Regression parameters
+REGRESSNAMES_info = sprintf('; REGRESSIONNAMES     = ''''\r\n');
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,REGRESSNAMES_info);
+
+% Outputs
+OUTPUTS_info = sprintf('; OUTPUTS             = ''Cc''\r\n');
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,OUTPUTS_info);
+
+% Error models
+ERRORMODELS_info = sprintf('; ERRORMODELS         = ''%s''\r\n',errorModels);
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,ERRORMODELS_info);
+
+% PARAMNAMES
+x = sprintf('%s,',parameterNames{:});
+PARAMNAMES_info = sprintf('; PARAMNAMES          = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,PARAMNAMES_info);
+
+% PARAMTRANS
+x = sprintf('%s,',PARAM_TRANSNAME_STRING{:});
+PARAMTRANS_info = sprintf('; PARAMTRANS          = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,PARAMTRANS_info);
+
+% PARAMINVTRANS
+x = sprintf('%s,',PARAM_INVTRANSNAME_STRING{:});
+PARAMINVTRANS_info = sprintf('; PARAMINVTRANS       = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,PARAMINVTRANS_info);
+
+% COVARIATENAMES
+COVARIATENAMES = [covNames,catNames];
+x = sprintf('%s,',COVARIATENAMES{:});
+COVARIATENAMES_info = sprintf('; COVARIATENAMES      = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,COVARIATENAMES_info);
+
+% COVARIATESUSED
+COVARIATESUSED = setdiff(explodePCIQM(strrep(strrep(options.covariateModel,'{',''),'}','')),parameterNames);
+x = sprintf('%s,',COVARIATESUSED{:});
+COVARIATESUSED_info = sprintf('; COVARIATESUSED      = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,COVARIATESUSED_info);
+
+% BETACOVNAMES
+x = sprintf('%s,',BETACOVNAMES{:});
+BETACOVNAMES_info = sprintf('; BETACOVNAMES        = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,BETACOVNAMES_info);
+
+% BETACOVTRANS
+x = sprintf('%s,',BETACOVTRANS{:});
+BETACOVTRANS_info = sprintf('; BETACOVTRANS        = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,BETACOVTRANS_info);
+
+% BETACATNAMES
+x = sprintf('%s,',BETACATNAMES{:});
+BETACATNAMES_info = sprintf('; BETACATNAMES        = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,BETACATNAMES_info);
+
+% BETACATREFERENCE
+x = ''; for k=1:length(BETACATREFERENCE), x=sprintf('%s%g,',x,BETACATREFERENCE(k)); end
+BETACATREFERENCE_info = sprintf('; BETACATREFERENCE    = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,BETACATREFERENCE_info);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Replace PROJECT_HEADER_PLACEHOLDER
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+content = fileread('project.mlxtran');
+content = strrep(content,'PROJECT_HEADER_PLACEHOLDER',strtrim(PROJECT_INFO_TEXT));
+fid = fopen('project.mlxtran','w');
+fprintf(fid,'%s',content);
+fclose(fid);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Do generate the default graphics settings so that 
+% predictions.txt file is generated and included NPDE and meanPWRES
+% Trick is to load project file and to add things and then to save the file
+% again.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+copyfile(which('template_project_graphics.xmlx'),'project_graphics.xmlx')
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Generate project_algorithms.xmlx file
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% only writing out K1, K2, Number of Chains, Seed, and auto settings for K1,K2,Number of chains
+fid = fopen('project_algorithms.xmlx','w');
+fprintf(fid,'<monolix>\n');
+fprintf(fid,'	<algorithms seed="%d">\n',SEED);
+fprintf(fid,'		<populationParameters>\n');
+fprintf(fid,'			<vna value="%d,%d"/>\n',K1,K2);
+fprintf(fid,'			<iop_Kauto value="%d,%d"/>\n',K1_AUTO,K2_AUTO);
+fprintf(fid,'			<nmc value="%d"/>\n',NRCHAINS);
+fprintf(fid,'		</populationParameters>\n');
+fprintf(fid,'	</algorithms>\n');
+fprintf(fid,'</monolix>\n');
+fclose(fid);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Change out of project path
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+cd(oldpath);
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/auxiliary/createPopPK_NLMEproject_ODE_Analytic_IQM.m b/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/auxiliary/createPopPK_NLMEproject_ODE_Analytic_IQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..e32532cf5345cca9aaec061a7865dfa89c3d27fa
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/auxiliary/createPopPK_NLMEproject_ODE_Analytic_IQM.m	
@@ -0,0 +1,490 @@
+function [FLAGanalyticModel,MODEL_SETTINGS] = createPopPK_NLMEproject_ODE_Analytic_IQM( ...
+                                FLAG_NONMEM,FLAG_ABSORPTION_DATA_PRESENT,modelNameFIT,TemplateModels, ... 
+                                FACTOR_UNITS, numberCompartments,saturableClearance, ...
+                                absorptionModel,lagTime,data,projectPath,dataRelPathFromProjectPath,optionsProject,FLAG_NONMEM__RATE_BIOAVAILABILITY_ISSUE__OK,analysisDataset)
+                           
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Define Data Information for NLME Project Creation
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Define data information
+data_NLME                            = [];
+data_NLME.dataRelPathFromProject     = dataRelPathFromProjectPath;
+data_NLME.dataFileName               = data.dataFileName;
+data_NLME.dataHeaderIdent            = data.header;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Define Options Information for Monolix Project Creation
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Define the options_MLX structure and handle default cases
+options_NLME                         = optionsProject;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Define vector for parameters that are switched to 0 ...
+% To then afterwards set the IIVdistribution for them to "N"
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+VECTOR_SWITCH_PARAM_0 = zeros(1,length(options_NLME.POPvalues0));
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle compartment number settings wrt to impact on 
+% estimated fixed and random effects and initial guesses
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if numberCompartments == 1,
+    % Do not estimate Q1,Vp1,Q2,Vp2 and set the Q12 values to 1e-10 etc.
+    % 'CL', 'Vc', 'Q1', 'Vp1', 'Q2', 'Vp2', 'Fiv', 'Fabs1', 'ka', 'Tlaginput1', 'Fabs0', 'Tk0input3', 'Tlaginput3', 'Frel0', 'VMAX', 'KM'
+    options_NLME.POPestimate(3:6)    = 0;
+    options_NLME.POPvalues0([3 5])   = 0;        % Setting Q1/2 to 0
+    VECTOR_SWITCH_PARAM_0([3 5])     = 1;        % Remember to set Q1 and Q2 to 'N' 
+    options_NLME.POPvalues0([4 6])   = 1;        % Setting Vp1/2 to 1
+    options_NLME.IIVestimate(3:6)    = 0;
+elseif numberCompartments == 2,
+    % Do not estimate Q2,Vp2 and set the Q2 value to 1e-10 and Vp2 to 1
+    % 'CL', 'Vc', 'Q1', 'Vp1', 'Q2', 'Vp2', 'Fiv', 'Fabs1', 'ka', 'Tlaginput1', 'Fabs0', 'Tk0input3', 'Tlaginput3', 'Frel0', 'VMAX', 'KM'
+    options_NLME.POPestimate(5:6)    = 0;
+    options_NLME.POPvalues0(5)       = 0;        % Setting Q2 to 0
+    VECTOR_SWITCH_PARAM_0([5])       = 1;        % Remember to set Q2 to 'N' 
+    options_NLME.POPvalues0(6)       = 1;        % Setting Vp2 to 1
+    options_NLME.IIVestimate(5:6)    = 0;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle clearance settings wrt to impact on 
+% estimated fixed and random effects and initial guesses
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if saturableClearance==0,
+    % Linear clearance only
+    % Do not estimate VMAX and KM and set VMAX to 1e-10 and KM to 1
+    % 'CL', 'Vc', 'Q1', 'Vp1', 'Q2', 'Vp2', 'Fiv', 'Fabs1', 'ka', 'Tlaginput1', 'Fabs0', 'Tk0input3', 'Tlaginput3', 'Frel0', 'VMAX', 'KM'
+    options_NLME.POPestimate(15:16)  = 0;
+    options_NLME.POPvalues0(15)      = 0;        % Setting VMAX to 0
+    VECTOR_SWITCH_PARAM_0([15])      = 1;        % Remember to set VMAX to 'N' 
+    options_NLME.POPvalues0(16)      = 1;        % Setting KM to 1
+    options_NLME.IIVestimate(15:16)  = 0;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle lagtime settings wrt to impact on 
+% estimated fixed and random effects and initial guesses
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if lagTime==0,
+    % No lagTime
+    % Do not estimate TlagAbs1 and TlagAbs0 and set both to 1e-10
+    % 'CL', 'Vc', 'Q1', 'Vp1', 'Q2', 'Vp2', 'Fiv', 'Fabs1', 'ka', 'Tlaginput1', 'Fabs0', 'Tk0input3', 'Tlaginput3', 'Frel0', 'VMAX', 'KM'
+    options_NLME.POPestimate([10 13])     = 0;
+    options_NLME.POPvalues0([10 13])      = 0;        % Setting Tlaginput1+3 to 0
+    VECTOR_SWITCH_PARAM_0([10 13])        = 1;        % Remember to set Tlaginput1+3 to 'N' 
+    options_NLME.IIVestimate([10 13])     = 0;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle absorption parameter information
+% If no absorption data present then do not estimate absorption parameters 
+% Otherwise, set it according to the absorption model setting
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~FLAG_ABSORPTION_DATA_PRESENT,
+    % No absorption data => disable estimation of all absorption relevant parameters
+    % ('Fabs1', 'ka', 'TlagAbs1', 'Fabs0', 'Tk0', 'TlagAbs0')
+    % 'CL', 'Vc', 'Q1', 'Vp1', 'Q2', 'Vp2', 'Fiv', 'Fabs1', 'ka', 'Tlaginput1', 'Fabs0', 'Tk0input3', 'Tlaginput3', 'Frel0', 'VMAX', 'KM'
+    options_NLME.POPestimate(8:14)          = 0;
+    options_NLME.POPvalues0(8:14)           = 0;        % Set param to 0
+    VECTOR_SWITCH_PARAM_0([8:14])           = 1;        % Remember to set parameters to 'N' 
+    options_NLME.IIVestimate(8:14)          = 0;
+else
+    % Absorption data present - handle parameters depending on desired absorption model
+    if absorptionModel==1,
+        % 1st order absorption (disable 0th order absorption param)
+        options_NLME.POPestimate(11:13)     = 0;
+        options_NLME.POPvalues0(11:13)      = 0;    
+        VECTOR_SWITCH_PARAM_0([11:13])      = 1;        % Remember to set parameters to 'N' 
+        options_NLME.IIVestimate(11:13)     = 0;
+        % Set Frel0 to 0 (1e-10) and disable its estimation
+        options_NLME.POPestimate(14)        = 0;
+        options_NLME.POPvalues0(14)         = 0;    
+        VECTOR_SWITCH_PARAM_0([14])         = 1;        % Remember to set parameters to 'N' 
+        options_NLME.IIVestimate(14)        = 0;
+    elseif absorptionModel==0,
+        % 0th order absorption (disable 1st order absorption param)
+        options_NLME.POPestimate(8:10)      = 0;
+        options_NLME.POPvalues0(8:10)       = 0;    
+        VECTOR_SWITCH_PARAM_0([8:10])       = 1;        % Remember to set parameters to 'N' 
+        options_NLME.IIVestimate(8:10)      = 0;
+        % Set Frel0 to 1 and disable its estimation
+        options_NLME.POPestimate(14)        = 0;
+        options_NLME.POPvalues0(14)         = 1;    
+        options_NLME.IIVestimate(14)        = 0;
+    elseif absorptionModel==2,
+        % Parallel mixed absorption model - keep all settings as desired by the modeler
+    elseif absorptionModel==3,
+        % Sequential mixed absorption model - switch off estimation of
+        % Tlaginput1 (it is set to Tk0input3 automatically
+        options_NLME.POPestimate(10)        = 0;
+        options_NLME.POPvalues0(10)         = 0;    
+        VECTOR_SWITCH_PARAM_0([10])         = 1;        % Remember to set parameters to 'N' 
+        options_NLME.IIVestimate(10)        = 0;        
+    else
+        % Unknown absorption model setting - error
+        error('Unknown setting for absorptionModel option.');
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle covariance settings 
+% Need to remove model parameter combinations that are not 
+% available in the current model.
+% For example a covariance on Vp2,CL makes no sense if not a 3 
+% compartment model and thus no random effect estimated for some of the
+% parameters
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+RANDOMEFFECTS_NOT_available_ODEmodelParamNames  = TemplateModels.ParameterNames.ODE(find(~options_NLME.IIVestimate));
+% No remove all elements in options_NLME.covarianceModel that do include
+% names in the RANDOMEFFECTS_NOT_available_ODEmodelParamNames list
+terms = explodePCIQM(options_NLME.covarianceModel,',','{','}');
+remove_terms_ix = [];
+for k=1:length(terms),
+    for k2=1:length(RANDOMEFFECTS_NOT_available_ODEmodelParamNames),
+        ix = regexp(terms{k},['\<' RANDOMEFFECTS_NOT_available_ODEmodelParamNames{k2} '\>']);
+        if ~isempty(ix),
+            remove_terms_ix = [remove_terms_ix k];
+        end
+    end
+end
+terms(unique(remove_terms_ix)) = [];
+x = sprintf('%s,',terms{:});
+options_NLME.covarianceModel = x(1:end-1);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle covariate settings 
+% Need to remove model parameter combinations that are not 
+% available in the current model.
+% For example a covariate on Vp2 makes no sense if not a 3 compartment
+% model - here we assume that covariates are only tested on parameters for
+% which fixed effects are estimated.
+% This is done by checking POPestimate and IIVestimate. If both for a
+% parameter are 0 then this parameter is assumed not to be present and a
+% potential covariate relationship is removed. 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+testFixed   = TemplateModels.ParameterNames.ODE(find(~options_NLME.POPestimate));
+testRandom  = TemplateModels.ParameterNames.ODE(find(~options_NLME.IIVestimate));
+testAll     = intersect(testFixed,testRandom);
+
+PARAMETERS_NOT_available_ODEmodelParamNames   = testAll;
+
+% No remove all elements in options_NLME.covarianceModel that do include
+% names in the FIXEDEFFECTS_NOT_available_ODEmodelParamNames list
+terms = explodePCIQM(options_NLME.covariateModel,',','{','}');
+remove_terms_ix = [];
+for k=1:length(terms),
+    for k2=1:length(PARAMETERS_NOT_available_ODEmodelParamNames),
+        ix = regexp(terms{k},['\<' PARAMETERS_NOT_available_ODEmodelParamNames{k2} '\>']);
+        if ~isempty(ix),
+            remove_terms_ix = [remove_terms_ix k];
+        end
+    end
+end
+terms(unique(remove_terms_ix)) = [];
+x = sprintf('%s,',terms{:});
+options_NLME.covariateModel = x(1:end-1);
+% Also remove the same terms for COVestimate and covariateModelValues
+% Also remove the same terms for COVestimate and covariateModelValues
+if ~isempty(options_NLME.covariateModelValues),
+    options_NLME.covariateModelValues(remove_terms_ix) = [];
+end
+if ~isempty(options_NLME.COVestimate),
+    options_NLME.COVestimate(remove_terms_ix) = [];
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Decide if ODE or analytic model
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if saturableClearance,
+    FLAGanalyticModel = 0;
+else
+    FLAGanalyticModel = 1;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Do only allow time varying covariate models for NONMEM and analytic for
+% now
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(options_NLME.covariateModelTV),
+    % time varying covariate defined
+    if ~FLAGanalyticModel,
+        error('Time varying covariates for now only in analytic models.');
+    end
+    if ~FLAG_NONMEM,
+        error('Time varying covariates for now only in NONMEM models.');
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle dataset - transform it according to requirements 
+% based on the absorption model settings
+%
+% MONOLIX:
+% ========
+% No absorption:        do nothing
+% 1st order absorption: do nothing
+% 0th order absorption: ADM=1 => ADM=3 
+% Mixed absorption:     Double all ADM=1 doses and set for copy ADM=3
+%                       Same for parallel and sequential absorption
+%
+% In NONMEM things need to be handled differently ... since NONMEM is old, messy and annoying ...
+% Do same as for MONOLIX but additionally:
+%  - set RATE=-2 for ADM0 doses
+%  - change from ADM/YTYPE to CMT only 
+%       - CMT=1 for observation with ODE model since linked to OUTPUT numbers
+%       - CMT=2 for observations with analytic model
+%
+% If dataset changed then create NLME project folder and save in NLME project folder
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Create folder "projectPath"
+try rmdir(projectPath,'s'); catch, end
+mkdir(projectPath);
+
+% Handle dataset according to absorption
+FLAG_changed_dataset = 0;
+
+% Handle general / MONOLIX
+if FLAG_ABSORPTION_DATA_PRESENT,
+    if absorptionModel == 1,
+        % 1st order absorption - keep as is
+    elseif absorptionModel == 0,
+        % 0th order absorption - do the changes ADM=1 -> ADM=3
+        analysisDataset.ADM(analysisDataset.ADM==1) = 3;
+        FLAG_changed_dataset = 1;
+    elseif absorptionModel == 2 || absorptionModel == 3,
+        % Mixed order absorption - do the changes
+        analysisDatasetADM13 = analysisDataset(analysisDataset.ADM==1,:);
+        analysisDatasetADM13.ADM(analysisDatasetADM13.ADM==1) = 3;
+        analysisDataset = [analysisDataset; analysisDatasetADM13];
+        analysisDataset = sortrows(analysisDataset,{'IXGDF','ADM'});
+        FLAG_changed_dataset = 1;
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% This workflow does not support combination of IV administration and 0th order absorption when using NONMEM.
+% The reason is not that this is impossible, but 95% of the code already implement special cases for NONMEM
+% and at this point I would rather drill a hole into my knee than to add 100 more exceptions. Please use MONOLIX
+% in this case - no exceptions need to be coded - easy and logical.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if FLAG_NONMEM,
+    if ~isempty(find(analysisDataset.ADM==2)),
+        % IV data present
+        if ~isempty(find(analysisDataset.ADM==3)),
+            % 0th order absorption present
+            error(sprintf('This workflow does not support combination of IV administration and 0th order absorption when using NONMEM.\nThe reason is not that this is impossible, but 95% of the code already implement special cases for NONMEM\nand at this point I would rather drill a hole into my knee than to add 100 more exceptions. Please use MONOLIX\nin this case - no exceptions need to be coded - easy and logical.'));
+        end
+        FLAG_IV = 1; % Needed for NONMEM code ... again a special case
+    else
+        FLAG_IV = 0; % Needed for NONMEM code ... again a special case
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle "final" special cases in NONMEM
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if FLAG_NONMEM,
+    % In case of NONMEM always need to change the dataset (now where 0th order absorption added)
+    % Reason: change to CMT instead of ADM/YTYPE
+    FLAG_changed_dataset = 1;
+    
+    % RATE=-2 for 0th order absorption doses
+    analysisDataset.RATE(analysisDataset.ADM==3) = -2;
+    
+    % Create CMT column
+    % ADM=0: observation compartment 2 => set CMT=1     (output number)
+    % ADM=1: administration compartment 1 => set CMT=1  (1st order abs)
+    % ADM=2: administration compartment 2 => set CMT=2  (infusion central)
+    % ADM=3: administration compartment 2 => set CMT=2  (0th order abs in central)
+    CMT = NaN(height(analysisDataset),1);
+    if FLAGanalyticModel,
+        CMT(analysisDataset.ADM==0) = 2; 
+    else
+        CMT(analysisDataset.ADM==0) = 1; % It is correct. The CMT column for IQM Tools is the output number for observations ...
+    end
+    CMT(analysisDataset.ADM==1) = 1;
+    CMT(analysisDataset.ADM==2) = 2;
+    CMT(analysisDataset.ADM==3) = 2;
+    % Check if CMT contains still NaN
+    if ~isempty(find(isnan(CMT))),
+        error('Check');
+    end
+    % Set YTYPE column in dataHeaderIdent to IGNORE
+    data_NLME.dataHeaderIdent = strrep(data_NLME.dataHeaderIdent,',YTYPE,',',IGNORE,');
+    % Set ADM column in dataHeaderIdent to IGNORE
+    data_NLME.dataHeaderIdent = strrep(data_NLME.dataHeaderIdent,',ADM,',',ADM,');
+    % Add CMT column to dataset
+    analysisDataset.CMT = CMT;
+    data_NLME.dataHeaderIdent = [data_NLME.dataHeaderIdent,',CMT'];    
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% If dataset was changed then save in project folder:
+% Change the name of the dataset to highlight that it has been changed
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if FLAG_changed_dataset,
+    % Change name
+    [p,f,e] = fileparts(data_NLME.dataFileName);
+    data_NLME.dataFileName = [f '_fixed4model' e];
+    % Save changed dataset in project folder
+    oldpath = pwd(); cd(projectPath);
+    IQMexportCSVdataset(analysisDataset,data_NLME.dataFileName);
+    cd(oldpath);
+    % Update path to dataset for model to NLME project path
+    data_NLME.dataRelPathFromProject = '.';
+end
+ 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Construct Monolix/NONMEM project
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if FLAGanalyticModel,
+    % Need to adjust the options
+    % Need to remove the ODE model parameters
+    % Find indices of analytic model parameters in the ODE parameters
+    ix_analytic = [];
+    for k=1:length(TemplateModels.ParameterNames.ANALYTIC),
+        ix_analytic = [ix_analytic strmatchIQM(TemplateModels.ParameterNames.ANALYTIC{k},TemplateModels.ParameterNames.ODE,'exact')];
+    end
+    ix_remove_ODE_param = setdiff([1:length(TemplateModels.ParameterNames.ODE)],ix_analytic);
+    % Do remove
+    options_NLME_ANALYTIC = options_NLME;
+    options_NLME_ANALYTIC.POPestimate(ix_remove_ODE_param) = [];
+    options_NLME_ANALYTIC.POPvalues0(ix_remove_ODE_param) = [];
+    options_NLME_ANALYTIC.IIVestimate(ix_remove_ODE_param) = [];
+    if ~isempty(options_NLME_ANALYTIC.IIVvalues0),
+        try
+            options_NLME_ANALYTIC.IIVvalues0(ix_remove_ODE_param) = [];
+        catch
+        end
+    end
+    % Set distribution
+    options_NLME_ANALYTIC.IIVdistribution = TemplateModels.IIVdistribution.ANALYTIC;
+    % Set distribution for parameters that are fixed to 0 to "N"
+    options_NLME_ANALYTIC.IIVdistribution(find(VECTOR_SWITCH_PARAM_0(1:length(TemplateModels.IIVdistribution.ANALYTIC)))) = {'N'};
+    
+    % Keep the project folder (removed and created above)
+    options_NLME_ANALYTIC.keepProjectFolder = 1;
+    
+    % Remove Tlaginput1 from parameters if sequential dosing
+    parameterNames  = TemplateModels.ParameterNames.ANALYTIC;    
+    if absorptionModel == 3,
+        % Need to remove Tlaginput1 from the parameters to be considered
+        % for estimation ... since Tlaginput1=Tk0input3
+        parameterNames(10) = [];
+        options_NLME_ANALYTIC.POPestimate(10) = [];
+        options_NLME_ANALYTIC.POPvalues0(10) = [];
+        options_NLME_ANALYTIC.IIVdistribution(10) = [];
+        options_NLME_ANALYTIC.IIVestimate(10) = [];
+        if ~isempty(options_NLME_ANALYTIC.IIVvalues0),
+            options_NLME_ANALYTIC.IIVvalues0(10) = [];      
+        end
+    end
+    
+    if ~FLAG_NONMEM,
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        % Create a MONOLIX NLME project
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        % Get model info - analytic model - used different one for 
+        % 0/1/01 parallel and 01 sequential absorption
+        if absorptionModel ~= 3,
+            modelName       = TemplateModels.Model.MONOLIX.ANALYTIC;
+        else
+            modelName       = TemplateModels.Model.MONOLIX.ANALYTIC_SEQ01ABS;
+        end
+        modelFile       = which(modelName);
+        
+        % Create analytic Monolix project
+        createPopPK_MONOLIXprojectIQM(modelNameFIT,modelName,modelFile,parameterNames,FACTOR_UNITS,data_NLME,projectPath,options_NLME_ANALYTIC);
+    else
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        % Create a NONMEM NLME project
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+       
+        % Need to use different ADVANs depending on the compartment number
+        % (for stability reasons, since Q=1e-10 is not good for NONMEM)
+        if numberCompartments==1,
+            modelADVAN = 'ADVAN2 TRANS2';
+            paramNamesODE   = {'CL','Vc','ka'};
+            paramNamesADVAN = {'CL','V','KA'};
+        elseif numberCompartments==2,
+            modelADVAN = 'ADVAN4 TRANS4';
+            paramNamesODE   = {'CL','Vc','Q1','Vp1','ka'};
+            paramNamesADVAN = {'CL','V2','Q', 'V3', 'KA'};
+        elseif numberCompartments==3,
+            modelADVAN = 'ADVAN12 TRANS4';
+            paramNamesODE   = {'CL','Vc','Q1','Vp1','Q2','Vp2','ka'};
+            paramNamesADVAN = {'CL','V2','Q3','V3', 'Q4','V4', 'KA'};
+        end
+        createPopPK_NONMEMprojectIQM(absorptionModel,FLAG_IV,parameterNames,FACTOR_UNITS,data_NLME,projectPath,options_NLME_ANALYTIC,modelADVAN,paramNamesODE,paramNamesADVAN);
+    end
+else
+    
+    % All parameters are passed, but they might require a reordering!
+    parameterNames  = TemplateModels.ParameterNames.ODE;
+    % Set distribution
+    options_NLME.IIVdistribution = TemplateModels.IIVdistribution.ODE;
+    % Set distribution for parameters that are fixed to 0 to "N"
+    options_NLME.IIVdistribution(find(VECTOR_SWITCH_PARAM_0)) = {'N'};
+
+    % Get model info
+    modelName       = TemplateModels.Model.ODE;
+    modelFile       = which(modelName);
+    
+    % Get correct dosing scheme ... and adapt inputs for that
+    if absorptionModel ~= 3,
+        % For non sequential absorption
+        dosingName      = TemplateModels.Model.DOSING;
+    else
+        % For sequential 0/1 order absorption
+        % (Tlaginput1 = Tk0input3)
+        dosingName  = TemplateModels.Model.DOSING_SEQ01ABS;
+        % Need to remove Tlaginput1 from the parameters to be considered
+        % for estimation ...
+        parameterNames(10) = [];
+        options_NLME.POPestimate(10) = [];
+        options_NLME.POPvalues0(10) = [];
+        options_NLME.IIVdistribution(10) = [];
+        options_NLME.IIVestimate(10) = [];
+        if ~isempty(options_NLME.IIVvalues0),
+            options_NLME.IIVvalues0(10) = [];
+        end
+    end
+    dosFile         = which(dosingName);
+	
+    % Load model and dosing
+    model           = IQMmodel(modelFile);
+    dosing          = IQMdosing(dosFile);
+    
+    % Update model name with modelNameFIT
+    ms              = struct(model);
+    ms.name         = modelNameFIT;
+    model           = IQMmodel(ms);
+    
+    % Update model with FACTOR_UNITS
+    model           = IQMparameters(model,'FACTOR_UNITS',FACTOR_UNITS);
+    
+    % Keep the project folder (removed and created above)
+    options_NLME.keepProjectFolder = 1;
+    
+    if ~FLAG_NONMEM,
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        % Create a MONOLIX NLME project
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        IQMcreateMONOLIXproject(model,dosing,data_NLME,projectPath,options_NLME,parameterNames)
+    else
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        % Create a NONMEM NLME project
+        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        % Again a special case for NONMEM ... if created in the popPK workflow the dosing compartment info needs to be 
+        % written in a special way ... 
+        
+        options_NLME.FLAG_NONMEM__RATE_BIOAVAILABILITY_ISSUE__OK = FLAG_NONMEM__RATE_BIOAVAILABILITY_ISSUE__OK;
+        options_NLME.FLAG_IV_POPPK = FLAG_IV;
+        options_NLME.absorptionModel_POPPK = absorptionModel;        
+        IQMcreateNONMEMproject(model,dosing,data_NLME,projectPath,options_NLME,parameterNames)        
+    end
+end
+
+% Return the full options for both ODE and ANALYTIC
+MODEL_SETTINGS = options_NLME;
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/auxiliary/createPopPK_NONMEMprojectIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/auxiliary/createPopPK_NONMEMprojectIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..5472d75d0118218a1deac29ddaa0c34ffe08018b
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/auxiliary/createPopPK_NONMEMprojectIQM.m	
@@ -0,0 +1,1841 @@
+function createPopPK_NONMEMprojectIQM(absorptionModel,FLAG_IV,parameterNames,FACTOR_UNITS,data,projectPath,options,modelADVAN,paramNamesODE,paramNamesADVAN)
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Define Default Properties (Never changing)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+projectName            = 'project';
+resultsFolder          = 'RESULTS';
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check input
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try
+    dataRelPathFromProject = data.dataRelPathFromProject;
+    dataFileName           = data.dataFileName;
+    dataHeaderIdent        = data.dataHeaderIdent;
+    
+    % Need to change the data header
+    % TIME => TIME2 (Since it can contain negative times)
+    % TIMEPOS => TIME (The normal NONMEM time ... since it is only positive)
+    dataHeaderIdent         = regexprep(dataHeaderIdent,'\<TIME\>','TIME2');
+    dataHeaderIdent         = regexprep(dataHeaderIdent,'\<TIMEPOS\>','TIME');
+catch
+    error('data input argument not defined correctly.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle optional arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try POPestimate                     = options.POPestimate;                      catch, POPestimate = [];                             end
+try POPvalues0                      = options.POPvalues0;                       catch, POPvalues0 = [];                              end
+try IIVdistribution                 = options.IIVdistribution;                  catch, IIVdistribution = {};                         end
+try IIVestimate                     = options.IIVestimate;                      catch, IIVestimate = [];                             end
+try IIVvalues0                      = options.IIVvalues0;                       catch, IIVvalues0 = [];                              end
+try errorModels                     = options.errorModels;                      catch, errorModels = '';                             end
+try errorParam0                     = options.errorParam0;                      catch, errorParam0 = [];                             end
+try covarianceModel                 = options.covarianceModel;                  catch, covarianceModel = 'diagonal';                 end
+try covariateModel                  = options.covariateModel;                   catch, covariateModel = {};                          end
+try covariateModelValues            = options.covariateModelValues;             catch, covariateModelValues = {};                    end
+try COVestimate                     = options.COVestimate;                      catch, COVestimate = {};                             end
+
+try COVcentering_covs               = options.COVcentering.covs;                catch, COVcentering_covs = {};                       end
+try COVcentering_values             = options.COVcentering.values;              catch, COVcentering_values = [];                     end
+
+try covariateModelTV                = options.covariateModelTV;                 catch, covariateModelTV = '';                        end
+
+try METHOD                          = options.algorithm.METHOD;                 catch, METHOD = 'SAEM';                              end
+try MAXEVAL                         = options.algorithm.MAXEVAL;                catch, MAXEVAL = 9999;                               end
+try SIGDIGITS                       = options.algorithm.SIGDIGITS;              catch, SIGDIGITS = 3;                                end
+try PRINT                           = options.algorithm.PRINT;                  catch, PRINT = 1;                                    end
+try M4                              = options.algorithm.M4;                     catch, M4 = 0;                                       end
+try SEED                            = options.algorithm.SEED;                   catch, SEED = 123456;                                end
+try K1                              = options.algorithm.K1;                     catch, K1 = 500;                                     end
+try K2                              = options.algorithm.K2;                     catch, K2 = 200;                                     end
+try NRCHAINS                        = options.algorithm.NRCHAINS;               catch, NRCHAINS = 1;                                 end
+try IMPORTANCESAMPLING              = options.algorithm.IMPORTANCESAMPLING;     catch, IMPORTANCESAMPLING = 0;                       end
+try ITS                             = options.algorithm.ITS;                    catch, ITS = 0;                                      end
+try ITS_ITERATIONS                  = options.algorithm.ITS_ITERATIONS;         catch, ITS_ITERATIONS = 10;                          end
+try IMP_ITERATIONS                  = options.algorithm.IMP_ITERATIONS;         catch, IMP_ITERATIONS = 5;                           end
+
+try SILENT                          = options.SILENT;                           catch, SILENT = 0;                                   end
+
+try keepProjectFolder               = options.keepProjectFolder;                catch, keepProjectFolder = 0;                        end   
+
+if ~iscell(COVcentering_covs),
+    COVcentering_covs = {COVcentering_covs};
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle methods - some IQM Tools limitations
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if strcmp(METHOD,'FO') && ITS==1,
+   error('The FO method should not be used with ITS=1.');
+end
+
+if ~strcmp(METHOD,'SAEM') && IMPORTANCESAMPLING==1,
+    error('The importance sampling (IMPORTANCESAMPLING=1) should only be used with the SAEM method.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Info text
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~SILENT,
+    disp(' ')
+    disp('==================================================================');
+    [xdummyx,projectFolderName] = fileparts(projectPath);
+    disp(sprintf('== Start of creation of %s/project.nmctl file',projectFolderName));
+    disp('==================================================================');
+    disp(' ')
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Create project and results folder
+% Change into project path
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+warning off
+oldpath = pwd;
+if ~keepProjectFolder,
+    try, rmdir(projectPath,'s'); catch, end
+end
+mkdir(projectPath); cd(projectPath)
+mkdir(resultsFolder);
+warning on
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Load data and get info about data
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+dataModeling = IQMloadCSVdataset([data.dataRelPathFromProject '/' data.dataFileName]);
+% Determine maximum number of data records per ID
+maxDATARECORDS_ID = -Inf;
+allID = unique(dataModeling.ID);
+for k=1:length(allID),
+    datak = dataModeling(dataModeling.ID==allID(k),:);
+    maxDATARECORDS_ID = max(maxDATARECORDS_ID,height(datak));
+end
+maxDATARECORDS = height(dataModeling);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Process data to get the dataheader and the median values for the covariates
+% and the categorical covariate names and their unique values.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[covariateMedianNames,covariateMedianValues,covariateCATNames,covariateCATValues,dataheader,dataCSV] = processDataAndGetMedianValuesIQM(oldpath,dataRelPathFromProject,dataFileName,dataHeaderIdent,SILENT,COVcentering_covs,COVcentering_values);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check and update default input arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check POPestimate thing
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(POPestimate),
+    POPestimate = ones(1,length(parameterNames));
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check POPvalues0 thing
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(POPvalues0),
+    POPvalues0 = ones(1,length(parameterNames));
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check IIV distribution things
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(IIVdistribution),
+    IIVdistribution = {};
+    for k=1:length(parameterNames),
+        IIVdistribution{k} = 'L';
+    end
+end
+
+% Check contents
+test = IIVdistribution;
+for k=1:length(IIVdistribution),
+    if ~ismember(test{k},{'L','N','G'}),
+        cd(oldpath);
+        error('Please make sure that only "N", "L", or "G" appear in the "IIVdistribution" variable.');
+    end
+end
+
+% Check length
+if length(IIVdistribution) ~= length(parameterNames),
+    cd(oldpath);
+    error('Please make sure that an equal number of IIVdistribution is defined as estimated parameters in the model.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check IIV estimation things
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(IIVestimate),
+    IIVestimate = ones(1,length(parameterNames));
+end
+% Check length
+if length(IIVestimate) ~= length(parameterNames),
+    cd(oldpath);
+    error('Please make sure that an equal number of IIVestimate is defined as estimated parameters in the model.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check IIVvalues0 thing
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(IIVvalues0),
+    IIVvalues0 = ones(1,length(parameterNames));
+end
+if length(parameterNames) ~= length(IIVvalues0),
+    cd(oldpath);
+    error('Please make sure IIVvalues0 is of same length as number of parameters to be estimated.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Convert covariate model into different syntax
+% '{CL,BMI0}, {Fsubcut,WT0}, {Vc,SEX,BMI0}'
+% to
+% {{'CL','BMI0'}, {'Fsubcut','WT0'}, {'Vc','SEX','BMI0'}}
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(covariateModel),
+    terms = explodePCIQM(covariateModel,',','{','}');
+    y = {};
+    for k=1:length(terms),
+        x = strrep(strtrim(terms{k}),' ','');
+        x = strrep(x,'{','{''');
+        x = strrep(x,'}','''}');
+        x = strrep(x,',',''',''');
+        y{k} = eval(x);
+    end
+    covariateModel = y;
+end
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check time varying covariate names
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if iscell(covariateModelTV),
+   error('covariateModelTV should be defined as a string with comma separated covariate names.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Get name of time varying covariates
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+covcatNamesTV = {};
+if ~isempty(covariateModelTV),
+    covcatNamesTV = explodePCIQM(covariateModelTV,',');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check covariateModelValues
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(covariateModel) && ~isempty(covariateModelValues),
+    error('If you define covariateModelValues, you also need to define the covariateModel.');
+end
+
+if isempty(covariateModelValues),
+    % Determine default covariateModelValues
+    covariateModelValues = {};
+    for k=1:length(covariateModel),
+        covariateModelValues{k} = zeros(1,length(covariateModel{k})-1);
+    end
+else
+    % Check correct length of covariateModelValues elements
+    if length(covariateModel) ~= length(covariateModelValues),
+        error('Number of elements in covariateModel and covariateModelValues needs to match.');
+    end
+    for k=1:length(covariateModel),
+        if length(covariateModel{k})-1 ~= length(covariateModelValues{k}),
+            error('Length of single elements in covariateModel and covariateModelValues needs to match (covariateModelValues elements being one shorter).');
+        end            
+    end    
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check COVestimate
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(covariateModel) && ~isempty(COVestimate),
+    error('If you define COVestimate, you also need to define the covariateModel.');
+end
+
+if isempty(COVestimate),
+    % Determine default COVestimate - all are estimates
+    COVestimate = {};
+    for k=1:length(covariateModel),
+        COVestimate{k} = ones(1,length(covariateModel{k})-1);
+    end
+else
+    % Check correct length of COVestimate elements
+    if length(covariateModel) ~= length(COVestimate),
+        error('Number of elements in covariateModel and COVestimate needs to match.');
+    end
+    for k=1:length(covariateModel),
+        if length(covariateModel{k})-1 ~= length(COVestimate{k}),
+            error('Length of single elements in covariateModel and COVestimate needs to match (COVestimate elements being one shorter).');
+        end            
+    end    
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Reorder estimation parameters to allow for block-diagonal covariance
+% matrix
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if strcmp(covarianceModel,'diagonal') || isempty(covarianceModel),
+    % Keep parameters in the given order
+    POPestimate_trans       = POPestimate;
+    POPvalues0_trans        = POPvalues0;
+    IIVestimate_trans       = IIVestimate;
+    IIVvalues0_trans        = IIVvalues0;
+    parameterNames_trans    = parameterNames;
+    IIVdistribution_trans   = IIVdistribution;    
+else
+    % Need to rearrange
+    % Determine the order of parameters as they appear in the
+    % covarianceModel definition
+    x = strrep(covarianceModel,'{','');
+    x = strrep(x,'}','');
+    terms = explodePCIQM(x);
+    % Check which parameters are missing
+    paramnames_order = terms;
+    for k=1:length(parameterNames),
+        if ~ismember(parameterNames{k},paramnames_order),
+            paramnames_order{end+1} = parameterNames{k};
+        end
+    end
+    % Determine the transformation indices
+    index_trans = [];
+    for k=1:length(paramnames_order),
+        index_trans(k) = strmatchIQM(paramnames_order{k},parameterNames,'exact');
+    end
+    % Ok, we got the new order of the parameters, now we need to change the
+    % order in a couple of things
+    % POPestimate
+    % POPvalues0
+    % IIVdistribution
+    % IIVestimate
+    % IIVvalues0
+    % parameterNames
+    POPestimate_trans       = POPestimate(index_trans);
+    POPvalues0_trans        = POPvalues0(index_trans);
+    IIVestimate_trans       = IIVestimate(index_trans);
+    IIVvalues0_trans        = IIVvalues0(index_trans);
+    parameterNames_trans    = parameterNames(index_trans);
+    IIVdistribution_trans   = IIVdistribution(index_trans);
+end
+% Update the variables to the transformed ones
+POPestimate             = POPestimate_trans;
+POPvalues0              = POPvalues0_trans;
+IIVestimate             = IIVestimate_trans;
+IIVvalues0              = IIVvalues0_trans;
+parameterNames          = parameterNames_trans;
+IIVdistribution         = IIVdistribution_trans;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Do additional checks and write out information
+% Definition of param_est and IIVestimation + reordering needed to be ready
+% before running these checks.
+% Additionally, the names of the covariates are determined and the
+% errorModels default setting is handled here.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%
+% Determine continuous and categorical covariates
+%%%%%%%%%%%%%%%%%%%%%%%
+dataHeaderIDs   = explodePCIQM(dataHeaderIdent,',');
+covIDs          = strmatchIQM('COV',upper(dataHeaderIDs));
+covNames        = dataheader(covIDs);
+catIDs          = strmatchIQM('CAT',upper(dataHeaderIDs));
+catNames        = dataheader(catIDs);
+
+%%%%%%%%%%%%%%%%%%%%%%%
+% Check if time varying covariates contain continuous covariates ... do not
+% allow for now (future feature)
+%%%%%%%%%%%%%%%%%%%%%%%
+for k=1:length(covcatNamesTV),
+    ix = strmatchIQM(covcatNamesTV{k},covNames,'exact');
+    if ~isempty(ix),
+        error('Time varying covariates defined that are continuous. Not allowed at the moment.');
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%
+% Check all headers
+%%%%%%%%%%%%%%%%%%%%%%%
+if ~SILENT,
+    disp(' ');
+    disp('Please check that the following matches between data header and identifiers do make sense:');
+    for k=1:length(dataheader),
+        fprintf('\t%s%s: %s\n',dataheader{k},char(32*ones(1,8-length(dataheader{k}))),dataHeaderIDs{k})
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%
+% Check residual error things
+%%%%%%%%%%%%%%%%%%%%%%%
+test = errorModels;
+test = strtrim(strrep(strrep(strrep(strrep(strrep(strrep(strrep(test,'const',''),'prop',''),'comb1',''),'exp',''),'band(0,100)',''),'logit',''),',',''));
+if ~isempty(test),
+    cd(oldpath);
+    error('Please make sure that only "const", "prop", "comb1", or "exp" appear in the "errorModels" variable.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle empty errorParam0
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(errorParam0),
+    terms = explodePCIQM(errorModels);
+    for k=1:length(terms),
+        if strcmp(lower(terms{k}),'const'),
+            errorParam0(end+1) = 1;
+        elseif strcmp(lower(terms{k}),'prop'),
+            errorParam0(end+1) = 0.3;
+        elseif strcmp(lower(terms{k}),'comb1'),
+            errorParam0(end+1) = 1;
+            errorParam0(end+1) = 0.3;          
+        elseif strcmp(lower(terms{k}),'exp'),
+            errorParam0(end+1) = 1;
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check errorParam0
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+terms = explodePCIQM(errorModels);
+nrneededelements = 0;
+for k=1:length(terms),
+    if strcmpi(terms{k},'const'),
+        nrneededelements = nrneededelements+1;
+    elseif strcmpi(terms{k},'prop'),
+        nrneededelements = nrneededelements+1;
+    elseif strcmpi(terms{k},'comb1'),
+        nrneededelements = nrneededelements+2;
+    elseif strcmpi(terms{k},'exp'),
+        nrneededelements = nrneededelements+1;
+    end
+end
+if length(errorParam0) ~= nrneededelements,
+    error('Incorrect number of elements in options.errorParam0.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%
+% Check covariance model
+%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(covarianceModel),
+    covarianceModel = 'diagonal';
+end
+
+if ~strcmp(covarianceModel,'diagonal'),
+    % Need to check that none of the parameters for which no IIV is estimated is used in the covarianceModel
+    param_est_noIIV = parameterNames(IIVestimate==0);
+    for k=1:length(param_est_noIIV),
+        if ~isempty(regexp(covarianceModel,['\<' param_est_noIIV{k} '\>'])),
+            cd(oldpath);
+            error('Please make sure none of the parameters for which NO IIV is estimated (IIVestimate 0) is used in the covarianceModel settings.');
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%
+% Check covariate model things
+%%%%%%%%%%%%%%%%%%%%%%%
+% First check that all first elements are estimated parameters of the model
+for k=1:length(covariateModel),
+    param = covariateModel{k}{1};
+    if isempty(strmatchIQM(param,parameterNames,'exact')),
+        cd(oldpath);
+        error('Please make sure that all parameters for which covariates are defined are defined by <estimate> in the model.');
+    end
+end
+
+% Second check that all defined covariates actually are covariates
+covcatNames = [covNames catNames];
+for k=1:length(covariateModel),
+    for k2=2:length(covariateModel{k}),
+        cov = covariateModel{k}{k2};
+        if isempty(strmatchIQM(cov,covcatNames,'exact')),
+            error('Please make sure that all covariates, defined in covariateModel, are defined in the dataset.');
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% OPEN File
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fid = fopen([projectName '.nmctl'],'w');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INFO
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; NONMEM PROJECT, created using IQM Tools\r\n');
+fprintf(fid,'; Date: %s\r\n',datestr(now,'yyyy-mmm-DD HH:MM'));
+fprintf(fid,'; By:   %s\r\n',usernameIQM());
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Placeholder for project information
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; ==PROJECT HEADER START===================================================\r\n');
+fprintf(fid,'PROJECT_HEADER_PLACEHOLDER\r\n');
+fprintf(fid,'; ==PROJECT HEADER END=====================================================\r\n');
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Define $SIZES
+% Set all LIM1,2,6 to TOTDREC=maxDATARECORDS!
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'$SIZES LIM1=%d\r\n',maxDATARECORDS);
+fprintf(fid,'$SIZES LIM2=%d\r\n',maxDATARECORDS);
+fprintf(fid,'$SIZES LIM6=%d\r\n',maxDATARECORDS);
+fprintf(fid,'$SIZES LTH=XXX\r\n');
+% Define PD as number of columns that are not skipped
+PD = length(explodePCIQM(data.dataHeaderIdent))-length(strfind(data.dataHeaderIdent,'IGNORE'))+5;
+fprintf(fid,'$SIZES PD=%d\r\n',PD);
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $PROBLEM
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[xdummyx,problemName]     = fileparts(projectPath);
+fprintf(fid,'$PROBLEM %s\r\n',problemName);
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $DATA
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'$DATA %s\r\n',strrep(fullfile(dataRelPathFromProject,dataFileName),'\','/'));
+fprintf(fid,'    IGNORE=@\r\n');
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $INPUT
+% Assumption: names for INPUT are used as in the dataset for CAT,COV,X
+% for all others as in dataHeaderIdent.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+dataHeaderIdentAll = explodePCIQM(dataHeaderIdent);
+
+text = '$INPUT';
+for k=1:length(dataheader),
+    col     = dataheader{k};
+    coltype = dataHeaderIdentAll{k};
+    
+    % Check if CAT, COV or X
+    if ismember(coltype,{'CAT','COV','X'}),
+        % Use name as in dataset header
+        text = sprintf('%s %s',text,col);
+    elseif strcmp(coltype,'IGNORE'),
+        % If column set to IGNORE then use SKIP in the $INPUT definition
+        text = sprintf('%s SKIP',text);
+    else
+        % Use name as in dataset ident
+        text = sprintf('%s %s',text,coltype);
+    end
+end
+fprintf(fid,'%s\r\n',wrapRowTextIQM(text,80,7));
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $SUBROUTINE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'$SUBROUTINE %s\r\n\r\n',modelADVAN);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $PK - Start
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'$PK\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $PK - PK parameters
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; Parameters\r\n');
+
+% FACTOR_UNITS
+fprintf(fid,'    FACTOR_UNITS = %g\r\n',FACTOR_UNITS);
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $PK - Start by THETAs
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+MU_param_text = {};
+for k=1:length(parameterNames)
+    MU_param_text{k} = sprintf('    MU_%d%s = THETA(%d)%sX#X#X    ; %s\r\n',k,char(32*ones(1,2-length(num2str(k)))),k,char(32*ones(1,2-length(num2str(k)))),parameterNames{k});
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $PK - Introduce time invariant covariates
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+beta_parameters     = {};
+beta_parameters_cov_project_info     = {};
+beta_parameters_cat_project_info     = {};
+THETA_INDEX_BETA    = [];
+cov_type_continuous = [];
+covparam            = {};
+covcov              = {};
+
+COV_transformation_info = {};
+CAT_reference_info = {};
+CAT_categories_info = {};
+
+COVCATestimate_info = [];
+
+%%%%%%%%%%%%%%%%%%%%
+% Handle the CONTINUOUS covariate definitions and their introduction into
+% the MU referencing.
+%%%%%%%%%%%%%%%%%%%%
+parameter_add_cov   = {};
+cov_add_cov         = {};
+cov_add_median      = [];
+covTrans_text       = {};
+count = 1;
+for kcov=1:length(covariateModel),
+    covParam = covariateModel{kcov}{1};
+    covCOVs  = covariateModel{kcov}(2:end);
+    for k2=1:length(covCOVs),
+        if ismember(covCOVs{k2},covariateMedianNames),
+            beta_parameters{end+1}      = sprintf('beta_%s(%s)',covParam,covCOVs{k2});
+            theta_index                 = length(parameterNames)+count;
+            THETA_INDEX_BETA(end+1)     = theta_index;
+            cov_type_continuous(end+1)  = 1;
+            count                       = count+1;
+            parameter_add_cov{end+1}    = covParam;
+            cov_add_cov{end+1}          = covCOVs{k2};
+            cov_median                  = covariateMedianValues(strmatchIQM(covCOVs{k2},covariateMedianNames,'exact'));
+            cov_add_median(end+1)       = cov_median;
+            
+            COVCATestimate_info(end+1)  = COVestimate{kcov}(k2);
+            
+            % find index of parameter to add covariate to
+            ix                          = strmatchIQM(covParam,parameterNames,'exact');
+            % Get transformation
+            TRANS                       = IIVdistribution{ix};
+            if TRANS=='N',
+                covTrans_text{end+1} = sprintf('+ THETA(%d)*log(%s/%g) ',theta_index,covCOVs{k2},cov_median);
+                COV_transformation_info{end+1} = sprintf('log(cov/%g)',cov_median);
+            elseif TRANS=='L',
+                covTrans_text{end+1} = sprintf('+ THETA(%d)*log(%s/%g) ',theta_index,covCOVs{k2},cov_median);
+                COV_transformation_info{end+1} = sprintf('log(cov/%g)',cov_median);
+            elseif TRANS=='G',
+                covTrans_text{end+1} = sprintf('+ THETA(%d)*log(%s/%g) ',theta_index,covCOVs{k2},cov_median);
+                COV_transformation_info{end+1} = sprintf('log(cov/%g)',cov_median);
+            end
+        end
+    end
+end
+% Aggregate covariate text for each parameter
+cov_add_text_param = cell(1,length(parameterNames));
+cov_add_text_param(1:end) = {''};
+for k=1:length(parameter_add_cov),
+    ix = strmatchIQM(parameter_add_cov{k},parameterNames,'exact');
+    cov_add_text_param{ix} = [cov_add_text_param{ix} covTrans_text{k}];
+end
+% Add continuous covariates into MU_param_text
+for k=1:length(MU_param_text),
+    MU_param_text{k} = strrep(MU_param_text{k},'X#X#X',[strtrim(cov_add_text_param{k}) 'X#X#X']);
+end
+% Save for later
+covparam            = parameter_add_cov;
+covcov              = cov_add_cov;
+
+beta_parameters_cov_project_info     = beta_parameters;
+
+
+%%%%%%%%%%%%%%%%%%%%
+% Handle the categorical covariates - ONLY time invariant ones here ...
+% time varying later
+% 
+% Example:
+% SEX_1 = 0 (can be omitted)
+% SEX_2 = 0
+% SEX_3 = 0
+% IF SEX==1 THEN SEX_1 = 1 (can be omitted)
+% IF SEX==2 THEN SEX_2 = 1
+% IF SEX==3 THEN SEX_3 = 1
+%     
+% MU_3  = THETA(3) + beta_SEX_2_WT*SEX_2 + beta_SEX_3_WT*SEX_3
+% 
+% Assume reference is always the first one with the smallest number
+%%%%%%%%%%%%%%%%%%%%
+
+text_defining_cat_auxiliaries = '';
+cov_text = cell(1,length(parameterNames));
+cov_text(1:end) = {''};
+covs_handled_text_defining_cat_auxiliaries = {};
+for kcov=1:length(covariateModel),
+    covParam = covariateModel{kcov}{1};
+    covCOVs  = covariateModel{kcov}(2:end);
+    for k2=1:length(covCOVs),
+        % Check if it is a time invariant covariate
+        if ~ismember(covCOVs{k2},covcatNamesTV) && ismember(covCOVs{k2},covariateCATNames),
+            cov                         = covCOVs{k2};
+            cov_values                  = covariateCATValues{strmatchIQM(covCOVs{k2},covariateCATNames,'exact')};
+            reference_value             = cov_values(1);
+            other_values                = cov_values(2:end);
+            
+            CAT_reference_info{end+1}   = reference_value;
+            CAT_categories_info{end+1}  = cov_values;
+                        
+            % Define the auxiliary text to be added before the MU thingy
+            if ~ismember(cov,covs_handled_text_defining_cat_auxiliaries),
+                for kaux=1:length(other_values),
+                    text_defining_cat_auxiliaries = sprintf('%s    %s_%d = 0 ; reference: %d\r\n',text_defining_cat_auxiliaries,cov,other_values(kaux),reference_value);
+                end
+                for kaux=1:length(other_values),
+                    text_defining_cat_auxiliaries = sprintf('%s    IF(%s.EQ.%d) %s_%d = 1\r\n',text_defining_cat_auxiliaries,cov,other_values(kaux),cov,other_values(kaux));
+                end
+                % Set cov as handled
+                covs_handled_text_defining_cat_auxiliaries{end+1} = cov;
+            end
+            
+            % Define the rest
+            for kaux=1:length(other_values),
+                COVCATestimate_info(end+1)  = COVestimate{kcov}(k2);
+                
+                covparam{end+1} = covParam;
+                covcov{end+1} = cov;
+                beta_parameters{end+1}      = sprintf('beta_%s(%s_%d)',covParam,cov,other_values(kaux));
+
+                % Check if beta_parameters_cat_project_info already
+                % contains element
+                element_add_check = sprintf('beta_%s(%s)',covParam,cov);
+                if isempty(strmatchIQM(element_add_check,beta_parameters_cat_project_info,'exact')),
+                    % not present => add it
+                    beta_parameters_cat_project_info{end+1} = element_add_check;
+                end
+                
+                if isempty(THETA_INDEX_BETA),
+                    nextindex = length(parameterNames)+1;
+                else
+                    nextindex                   = max(THETA_INDEX_BETA)+1;
+                end
+                THETA_INDEX_BETA(end+1)     = nextindex;
+                cov_type_continuous(end+1)  = 0;
+                ixParam                     = strmatchIQM(covParam,parameterNames,'exact');
+                cov_text{ixParam}           = sprintf('%s + THETA(%d)*%s_%d',cov_text{ixParam},nextindex,cov,other_values(kaux));
+            end
+        end
+    end
+end
+
+% Add categorical covariates into MU_param_text
+for k=1:length(MU_param_text),
+    MU_param_text{k} = strrep(MU_param_text{k},'X#X#X',cov_text{k});
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $PK - Write out the auxiliaries if needed
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(text_defining_cat_auxiliaries),
+    fprintf(fid,'; Auxiliary definitions for handling categorical covariates\r\n');
+    fprintf(fid,'%s\r\n',text_defining_cat_auxiliaries);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $PK - MU Referencing
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; MU Referencing\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle MU_param_text to wrap lines
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+MAXLENGTHLINE = 80;
+for k=1:length(MU_param_text),
+    if length(MU_param_text{k}) > MAXLENGTHLINE,
+        xxx = MU_param_text{k};
+        % Get first additive element
+        ix = strfind(xxx,' + ');
+        ix = ix(1);
+        text_start = xxx(1:ix(1));
+        text_wrap = xxx(ix(1)+3:end);
+        pieces_wrap = {};
+        while length(text_wrap)>MAXLENGTHLINE,
+            ix = strfind(text_wrap,' + ');
+            ixx = ix(find(ix>MAXLENGTHLINE)-1);
+            if ~isempty(ixx),
+                ix = ixx(1);
+            else
+                ix = ix(end);
+            end
+            pieces_wrap{end+1} = text_wrap(1:ix);
+            text_wrap = text_wrap(ix+3:end);
+        end        
+        pieces_wrap{end+1} = text_wrap;
+        for k2=1:length(pieces_wrap),
+            if k2==1,
+                pieces_wrap{k2} = sprintf('    MU%dWRAP_%d = %s',k,k2,strtrim(pieces_wrap{k2}));
+            else
+                pieces_wrap{k2} = sprintf('    MU%dWRAP_%d = MU%dWRAP_%d + %s',k,k2,k,k2-1,strtrim(pieces_wrap{k2}));
+            end
+        end
+        pieces_wrap{end+1} = sprintf('%s + MU%dWRAP_%d',text_start,k,k2);
+        
+        % Put together
+        xxx = '';
+        for k2=1:length(pieces_wrap),
+            xxx = sprintf('%s%s\r\n',xxx,pieces_wrap{k2});
+        end
+        
+        MU_param_text{k} = xxx;
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $PK - Write out the MU parameter definitions with covariates
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for k=1:length(MU_param_text),
+    fprintf(fid,'%s',MU_param_text{k});
+end
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $PK - Parameter transformations
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; MU+ETA\r\n');
+for k=1:length(parameterNames),
+    fprintf(fid,'    T_%s%s = MU_%d + ETA(%d)\r\n',parameterNames{k},char(32*ones(1,cellmaxlengthIQM(parameterNames)-length(parameterNames{k})+1)),k,k);
+end
+fprintf(fid,'\r\n');
+
+fprintf(fid,'; Parameter transformations\r\n');
+for k=1:length(parameterNames),
+    if IIVdistribution{k} == 'N',
+        fprintf(fid,'    %s%s = T_%s\r\n',parameterNames{k},char(32*ones(1,cellmaxlengthIQM(parameterNames)-length(parameterNames{k})+1)),parameterNames{k});
+    elseif  IIVdistribution{k} == 'L',
+        fprintf(fid,'    %s%s = EXP(T_%s)\r\n',parameterNames{k},char(32*ones(1,cellmaxlengthIQM(parameterNames)-length(parameterNames{k})+1)),parameterNames{k});
+    elseif  IIVdistribution{k} == 'G',
+        fprintf(fid,'    %s%s = EXP(T_%s)/(1+EXP(T_%s))\r\n',parameterNames{k},char(32*ones(1,cellmaxlengthIQM(parameterNames)-length(parameterNames{k})+1)),parameterNames{k},parameterNames{k});
+    else
+        error('Unknown distribution.');
+    end
+end
+fprintf(fid,'\r\n');
+
+
+
+
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%
+% Handle the time varying categorical covariates (if present)
+% Do same as for time invariant ...
+% 
+% Example:
+% SEX_1 = 0 (can be omitted)
+% SEX_2 = 0
+% SEX_3 = 0
+% IF SEX==1 THEN SEX_1 = 1 (can be omitted)
+% IF SEX==2 THEN SEX_2 = 1
+% IF SEX==3 THEN SEX_3 = 1
+%     
+% MU_3  = THETA(3) + beta_SEX_2_WT*SEX_2 + beta_SEX_3_WT*SEX_3
+% 
+% Assume reference is always the first one with the smallest number
+%%%%%%%%%%%%%%%%%%%%
+
+text_defining_cat_auxiliaries = '';
+cov_text = cell(1,length(parameterNames));
+cov_text(1:end) = {''};
+covs_handled_text_defining_cat_auxiliaries = {};
+for kcov=1:length(covariateModel),
+    covParam = covariateModel{kcov}{1};
+    covCOVs  = covariateModel{kcov}(2:end);
+    for k2=1:length(covCOVs),
+        % Check if it is a time varying covariate
+        if ismember(covCOVs{k2},covcatNamesTV) && ismember(covCOVs{k2},covariateCATNames),
+            cov                         = covCOVs{k2};
+            cov_values                  = covariateCATValues{strmatchIQM(covCOVs{k2},covariateCATNames,'exact')};
+            reference_value             = cov_values(1);
+            other_values                = cov_values(2:end);
+            
+            CAT_reference_info{end+1}   = reference_value;
+            CAT_categories_info{end+1}  = cov_values;
+                        
+            % Define the auxiliary text to be added before the MU thingy
+            if ~ismember(cov,covs_handled_text_defining_cat_auxiliaries),
+                for kaux=1:length(other_values),
+                    text_defining_cat_auxiliaries = sprintf('%s    %s_%d = 0 ; reference: %d\r\n',text_defining_cat_auxiliaries,cov,other_values(kaux),reference_value);
+                end
+                for kaux=1:length(other_values),
+                    text_defining_cat_auxiliaries = sprintf('%s    IF(%s.EQ.%d) %s_%d = 1\r\n',text_defining_cat_auxiliaries,cov,other_values(kaux),cov,other_values(kaux));
+                end
+                % Set cov as handled
+                covs_handled_text_defining_cat_auxiliaries{end+1} = cov;
+            end
+            
+            % Define the rest
+            for kaux=1:length(other_values),
+                COVCATestimate_info(end+1)  = COVestimate{kcov}(k2);
+                
+                covparam{end+1} = covParam;
+                covcov{end+1} = cov;
+                beta_parameters{end+1}      = sprintf('beta_%s(%s_%d)',covParam,cov,other_values(kaux));
+
+                % Check if beta_parameters_cat_project_info already
+                % contains element
+                element_add_check = sprintf('beta_%s(%s)',covParam,cov);
+                if isempty(strmatchIQM(element_add_check,beta_parameters_cat_project_info,'exact')),
+                    % not present => add it
+                    beta_parameters_cat_project_info{end+1} = element_add_check;
+                end
+                
+                if isempty(THETA_INDEX_BETA),
+                    nextindex = length(parameterNames)+1;
+                else
+                    nextindex                   = max(THETA_INDEX_BETA)+1;
+                end
+                THETA_INDEX_BETA(end+1)     = nextindex;
+                cov_type_continuous(end+1)  = 0;
+                ixParam                     = strmatchIQM(covParam,parameterNames,'exact');
+                cov_text{ixParam}           = sprintf('%s * EXP(THETA(%d)*%s_%d)',cov_text{ixParam},nextindex,cov,other_values(kaux));
+            end
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $PK - Write out the auxiliaries if needed
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(text_defining_cat_auxiliaries),
+    fprintf(fid,'; Auxiliary definitions for handling time dependent categorical covariates\r\n');
+    fprintf(fid,'%s\r\n',text_defining_cat_auxiliaries);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $PK - Writing renaming formulas to wrap afterwards
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Need to add parameters to parametersODE and parametersADVAN that are not
+% in there but for which time dependent covariates have been defined.
+% Only temporary adding ... bit crude but if it works :)
+% AND: only ad if not yet present
+
+% Step 1: determine parameters for which time varying covariates are
+% available:
+xx = {};
+for k=1:length(cov_text),
+    if ~isempty(cov_text{k}),
+        xx{end+1} = parameterNames{k};
+    end
+end
+
+% Step 2: Check if already present - only add if parameter not present
+yy = {};
+for k=1:length(xx),
+    ix = strmatchIQM(xx{k},paramNamesODE,'exact');
+    if isempty(ix),
+        % Parameter not yet present ... need to add
+        yy{end+1} = xx{k};
+    else
+        % Parameter already present ... no need to add
+    end
+end
+
+% Step 3: Add the still missin parameters 
+paramNamesODE_HELP = [paramNamesODE yy];
+paramNamesADVAN_HELP = [paramNamesADVAN yy];
+
+PARAM_RENAME_TEXT = {};
+for k=1:length(paramNamesODE_HELP),
+    PARAM_RENAME_TEXT{k} = sprintf('    %s = %s%s\r\n',paramNamesADVAN_HELP{k},paramNamesODE_HELP{k},cov_text{ strmatchIQM(paramNamesODE_HELP{k},parameterNames) });
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle PARAM_RENAME_TEXT to wrap lines
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+MAXLENGTHLINE = 70;
+for k=1:length(PARAM_RENAME_TEXT),
+    if length(PARAM_RENAME_TEXT{k}) > MAXLENGTHLINE,
+        xxx = PARAM_RENAME_TEXT{k};
+        % Get first additive element
+        ix = strfind(xxx,' * ');
+        ix = ix(1);
+        text_start = xxx(1:ix(1));
+        text_wrap = xxx(ix(1)+3:end);
+        pieces_wrap = {};
+        while length(text_wrap)>MAXLENGTHLINE,
+            ix = strfind(text_wrap,' * ');
+            ixx = ix(find(ix>MAXLENGTHLINE)-1);
+            if ~isempty(ixx),
+                ix = ixx(1);
+            else
+                ix = ix(end);
+            end
+            pieces_wrap{end+1} = text_wrap(1:ix);
+            text_wrap = text_wrap(ix+3:end);
+        end        
+        pieces_wrap{end+1} = text_wrap;
+        for k2=1:length(pieces_wrap),
+            if k2==1,
+                pieces_wrap{k2} = sprintf('    PA%dWRAP_%d = %s',k,k2,strtrim(pieces_wrap{k2}));
+            else
+                pieces_wrap{k2} = sprintf('    PA%dWRAP_%d = PA%dWRAP_%d * %s',k,k2,k,k2-1,strtrim(pieces_wrap{k2}));
+            end
+        end
+        pieces_wrap{end+1} = sprintf('%s * PA%dWRAP_%d',text_start,k,k2);
+        
+        % Put together
+        xxx = '';
+        for k2=1:length(pieces_wrap),
+            xxx = sprintf('%s%s\r\n',xxx,pieces_wrap{k2});
+        end
+        
+        PARAM_RENAME_TEXT{k} = xxx;
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $PK - Renaming to match the used ADVAN/TRANS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; Renaming to match %s\r\n',modelADVAN);
+for k=1:length(PARAM_RENAME_TEXT),
+    fprintf(fid,'%s',PARAM_RENAME_TEXT{k});
+end
+fprintf(fid,'\r\n');
+
+
+
+
+
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $PK - Compartment assignment, etc.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if absorptionModel == 0,
+    % Zero order absorption into central compartment
+    % Additional IV administration not allowed
+    if FLAG_IV == 1,
+        error('IV dosing and zero order absorption into central compartment with NONMEM not handled automatically.');
+    end
+    fprintf(fid,'; Dosing compartments info\r\n');
+    fprintf(fid,'    F2 = FACTOR_UNITS*Fabs0*Frel0     ; Ac\r\n');
+    fprintf(fid,'    \r\n');
+    fprintf(fid,'    ALAG2 = Tlaginput3\r\n');
+    fprintf(fid,'    \r\n');
+    fprintf(fid,'    D2 = Tk0input3\r\n');
+    fprintf(fid,'\r\n');
+    fprintf(fid,'    S2 = %s\r\n',paramNamesADVAN{strmatchIQM('Vc',paramNamesODE,'exact')});
+    fprintf(fid,'\r\n');    
+elseif absorptionModel == 1,
+    if FLAG_IV==1,
+        % Mixed 1st order and IV
+        fprintf(fid,'; Dosing compartments info\r\n');
+        fprintf(fid,'    F1 = FACTOR_UNITS*Fabs1           ; Ad\r\n');
+        fprintf(fid,'    F2 = FACTOR_UNITS*Fiv             ; Ac\r\n');
+        fprintf(fid,'    \r\n');
+        fprintf(fid,'    ALAG1 = Tlaginput1\r\n');
+        fprintf(fid,'\r\n');
+        fprintf(fid,'    S2 = %s\r\n',paramNamesADVAN{strmatchIQM('Vc',paramNamesODE,'exact')});
+        fprintf(fid,'\r\n');
+    else
+        % Only 1st order absorption
+        fprintf(fid,'; Dosing compartments info\r\n');
+        fprintf(fid,'    F1 = FACTOR_UNITS*Fabs1           ; Ad\r\n');
+        fprintf(fid,'    \r\n');
+        fprintf(fid,'    ALAG1 = Tlaginput1\r\n');
+        fprintf(fid,'\r\n');
+        fprintf(fid,'    S2 = %s\r\n',paramNamesADVAN{strmatchIQM('Vc',paramNamesODE,'exact')});
+        fprintf(fid,'\r\n');
+    end
+elseif absorptionModel == 2,
+    % No IV allowed. Parallel zero and first order absorption
+    if FLAG_IV == 1,
+        error('IV dosing and zero order absorption into central compartment with NONMEM not handled automatically.');
+    end
+    % CMT=2 dose is 0 order absorption
+    fprintf(fid,'; Dosing compartments info\r\n');
+    fprintf(fid,'    F1 = FACTOR_UNITS*Fabs1*(1-Frel0) ; Ad\r\n');
+    fprintf(fid,'    F2 = FACTOR_UNITS*Fabs0*Frel0     ; Ac\r\n');
+    fprintf(fid,'    \r\n');
+    fprintf(fid,'    ALAG1 = Tlaginput1\r\n');
+    fprintf(fid,'    ALAG2 = Tlaginput3\r\n');
+    fprintf(fid,'    \r\n');
+    fprintf(fid,'    D2 = Tk0input3\r\n');
+    fprintf(fid,'\r\n');
+    fprintf(fid,'    S2 = %s\r\n',paramNamesADVAN{strmatchIQM('Vc',paramNamesODE,'exact')});
+    fprintf(fid,'\r\n');
+elseif absorptionModel == 3,
+    % Sequential 0/1 order absorption
+    % Set ALAG1 to Tk0input3
+    % Additional IV administration not allowed
+    if FLAG_IV == 1,
+        error('IV dosing and zero order absorption into central compartment with NONMEM not handled automatically.');
+    end
+    fprintf(fid,'; Dosing compartments info\r\n');
+    fprintf(fid,'    F1 = FACTOR_UNITS*Fabs1*(1-Frel0) ; Ad\r\n');
+    fprintf(fid,'    F2 = FACTOR_UNITS*Fabs0*Frel0     ; Ac\r\n');
+    fprintf(fid,'    \r\n');
+    fprintf(fid,'    ALAG1 = Tk0input3\r\n');
+    fprintf(fid,'    ALAG2 = Tlaginput3\r\n');
+    fprintf(fid,'    \r\n');
+    fprintf(fid,'    D2 = Tk0input3\r\n');
+    fprintf(fid,'\r\n');
+    fprintf(fid,'    S2 = %s\r\n',paramNamesADVAN{strmatchIQM('Vc',paramNamesODE,'exact')});
+    fprintf(fid,'\r\n');
+else
+    error('Unknown absorption model.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $ERROR
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'$ERROR\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $ERROR - error models
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Define next index for THETA parameters
+if isempty(THETA_INDEX_BETA),
+    THETA_INDEX_NEXT = length(parameterNames)+1;
+else
+    THETA_INDEX_NEXT = max(THETA_INDEX_BETA)+1;
+end
+THETA_ERROR_MODELS_IX = [];
+THETA_ERROR_MODELS_NAME = {};
+THETA_ERROR_MODELS_VALUE = [];
+error_model = explodePCIQM(errorModels);
+
+output_parameters_project_info = {};
+
+% Check if BLOQ data is to be handled in the MODEL (M3 and M4 methods)
+CENS_tobehandled = 0;
+if ~isempty(strfind(data.dataHeaderIdent,',CENS')),
+    if ~isempty(find(dataCSV.CENS==1)),
+        CENS_tobehandled = 1;
+        if ~SILENT,
+            disp(' ');
+            disp('BLOQ - Handling in the NONMEM code:');
+            disp('===================================');
+            if M4,
+                disp('Using the M4 method.');
+            else
+                disp('Using the M3 method.');
+            end
+            disp(' ');
+        end
+    end
+end
+
+fprintf(fid,'; just to avoid a NONMEM warning\r\n');
+if CENS_tobehandled,
+    fprintf(fid,'    CUMD  = 0 ; only needed for M4 method\r\n');
+    fprintf(fid,'    CUMDZ = 0 ; only needed for M4 method\r\n');
+end
+fprintf(fid,'    Y     = 0.1\r\n\r\n');
+
+
+fprintf(fid,'; Error model\r\n');
+fprintf(fid,'    ; Get YTYPE information - always same for popPK workflow\r\n');
+fprintf(fid,'    IF(EVID.EQ.1) THEN\r\n');
+fprintf(fid,'        YTYPE = 0\r\n');
+fprintf(fid,'    ELSE\r\n');
+fprintf(fid,'        YTYPE = 1\r\n');
+fprintf(fid,'    ENDIF\r\n');
+fprintf(fid,'\r\n');
+
+fprintf(fid,'    IPRED  = F\r\n');
+fprintf(fid,'    IRES   = DV - IPRED\r\n');
+
+count = 1;
+if strcmp(lower(error_model{1}),'const'),
+    fprintf(fid,'    W      = THETA(%d)\r\n',THETA_INDEX_NEXT);
+    THETA_ERROR_MODELS_IX(end+1) = THETA_INDEX_NEXT;
+    THETA_ERROR_MODELS_NAME{end+1} = sprintf('Additive error');
+    THETA_ERROR_MODELS_VALUE(end+1) = errorParam0(count);
+    count = count + 1;
+    THETA_INDEX_NEXT = THETA_INDEX_NEXT+1;
+    output_parameters_project_info{end+1} = sprintf('error_ADD1');
+elseif strcmp(lower(error_model{1}),'prop'),
+    fprintf(fid,'    W      = THETA(%d)*IPRED\r\n',THETA_INDEX_NEXT);
+    THETA_ERROR_MODELS_IX(end+1) = THETA_INDEX_NEXT;
+    THETA_ERROR_MODELS_NAME{end+1} = sprintf('Proportional error');
+    THETA_ERROR_MODELS_VALUE(end+1) = errorParam0(count);
+    count = count + 1;
+    THETA_INDEX_NEXT = THETA_INDEX_NEXT+1;
+    output_parameters_project_info{end+1} = sprintf('error_PROP1');
+elseif strcmp(lower(error_model{1}),'comb1'),
+    fprintf(fid,'    W      = SQRT(THETA(%d)**2 + (THETA(%d)*IPRED)**2)\r\n',THETA_INDEX_NEXT,THETA_INDEX_NEXT+1);
+    THETA_ERROR_MODELS_IX(end+1) = THETA_INDEX_NEXT;
+    THETA_ERROR_MODELS_IX(end+1) = THETA_INDEX_NEXT+1;
+    THETA_ERROR_MODELS_NAME{end+1} = sprintf('Additive error');
+    THETA_ERROR_MODELS_NAME{end+1} = sprintf('Proportional error');
+    THETA_ERROR_MODELS_VALUE(end+1) = errorParam0(count);
+    count = count + 1;
+    THETA_ERROR_MODELS_VALUE(end+1) = errorParam0(count);
+    count = count + 1;
+    THETA_INDEX_NEXT = THETA_INDEX_NEXT+2;
+    output_parameters_project_info{end+1} = sprintf('error_ADD1');
+    output_parameters_project_info{end+1} = sprintf('error_PROP1');
+else
+    error('Unknown error model definition.');
+end
+fprintf(fid,'    IWRES  = IRES/W\r\n');
+
+% Handle different BLOQ methods if CENS column in dataset - only
+% handled if non zero elements present in CENS column
+% Reason: handling CENS=1 in M3 and M4 requires LAPLACIAN in the $EST
+% statement. To be avoided if not needed.
+
+if ~CENS_tobehandled,
+    % NO CENS column in the dataset (or no 1 entries in CENS) => just use standard
+    fprintf(fid,'    IF(YTYPE.EQ.1) THEN\r\n');
+    fprintf(fid,'        Y      = IPRED + W*ERR(1)\r\n');
+    fprintf(fid,'    ENDIF\r\n');
+else
+    % CENS column in the dataset
+    
+    % Handle uncensored values (CENS==0)
+    fprintf(fid,'    IF(YTYPE.EQ.1.AND.CENS.EQ.0) THEN\r\n');
+    fprintf(fid,'        ; Handle data above LLOQ\r\n');
+    fprintf(fid,'        F_FLAG = 0\r\n');
+    fprintf(fid,'        Y      = IPRED + W*ERR(1)\r\n');
+    fprintf(fid,'    ENDIF\r\n');
+    
+    % Handle censored BLOQ values (CENS==1) - assumption that LLOQ in DV
+    
+    if ~M4,
+        % M3 method
+        fprintf(fid,'    IF(YTYPE.EQ.1.AND.CENS.EQ.1) THEN\r\n');
+        fprintf(fid,'        ; Handle data below LLOQ (M3 method - assuming LLOQ in DV and CENS=1)\r\n');
+        fprintf(fid,'        F_FLAG = 1\r\n');
+        fprintf(fid,'        Y      = PHI((DV-IPRED)/W)\r\n');
+        fprintf(fid,'    ENDIF\r\n');
+    else
+        % M4 method
+        fprintf(fid,'    IF(YTYPE.EQ.1.AND.CENS.EQ.1) THEN\r\n');
+        fprintf(fid,'        ; Handle data below LLOQ (M4 method - assuming LLOQ in DV and CENS=1)\r\n');
+        fprintf(fid,'        F_FLAG = 1\r\n');
+        fprintf(fid,'        CUMD   = PHI((DV-IPRED)/W)\r\n');
+        fprintf(fid,'        CUMDZ  = PHI(-IPRED/W)\r\n');
+        fprintf(fid,'        Y      = (CUMD-CUMDZ)/(1-CUMDZ)\r\n');
+        fprintf(fid,'    ENDIF\r\n');
+    end
+end
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Assign variables to report in tables
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% ETAs:
+fprintf(fid,'; Assign variables to report in tables\r\n');
+for k=1:length(parameterNames),
+    fprintf(fid,'    ETA_%s%s = ETA(%d)\r\n',parameterNames{k},char(32*ones(1,cellmaxlengthIQM(parameterNames)-length(parameterNames{k})+1)),k);
+end
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $THETA for model parameters
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'$THETA\r\n');
+
+fprintf(fid,'; Model parameters\r\n');
+
+THETA_GUESS0_STRING = {};
+PARAM_TRANSNAME_STRING = {};
+PARAM_INVTRANSNAME_STRING = {};
+initialGuess_noTrans = [];
+for k=1:length(parameterNames),
+    initialGuess = POPvalues0(k);
+    initialGuess_noTrans(k) = POPvalues0(k);
+    if IIVdistribution{k} == 'N',
+        initialGuess = initialGuess;
+        if POPestimate(k),
+            if initialGuess == 0,
+                initialGuess = 0.01;
+            end
+        end
+        PARAM_INVTRANSNAME_STRING{k} = '(psi)';
+        PARAM_TRANSNAME_STRING{k} = '(phi)';
+    elseif IIVdistribution{k} == 'L';
+        initialGuess = log(initialGuess);
+        if POPestimate(k),
+            if initialGuess == 0,
+                initialGuess = 0.01;
+            end
+        end
+        PARAM_INVTRANSNAME_STRING{k} = 'log(psi)';
+        PARAM_TRANSNAME_STRING{k} = 'exp(phi)';
+    elseif IIVdistribution{k} == 'G',
+        initialGuess = log(initialGuess/(1-initialGuess));
+        if POPestimate(k),
+            if initialGuess == 0,
+                initialGuess = 0.01;
+            end
+        end
+        PARAM_INVTRANSNAME_STRING{k} = 'log(psi./(1-psi))';
+        PARAM_TRANSNAME_STRING{k} = 'exp(phi)./(1+exp(phi))';
+    else
+        error('Unknown parameter transformation.');
+    end
+    THETA_GUESS0_STRING{k} = sprintf('%1.3g',initialGuess);
+    % Check if parameter fixed or not
+    if POPestimate(k) == 0,
+        THETA_GUESS0_STRING{k} = [THETA_GUESS0_STRING{k} '  FIX'];
+    end
+end    
+
+for k=1:length(parameterNames),
+    texttext = strrep(PARAM_INVTRANSNAME_STRING{k},'psi',parameterNames{k});
+    fprintf(fid,'    %s%s ; %d %s (%1.3g)\r\n',THETA_GUESS0_STRING{k},char(32*ones(1,cellmaxlengthIQM(THETA_GUESS0_STRING)-length(THETA_GUESS0_STRING{k})+1)),k,texttext,initialGuess_noTrans(k));
+end
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $THETA for continuous covariate parameters
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+THETA_INDEX_BETA_cov = THETA_INDEX_BETA(cov_type_continuous==1);
+beta_parameters_cov  = beta_parameters(cov_type_continuous==1);
+
+if ~isempty(COVestimate) && ~isempty(THETA_INDEX_BETA_cov),
+    fprintf(fid,'; Continuous covariate model parameters\r\n');
+    count = 1;
+    for kparam=1:length(COVestimate),
+        for kcov=1:length(COVestimate{kparam}),
+            estimate = COVestimate{kparam}(kcov);
+            value    = covariateModelValues{kparam}(kcov);
+            cov      = covariateModel{kparam}{kcov+1};
+            if ismember(cov,covNames),
+                % Only handle if covariate member iof continuous covariates
+                index    = THETA_INDEX_BETA_cov(count);
+                param    = beta_parameters_cov{count};
+                count    = count+1;
+                if estimate,
+                    if value==0,
+                        value = 0.01;
+                    end
+                    fprintf(fid,'    %g ; %d %s\r\n',value,index,param);
+                else
+                    fprintf(fid,'    %g FIX ; %d %s\r\n',value,index,param);
+                end
+            end
+        end
+    end
+    fprintf(fid,'\r\n');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $THETA for categorical covariate parameters
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+THETA_INDEX_BETA_cat = THETA_INDEX_BETA(cov_type_continuous==0);
+beta_parameters_cat  = beta_parameters(cov_type_continuous==0);
+covcov_cat           = covcov(cov_type_continuous==0);
+covparam_cat         = covparam(cov_type_continuous==0);
+
+if ~isempty(COVestimate) &&  ~isempty(THETA_INDEX_BETA_cat),
+    fprintf(fid,'; Categorical covariate model parameters\r\n');
+    for k=1:length(THETA_INDEX_BETA_cat),
+        % Get parameter name
+        param = covparam_cat{k};
+        % Get covariate name
+        cov = covcov_cat{k};
+        
+        % Find index of parameter in covariateModel
+        covModelAllParam = {};
+        for k2=1:length(covariateModel),
+            covModelAllParam{end+1} = covariateModel{k2}{1};
+        end
+        ixparam = strmatchIQM(param,covModelAllParam,'exact');
+        
+        % Find index of cov in covariateModel{ixparam}
+        ixcov = strmatchIQM(cov,covariateModel{ixparam},'exact');
+        
+        % Is this covariate estimated?
+        estimate = COVestimate{ixparam}(ixcov-1);
+        % Which is the value
+        value = covariateModelValues{ixparam}(ixcov-1);
+        
+        % Write out
+        if estimate,
+            if value == 0,
+                value = 0.01;
+            end
+            fprintf(fid,'    %g ; %d %s\r\n',value,THETA_INDEX_BETA_cat(k),beta_parameters_cat{k});
+        else
+            fprintf(fid,'    %g FIX ; %d %s\r\n',value,THETA_INDEX_BETA_cat(k),beta_parameters_cat{k});
+        end
+    end
+    fprintf(fid,'\r\n');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $THETA for error model parameters
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; Error model parameters\r\n');
+for k=1:length(THETA_ERROR_MODELS_IX),
+    fprintf(fid,'    %g%s ; %d %s\r\n',THETA_ERROR_MODELS_VALUE(k),char(32*ones(1,cellmaxlengthIQM(THETA_GUESS0_STRING)-length('1')+1)),THETA_ERROR_MODELS_IX(k),THETA_ERROR_MODELS_NAME{k});
+end
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $OMEGA
+% Using standard deviations and correlations
+%
+% $OMEGA STANDARD CORRELATION BLOCK(2)
+% 0.8
+% -0.394 0.762
+%
+% or:
+% $OMEGA
+% 0.8 STANDARD
+% 0.5 STANDARD
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+	
+if strcmp(lower(covarianceModel),'diagonal') || isempty(covarianceModel),
+    fprintf(fid,'$OMEGA\r\n');
+    OMEGA_GUESS0_STRING = {};
+    for k=1:length(parameterNames),
+        if IIVestimate(k) == 0,
+            % Set IIV value to 0 and FIX
+            OMEGA_GUESS0_STRING{k} = sprintf('0 STANDARD FIX');
+        elseif IIVestimate(k) == 1,
+            value = IIVvalues0(k);
+            if value == 0,
+                value = 0.1;
+            end
+            % Set IIV value
+%             OMEGA_GUESS0_STRING{k} = sprintf('%1.2g',(value)^2); % Convert IIV values from STD to VAR
+            OMEGA_GUESS0_STRING{k} = sprintf('%1.2g STANDARD',value); % USE STD
+        elseif IIVestimate(k) == 2,
+            % Set IIV value and FIX
+%             OMEGA_GUESS0_STRING{k} = sprintf('%1.2g  FIX',(IIVvalues0(k))^2); % Convert IIV values from STD to VAR
+            OMEGA_GUESS0_STRING{k} = sprintf('%1.2g STANDARD FIX',IIVvalues0(k)); % Convert IIV values from STD to VAR
+        end
+    end
+    for k=1:length(parameterNames),
+        fprintf(fid,'    %s%s ; %d %s\r\n',OMEGA_GUESS0_STRING{k},char(32*ones(1,cellmaxlengthIQM(OMEGA_GUESS0_STRING)-length(OMEGA_GUESS0_STRING{k})+1)),k,parameterNames{k});
+    end
+else
+    % Handle the covariances ... block by block
+    terms = explodePCIQM(covarianceModel,',','{','}');
+    for k=1:length(terms),
+        block = terms{k};
+        block = strrep(block,'{','');
+        block = strrep(block,'}','');
+        block = explodePCIQM(block);
+        ix_parameters = [];
+        for k2=1:length(block),
+            ix_parameters(end+1) = strmatchIQM(block{k2},parameterNames,'exact');
+        end
+        % Need to reorder each block to match the order of the parameters
+        % in param_est.name. It already has been made sure that they are
+        % sequential.
+        ix_parameters_ordered = sort(ix_parameters,'ascend');
+        % Construct the block text
+        blockText = sprintf('$OMEGA STANDARD CORRELATION BLOCK(%d)\r\n',length(block));
+        blockMatrix = 0.1*ones(length(ix_parameters_ordered));
+        for k=1:length(ix_parameters_ordered),
+            value = IIVvalues0(ix_parameters_ordered(k));
+            if value == 0,
+                value = 0.1;
+            end
+            blockMatrix(k,k) = value; % No need to convert, since in STD
+        end
+        for krow=1:length(block),
+            for kcol=1:krow,
+                blockText = sprintf('%s    %1.2g',blockText,blockMatrix(krow,kcol));
+            end
+            blockText = sprintf('%s    ; %d %s',blockText,ix_parameters_ordered(krow),parameterNames{ix_parameters_ordered(krow)});
+            blockText = sprintf('%s\r\n',blockText);
+        end
+        fprintf(fid,'%s\r\n',blockText);
+    end
+    
+    % Finally find the parameters that have not been handled yet by the
+    % block things ...
+    x = strrep(covarianceModel,'{','');
+    x = strrep(x,'}','');
+    terms = explodePCIQM(x);
+    missingParam = setdiff(parameterNames,terms);
+    % These are not in the right order ...
+    ix_parameters = [];
+    for k2=1:length(missingParam),
+        ix_parameters(end+1) = strmatchIQM(missingParam{k2},parameterNames,'exact');
+    end
+    % Need to reorder according to their appearance in the model
+    % It already has been made sure that they are sequential.
+    ix_parameters_ordered = sort(ix_parameters,'ascend');
+    
+    if ~isempty(missingParam),
+        fprintf(fid,'$OMEGA\r\n');
+    end
+    OMEGA_GUESS0_STRING = {};
+    for k=1:length(missingParam),
+        if IIVestimate(ix_parameters_ordered(k)) == 0,
+            % Set IIV value to 0 and FIX
+            OMEGA_GUESS0_STRING{k} = sprintf('0 STANDARD FIX');
+        elseif IIVestimate(ix_parameters_ordered(k)) == 1,
+            value = IIVvalues0(ix_parameters_ordered(k));
+            if value == 0,
+                value = 0.1;
+            end
+            % Set IIV value
+            OMEGA_GUESS0_STRING{k} = sprintf('%1.2g STANDARD',value); % Need to convert from STD to VAR
+        elseif IIVestimate(ix_parameters_ordered(k)) == 2,
+            % Set IIV value and FIX
+            OMEGA_GUESS0_STRING{k} = sprintf('%1.2g STANDARD FIX',IIVvalues0(ix_parameters_ordered(k))); % Need to convert from STD to VAR
+        end
+    end    
+    for k=1:length(missingParam),
+        fprintf(fid,'    %s%s ; %d %s\r\n',OMEGA_GUESS0_STRING{k},char(32*ones(1,cellmaxlengthIQM(OMEGA_GUESS0_STRING)-length(OMEGA_GUESS0_STRING{k})+1)),ix_parameters_ordered(k),parameterNames{ix_parameters_ordered(k)});
+    end
+end
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $SIGMA
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'$SIGMA 1 FIX\r\n');
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $ESTIMATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Need to add 'LAPLACIAN NUMERICAL SLOW' as arguments for $EST definitions
+% with INTERACTION if M3 or M4 method handled (CENS_tobehandled=1).
+if CENS_tobehandled==1,
+    addTEXT_INTERACTION = 'LAPLACIAN NUMERICAL SLOW';
+else
+    addTEXT_INTERACTION = '';
+end
+
+% Check if ITS done as first method
+if ITS,
+    % ITS
+    if strcmp(upper(METHOD),'FO') || strcmp(upper(METHOD),'FOCE'),
+        text = sprintf('$ESTIMATION METHOD=ITS NOINTERACTION NOABORT NITER=%d SIGDIGITS=%d PRINT=%d\r\n',ITS_ITERATIONS,SIGDIGITS,PRINT);
+    else
+        text = sprintf('$ESTIMATION METHOD=ITS INTERACTION %s NOABORT NITER=%d SIGDIGITS=%d PRINT=%d\r\n',addTEXT_INTERACTION,ITS_ITERATIONS,SIGDIGITS,PRINT);
+    end
+    fprintf(fid,'%s\r\n',wrapRowTextIQM(text,80,12));
+end    
+
+% Then the "Main" Method
+if strcmp(upper(METHOD),'FO'),
+    % FO
+    text = sprintf('$ESTIMATION METHOD=ZERO NOINTERACTION NOABORT MAXEVAL=%d CTYPE=4 POSTHOC SIGDIGITS=%d PRINT=%d\r\n',MAXEVAL,SIGDIGITS,PRINT);
+    fprintf(fid,'%s\r\n',wrapRowTextIQM(text,80,12));
+elseif strcmp(upper(METHOD),'FOCE'),
+    % FOCE
+    text = sprintf('$ESTIMATION METHOD=CONDITIONAL NOINTERACTION NOABORT MAXEVAL=%d CTYPE=4 POSTHOC SIGDIGITS=%d PRINT=%d\r\n',MAXEVAL,SIGDIGITS,PRINT);
+    fprintf(fid,'%s\r\n',wrapRowTextIQM(text,80,12));
+elseif strcmp(upper(METHOD),'FOCEI'),
+    % FOCEI
+    text = sprintf('$ESTIMATION METHOD=CONDITIONAL INTERACTION %s NOABORT MAXEVAL=%d CTYPE=4 POSTHOC SIGDIGITS=%d PRINT=%d\r\n',addTEXT_INTERACTION,MAXEVAL,SIGDIGITS,PRINT);
+    fprintf(fid,'%s\r\n',wrapRowTextIQM(text,80,12));
+elseif strcmp(upper(METHOD),'SAEM'),
+    % SAEM
+    text = sprintf('$ESTIMATION METHOD=SAEM INTERACTION %s NOABORT NBURN=%d NITER=%d ISAMPLE=%d CONSTRAIN=1 CTYPE=0 SEED=%d POSTHOC SIGDIGITS=%d PRINT=%d\r\n',addTEXT_INTERACTION,K1,K2,NRCHAINS,SEED,SIGDIGITS,PRINT);
+    fprintf(fid,'%s\r\n',wrapRowTextIQM(text,80,12));
+else
+    error('Unknown estimation method.');
+end
+
+% Then check if importance sampling to be done for objective function evaluation
+if IMPORTANCESAMPLING,
+%     text = sprintf('$ESTIMATION METHOD=IMP NOABORT EONLY=1 ISAMPLE=1000 NITER=%d MAPITER=0 SIGDIGITS=%d PRINT=%d',IMP_ITERATIONS,SIGDIGITS,PRINT);
+    text = sprintf('$ESTIMATION METHOD=IMP INTERACTION %s NOABORT EONLY=1 ISAMPLE=1000 NITER=%d MAPITER=0 SIGDIGITS=%d PRINT=%d',addTEXT_INTERACTION,IMP_ITERATIONS,SIGDIGITS,PRINT);
+    fprintf(fid,'%s\r\n',wrapRowTextIQM(text,80,12));
+end
+
+fprintf(fid,'\r\n');
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $COVARIANCE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'$COVARIANCE UNCONDITIONAL MATRIX=S\r\n');
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Define FORMAT for all TABLEs
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORMAT = 's1PG15.6';
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $TABLE similar to predictions.txt in MONOLIX 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if strcmp(METHOD,'FO'),
+    text = sprintf('$TABLE ID TIME TIME2 YTYPE MDV EVID DV CENS IPRED IRES IWRES NPDE NPRED=XPRED  NRES=XRES  NWRES=XWRES  NOPRINT ONEHEADER NOAPPEND FILE=project.pred FORMAT=%s',FORMAT);
+elseif strcmp(METHOD,'FOCE'), 
+    text = sprintf('$TABLE ID TIME TIME2 YTYPE MDV EVID DV CENS IPRED IRES IWRES NPDE NPRED=XPRED  CRES=XRES  CWRES=XWRES  NOPRINT ONEHEADER NOAPPEND FILE=project.pred FORMAT=%s',FORMAT);
+elseif strcmp(METHOD,'FOCEI'),
+    text = sprintf('$TABLE ID TIME TIME2 YTYPE MDV EVID DV CENS IPRED IRES IWRES NPDE CPREDI=XPRED CRESI=XRES CWRESI=XWRES NOPRINT ONEHEADER NOAPPEND FILE=project.pred FORMAT=%s',FORMAT);
+elseif strcmp(METHOD,'SAEM'),
+    text = sprintf('$TABLE ID TIME TIME2 YTYPE MDV EVID DV CENS IPRED IRES IWRES NPDE EPRED=XPRED  ERES=XRES  EWRES=XWRES  NOPRINT ONEHEADER NOAPPEND FILE=project.pred FORMAT=%s ESAMPLE=1000 SEED=%d',FORMAT,SEED);
+else
+    error('Unknown method');
+end
+text = wrapRowTextIQM(text,80,7);
+% Print out table command
+fprintf(fid,'%s\r\n',text);
+fprintf(fid,'\r\n');
+  
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $TABLE similar to indiv_eta.txt in MONOLIX - include all covariates
+% in the dataset
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+text = 'ID';
+for k=1:length(parameterNames),
+    text = sprintf('%s ETA_%s',text,parameterNames{k});
+end
+% Add covariates
+for k=1:length(covNames),
+    text = sprintf('%s %s',text,covNames{k});
+end
+for k=1:length(catNames),
+    text = sprintf('%s %s',text,catNames{k});
+end
+% Create the full table command
+text = sprintf('$TABLE %s NOPRINT ONEHEADER FIRSTONLY NOAPPEND FILE=project.eta FORMAT=%s',text,FORMAT);
+text = wrapRowTextIQM(text,80,7);
+% Print out table command
+fprintf(fid,'%s\r\n',text);
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $TABLE similar to indiv_parameters.txt in MONOLIX - include all covariates
+% in the dataset - also include the regression parameters
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+text = 'ID';
+for k=1:length(parameterNames),
+    text = sprintf('%s %s',text,parameterNames{k});
+end
+% Add covariates
+for k=1:length(covNames),
+    text = sprintf('%s %s',text,covNames{k});
+end
+for k=1:length(catNames),
+    text = sprintf('%s %s',text,catNames{k});
+end
+% Create the full table command
+text = sprintf('$TABLE %s NOPRINT ONEHEADER FIRSTONLY NOAPPEND FILE=project.indiv FORMAT=%s',text,FORMAT);
+text = wrapRowTextIQM(text,80,7);
+% Print out table command
+fprintf(fid,'%s\r\n',text);
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Close file and change out of project path
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fclose(fid);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Construct PROJECT_HEADER_PLACEHOLDER information
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+PROJECT_INFO_TEXT = '';
+
+% Method
+METHOD_ALL = METHOD;
+if ITS,
+    METHOD_ALL = ['ITS,' METHOD_ALL];
+end
+if IMPORTANCESAMPLING,
+    METHOD_ALL = [METHOD_ALL ',IMP'];
+end
+METHOD_info = sprintf('; METHOD              = ''%s''\r\n',METHOD_ALL);
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,METHOD_info);
+
+% Data location
+DATA_info = sprintf('; DATA                = ''%s''\r\n',strrep(fullfile(dataRelPathFromProject,dataFileName),'\','/'));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,DATA_info);
+
+% DOSINGTYPES
+DOSINGTYPES = {'BOLUS' 'INFUSION' 'ABSORPTION0'};
+x = sprintf('%s,',DOSINGTYPES{:});
+DOSINGTYPES_info = sprintf('; DOSINGTYPES         = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,DOSINGTYPES_info);
+
+% covNames
+x = sprintf('%s,',covNames{:});
+COVNAMES_info = sprintf('; COVNAMES            = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,COVNAMES_info);
+
+% catNames
+x = sprintf('%s,',catNames{:});
+CATNAMES_info = sprintf('; CATNAMES            = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,CATNAMES_info);
+
+% Regression parameters
+REGRESSNAMES_info = sprintf('; REGRESSIONNAMES     = ''''\r\n');
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,REGRESSNAMES_info);
+
+% Outputs
+OUTPUTS_info = sprintf('; OUTPUTS             = ''Cc''\r\n');
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,OUTPUTS_info);
+
+% Error models
+ERRORMODELS_info = sprintf('; ERRORMODELS         = ''%s''\r\n',errorModels);
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,ERRORMODELS_info);
+
+% ERRORNAMES
+x = sprintf('%s,',output_parameters_project_info{:});
+ERRORNAMES_info = sprintf('; ERRORNAMES          = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,ERRORNAMES_info);
+
+% PARAMNAMES
+x = sprintf('%s,',parameterNames{:});
+PARAMNAMES_info = sprintf('; PARAMNAMES          = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,PARAMNAMES_info);
+
+% PARAMTRANS
+x = sprintf('%s,',PARAM_TRANSNAME_STRING{:});
+PARAMTRANS_info = sprintf('; PARAMTRANS          = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,PARAMTRANS_info);
+
+% PARAMINVTRANS
+x = sprintf('%s,',PARAM_INVTRANSNAME_STRING{:});
+PARAMINVTRANS_info = sprintf('; PARAMINVTRANS       = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,PARAMINVTRANS_info);
+
+% COVARIATENAMES
+COVARIATENAMES = [covariateMedianNames,covariateCATNames];
+x = sprintf('%s,',COVARIATENAMES{:});
+COVARIATENAMES_info = sprintf('; COVARIATENAMES      = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,COVARIATENAMES_info);
+
+% COVARIATESUSED
+COVARIATESUSED = setdiff(explodePCIQM(strrep(strrep(options.covariateModel,'{',''),'}','')),parameterNames);
+x = sprintf('%s,',COVARIATESUSED{:});
+COVARIATESUSED_info = sprintf('; COVARIATESUSED      = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,COVARIATESUSED_info);
+
+% BETACOVNAMES
+x = sprintf('%s,',beta_parameters_cov_project_info{:});
+BETACOVNAMES_info = sprintf('; BETACOVNAMES        = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,BETACOVNAMES_info);
+
+% BETACOVTRANS
+x = sprintf('%s,',COV_transformation_info{:});
+BETACOVTRANS_info = sprintf('; BETACOVTRANS            = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,BETACOVTRANS_info);
+
+% BETACATNAMES
+x = sprintf('%s,',beta_parameters_cat_project_info{:});
+BETACATNAMES_info = sprintf('; BETACATNAMES        = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,BETACATNAMES_info);
+
+% BETACATREFERENCE
+x = ''; for k=1:length(CAT_reference_info), x=sprintf('%s%g,',x,CAT_reference_info{k}); end
+BETACATREFERENCE_info = sprintf('; BETACATREFERENCE    = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,BETACATREFERENCE_info);
+
+% BETACATCATEGORIES
+x = ''; 
+for k=1:length(CAT_categories_info), 
+    x = [x '['];
+    x2 = '';
+    x2 = sprintf('%d ',CAT_categories_info{k});
+    x = [x x2(1:end-1) '],'];
+end
+BETACATCATEGORIES_info = sprintf('; BETACATCATEGORIES   = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,BETACATCATEGORIES_info);
+
+% ALL THETANAMES
+x = [parameterNames beta_parameters output_parameters_project_info];
+y = sprintf('%s,',x{:});
+THETANAMES_info = sprintf('; THETANAMES          = ''%s''\r\n',y(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,THETANAMES_info);
+
+% THETAESTIMATE
+% Add theta for parameters
+PARAM_info = sprintf('%d,',POPestimate);
+% Add theta for covariates
+COVCAT_info = sprintf('%d,',COVCATestimate_info);
+if isempty(COVCATestimate_info),
+    COVCAT_info = [];
+end
+% Add theta for error models
+x = ones(1,length(output_parameters_project_info));
+ERROR_info = sprintf('%d,',x);
+% Combine
+ESTIMATE_info = strtrim([PARAM_info COVCAT_info ERROR_info]);
+% Create text
+THETAESTIMATE_info = sprintf('; THETAESTIMATE       = ''%s''\r\n',ESTIMATE_info(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,THETAESTIMATE_info);
+
+% ALL ETANAMES (should be same as PARAMNAMES)
+x = sprintf('omega(%s),',parameterNames{:});
+ETANAMES_info = sprintf('; ETANAMES            = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,ETANAMES_info);
+
+% ETAESTIMATE
+ETAESTIMATE = sprintf('%d,',IIVestimate); 
+ETAESTIMATE_info = sprintf('; ETAESTIMATE         = ''%s''\r\n',ETAESTIMATE(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,ETAESTIMATE_info);
+
+% ALL CORRNAMES 
+cov = explodePCIQM(covarianceModel,',','{','}');
+text = '';
+for k=1:length(cov),
+    covk = strrep(strrep(cov{k},'{',''),'}','');
+    covk = explodePCIQM(covk);
+    for k1=1:length(covk),
+        for k2=1:k1,
+            if k1~=k2,
+                text = sprintf('%scorr(%s,%s),',text,covk{k2},covk{k1});
+            end
+        end
+    end
+end
+CORR_info = sprintf('; CORRELATIONNAMES    = ''%s''\r\n',text(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,CORR_info);
+
+% CORRESTIMATE
+if ~isempty(text),
+    CORRestimate = ones(1,length(explodePCIQM(text(1:end-1))));
+    x = sprintf('%d,',CORRestimate); 
+    CORRESTIMATE_info = sprintf('; CORRESTIMATE        = ''%s''\r\n',x(1:end-1));
+else
+    CORRestimate = 0;
+    CORRESTIMATE_info = sprintf('; CORRESTIMATE        = ''''\r\n');
+end
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,CORRESTIMATE_info);
+
+% Get and store number of observations in the data
+% Remove MDV=1 records
+x = dataCSV(dataCSV.MDV==0,:);
+% Remove CMT>nrOUTPUTS or YTYPE>nrOUTPUT
+nrOUTPUTS = 1;
+x(x.YTYPE > nrOUTPUTS,:) = [];
+
+% Write out number of observations
+nOBS = height(x);
+NROBS_info = sprintf('; NROBSERVATIONS      = ''%d''\r\n',nOBS);
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,NROBS_info);
+
+% Determine the number of estimated parameters (THETA and ETA)
+NRPARAMETERS_ESTIMATED = sum(eval(['[' ESTIMATE_info(1:end-1) ']']))+sum(eval(['[' ETAESTIMATE(1:end-1) ']'])==1)+sum(CORRestimate);
+NRPARAMETERS_ESTIMATED_info = sprintf('; NRPARAM_ESTIMATED   = ''%d''\r\n',NRPARAMETERS_ESTIMATED);
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,NRPARAMETERS_ESTIMATED_info);
+
+% Info about residual names depending on the selected method
+RESIDUAL_NAMES_USED = sprintf('; RESIDUAL_NAMES_USED = ''XPRED,XRES,XWRES''\r\n');
+if strcmp(METHOD,'FO'),
+    RESIDUAL_NAMES_ORIG = sprintf('; RESIDUAL_NAMES_ORIG = ''NPRED,NRES,NWRES''\r\n');
+elseif strcmp(METHOD,'FOCE'), 
+    RESIDUAL_NAMES_ORIG = sprintf('; RESIDUAL_NAMES_ORIG = ''NPRED,CRES,CWRES''\r\n');
+elseif strcmp(METHOD,'FOCEI'),
+    RESIDUAL_NAMES_ORIG = sprintf('; RESIDUAL_NAMES_ORIG = ''CPREDI,CRESI,CWRESI''\r\n');
+elseif strcmp(METHOD,'SAEM'),
+    RESIDUAL_NAMES_ORIG = sprintf('; RESIDUAL_NAMES_ORIG = ''EPRED,ERES,EWRES''\r\n');
+end
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,RESIDUAL_NAMES_USED);
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,RESIDUAL_NAMES_ORIG);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Replace PROJECT_HEADER_PLACEHOLDER
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+content = fileread('project.nmctl');
+content = strrep(content,'PROJECT_HEADER_PLACEHOLDER',strtrim(PROJECT_INFO_TEXT));
+x = [parameterNames beta_parameters output_parameters_project_info]; % get theta names
+content = strrep(content,'$SIZES LTH=XXX',sprintf('$SIZES LTH=%d',length(x)));
+fid = fopen('project.nmctl','w');
+fprintf(fid,'%s',content);
+fclose(fid);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Go back to old path
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+cd(oldpath);
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/auxiliary/isSequentialAbsorptionPopPKIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/auxiliary/isSequentialAbsorptionPopPKIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..4e643db931773f029bda4651432574ef95b14908
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/auxiliary/isSequentialAbsorptionPopPKIQM.m	
@@ -0,0 +1,57 @@
+function [sequentialAbsorption] = isSequentialAbsorptionPopPKIQM(NLMEproject)
+% This function checks the contents of an NLME project and returns information
+% if sequential or parallel mixed order absorption was used. This is
+% important for a number of simulation scenarios. Can only be done for
+% models that have been generated using the popPK workflow in IQM tools. If
+% not determinable "unknown" is returned.
+%
+% [SYNTAX]
+% [sequentialAbsorption] = isSequentialAbsorptionPopPKIQM(NLMEproject)
+%
+% [INPUT]
+% NLMEproject:      String with the name of the NLME project folder for
+%                   which to generate this VPC. 
+%                   Needs to include the absolute or relative path to the
+%                   folder. 
+%
+% [OUTPUT]
+% sequentialAbsorption:   0 if other or undeterminable
+%                         1 if yes
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Set default output value
+sequentialAbsorption = 0;
+
+% Save old path and change into project folder
+oldpath = pwd;
+cd(NLMEproject);
+
+% Handle MONOLIX 
+if isMONOLIXprojectIQM('.'),
+    % If analytic model template_popPK_model_ANALYTIC_SEQ01ABS_MLXTRAN.txt present
+    x = dir('template_popPK_model_ANALYTIC_SEQ01ABS_MLXTRAN.txt');
+    if ~isempty(x),
+        sequentialAbsorption = 1;
+    end
+    % If ODE and "Tlaginput1 = Tk0input3" present in model_MLXTRAN.txt
+    x = dir('model_MLXTRAN.txt');
+    if ~isempty(x),
+        content = fileread('model_MLXTRAN.txt');
+        if ~isempty(strfind(content,'Tlaginput1 = Tk0input3')),
+            sequentialAbsorption = 1;
+        end
+    end
+end
+
+% Handle NONMEM
+if isNONMEMprojectIQM('.'),
+    % If text "ALAG1 = Tk0input3" present in model then it is sequential
+    content = fileread('project.nmctl');
+    if ~isempty(strfind(content,'ALAG1 = Tk0input3')),        
+        sequentialAbsorption = 1;
+    end
+end
+
+% Change to oldpath back
+cd(oldpath);
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/auxiliary/templateModels/template_popPK_dosing.dos b/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/auxiliary/templateModels/template_popPK_dosing.dos
new file mode 100644
index 0000000000000000000000000000000000000000..1ce5321ff3fa4d4f928ecfa6dbabc70278ef9c5e
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/auxiliary/templateModels/template_popPK_dosing.dos	
@@ -0,0 +1,30 @@
+********** DOSING NAME
+template_dosing
+
+********** DOSING NOTES
+This is a template dosing scheme for popPK analysis.
+
+INPUT1: Bolus into 1st order absorption dosing compartment
+INPUT2: INFUSION or BOLUS into central comparment (Tinf)
+INPUT3: 0 order absorption into central compartment
+
+Non-sequential absorption models.
+
+********** INPUT1
+type:   BOLUS
+time:   0            % time for first application or all applications (scalar or vector)
+D:      0            % dose (scalar or vector)
+Tlag:   1            % <estimate> lag time for input application
+
+********** INPUT2
+type:   INFUSION
+time:   0            % time for first application or all applications (scalar or vector)
+D:      0            % dose (scalar or vector)
+Tinf:   1            % Infusion rate (required)
+
+********** INPUT3
+type:   ABSORPTION0
+time:   0            % time for first application or all applications (scalar or vector)
+D:      0            % dose (scalar or vector)
+Tk0:    1            % <estimate> Absorption duration (required)
+Tlag:   1            % <estimate> lag time for input application
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/auxiliary/templateModels/template_popPK_dosing_SEQ01ABS.dos b/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/auxiliary/templateModels/template_popPK_dosing_SEQ01ABS.dos
new file mode 100644
index 0000000000000000000000000000000000000000..40685f1b5ab1b804c2dd911cdf3c37b928d5ff21
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/auxiliary/templateModels/template_popPK_dosing_SEQ01ABS.dos	
@@ -0,0 +1,31 @@
+********** DOSING NAME
+template_dosing
+
+********** DOSING NOTES
+This is a template dosing scheme for popPK analysis.
+
+INPUT1: Bolus into 1st order absorption dosing compartment
+INPUT2: INFUSION or BOLUS into central comparment (Tinf)
+INPUT3: 0 order absorption into central compartment
+
+Sequential absorption model (Tlaginput1 = Tk0input3), leading to first 0 order
+absorption, followed by 1st order absorption.
+
+********** INPUT1
+type:   BOLUS
+time:   0            % time for first application or all applications (scalar or vector)
+D:      0            % dose (scalar or vector)
+Tlag:   Tk0input3    % for sequential 0/1 order absorption
+
+********** INPUT2
+type:   INFUSION
+time:   0            % time for first application or all applications (scalar or vector)
+D:      0            % dose (scalar or vector)
+Tinf:   1            % Infusion rate (required)
+
+********** INPUT3
+type:   ABSORPTION0
+time:   0            % time for first application or all applications (scalar or vector)
+D:      0            % dose (scalar or vector)
+Tk0:    1            % <estimate> Absorption duration (required)
+Tlag:   1            % <estimate> lag time for input application
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/auxiliary/templateModels/template_popPK_model.txt b/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/auxiliary/templateModels/template_popPK_model.txt
new file mode 100644
index 0000000000000000000000000000000000000000..7bfea2ae271c8ffe2db42c49e1c0fdb712ac152d
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/auxiliary/templateModels/template_popPK_model.txt	
@@ -0,0 +1,86 @@
+********** MODEL NAME
+template_basemodel
+
+********** MODEL NOTES
+This is a template for a popPK basemodel.
+
+Features
+========
+- Central compartment Ac
+- 2 peripheral compartments Ap1 and Ap2
+- Linear clearance from central compartment
+- Saturable (Michaelis-Menten) clearance from central compartment
+- Linear distribution between central and peripheral compartments
+- Allowing for 2 differnt inputs
+	    - INPUT1: first order absorption into central compartment
+	    - INPUT2: bolus/infusion into central compartment
+        - INPUT3: zero order absorption into central compartment
+
+Limitation
+==========
+    
+Units:
+======
+- No assumption is made regarding the time units
+- Units of INPUT dose and OUTPUT concentration need to match or be 
+  adjusted by FACTOR_UNITS 
+
+********** MODEL STATES
+
+% Dosing compartment for first order absorption
+d/dt(Ad)    = -ka*Ad + FACTOR_UNITS*Fabs1*(1-Frel0)*INPUT1
+
+% Central compartment
+d/dt(Ac)    = +ka*Ad - CL/Vc*Ac - (VMAX*Ac/Vc)/(KM+Ac/Vc) - Q1/Vc*Ac + Q1/Vp1*Ap1 - Q2/Vc*Ac + Q2/Vp2*Ap2 + FACTOR_UNITS*Fiv*INPUT2 + FACTOR_UNITS*Fabs0*Frel0*INPUT3  
+
+% First peripheral compartment
+d/dt(Ap1)   =                                             + Q1/Vc*Ac - Q1/Vp1*Ap1 
+
+% Second peripheral compartment
+d/dt(Ap2)   =                                                                     + Q2/Vc*Ac - Q2/Vp2*Ap2
+
+********** MODEL PARAMETERS
+
+% Linear components
+FACTOR_UNITS = 1
+
+CL           = 0     % <estimate>   
+Vc           = 1     % <estimate>             
+Q1           = 0     % <estimate>   
+Vp1          = 1     % <estimate>   
+Q2           = 0     % <estimate>   
+Vp2          = 1     % <estimate>   
+
+Fiv          = 1     % <estimate>   
+
+% 1st order absorption param (except lag time - defined in dosing)
+Fabs1        = 1     % <estimate>   
+ka           = 1     % <estimate>   
+
+% 0 order absorption param (except lag time and duration - defined in dosing)
+Frel0        = 0     % <estimate> Fraction of dose going in as 0 order absorption
+Fabs0        = 1     % <estimate>   
+
+% Saturable elimination
+VMAX         = 0     % <estimate>   
+KM           = 1     % <estimate>   
+
+********** MODEL VARIABLES
+
+% Determine concentration in dataset units
+Cc          = Ac/Vc 
+
+% Set output variable for Monolix
+OUTPUT1     = Cc
+
+********** MODEL REACTIONS
+
+
+********** MODEL FUNCTIONS
+
+
+********** MODEL EVENTS
+
+
+********** MODEL MATLAB FUNCTIONS
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/auxiliary/templateModels/template_popPK_model_ANALYTIC_MLXTRAN.txt b/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/auxiliary/templateModels/template_popPK_model_ANALYTIC_MLXTRAN.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ca719b0c093b845057955264201fd35ea1627693
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/auxiliary/templateModels/template_popPK_model_ANALYTIC_MLXTRAN.txt	
@@ -0,0 +1,61 @@
+; =============================================
+DESCRIPTION: template_basemodel
+; =============================================
+	This is a template for a popPK basemodel. ANALYTIC version.
+	
+	Features
+	========
+	- Central compartment Ac
+	- 2 peripheral compartments Ap1 and Ap2
+	- Linear clearance from central compartment
+	- Linear distribution between central and peripheral compartments
+	- Allowing for 2 differnt inputs
+	    - INPUT1: first order absorption into central compartment
+	    - INPUT2: bolus/infusion into central compartment
+        - INPUT3: zero order absorption into central compartment
+	
+	Limitation
+	==========
+	    
+	Units:
+	======
+	- No assumption is made regarding the the units
+	- Units of INPUT dose and OUTPUT concentration need to match or be 
+	  adjusted by FACTOR_UNITS
+
+; =============================================
+INPUT:
+; =============================================
+	parameter = {CL, Vc, Q1, Vp1, Q2, Vp2, Fiv, Fabs1, ka, Tlaginput1, Fabs0, Tk0input3, Tlaginput3,Frel0}
+
+; =============================================
+PK:
+; =============================================
+	FACTOR_UNITS = 1
+	compartment(cmt=1, amount=Ac)
+	compartment(cmt=2, amount=Ap1)
+	compartment(cmt=3, amount=Ap2)
+	oral(adm=1, cmt=1, ka, p=FACTOR_UNITS*Fabs1*(1-Frel0), Tlag=Tlaginput1)
+	iv(adm=2, cmt=1, p=FACTOR_UNITS*Fiv)
+	absorption(adm=3, cmt=1, Tk0=Tk0input3, p=FACTOR_UNITS*Fabs0*Frel0, Tlag=Tlaginput3)
+
+	; Transfer between compartments
+    
+	; Ac<->Ap1
+	transfer(from=1, to=2, kt=Q1/Vc)
+    	transfer(from=2, to=1, kt=Q1/Vp1)
+	
+	; Ac<->Ap2
+	transfer(from=1, to=3, kt=Q2/Vc)
+    	transfer(from=3, to=1, kt=Q2/Vp2)
+
+	; Clearance
+	elimination(cmt=1, k=CL/Vc)
+    
+	; Calculate concentration
+	Cc = Ac/Vc
+
+; =============================================
+OUTPUT:
+; =============================================
+	output = {Cc}
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/auxiliary/templateModels/template_popPK_model_ANALYTIC_SEQ01ABS_MLXTRAN.txt b/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/auxiliary/templateModels/template_popPK_model_ANALYTIC_SEQ01ABS_MLXTRAN.txt
new file mode 100644
index 0000000000000000000000000000000000000000..7eb511c0e598a1cd3071ceb6700f5ecbb39b7184
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/10-PopPKmodel/auxiliary/templateModels/template_popPK_model_ANALYTIC_SEQ01ABS_MLXTRAN.txt	
@@ -0,0 +1,63 @@
+; =============================================
+DESCRIPTION: template_basemodel
+; =============================================
+	This is a template for a popPK basemodel. ANALYTIC version.
+	Specifically for the case of sequential 0th/1st order absorption with Tlaginput1 fixed to Tk0input3.
+	This means that Tlaginput1 should not be estimated with this template model.
+	
+	Features
+	========
+	- Central compartment Ac
+	- 2 peripheral compartments Ap1 and Ap2
+	- Linear clearance from central compartment
+	- Linear distribution between central and peripheral compartments
+	- Allowing for 2 differnt inputs
+	    - INPUT1: first order absorption into central compartment
+	    - INPUT2: bolus/infusion into central compartment
+        - INPUT3: zero order absorption into central compartment
+	
+	Limitation
+	==========
+	    
+	Units:
+	======
+	- No assumption is made regarding the the units
+	- Units of INPUT dose and OUTPUT concentration need to match or be 
+	  adjusted by FACTOR_UNITS
+
+; =============================================
+INPUT:
+; =============================================
+	parameter = {CL, Vc, Q1, Vp1, Q2, Vp2, Fiv, Fabs1, ka, Fabs0, Tk0input3, Tlaginput3,Frel0}
+
+; =============================================
+PK:
+; =============================================
+	FACTOR_UNITS = 1
+	compartment(cmt=1, amount=Ac)
+	compartment(cmt=2, amount=Ap1)
+	compartment(cmt=3, amount=Ap2)
+	oral(adm=1, cmt=1, ka, p=FACTOR_UNITS*Fabs1*(1-Frel0), Tlag=Tk0input3)
+	iv(adm=2, cmt=1, p=FACTOR_UNITS*Fiv)
+	absorption(adm=3, cmt=1, Tk0=Tk0input3, p=FACTOR_UNITS*Fabs0*Frel0, Tlag=Tlaginput3)
+
+	; Transfer between compartments
+    
+	; Ac<->Ap1
+	transfer(from=1, to=2, kt=Q1/Vc)
+    	transfer(from=2, to=1, kt=Q1/Vp1)
+	
+	; Ac<->Ap2
+	transfer(from=1, to=3, kt=Q2/Vc)
+    	transfer(from=3, to=1, kt=Q2/Vp2)
+
+	; Clearance
+	elimination(cmt=1, k=CL/Vc)
+    
+	; Calculate concentration
+	Cc = Ac/Vc
+
+; =============================================
+OUTPUT:
+; =============================================
+	output = {Cc}
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/11-PopPDmodel/IQMcleanPopPDdataWrapper.m b/IQMtools V1.2.2.2/IQMpro/tools/11-PopPDmodel/IQMcleanPopPDdataWrapper.m
new file mode 100644
index 0000000000000000000000000000000000000000..386e22067281c6397739924a294b6a00e8c87fcf
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/11-PopPDmodel/IQMcleanPopPDdataWrapper.m	
@@ -0,0 +1,134 @@
+function [dataCleaned] = IQMcleanPopPDdataWrapper(data,DOSENAME,OBSNAME,covNames,catNames,removeSUBJECT,removeREC,outputPath,catImputationValues)
+% This function is a wrapper for different cleaning functions for standard
+% popPD datasets. Standard here means single compound and single PD
+% readout.
+% 
+% The following "cleaning" functions are called in sequence:
+% 
+% 1) IQMcleanRemoveRecordsSUBJECTs - removes manually selected records and subjects
+%
+% 2) IQMselectDataEvents - keeps only selected dose and observation
+%
+% 3) IQMcleanRemoveIGNOREDrecords - removes ignored records by IGNORE column
+% 
+% 4) IQMcleanRemoveSubjectsNoObservations - removes subjects without PD observations
+% 
+% 5) IQMcleanRemoveZeroDoses - removes doses with 0 amount
+%
+% 6) IQMcleanImputeCovariates - imputes covariates - continuous to the median, categorical to 99 or to provided imputation values
+%
+% 7) Removes all observation records that are set to MDV=1
+% 
+% [SYNTAX]
+% [dataCleaned] = IQMcleanPopPDdataWrapper(data,DOSENAME,OBSNAME,covNames,catNames)
+% [dataCleaned] = IQMcleanPopPDdataWrapper(data,DOSENAME,OBSNAME,covNames,catNames,removeSUBJECT,removeREC)
+% [dataCleaned] = IQMcleanPopPDdataWrapper(data,DOSENAME,OBSNAME,covNames,catNames,removeSUBJECT,removeREC,outputPath)
+% [dataCleaned] = IQMcleanPopPDdataWrapper(data,DOSENAME,OBSNAME,covNames,catNames,removeSUBJECT,removeREC,outputPath,catImputationValues)
+%
+% [INPUT]
+% data:           Dataset in task specific dataset format.
+% DOSENAME:       String with the NAME of the dosing event to consider.
+% OBSNAME:        String with the NAME of the observation event to consider.
+% covNames:       Cell-array with names of continuous covariates
+% catNames:       Cell-array with names of categorical covariates
+% removeSUBJECT:  Cell-matrix with 2 columns. First column contains the
+%                 USUBJID identifiers of the subjects to be removed
+%                 from the dataset. The second column contains strings,
+%                 which define the reason why this subject is removed.
+%                 Default: {} - nothing removed.
+% removeREC:      Cell-matrix with 2 columns. First column contains the indices
+%                 of the records to be removed from the dataset. The second
+%                 column contains strings, which define the reason why this
+%                 record is removed. The indices correspond to the number
+%                 of the row in the dataset (-1 due to the header). These
+%                 indices are also displayed as IX# in the individual plots
+%                 when using the IQMexplorePDdataWrapper function.
+%                 Default: {} - nothing removed.
+% outputPath:     Path where to store the cleaning log files
+%                 Default: '../Output/DataCleaning/';
+% catImputationValues: Vector with values for imputation of categorical
+%                 covariates. If not provided "99" will be used for all
+%                 imputed categorical covariates. Vector needs same order
+%                 and number of elements as catNames. 
+%
+% [OUTPUT]
+% dataCleaned:    Cleaned dataset 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Handle variable input arguments
+if nargin<5 || nargin>9,
+    error('Incorrect number of input arguments.');
+end
+if nargin<6,
+    removeSUBJECT = {};
+end
+if nargin<7,
+    removeREC = {};
+end
+if nargin<8,
+    outputPath = '../Output/DataCleaning/';
+end
+if nargin<9,
+    catImputationValues = [];
+end
+
+% Handle cell thing
+if ischar(covNames),
+    covNames = {covNames};
+end
+if ischar(catNames),
+    catNames = {catNames};
+end
+
+% Handle cell thingy
+if ischar(OBSNAME),
+    OBSNAME = {OBSNAME};
+end
+% if length(OBSNAME) > 1,
+%     error('OBSNAME can only contain one NAME.');
+% end
+% OBSNAME = OBSNAME{1};
+
+if ischar(DOSENAME),
+    DOSENAME = {DOSENAME};
+end
+% if length(DOSENAME) > 1,
+%     error('DOSENAME can only contain one NAME.');
+% end
+% DOSENAME = DOSENAME{1};
+
+% Remove manually selected records and subjects (first thing to do to
+% ensure numbers for records are correct)
+filename = [outputPath '/01_Manually_Selected_Records_and_Subjects'];
+datax = IQMcleanRemoveRecordsSUBJECTs(data,removeSUBJECT,removeREC,filename);
+
+% Keep only selected dose and observation
+datax = IQMselectDataEvents(datax,[DOSENAME OBSNAME]); 
+
+% Remove ignored revcords by IGNORE column
+filename = [outputPath '/02_IGNORE_column'];
+datax = IQMcleanRemoveIGNOREDrecords(datax,filename);
+
+% Remove subjects without PD observations
+filename = [outputPath '/03_Subjects_without_observations'];
+datax = IQMcleanRemoveSubjectsNoObservations(datax,filename);
+
+% Remove doses with 0 amount
+filename = [outputPath '/04_Dose_Records_zero_amount'];
+datax = IQMcleanRemoveZeroDoses(datax,filename);
+
+% Covariate imputation
+filename = [outputPath '/05_Covariate_Imputation'];
+if isempty(catImputationValues),
+    catImputationValues = 99*ones(1,length(catNames));
+end
+datax = IQMcleanImputeCovariates(datax,covNames,catNames,catImputationValues,filename);
+
+% Remove all MDV=1 observation records
+datax(datax.MDV==1 & datax.EVID==0,:) = [];
+
+% Assign output
+dataCleaned = datax;
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/12-SimplifiedPopPKmodel/IQMsimplifiedPopPKcheckData.m b/IQMtools V1.2.2.2/IQMpro/tools/12-SimplifiedPopPKmodel/IQMsimplifiedPopPKcheckData.m
new file mode 100644
index 0000000000000000000000000000000000000000..0a0537d8a10ddc831f068e05cd8757efedf8c29e
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/12-SimplifiedPopPKmodel/IQMsimplifiedPopPKcheckData.m	
@@ -0,0 +1,103 @@
+function [simplifiedPopPKInfo] = IQMsimplifiedPopPKcheckData( outputPath, simplifiedPopPKInfo )
+% This function checks the data provided for the simplified popPK workflow
+% for consistency. In the MATLAB command window it will return information
+% about the findings.
+% Additionally, this function will generate the task dependent dataset for
+% the popPK analysis. Information about covariates and the path to the task
+% dependent dataset (exported to outputPath/Data/data_01_Task.csv) will be
+% added to this structure.  
+%
+% [SYNTAX]
+% [simplifiedPopPKInfo] = IQMsimplifiedPopPKcheckData( outputPath )
+% [simplifiedPopPKInfo] = IQMsimplifiedPopPKcheckData( outputPath, simplifiedPopPKInfo )
+%
+% [INPUT]
+% outputPath:           Path where to store all project information and
+%                       output, etc.
+% simplifiedPopPKInfo:  MATLAB structure with information about the project.
+%
+% If called without an input argument, the function will attempt to load
+% the required information from the mat file that should be stored in
+% simplifiedPopPKInfo.
+%
+% [OUTPUT]
+% simplifiedPopPKInfo: Same as input argument but with added fields:
+%
+%   simplifiedPopPKInfo.dataTaskPath:  string with path to task dataset
+%   simplifiedPopPKInfo.covNames:      cell-array with names of continuous
+%                                      covariates to consider in the analysis
+%   simplifiedPopPKInfo.catNames:      cell-array with names of categorical
+%                                      covariates to consider in the analysis
+%
+% If at least one of the required columns is not present an error will be
+% shown. Warnings might be shown for other detected things. No claim on
+% completeness of checks is done!
+%
+% The output argument is also stored as mat file in the outputPath folder,
+% allowing subsequent functions to be called without an output argument (or
+% with an optional one).
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Check if input argument is given
+if nargin==0,
+    error('Please provide at least the outputPath argument for the function.');
+elseif nargin==1,
+    % If not then attempt loading 
+    structurePath = [outputPath '/simplifiedPopPKInfo'];
+    load(structurePath);
+elseif nargin>2,
+    error('Incorrect number of input arguments.');
+end
+
+% Update outputPath field ....
+simplifiedPopPKInfo.outputPath = outputPath;
+
+% Check if required fields are defined
+try outputPath = simplifiedPopPKInfo.outputPath;    catch  error('The input argument does not contain the field "outputPath".');                                    end
+try dataPath   = simplifiedPopPKInfo.dataPath;      catch  error('The input argument does not contain the field "dataPath".');                                      end
+try nameDose   = simplifiedPopPKInfo.nameDose;      catch  error('The input argument does not contain the field "nameDose".');                                      end
+try namePK     = simplifiedPopPKInfo.namePK;        catch  error('The input argument does not contain the field "namePK".');                                        end
+try selectCOVS = simplifiedPopPKInfo.selectCOVS;    catch  error('The input argument does not contain the field "selectCOVS" - run IQMsimplifiedPopPKinit first.'); end
+try selectCATS = simplifiedPopPKInfo.selectCATS;    catch  error('The input argument does not contain the field "selectCATS" - run IQMsimplifiedPopPKinit first.'); end
+try covNames   = simplifiedPopPKInfo.covNames;      catch  error('The input argument does not contain the field "covNames" - run IQMsimplifiedPopPKinit first.');   end
+try catNames   = simplifiedPopPKInfo.catNames;      catch  error('The input argument does not contain the field "catNames" - run IQMsimplifiedPopPKinit first.');   end
+
+% Sanity check if general data format is correct
+dataGeneral = IQMcheckGeneralDataFormat(dataPath);
+
+% Generate covariate information
+% The "covariateInfoTimeIndependent" variable based on the user selected
+% covariates and the covNames and catNames variables that will have added
+% default covariates.
+covariateInfoTimeIndependent = {};
+for k=1:length(selectCOVS),
+    x = selectCOVS{k};
+    terms = explodePCIQM(x);
+    covariateInfoTimeIndependent{end+1,1} = terms{1};
+    covariateInfoTimeIndependent{end,2} = terms{2};
+    covNames{end+1} = terms{2};
+end
+for k=1:length(selectCATS),
+    x = selectCATS{k};
+    terms = explodePCIQM(x);
+    covariateInfoTimeIndependent{end+1,1} = terms{1};
+    covariateInfoTimeIndependent{end,2} = terms{2};
+    catNames{end+1} = terms{2};
+end
+   
+% Create the task dependent dataset
+dataTask = IQMconvertGeneral2TaskDataset(dataGeneral,nameDose,namePK,covariateInfoTimeIndependent);
+
+% Save the task dependent dataset in the output path
+dataTaskPath = [outputPath '/Data/data_01_Task.csv'];
+IQMexportCSVdataset(dataTask,dataTaskPath);
+
+% Add updated information to the simplifiedPopPKInfo structure
+simplifiedPopPKInfo.covNames        = unique(covNames);
+simplifiedPopPKInfo.catNames        = unique(catNames);
+simplifiedPopPKInfo.dataTaskPath    = dataTaskPath;
+
+% Save simplifiedPopPKInfo output structure in outputPath
+structurePath = [outputPath '/simplifiedPopPKInfo'];
+save(structurePath,'simplifiedPopPKInfo');
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/12-SimplifiedPopPKmodel/IQMsimplifiedPopPKexploreData.m b/IQMtools V1.2.2.2/IQMpro/tools/12-SimplifiedPopPKmodel/IQMsimplifiedPopPKexploreData.m
new file mode 100644
index 0000000000000000000000000000000000000000..c36b8464e5e4f0eda56763c7d1b6978a4226c3a7
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/12-SimplifiedPopPKmodel/IQMsimplifiedPopPKexploreData.m	
@@ -0,0 +1,63 @@
+function [simplifiedPopPKInfo] = IQMsimplifiedPopPKexploreData(outputPath, simplifiedPopPKInfo)
+% This function generates a number of graphical and statistical analyses
+% that everyone typically would like to see for PK data. The output of this
+% function is stored in the folder "outputPath"/Output/01_Data_Exploration.
+%
+% [SYNTAX]
+% [simplifiedPopPKInfo] = IQMsimplifiedPopPKexploreData( outputPath )
+% [simplifiedPopPKInfo] = IQMsimplifiedPopPKexploreData( outputPath, simplifiedPopPKInfo )
+%
+% [INPUT]
+% outputPath:           Path where to store all project information and
+%                       output, etc.
+% simplifiedPopPKInfo: MATLAB structure with information about the project.
+%
+% If called without an input argument, the function will attempt to load
+% the required information from the mat file that should be stored in
+% simplifiedPopPKInfo.
+%
+% [OUTPUT]
+% PDFs and text files are generated. Standard covariates are found automatically.
+% If desired, the user can define the covariates to use manually.
+%
+% The output argument is identical to the input argument ... no changes
+% made.
+%
+% The output argument is also stored as mat file in the outputPath folder,
+% allowing subsequent functions to be called without an output argument (or
+% with an optional one).
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Check if input argument is given
+if nargin==0,
+    error('Please provide at least the outputPath argument for the function.');
+elseif nargin==1,
+    % If not then attempt loading 
+    structurePath = [outputPath '/simplifiedPopPKInfo'];
+    load(structurePath);
+elseif nargin>2,
+    error('Incorrect number of input arguments.');
+end
+
+% Update outputPath field ....
+simplifiedPopPKInfo.outputPath = outputPath;
+
+% Check if required fields are defined
+try outputPath   = simplifiedPopPKInfo.outputPath;      catch  error('The input argument does not contain the field "outputPath".');                                            end
+try dataTaskPath = simplifiedPopPKInfo.dataTaskPath;    catch  error('The input argument does not contain the field "dataTaskPath" - Run IQMsimplifiedPopPKcheckData first.');  end
+try nameDose     = simplifiedPopPKInfo.nameDose;        catch  error('The input argument does not contain the field "nameDose".');                                              end
+try namePK       = simplifiedPopPKInfo.namePK;          catch  error('The input argument does not contain the field "namePK".');                                                end
+try covNames     = simplifiedPopPKInfo.covNames;        catch  error('The input argument does not contain the field "covNames" - run IQMsimplifiedPopPKinit first.');           end
+try catNames     = simplifiedPopPKInfo.catNames;        catch  error('The input argument does not contain the field "catNames" - run IQMsimplifiedPopPKinit first.');           end
+
+% Define the options (just the output folder)
+options             = [];
+options.outputPath  = [outputPath '/Output/01_Data_Exploration'];
+
+% Run the PopPK graphical plots
+IQMexplorePKdataWrapper(dataTaskPath,nameDose,namePK,covNames,catNames,options)
+
+% Save simplifiedPopPKInfo output structure in outputPath
+structurePath = [outputPath '/simplifiedPopPKInfo'];
+save(structurePath,'simplifiedPopPKInfo');
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/12-SimplifiedPopPKmodel/IQMsimplifiedPopPKgetNLMEdata.m b/IQMtools V1.2.2.2/IQMpro/tools/12-SimplifiedPopPKmodel/IQMsimplifiedPopPKgetNLMEdata.m
new file mode 100644
index 0000000000000000000000000000000000000000..fd5abd5ebe4fb1e6fe8d35c3358da5b47c00289f
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/12-SimplifiedPopPKmodel/IQMsimplifiedPopPKgetNLMEdata.m	
@@ -0,0 +1,80 @@
+function [simplifiedPopPKInfo] = IQMsimplifiedPopPKgetNLMEdata(outputPath, simplifiedPopPKInfo)
+% This function allows some cleaning of the dataset. It then converts the
+% cleaned dataset to an NLME dataset for the analysis with NONMEM and/or
+% MONOLIX and saves this dataset in the "outputPath"/Data folder as
+% "data_02_NLME.csv". Information about the cleaning are stored in
+% "outputPath"/Output/02_Data_Cleaning.
+%
+% [SYNTAX]
+% [simplifiedPopPKInfo] = IQMsimplifiedPopPKgetNLMEdata( outputPath )
+% [simplifiedPopPKInfo] = IQMsimplifiedPopPKgetNLMEdata( outputPath, simplifiedPopPKInfo )
+%
+% [INPUT]
+% outputPath:           Path where to store all project information and
+%                       output, etc.
+% simplifiedPopPKInfo: MATLAB structure with information about the project.
+%
+% If called without an input argument, the function will attempt to load
+% the required information from the mat file that should be stored in
+% simplifiedPopPKInfo.
+%
+% [OUTPUT]
+% PDFs and text files are generated. Standard covariates are found automatically.
+% If desired, the user can define the covariates to use manually.
+%
+% The output argument is also stored as mat file in the outputPath folder,
+% allowing subsequent functions to be called without an output argument (or
+% with an optional one).
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Check if input argument is given
+if nargin==0,
+    error('Please provide at least the outputPath argument for the function.');
+elseif nargin==1,
+    % If not then attempt loading 
+    structurePath = [outputPath '/simplifiedPopPKInfo'];
+    load(structurePath);
+elseif nargin>2,
+    error('Incorrect number of input arguments.');
+end
+
+% Update outputPath field ....
+simplifiedPopPKInfo.outputPath = outputPath;
+
+% Check if required fields are defined
+try outputPath      = simplifiedPopPKInfo.outputPath;      catch  error('The input argument does not contain the field "outputPath".');                                            end
+try dataTaskPath    = simplifiedPopPKInfo.dataTaskPath;    catch  error('The input argument does not contain the field "dataTaskPath" - Run IQMsimplifiedPopPKcheckData first.');  end
+try nameDose        = simplifiedPopPKInfo.nameDose;        catch  error('The input argument does not contain the field "nameDose".');                                              end
+try namePK          = simplifiedPopPKInfo.namePK;          catch  error('The input argument does not contain the field "namePK".');                                                end
+try covNames        = simplifiedPopPKInfo.covNames;        catch  error('The input argument does not contain the field "covNames" - run IQMsimplifiedPopPKinit first.');           end
+try catNames        = simplifiedPopPKInfo.catNames;        catch  error('The input argument does not contain the field "catNames" - run IQMsimplifiedPopPKinit first.');           end
+try BLOQmethod      = simplifiedPopPKInfo.BLOQmethod;      catch  BLOQmethod    = 0;        end
+try removeSUBJECT   = simplifiedPopPKInfo.removeSUBJECT;   catch  removeSUBJECT = {};       end
+try removeRECORD    = simplifiedPopPKInfo.removeRECORD;    catch  removeRECORD  = {};       end
+
+% Define default categorical covariate imputation values
+catImputationValues = 999*ones(size(catNames));
+
+% Define the options (just the output folder)
+pathCleaningResults = [outputPath '/Output/02_Data_Cleaning'];
+
+% Do the cleaning
+dataloaded          = IQMloadCSVdataset(dataTaskPath);
+dataCleaned         = IQMcleanPopPKdataWrapper(dataloaded,nameDose,namePK,covNames,catNames,removeSUBJECT,removeRECORD,pathCleaningResults,catImputationValues);
+
+% Handle BLOQ data
+dataCleanedBLOQ     = IQMhandleBLOQdata(dataCleaned,BLOQmethod,[outputPath '/Output/02_Data_Cleaning/07_BLOQ_handling']);
+
+% Export to NLME dataset
+dataNLMEpath        = [outputPath '/Data/data_02_NLME.csv'];
+dataNLME            = IQMconvertTask2NLMEdataset(dataCleanedBLOQ,nameDose,namePK,covNames,catNames,{},dataNLMEpath);
+dataheaderNLME      = IQMgetNLMEdataHeader(dataNLME,covNames,catNames);
+
+% Update simplifiedPopPKInfo structure with new information
+simplifiedPopPKInfo.dataNLMEpath    = dataNLMEpath;
+simplifiedPopPKInfo.dataheaderNLME  = dataheaderNLME;
+
+% Save simplifiedPopPKInfo output structure in outputPath
+structurePath = [outputPath '/simplifiedPopPKInfo'];
+save(structurePath,'simplifiedPopPKInfo');
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/12-SimplifiedPopPKmodel/IQMsimplifiedPopPKinit.m b/IQMtools V1.2.2.2/IQMpro/tools/12-SimplifiedPopPKmodel/IQMsimplifiedPopPKinit.m
new file mode 100644
index 0000000000000000000000000000000000000000..7770f6fd46777bf757e7bbe5976a7b770928513b
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/12-SimplifiedPopPKmodel/IQMsimplifiedPopPKinit.m	
@@ -0,0 +1,89 @@
+function [simplifiedPopPKInfo] = IQMsimplifiedPopPKinit( outputPath, simplifiedPopPKInfo )
+% This function checks the contents of "simplifiedPopPKInfo" and might add
+% additional information.
+%
+% [SYNTAX]
+% [simplifiedPopPKInfo] = IQMsimplifiedPopPKinit( outputPath, simplifiedPopPKInfo )
+%
+% [INPUT]
+% outputPath:           String with path where to store all project
+%                       information and output, etc.
+% simplifiedPopPKInfo: MATLAB structure with at least the following fields:
+%
+%   simplifiedPopPKInfo.outputPath: String with the path where to store the
+%                                   output of the analysis
+%   simplifiedPopPKInfo.dataPath:   String with the path to the dataset to
+%                                   use. This dataset has to be in the
+%                                   general dataset format. 
+%   simplifiedPopPKInfo.nameDose:   NAME of a dose record in the dataset
+%   simplifiedPopPKInfo.namePK:     NAME of a PK record in the dataset
+% 
+% Optionally, the following fields can be defined:
+%
+%   simplifiedPopPKInfo.selectCOVS: Selection of continuous covariates (see
+%                                   below). If field not present then no
+%                                   covariates will be considered. 
+%   simplifiedPopPKInfo.selectCATS: Selection of categorical covariates (see
+%                                   below). If field not present then no
+%                                   covariates will be considered. 
+%
+% The format of how covariates are selected is explained by an example
+% below. "{}" parentheses have to be put around. Inside these there are
+% 'NAME, covariateName' elements separated by commata. "NAME" is the entry
+% in the NAME column in the dataset for this covariate. "covariateName" is
+% a shorter name that is going to be used as column name in the NLME
+% modeling dataset.
+%
+% Examples: 
+%           selectCOVS = {'Weight,WT0','Age,AGE0'}
+%           selectCATS = {'Gender,SEX','Ethnicity,ETN'};
+%
+% [OUTPUT]
+% simplifiedPopPKInfo: Same as input argument but with potentially added
+%   information if optional fields were missing. Additionally, default
+%   covariates are going to be added that the user does not need to define
+%   (DOSE, STUDYN, TRT). 
+% This output argument is also stored as mat file in the outputPath folder,
+% allowing subsequent functions to be called without an output argument (or
+% with an optional one).
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+% Check if input argument is given
+if nargin~=2,
+    error('Incorrect number of input arguments.');
+end
+
+% Add outputPath to structure
+simplifiedPopPKInfo.outputPath = outputPath;
+
+% Check if required fields are defined
+try dataPath    = simplifiedPopPKInfo.dataPath;     catch error('Field "dataPath" not defined.');       end
+try nameDose    = simplifiedPopPKInfo.nameDose;     catch error('Field "nameDose" not defined.');       end
+try namePK      = simplifiedPopPKInfo.namePK;       catch error('Field "namePK" not defined.');         end
+
+% Handle optional fields
+try selectCOVS  = simplifiedPopPKInfo.selectCOVS;   catch simplifiedPopPKInfo.selectCOVS = {};          end
+try selectCATS  = simplifiedPopPKInfo.selectCATS;   catch simplifiedPopPKInfo.selectCATS = {};          end
+
+% Handle cell-array requirement for selectCOVS and selectCATS
+if ischar(simplifiedPopPKInfo.selectCOVS), simplifiedPopPKInfo.selectCOVS = {simplifiedPopPKInfo.selectCOVS}; end
+if ischar(simplifiedPopPKInfo.selectCATS), simplifiedPopPKInfo.selectCATS = {simplifiedPopPKInfo.selectCATS}; end
+
+% Add additional covariates to the information. These covariates are
+% generated automatically during the conversion from the general to the
+% task specific dataset.
+
+simplifiedPopPKInfo.covNames = {'DOSE'};
+simplifiedPopPKInfo.catNames = {'STUDYN','TRT'};
+
+% Remove outputPath folder to initialize project and create folder
+if exist(outputPath) == 7,
+    error('Output Path exists already! Please choose a different output path or remove the present.');
+end
+% try rmdir(outputPath,'s'); end
+mkdir(outputPath);
+
+% Save simplifiedPopPKInfo output structure in outputPath
+structurePath = [outputPath '/simplifiedPopPKInfo'];
+save(structurePath,'simplifiedPopPKInfo');
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/12-SimplifiedPopPKmodel/IQMsimplifiedPopPKmodel.m b/IQMtools V1.2.2.2/IQMpro/tools/12-SimplifiedPopPKmodel/IQMsimplifiedPopPKmodel.m
new file mode 100644
index 0000000000000000000000000000000000000000..196e53d919a36fff073315c52b4febe4868c4453
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/12-SimplifiedPopPKmodel/IQMsimplifiedPopPKmodel.m	
@@ -0,0 +1,350 @@
+function [] = IQMsimplifiedPopPKmodel(outputPath,nameSpace,modeltestUSER,options,buildModelsOnly)
+% This function allows to explore the popPK model space according to user
+% defined criteria. Reasonable defaults will be used to allow simpler
+% running of first PK models of interest.
+%
+% [SYNTAX]
+% [] = IQMsimplifiedPopPKmodel(outputPath)
+% [] = IQMsimplifiedPopPKmodel(outputPath,nameSpace,modeltestUSER)
+% [] = IQMsimplifiedPopPKmodel(outputPath,nameSpace,modeltestUSER,options)
+% [] = IQMsimplifiedPopPKmodel(outputPath,nameSpace,modeltestUSER,options,buildModelsOnly)
+%
+% [INPUT]
+% outputPath:           Path where to store all project information and
+%                       output, etc.
+% nameSpace:            Defining the folder in outputPath/Models where to
+%                       store the generated models - will be used only if
+%                       the initial guess part is not used.
+% modeltestUSER:        User defined popPK subspace to test. modeltestUSER is
+%                       defined exactly as modeltest for the function
+%                       IQMbuildPopPKModelSpace, so please have a look at
+%                       the help text of IQMbuildPopPKModelSpace. 
+% options:              User defined options for the algorithm
+%                       settings, etc.
+% buildModelsOnly:      =0: build and run models, =1: build models only
+%                       (default: 0)
+%
+% [OUTPUT]
+% Models are generated in the outputPath/Models folder. 
+% results: structure wirth relevant information about the tested models.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Load some settings
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SETUP_PATHS_TOOLS_IQMPRO
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle input arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin<1,
+    error('Please provide at least the outputPath argument for the function.');
+end
+
+if nargin<2,
+    nameSpace = '';
+end
+
+if nargin<3,
+    modeltestUSER = [];
+end
+
+if nargin<4,
+    options = [];
+end
+
+if nargin<5,
+    buildModelsOnly = 0;
+end
+
+if nargin>5,
+    error('Incorrect number of input arguments.');
+end
+
+% Load simplifiedPopPKInfo
+structurePath = [outputPath '/simplifiedPopPKInfo'];
+load(structurePath);
+simplifiedPopPKInfo.outputPath = outputPath;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Get information about project
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try outputPath      = simplifiedPopPKInfo.outputPath;      catch  error('The input argument does not contain the field "outputPath".');                                            end
+try dataNLMEpath    = simplifiedPopPKInfo.dataNLMEpath;    catch  error('The input argument does not contain the field "dataNLMEpath" - Run IQMsimplifiedPopPKgetNLMEdata first.');  end
+try dataheaderNLME  = simplifiedPopPKInfo.dataheaderNLME;  catch  error('The input argument does not contain the field "dataheaderNLME" - Run IQMsimplifiedPopPKgetNLMEdata first.');  end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Read out modeltestUSER -- and define default values if not user provided
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Required arguments for normal popPK workflow function IQMbuildPopPKModelSpace
+try numberCompartments      = modeltestUSER.numberCompartments;     catch, numberCompartments    = [1 2 3];         end
+try errorModels             = modeltestUSER.errorModels;            catch, errorModels           = {'comb1'};       end
+try errorParam0             = modeltestUSER.errorParam0;            catch, errorParam0           = [];              end % Default defined below  
+try saturableClearance      = modeltestUSER.saturableClearance;     catch, saturableClearance    = 0;               end      
+try FACTOR_UNITS            = modeltestUSER.FACTOR_UNITS;           catch, FACTOR_UNITS          = [];              end % Default defined below  
+try POPvalues0              = modeltestUSER.POPvalues0;             catch, POPvalues0            = [];              end % Default defined below       
+try POPestimate             = modeltestUSER.POPestimate;            catch, POPestimate           = [];              end % Default defined below       
+try IIVestimate             = modeltestUSER.IIVestimate;            catch, IIVestimate           = [];              end % Default defined below      
+
+% Optional arguments for normal popPK workflow function IQMbuildPopPKModelSpace
+try absorptionModel         = modeltestUSER.absorptionModel;        catch, absorptionModel       = 1;               end % First order only 
+try lagTime                 = modeltestUSER.lagTime;                catch, lagTime               = 0;               end % No lag time   
+try IIVvalues0              = modeltestUSER.IIVvalues0;             catch, IIVvalues0            = [];              end % Use normal default in IQMbuildPopPKModelSpace
+try covarianceModels        = modeltestUSER.covarianceModels;       catch, covarianceModels      = '';              end % Diagonal
+try covariateModels         = modeltestUSER.covariateModels;        catch, covariateModels       = '';              end % No covariates  
+try covariateModelValues    = modeltestUSER.covariateModelValues;   catch, covariateModelValues  = {};              end   
+try COVestimate             = modeltestUSER.COVestimate;            catch, COVestimate           = {};              end   
+try COVcentering.covs    	= modeltestUSER.COVcentering.covs;      catch, COVcentering.covs     = {};              end   
+try COVcentering.value      = modeltestUSER.COVcentering.values;    catch, COVcentering.value    = [];              end   
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Load dataNLME
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+dataNLME            = IQMloadCSVdataset(dataNLMEpath);
+
+% Update dataNLMEpath to match structure of popPK workflow
+[~,f,e] = fileparts(dataNLMEpath);
+dataNLMEpathChanged = ['../Data/' f e];
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Determine DEFAULT information
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Determine default nameSpace if not provided by user
+if isempty(nameSpace),
+    nameSpace = 'MODEL_01_BASE';
+end
+
+%% Determine NRCHAINS such that 100 subjects present
+Nsubjects           = length(unique(dataNLME.ID));
+NRCHAINS            = ceil(100/Nsubjects);
+
+%% Determine default for estimation of Fabs1, Fabs0, or Fiv 
+% Also determine default initial guesses for Fabs1, Fabs0
+EST_Fiv             = 0; % by default not estimated
+
+FLAG_IV_data        = ~isempty(find(dataNLME.ADM==2));
+FLAG_ABS_data       = ~isempty(find(dataNLME.ADM==1));
+
+if FLAG_ABS_data && FLAG_IV_data,
+    % If both data (IV and absorption) present then allow estimation of
+    % Fabs0 and Fabs1. Set initial guesses to 0.5 for each.
+    EST_Fabs01      = 1;
+    Fabs0           = 0.5;
+    Fabs1           = 0.5;
+else
+    % If not both type of data present then dissallow estimation of Fabs1
+    % and Fabs0 and set both to 1 as initial guess.
+    EST_Fabs01      = 0;
+    Fabs0           = 1;
+    Fabs1           = 1;
+end  
+
+%% Determine default value for additive error (very important ...)
+% Get values of data - 5% quantileIQM as starting guess for additive error
+ADD_ERROR_0         = quantileIQM(dataNLME.DV(dataNLME.EVID==0),0.05);
+if ADD_ERROR_0 == 0,
+    ADD_ERROR_0     = 1;
+end
+
+%% Define default initial guesses for error parameters
+% This is for an addprop model ....
+errorParam0 = [ADD_ERROR_0 0.3];
+
+%% Determine default FACTOR_UNITS based on unit definitions in the dataset
+% Only determine if not provided by the user
+if isempty(FACTOR_UNITS),
+    UNIT_DOSE           = unique(dataNLME.UNIT(dataNLME.YTYPE==0)); UNIT_DOSE = UNIT_DOSE{1};
+    UNIT_CONC           = unique(dataNLME.UNIT(dataNLME.YTYPE==1)); UNIT_CONC = UNIT_CONC{1};
+    if strcmp(lower(UNIT_DOSE),'mg') && strcmp(lower(UNIT_CONC),'ug/ml'),
+        FACTOR_UNITS    = 1;
+    elseif strcmp(lower(UNIT_DOSE),'ug') && strcmp(lower(UNIT_CONC),'ng/ml'),
+        FACTOR_UNITS    = 1;
+    elseif strcmp(lower(UNIT_DOSE),'mg') && strcmp(lower(UNIT_CONC),'ng/ml'),
+        FACTOR_UNITS    = 1000;
+    else
+        error('Incorrect definitions of dose and concentration units - please provide the FACTOR_UNITS parameter manually.');
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Read out options -- and define default values if not user provided
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try xx = options.parameterEstimationTool;               catch, options.parameterEstimationTool          = 'MONOLIX';                end %#ok<*NASGU>
+try xx = options.N_PROCESSORS_PAR;                      catch, options.N_PROCESSORS_PAR                 = getN_PROCESSORS_PARIQM;   end     
+try xx = options.N_PROCESSORS_SINGLE;                   catch, options.N_PROCESSORS_SINGLE              = 1;                        end
+try xx = options.algorithm.SEED;                        catch, options.algorithm.SEED                   = 123456;                   end
+try xx = options.algorithm.K1;                          catch, options.algorithm.K1                     = 500;                      end
+try xx = options.algorithm.K2;                          catch, options.algorithm.K2                     = 200;                      end
+try xx = options.algorithm.K1_AUTO;                     catch, options.algorithm.K1_AUTO                = 0;                        end
+try xx = options.algorithm.K2_AUTO;                     catch, options.algorithm.K2_AUTO                = 0;                        end
+try xx = options.algorithm.NRCHAINS;                    catch, options.algorithm.NRCHAINS               = NRCHAINS;                 end
+try xx = options.algorithm.METHOD;                      catch, options.algorithm.METHOD                 = 'SAEM';                   end
+try xx = options.algorithm.MAXEVAL;                     catch, options.algorithm.MAXEVAL                = 9999;                     end
+try xx = options.algorithm.SIGDIGITS;                   catch, options.algorithm.SIGDIGITS              = 3;                        end
+try xx = options.algorithm.PRINT;                       catch, options.algorithm.PRINT                  = 1;                        end
+try xx = options.algorithm.M4;                          catch, options.algorithm.M4                     = 0;                        end
+try xx = options.algorithm.ITS;                         catch, options.algorithm.ITS                    = 1;                        end
+try xx = options.algorithm.ITS_ITERATIONS;              catch, options.algorithm.ITS_ITERATIONS         = 10;                       end
+try xx = options.algorithm.IMPORTANCESAMPLING;          catch, options.algorithm.IMPORTANCESAMPLING     = 1;                        end
+try xx = options.algorithm.IMP_ITERATIONS;              catch, options.algorithm.IMP_ITERATIONS         = 10;                       end
+try xx = options.algorithm.LLsetting;                   catch, options.algorithm.LLsetting              = 'linearization';          end
+try xx = options.algorithm.FIMsetting;                  catch, options.algorithm.FIMsetting             = 'linearization';          end
+try xx = options.algorithm.INDIVparametersetting;       catch, options.algorithm.INDIVparametersetting  = 'conditionalMode';        end
+
+optionsModelSpace = [];
+try optionsModelSpace.buildModelsOnly   = options.buildModelsOnly;      catch, optionsModelSpace.buildModelsOnly    = 0;            end
+try optionsModelSpace.Ntests            = options.Ntests;               catch, optionsModelSpace.Ntests             = 1;            end
+try 
+    optionsModelSpace.std_noise_setting = options.std_noise_setting;    
+catch
+    if optionsModelSpace.Ntests == 1,
+        optionsModelSpace.std_noise_setting  = 0;
+    else
+        optionsModelSpace.std_noise_setting  = 0.5;
+    end
+end
+
+optionsModelSpace.buildModelsOnly = buildModelsOnly;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Determine modeltest structure for first model and run it 
+% Aimed at obtaining initial guesses. 
+%
+% Note: this model is only run in case that the user does not provide
+% initial guesses for POPvalues0. Or that this model has already been run
+% at least once ('../Models/MODEL_00_INITIAL_GUESSES') present.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Check if it has already been run
+try
+    RESULTS             = parseProjectFolderResultsIQM([outputPath '/Models/MODEL_00_INITIAL_GUESSES'],NLME_ORDER_CRITERION);
+    INIT_RUN_ALREADY    = 1;
+catch
+    INIT_RUN_ALREADY    = 0;
+end
+
+if isempty(POPvalues0),
+    if ~INIT_RUN_ALREADY,
+        % Run it to generate results ... if already run then no need to rerun
+        % Use one compartment, 1st order absorption no lag time, addprop error model
+        
+        modeltest                       = [];
+        modeltest.numberCompartments    = 1; % Do only use 1 compartment for this step
+        modeltest.errorModels           = 'comb1';
+        modeltest.errorParam0           = errorParam0;
+        modeltest.saturableClearance    = 0;
+        modeltest.FACTOR_UNITS          = FACTOR_UNITS;
+        
+        %                                   CL    Vc    Q1    Vp1    Q2    Vp2    Fiv      Fabs1        ka    TlagAbs1   Fabs0          Tk0   TlagAbs0   Frel0   VMAX   KM
+        modeltest.POPvalues0            = [ 5     10    5     100    5     100    1        Fabs1        0.5   0.5        Fabs0          0.5   0.5        0.5     10      10];
+        modeltest.POPestimate           = [ 1     1     1     1      1     1      EST_Fiv  EST_Fabs01   1     1          EST_Fabs01     1     1          1       1       1];
+        modeltest.IIVestimate           = [ 1     1     1     1      1     1      EST_Fiv  EST_Fabs01   1     1          EST_Fabs01     1     1          1       1       1];
+        
+        % Change into a folder to allow for popPK workflow tools to work
+        oldpath = pwd();
+        cd([outputPath '/Data']);
+        
+        % Create the PK model subspace and run the models
+        IQMbuildPopPKModelSpace('MODEL_00_INITIAL_GUESSES', modeltest, dataNLMEpathChanged, dataheaderNLME, options, optionsModelSpace);
+        
+        % Change out of path
+        cd(oldpath);
+    end
+    
+    % Read all results and sort by ranking criterion (NLME_ORDER_CRITERION)
+    RESULTS             = parseProjectFolderResultsIQM([outputPath '/Models/MODEL_00_INITIAL_GUESSES'],NLME_ORDER_CRITERION);
+    ranking_var         = sortrows([[1:length(RESULTS)]' [RESULTS.BIC]'],2);
+    RANKING             = ranking_var(:,1);
+    RESULTS_ORDERD      = RESULTS(RANKING);
+    % Read parameter results for best model to use as initial guesses for
+    % next run ... in this run only 1 compartment models have been tried to
+    % get good estimates for CL, Vc,
+    CL0                 =  RESULTS_ORDERD(1).rawParameterInfo.fixedEffects.values(1);
+    Vc0                 =  RESULTS_ORDERD(1).rawParameterInfo.fixedEffects.values(2);
+    Fabs10              =  RESULTS_ORDERD(1).rawParameterInfo.fixedEffects.values(8);
+    ka0                 =  RESULTS_ORDERD(1).rawParameterInfo.fixedEffects.values(9);
+    Tlag0               =  RESULTS_ORDERD(1).rawParameterInfo.fixedEffects.values(10);
+    try
+        VMAX0           =  RESULTS_ORDERD(1).rawParameterInfo.fixedEffects.values(15);
+        KM0             =  RESULTS_ORDERD(1).rawParameterInfo.fixedEffects.values(16);
+    catch
+        VMAX0           =  10;
+        KM0             =  10;
+    end
+    %                       CL    Vc    Q1    Vp1    Q2    Vp2    Fiv      Fabs1        ka    TlagAbs1   Fabs0      Tk0   TlagAbs0   Frel0   VMAX   KM
+    POPvalues0          = [ CL0   Vc0   CL0   10*Vc0 CL0   10*Vc0 1        Fabs10       ka0   0.5        Fabs10     0.5   0.5        0.5     VMAX0   KM0];
+    % Get starting guesses for error model parameters
+    errorParam0         = abs(RESULTS_ORDERD(1).rawParameterInfo.errorParameter.values);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Now define and run the models of interest ... previous step was only to 
+% obtain reasonable initial guesses ...
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+modeltest                       = [];
+
+modeltest.numberCompartments    = numberCompartments; 
+
+% Need to handle the errorParam0 thingy ...
+modeltest.errorModels           = errorModels;
+modeltest.errorParam0           = {};
+for k=1:length(errorModels),
+    if strcmp(errorModels{k},'const'),
+        modeltest.errorParam0{k} = errorParam0(1);
+    elseif strcmp(errorModels{k},'prop'),
+        modeltest.errorParam0{k} = errorParam0(2);
+    elseif strcmp(errorModels{k},'comb1'),
+        modeltest.errorParam0{k} = errorParam0;
+    else
+        error('Incorrect definition of an error model in modeltest.errorModels.');
+    end
+end
+
+modeltest.saturableClearance    = saturableClearance;
+modeltest.FACTOR_UNITS          = FACTOR_UNITS;
+
+%                                   CL    Vc    Q1    Vp1    Q2    Vp2    Fiv      Fabs1        ka    TlagAbs1   Fabs0          Tk0   TlagAbs0   Frel0   VMAX   KM
+modeltest.POPvalues0            = POPvalues0; % These are defined now either by user or by previous run
+
+if isempty(POPestimate),
+    modeltest.POPestimate       = [ 1     1     1     1      1     1      EST_Fiv  EST_Fabs01   1     1          EST_Fabs01     1     1          1       1       1];
+else
+    modeltest.POPestimate       = POPestimate;
+end
+
+if isempty(IIVestimate),
+    modeltest.IIVestimate       = [ 1     1     1     1      1     1      EST_Fiv  EST_Fabs01   1     1          EST_Fabs01     1     1          1       1       1];
+else
+    modeltest.IIVestimate       = IIVestimate;
+end
+
+modeltest.absorptionModel       = absorptionModel;
+modeltest.lagTime               = lagTime;
+modeltest.IIVvalues0            = IIVvalues0;      
+modeltest.covarianceModels      = covarianceModels;
+modeltest.covariateModels       = covariateModels; 
+modeltest.covariateModelValues  = covariateModelValues;
+modeltest.COVestimate           = COVestimate;
+modeltest.COVcentering.covs     = COVcentering.covs;
+modeltest.COVcentering.values   = COVcentering.value;
+
+% Run the models of interest
+oldpath = pwd();
+cd([outputPath '/Data']);
+IQMbuildPopPKModelSpace(nameSpace, modeltest, dataNLMEpathChanged, dataheaderNLME, options, optionsModelSpace);
+cd(oldpath);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Load and display results 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+oldpath = pwd();
+cd([outputPath '/Models/' nameSpace]);
+if exist('model_parameters.txt'),
+    edit model_parameters.txt
+end
+cd(oldpath);
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/14-GeneralLinearNLMEmodel/IQMcreateGeneralLinearNLMEproject.m b/IQMtools V1.2.2.2/IQMpro/tools/14-GeneralLinearNLMEmodel/IQMcreateGeneralLinearNLMEproject.m
new file mode 100644
index 0000000000000000000000000000000000000000..67eb170e2b6558bc74320a4ebf711365b55b33a0
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/14-GeneralLinearNLMEmodel/IQMcreateGeneralLinearNLMEproject.m	
@@ -0,0 +1,310 @@
+function [] = IQMcreateGeneralLinearNLMEproject(TOOL,modelinfo,modelinput,modeloutput,data,projectPath,options)
+% This function allows to generate a general linear model using NONMEM
+% (ADVAN5 or ADVAN7) or MONOLIX.
+%
+% "General Linear Model" means linear models without endogenous production
+% and without non-zero initial conditions. Maybe over time these
+% limitations canbe relaxed ... but not now ... Also, although linear
+% models are generated using MONOLIX/MLXTRAN ... they seem to be integrated
+% ... Lixoft support is not answering on this ...
+%
+% Handling the BLOQ Methods M3 and M4:  
+%   M3 or M4 method of BLOQ handling can be used. This requires a CENS
+%   column in the dataset (CENS=0 for >=LLOQ values, CENS=1 for <LLOQ
+%   values and DV=LLOQ in case of CENS=1 (just as in MONOLIX). Since M3 and
+%   M4 requires the use of "LAPLACIAN NUMERICAL SLOW" in the $EST
+%   statements with INTERACTION, the code for M3 or M4 is only added to the
+%   model if the CENS column has non-zero entries - meaning that the model
+%   in this case needs to be generated for each dataset to be run. M3 is
+%   the default method. M4 can be selected in the options by setting
+%   options.algorithm.M4 = 1.
+%
+% ASSUMPTIONS:
+% ============
+% - MU Referencing always used. 
+% - Continuous covariates are always log-transformed, independent
+%   of the distribution of the parameter on which they are added. Centering
+%   by the median (or user defined values) for the covariates. 
+% - Always untransformed categorical covariates. Several categories per
+%   covariate possible but all need to be numeric and integers.
+% - IIV correlation parameters always 0.1 at the initial guess.
+% - NONMEM: Selection of PRED,RES,WRES outputs dependent on the method that is used
+%   for estimation (in the tables renamed to: XPRED, XRES, XWRES):
+%       - PREDI RESI WRESI if FO
+%       - CPREDI, CRESI, CWRESI if FOCE
+%       - EPRED, ERES, EWRES if SAEM
+% - Default values for add and prop errors: 1 and 0.3
+% - Dataset can contain CMT or (ADM+YTYPE) columns. The output on the
+%   screen of this function will guide the user as to the needed values in
+%   these columns.
+%       - ADM+YTYPE but not CMT 
+%           - YTYPE defines number of output
+%           - ADM used as CMT column
+%
+%       - ADM+CMT but not YTYPE
+%           - YTYPE is inferred based on CMT for observation records (in $ERROR)
+%             But this means that CMT needs to follow the OUTPUTn numbering! 
+%           - CMT will be used as defined for selecting the dosing compartments
+%           - ADM is used to inform potential switchings for NONMEM parameters in the PK section
+%
+% [SYNTAX]
+% [] = IQMcreateGeneralLinearNLMEproject(TOOL,modelinfo,modelinput,modeloutput,data,projectPath)
+% [] = IQMcreateGeneralLinearNLMEproject(TOOL,modelinfo,modelinput,modeloutput,data,projectPath,options)
+%
+% [INPUT]
+% TOOL:                 'NONMEM' or 'MONOLIX'
+% modelinfo:            MATLAB structure with following fields:
+%   modelinfo.modelADVAN:                  'ADVAN5' or 'ADVAN7' (default: 'ADVAN7')
+%                                          Only used if NONMEM specified as TOOL
+%   modelinfo.nrCompartments:              Number of states/compartments in the model
+%   modelinfo.parameterNames:              Cell-array with names of parameters to be estimated
+%   modelinfo.parameterNamesGeneral:       Cell-array with parameter names of the general linear model to define
+%                                          all others will be kept on 0. 
+%                                          Syntax: 
+%                                               Rate parameter from compartment 1 to compartment 2 is: k1T2 
+%                                               Rate parameter from compartment 3 to compartment 2 is: k3T2 
+%                                               Elimination rate parameter from compartment 2 is: k2T0
+%   modelinfo.parameterExpressionsGeneral: Cell-array linking the parameters to be estimated to the parameters in 
+%                                          the general linear model in terms of expressions.
+%                                          Same order as parameterNamesGeneral. For example, if first element in 
+%                                          parameterNamesGeneral is 'k2T0' then first element here could be 'CL/Vc',
+%   EXAMPLE:
+%       modelinfo                               = [];
+%       modelinfo.nrCompartments                = 3;
+%       modelinfo.parameterNames                = {'ka' 'CL' 'V' 'FM' 'CLM' 'VM'};
+%       modelinfo.parameterNamesGeneral         = {'k1T2'   'k2T0'              'k2T3'       'k3T0'};
+%       modelinfo.parameterExpressionsGeneral   = {'ka'     'CL*(1-FM)/V'       'CL*FM/V'    'CLM/VM'};
+%
+%       This example realizes a PK model with first order absorption and a
+%       metabolite. Both parent and metabolite are described by a one
+%       compartment model.
+% 
+% modelinput:           Cell-array of cell-arrays. Each inner cell-array
+%                       describes one dosing input and links the data to the model.
+%                       First element: A name for the input.
+%                       Second element: Type of the administration (use
+%                         only 'BOLUS', 'INFUSION' or 'ADMINISTRATION0'
+%                       Third element: Number of the compartment to which
+%                         the dose should be added (match with CMT number in
+%                         dataset .... if ADM is used then ADM should be the 
+% 					      compartment number in the model).
+%                       Fourth element: String with text to write after
+%                         "F<<compartment number>>" ... this can be an
+%                         expression, allowing simple definition of nonlinear
+%                         bioavailability - can depend on covariates,
+%                         regression parameters etc.
+% 						Fifth element: String with expression (or single parameter)
+% 						  for lag time definition.
+% 						Sixth element: String with expression (or single parameter)
+% 						  for definition of 0 order absorption. In this case it
+% 					      would be good to set the "type" to "ABSORPTION0"
+%   EXAMPLE:
+%       modelinput  = { {'INPUT1', 'BOLUS', 1,'Fabs1'}  {'INPUT2', 'INFUSION', 2,'1', 'Tlag' 'Duration'} };
+% 
+%       This example realizes a bolus administration into the first
+%       compartment with F1=Fabs1. And an infusion into second compartment
+%       with F2=1. Note that the difference between bolus and infusion is
+%       only defined by the value in the RATE column: 0 is bolus, >1 is
+%       infusion. The distinction is only needed later when simulation in
+%       IQM Tools should be done (e.g. VPC).
+%
+% modeloutput:          Cell-array of cell-arrays. Each inner cell-array
+%                       describes one observation output and links the data
+%                       to the model. 
+%                       First element: A name for the output.
+%                       Second element: Number of the compartment in the model
+%                         which to use as output (scaled output). YTYPE is used 
+%                         to match to the order to the outputs.
+%                       Third element: String with scaling expression,
+%                         allowing to transform the output to the desired
+%                         units.
+%   EXAMPLE:
+%       modeloutput = { {'CP', 2,'V*495.45/1000000'} {'CM', 3,'VM*435.49/1000000'} };
+%
+%       This example defines an output 'CP' which is measured as the amount
+%       in the second compartment and scaled (divided) by the term
+%       V*495.45/1000000 to obtain concentrations in nmol/L. Similar with
+%       the second output - here measured in the third compartment and
+%       given the name "CM".
+% 
+% data:                 Structure with following fields:
+%   data.dataRelPathFromProject:    path to data file - relative to the
+%                                   projectPath folder.
+%   data.dataFileName:              data file filename
+%   data.dataHeaderIdent:           String with datafile header identifiers (example: 'ID,TIME,Y,MDV,EVID,AMT,TINF,ADM,YTYPE,COV,COV,CAT') 
+%
+% projectPath:          String with the path/foldername to which the project files are to be written (example: 'FIT_01' or 'Models/FITS/FIT_01') 
+%
+% options:              Structure with following fields (all optional with default settings):
+%   options.POPestimate:            Vector with 0 and 1 entries. 1 if pop parameter is estimated, 0 if not. Default or []: => all are estimated
+%   options.POPvalues0:             Vector with pop parameter initial values. Default or []: => all values 1 (does not really make sense)
+%   options.IIVdistribution:        Cell-array with information about parameter distribution. L (lognormal), N (normal), G (logit)
+%                                       Example: {'L' 'L' 'L' 'L' 'N' 'L' 'L' 'L'}. Default or {}: => use lognormal for all
+%   options.IIVestimate:            Vector with 0 and 1 entries. 1 if random effect is estimated, 0 if not. Default or []: => all are estimated
+%                                   0: IIV not estimated (IIVvalues0 not used) 
+%                                   1: IIV estimated (IIVvalues0 as starting guesses)
+%                                   2: IIV not estimated but fixed on IIVvalues0 value
+%   options.IIVvalues0:             Vector with random effect parameter
+%                                   initial values. Default or []: => all set to 0.5
+%                                   If IIV not estimated then defined initial guess not used but replaced by 0
+%   options.errorModels:            String with definition of residual error models, comma separated for each output.
+%                                   Possible values: const,prop,comb1. Example: 'comb1,prop', Default or '': => const for all outputs
+%   options.errorParam0:            Vector allowing to pass initial guesses for error model parameters. Same order as error models. 
+%                                   'const': a, 'prop': b, 'comb1': a,b
+%   options.covarianceModel:        Definition of covariance model. String with cell-array text inside, grouping the parameters to consider having 
+%                                   correlated random effects. Example: '{CL,Vc},{Q,Vp,KM}'. Default: 'diagonal'
+%   options.covariateModel:         Definition of covariate model. Cell-array. Each element is a sub-cell-array. First element in sub-cell-array is the 
+%                                   parameter to which to add the covariate, all following elements define the covariates as named in the dataset.
+%                                   Example: '{CL,BMI0}, {Fsubcut,WT0}, {Vc,SEX,BMI0}'. Default: '' => no covariates
+%                                   By default (and so far not changeable, the continuous covariates are all weighted by their median, determined from the dataset)
+%                                   >>>Covariates can be added to all parameters for which not both IIVestimate and POPestimate are 0.
+%   options.covariateModelValues:   Definition of covariate coefficients for the selected covariate model. 
+%                                   Syntax is similar to options.covariateModel. It is a cell-array containing vectors instead of cell-arrays.
+%                                   Each vector contains values for the covariate coefficients, matching the covariateModel definition order.
+%                                   Example: if options.covariateModel = '{CL,BMI0,AGE0}, {Fsubcut,WT0}, {Vc,SEX,BMI0}'
+%                                   Then: options.covariateModelValues = {[0.5,0], [0.75], [0,0]}
+%                                   Defines the initial guesses for the covariate coefficients for BMI0 on CL to be 0.5, WT0 on Fsubcut to be 0.75, and the other ones are 0.
+%                                   If not defined, all covariate coefficients start from 0 in the estimation.
+%   options.COVestimate:            Same structure as options.covariateModelValues but with entries 0 or 1. 0 means not estimated, 1 means estimated.
+%                                   By default all are estimated.
+%                                   In the example above options.COVestimate = {[0,1], [1], [1,0]}   will estimate AE0 on CL, WT0 on Fsubcut, SEX on Vc.
+%                                   The other coefficients will be kept fixed.
+%   options.COVcentering.covs:      Cell-array with covariates that should be centered around a custom value. 
+%   options.COVcentering.values:    Vector with centering values. 
+%   options.Ntests:                 Doing robustness analysis - number of models to generate with different initial guesses (randomly generated based on POPvalues0)
+%                                   Default: 1 (no robustness analysis, using initial guesses as provided)
+%   options.std_noise_setting:      Standard deviation to use to add noise to the initial parameter guesses (default=0.5 (50%CV))
+%                                   Normal:         Parameter_guess + std_noise_setting*Parameter_guess*randomNumbers(0-1)
+%                                   Lognormal:      Parameter_guess * exp(std_noise_setting*randomNumbers(0-1))
+%                                   Logitnormal:    Similar and between 0-1
+%   options.keepProjectFolder:      =0: remover already existing folder, =1: keep it
+%
+% ALGORITHM SETTINGS:
+% ===================
+%
+%       General settings:
+%       -----------------
+%       options.algorithm.SEED:         Seed setting. Defualt: 123456
+%       options.algorithm.K1:           First iterations. Default: 500
+%       options.algorithm.K2:           Final iterations. Default: 200
+%       options.algorithm.NRCHAINS:     Number of parallel chains. Default: 1
+%
+%       NONMEM
+%       ------
+%       options.algorithm.METHOD:       'FO','FOCE','FOCEI','SAEM' (default: SAEM)
+%       options.algorithm.MAXEVAL:      Default: 9999
+%       options.algorithm.SIGDIGITS:    Default: 3
+%       options.algorithm.PRINT:        Default: 1
+%
+%       options.algorithm.M4:           Default: 0 (default: M3 method if dataset formated with CENS column and non-zero entries in it.)
+%
+%       options.algorithm.ITS:                  Allow to run an ITS method as first method befor all other methods (METHOD)
+%                                               ITS = 0 or 1 (default: 0 if not FO) - ITS=1 only accepted if not FO!
+%       options.algorithm.ITS_ITERATIONS:       Number of iterations for ITS (default: 10)
+%
+%       options.algorithm.IMPORTANCESAMPLING:   Allow determination of the OFV - only accepted after SAEM
+%                                               Default: 0, If 1 then do the importance sampling
+%       options.algorithm.IMP_ITERATIONS:       Number of iterations for importance sampling (default: 5)
+% 
+%       MONOLIX
+%       -------
+%       options.algorithm.LLsetting:    'linearization' (default) or 'importantsampling'
+%       options.algorithm.FIMsetting:   'linearization' (default) or 'stochasticApproximation'
+%       options.algorithm.INDIVparametersetting: 'conditionalMode' (default) ... others not considered for now. 
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle variable input arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+if nargin<7,
+    options = [];
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle robustness analysis settings - if present
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Get info from input arguments
+try Ntests                          = options.Ntests;                           catch, Ntests = 1;                end
+try std_noise_setting               = options.std_noise_setting;                catch, std_noise_setting = 0.5;   end
+try POPestimate                     = options.POPestimate;                      catch, POPestimate = [];          end
+try POPvalues0                      = options.POPvalues0;                       catch, POPvalues0 = [];           end
+try IIVdistribution                 = options.IIVdistribution;                  catch, IIVdistribution = {};      end
+
+% Handle it
+if Ntests>1,
+    % Check if POPvalues0 and POPestimate defined
+    if isempty(POPestimate) || isempty(POPvalues0),
+        error('When doing robustness analysis, please define options.POPvalues0 and options.POPestimate!');
+    end
+    
+    % Define IIVdistribution if still empty (default: all 'L')
+    if isempty(IIVdistribution),
+        for k=1:length(POPvalues0),
+            IIVdistribution{k} = 'L';
+        end
+    end
+    
+    % Sample Ntests new POPvalues0 for the ones that are estimated using
+    % std_noise_setting as standard deviation
+    
+    % Allocating variable
+    POPvalues0_sampled                              = POPvalues0(ones(1,Ntests),:);
+    
+    % Sampling normally distributed (IIV) parameters - which are also estimated on a population level
+    ix_normal_sampled                               = find(strcmp(IIVdistribution,'N').*POPestimate);
+    POPvalues0_sampled(:,ix_normal_sampled)         = POPvalues0(ones(1,Ntests),ix_normal_sampled) + std_noise_setting*POPvalues0(ones(1,Ntests),ix_normal_sampled).*randn(Ntests,length(ix_normal_sampled));
+
+    % Sampling log normally distributed (IIV) parameters - which are also estimated on a population level
+    ix_lognormal_sampled                            = find(strcmp(IIVdistribution,'L').*POPestimate);
+    MU                                              = log(POPvalues0(ones(1,Ntests),ix_lognormal_sampled));
+    XXX                                             = MU + std_noise_setting.*randn(Ntests,length(ix_lognormal_sampled));
+    POPvalues0_sampled(:,ix_lognormal_sampled)      = exp(XXX);
+    
+    % Sampling logit normally distributed parameters - which are also estimated on a population level
+    ix_logitnormal_sampled                          = find(strcmp(IIVdistribution,'G').*POPestimate);
+    MU                                              = log(POPvalues0(ones(1,Ntests),ix_logitnormal_sampled)./(1-POPvalues0(ones(1,Ntests),ix_logitnormal_sampled)));
+    XXX                                             = MU + std_noise_setting.*randn(Ntests,length(ix_logitnormal_sampled));
+    POPvalues0_sampled(:,ix_logitnormal_sampled)    = exp(XXX)./(1+exp(XXX));
+    
+    % Clean folder
+    try rmdir(projectPath,'s'); catch, end
+    
+    % Create Ntests different models in the projectPath/MODEL_01/02, ... folders
+    % Do this by call again this function here (IQMcreateGeneralLinearNLMEproject)
+    for k=1:Ntests,
+        % Setup new project creation stuff
+        dataK                           = data;
+        dataK.dataRelPathFromProject    = ['../' data.dataRelPathFromProject];
+        projectPathK                    = [projectPath sprintf('/MODEL_%s',preFillCharIQM(k,length(num2str(Ntests)),'0'))];
+        optionsK                        = options;
+        optionsK.Ntests                 = 1;
+        optionsK.std_noise_setting      = 0;
+        optionsK.POPvalues0             = POPvalues0_sampled(k,:);
+        IQMcreateGeneralLinearNLMEproject(TOOL,modelinfo,modelinput,modeloutput,dataK,projectPathK,optionsK)
+    end
+    % Ready, return
+    return
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Create TOOL dependent NLME project
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+if strcmpi(TOOL,'NONMEM'),
+    createGeneralLinear_NONMEMprojectIQM(modelinfo,modelinput,modeloutput,data,projectPath,options)
+elseif strcmpi(TOOL,'MONOLIX'),
+    createGeneralLinear_MONOLIXprojectIQM(modelinfo,modelinput,modeloutput,data,projectPath,options)
+else
+    error('Unknown "TOOL" definition.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Create TEXT model in projectPath
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+filename = fullfile(projectPath,'model');
+createGeneralLinear_TEXTmodelIQM(modelinfo,modelinput,modeloutput,options,filename)
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/14-GeneralLinearNLMEmodel/auxiliary/MONOLIX/createGeneralLinear_MLXTRANfileIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/14-GeneralLinearNLMEmodel/auxiliary/MONOLIX/createGeneralLinear_MLXTRANfileIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..d00c6f2c1efa10d70a9df6fde9352c983bfea732
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/14-GeneralLinearNLMEmodel/auxiliary/MONOLIX/createGeneralLinear_MLXTRANfileIQM.m	
@@ -0,0 +1,385 @@
+function [] = createGeneralLinear_MLXTRANfileIQM(modelinfo,modelinput,modeloutput,data,filename,SILENT)
+% This function creates an MLXTRAN structural model file for a generalized 
+% linear model based on some input arguments. Typically, this function is
+% not called by a user - but it is an auxiliary function for
+% IQMcreateGeneralLinearNLMEproject.
+%
+% Regression parameters are taken directly from the information in the
+% dataset.
+% 
+% [SYNTAX]
+% [] = createGeneralLinear_MLXTRANfileIQM(modelinfo,modelinput,modeloutput,data,filename)
+% [] = createGeneralLinear_MLXTRANfileIQM(modelinfo,modelinput,modeloutput,data,filename,SILENT)
+%
+% [INPUT]
+% modelinfo:            MATLAB structure with following fields:
+%   modelinfo.nrCompartments:              Number of states/compartments in the model
+%   modelinfo.parameterNames:              Cell-array with names of parameters to be estimated
+%   modelinfo.parameterNamesGeneral:       Cell-array with parameter names of the general linear model to define
+%                                          all others will be kept on 0. 
+%                                          Syntax: 
+%                                               Rate parameter from compartment 1 to compartment 2 is: k1T2 
+%                                               Rate parameter from compartment 3 to compartment 2 is: k3T2 
+%                                               Elimination rate parameter from compartment 2 is: k2T0
+%   modelinfo.parameterExpressionsGeneral: Cell-array linking the parameters to be estimated to the parameters in 
+%                                          the general linear model in terms of expressions.
+%                                          Same order as parameterNamesGeneral. For example, if first element in 
+%                                          parameterNamesGeneral is 'k20' then first element here could be 'CL/Vc',
+%   EXAMPLE:
+%       modelinfo                               = [];
+%       modelinfo.nrCompartments                = 3;
+%       modelinfo.parameterNames                = {'ka' 'CL' 'V' 'FM' 'CLM' 'VM'};
+%       modelinfo.parameterNamesGeneral         = {'k1T2'   'k2T0'              'k2T3'       'k3T0'};
+%       modelinfo.parameterExpressionsGeneral   = {'ka'     'CL*(1-FM)/V'       'CL*FM/V'    'CLM/VM'};
+%
+%       This example realizes a PK model with first order absorption and a
+%       metabolite. Both parent and metabolite are described by a one
+%       compartment model.
+% 
+% modelinput:           Cell-array of cell-arrays. Each inner cell-array
+%                       describes one dosing input and links the data to the model.
+%                       First element: A name for the input.
+%                       Second element: Type of the administration (use
+%                         only 'BOLUS', 'INFUSION' or 'ADMINISTRATION0'
+%                       Third element: Number of the compartment to which
+%                         the dose should be added (match with CMT number in
+%                         dataset)
+%                       Fourth element: String with text to write after
+%                         "F<<compartment number>>" ... this can be an
+%                         expression, allowing simple definition of nonlinear
+%                         bioavailability - can depend on covariates,
+%                         regression parameters etc.
+% 						Fifth element: String with expression (or single parameter)
+% 						  for lag time definition.
+% 						Sixth element: String with expression (or single parameter)
+% 						  for definition of 0 order absorption. In this case it
+% 					      would be good to set the "type" to "ABSORPTION0"
+%   EXAMPLE:
+%       modelinput  = { {'INPUT1', 'BOLUS', 1,'Fabs1'}  {'INPUT2', 'INFUSION', 2,'1', 'Tlag' 'Duration'} };
+% 
+%       This example realizes a bolus administration into the first
+%       compartment with F1=Fabs1. And an infusion into second compartment
+%       with F2=1. Note that the difference between bolus and infusion is
+%       only defined by the value in the RATE column: 0 is bolus, >1 is
+%       infusion. The distinction is only needed later when simulation in
+%       IQM Tools should be done (e.g. VPC).
+%
+% modeloutput:          Cell-array of cell-arrays. Each inner cell-array
+%                       describes one observation output and links the data
+%                       to the model. 
+%                       First element: A name for the output.
+%                       Second element: Number of the compartment to which
+%                         the dose should be added (match with CMT number in
+%                         dataset)
+%                       Third element: String with scaling expression,
+%                         allowing to transform the output to the desired
+%                         units.
+%   EXAMPLE:
+%       modeloutput = { {'CP', 2,'V*495.45/1000000'} {'CM', 3,'VM*435.49/1000000'} };
+%
+%       This example defines an output 'CP' which is measured as the amount
+%       in the second compartment and scaled (divided) by the term
+%       V*495.45/1000000 to obtain concentrations in nmol/L. Similar with
+%       the second output - here measured in the third compartment and
+%       given the name "CM".
+% 
+% data:                 Structure with following fields:
+%   data.dataRelPathFromProject:    path to data file - relative to the
+%                                   projectPath folder.
+%   data.dataFileName:              data file filename
+%   data.dataHeaderIdent:           String with datafile header identifiers (example: 'ID,TIME,Y,MDV,EVID,AMT,TINF,ADM,YTYPE,COV,COV,CAT') 
+%
+% filename:     Name of the created MLXTRAN file 
+% SILENT:       No output to command window during run if 1, otherwise 0 (default: 0)
+%
+% [OUTPUT]
+% Exported MLXTRAN file for the model ... or error messages ;)
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HANDLE VARIABLE INPUT ARGUMENTS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin < 6,
+    SILENT = 0;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Handle some input arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Required parameters
+try nrCompartments              = modelinfo.nrCompartments;                 catch, error('Please define modelinfo.nrCompartments,');                 end
+try parameterNames              = modelinfo.parameterNames;                 catch, error('Please define modelinfo.parameterNames,');                end
+try parameterNamesGeneral       = modelinfo.parameterNamesGeneral;          catch, error('Please define modelinfo.parameterNamesGeneral,');         end
+try parameterExpressionsGeneral = modelinfo.parameterExpressionsGeneral;    catch, error('Please define modelinfo.parameterExpressionsGeneral,');   end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle modelinput and modeloutput - cellarray of cellarrays
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~iscell(modelinput{1}),
+    modelinput = {modelinput};
+end
+
+if ~iscell(modeloutput{1}),
+    modeloutput = {modeloutput};
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Start conversion protocol with important information
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~SILENT,
+    fprintf('======================================================================\n');
+    fprintf('======================================================================\n');
+    fprintf('Conversion of general linear model description to MLXTRAN syntax.\n');
+    fprintf('Please read carefully the information below - it is important to\n');
+    fprintf('ensure correct use of the MLXTRAN model\n');
+    fprintf('==========================================================\n');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% OPEN FILE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fid = fopen(filename,'w');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INFO
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; MLXTRAN model, created using IQM Tools\r\n');
+fprintf(fid,'; Date: %s\r\n',datestr(now,'yyyy-mmm-DD HH:MM'));
+fprintf(fid,'; By:   %s\r\n',usernameIQM());
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DESCRIPTION (name and notes)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% First line: model name 
+fprintf(fid,'; =============================================\r\n');
+fprintf(fid,'DESCRIPTION: %s\r\n',filename);
+fprintf(fid,'; =============================================\r\n');
+notes = sprintf('Automatically generated linear model.');
+% write out notes
+fprintf(fid,'\t%s\r\n',notes);
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INPUT (parameters etc.)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; =============================================\r\n');
+fprintf(fid,'INPUT:\r\n');
+fprintf(fid,'; =============================================\r\n');
+% Parameters to be estimated are the parameters in the model, marked to be
+% estimated and additional parameters from the dosing scheme also marked for estimation.
+% These parameters are defined in the moddosinfo.param_est structure.
+% Add the parameter names for the parameters to be estimated
+fprintf(fid,'\tparameter = {');
+for k=1:length(parameterNames)-1,
+    fprintf(fid,'%s, ',parameterNames{k});
+end
+fprintf(fid,'%s}',parameterNames{end});
+fprintf(fid,'\r\n');
+
+% Find regression parameters in the right order
+ix_regress = strmatchIQM('X',explodePCIQM(data.dataHeaderIdent),'exact');
+dataheader = IQMloadCSVdataset(fullfile(data.dataRelPathFromProject,data.dataFileName),1);
+regressors = dataheader(ix_regress);
+
+% Regression parameters (if defined)
+if ~isempty(regressors),
+    fprintf(fid,'\tregressor = {');
+    for k=1:length(regressors)-1,
+        fprintf(fid,'%s, ',regressors{k});
+    end
+    fprintf(fid,'%s}',regressors{end});
+    fprintf(fid,'\r\n');
+    % Warn the user:
+    if ~SILENT,
+        fprintf('\tRegression parameters present in model:\n');
+        fprintf('\t\tMake sure these parameters appear in the same order in\n');
+        fprintf('\t\tthe dataset as in the model!\n');
+        fprintf('\t=========================================================\n');
+    end
+end
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% PK (input application information)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% write section identifier
+fprintf(fid,'; =============================================\r\n');
+fprintf(fid,'PK:\r\n');
+fprintf(fid,'; =============================================\r\n');
+fprintf(fid,'\r\n');
+
+% Define ALL compartments
+% Use "amount", since everything else is taken care of by the equations in the model.
+fprintf(fid,'; Define compartments\r\n');
+fprintf(fid,'\r\n');
+for k=1:nrCompartments,
+    fprintf(fid,'\tcompartment(cmt=%d, amount=%s)\r\n',k,sprintf('A%d',k));
+end
+fprintf(fid,'\r\n');
+
+% Define dosing inputs
+fprintf(fid,'; Define dosing inputs\r\n');
+fprintf(fid,'\r\n');
+
+% Write out dosing type and additional information
+for k=1:length(modelinput),
+    % adm: number of input
+    INPUT_NUMBER    = k;
+    % cmt number
+    CMT_NUMBER      = modelinput{k}{3};
+    % Fraction
+    FRACTION        = modelinput{k}{4};
+    % Tlag
+    TLAGNAME        = '';
+    if length(modelinput{k}) > 4,
+        TLAGNAME = modelinput{k}{5};
+    end
+    
+    % Handle infusion
+    if strcmp(modelinput{k}{2},'INFUSION'),
+        fprintf(fid,'\tiv(adm=%d, cmt=%d, p=%s',INPUT_NUMBER,CMT_NUMBER,FRACTION);
+        if isempty(TLAGNAME),
+            fprintf(fid,')\r\n');
+        else
+            fprintf(fid,', Tlag=%s)\r\n',TLAGNAME);
+        end
+    end
+    
+    % Handle 1st order absorption
+    if strcmp(modelinput{k}{2},'ABSORPTION1'),
+        % First order absorption can not be used ... the absorption
+        % compartment should be defined by the user and a BOLUS should
+        % be given
+        error(sprintf('First order absorption can not be used ... the absorption\ncompartment should be defined by the user and a BOLUS should\nbe given.'));
+    end
+    
+    % Handle 0 order absorption
+    if strcmp(modelinput{k}{2},'ABSORPTION0'),
+        if length(modelinput{k}) < 6,
+            error('modelinput for 0 order absorption needs to contain 6 elements. The last being the name of the duration parameter.');
+        end
+        TK0_PARAMETER = modelinput{k}{6};
+        fprintf(fid,'\tabsorption(adm=%d, cmt=%d, Tk0=%s, p=%s',INPUT_NUMBER,CMT_NUMBER,TK0_PARAMETER,FRACTION);
+        if isempty(TLAGNAME),
+            fprintf(fid,')\r\n');
+        else
+            fprintf(fid,', Tlag=%s)\r\n',TLAGNAME);
+        end
+    end
+    
+    % Handle bolus
+    if strcmp(modelinput{k}{2},'BOLUS'),
+        fprintf(fid,'\tiv(adm=%d, cmt=%d, p=%s',INPUT_NUMBER,CMT_NUMBER,FRACTION);
+        if isempty(TLAGNAME),
+            fprintf(fid,')\r\n');
+        else
+            fprintf(fid,', Tlag=%s)\r\n',TLAGNAME);
+        end
+    end
+    
+end
+fprintf(fid,'\r\n');
+        
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Define the transfers and eliminations ...
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; Transfer between compartments\r\n');
+fprintf(fid,'\r\n');
+
+% Generate transfer matrix and elimination vector - first and initialize with 0
+TransferMatrix = cell(nrCompartments); TransferMatrix(1:end,1:end) = {'0'};
+EliminationVector = cell(nrCompartments,1); EliminationVector(1:end) = {'0'};
+
+% Parse information into TransferMatrix
+for k=1:length(parameterNamesGeneral),
+    param = parameterNamesGeneral{k};
+    
+    % remove the 'k'
+    param = strrep(param,'k','');
+    terms = explodePCIQM(param,'T');
+    
+    % check
+    if length(terms) ~= 2,
+        error('Incorrect definition of general rate parameters. Use "k#T#" where # indicates numbers of compartment.');
+    end
+    
+    % Get numbers
+    start_ix = eval(terms{1});
+    end_ix   = eval(terms{2});
+    
+    % check 
+    if start_ix == 0,
+        error('This should not happen ... in NONMEM it should work ... but not with MONOLIX ... sorry');
+    end
+    
+    % Fill in TransferMatrix
+    if end_ix ~= 0,
+        TransferMatrix{start_ix,end_ix} = parameterExpressionsGeneral{k};
+    else
+        EliminationVector{start_ix} = parameterExpressionsGeneral{k};
+    end
+end
+
+% Write out transfer equations
+for ke=1:nrCompartments,
+    for ks=1:ke,
+        forward = TransferMatrix{ks,ke};
+        reverse = TransferMatrix{ke,ks};
+        if ~strcmp(forward,'0') || ~strcmp(reverse,'0'),
+            fprintf(fid,'\t; Transfer A%d<->A%d\r\n',ks,ke);
+            fprintf(fid,'\ttransfer(from=%d, to=%d, kt=%s)\r\n',ks,ke,forward);
+            fprintf(fid,'\ttransfer(from=%d, to=%d, kt=%s)\r\n',ke,ks,reverse);
+            fprintf(fid,'\r\n');
+        end
+    end
+end
+
+fprintf(fid,'; Elimination from compartments\r\n');
+fprintf(fid,'\r\n');
+
+% Write out elimination equations
+for ks=1:nrCompartments,
+    forward = EliminationVector{ks};
+    if ~strcmp(forward,'0'),
+        fprintf(fid,'\t; Clearance from A%d\r\n',ks);
+        fprintf(fid,'\telimination(cmt=%d, k=%s)\r\n',ks,forward);
+        fprintf(fid,'\r\n');
+    end
+end
+
+fprintf(fid,'; Calculate output variables\r\n');
+fprintf(fid,'\r\n');
+
+for k=1:length(modeloutput),
+    fprintf(fid,'\t%s = A%d / (%s)\r\n',modeloutput{k}{1},modeloutput{k}{2},modeloutput{k}{3});    
+end
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% OUTPUT (all the outputs and expressions, defined in the model
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% write section identifier
+fprintf(fid,'; =============================================\r\n');
+fprintf(fid,'OUTPUT:\r\n');
+fprintf(fid,'; =============================================\r\n');
+fprintf(fid,'\toutput = {');
+for k=1:length(modeloutput)-1,
+    fprintf(fid,'%s, ',modeloutput{k}{1});
+end
+fprintf(fid,'%s}',modeloutput{end}{1});
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CLOSE FILE AND RETURN
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fclose(fid);
+
+
+   
+
+
+
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/14-GeneralLinearNLMEmodel/auxiliary/MONOLIX/createGeneralLinear_MONOLIXprojectIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/14-GeneralLinearNLMEmodel/auxiliary/MONOLIX/createGeneralLinear_MONOLIXprojectIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..3f7a2e9727ef932dbc72afaa736534015fda0795
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/14-GeneralLinearNLMEmodel/auxiliary/MONOLIX/createGeneralLinear_MONOLIXprojectIQM.m	
@@ -0,0 +1,1164 @@
+function createGeneralLinear_MONOLIXprojectIQM(modelinfo,modelinput,modeloutput,data,projectPath,options)
+% This function allows to generate a general linear model using MONOLIX.
+% 
+% ASSUMPTIONS:
+% ============
+% - MU Referencing always used. 
+% - Continuous covariates are always log-transformed, independent
+%   of the distribution of the parameter on which they are added. Centering
+%   by the median (or user defined values) for the covariates. 
+% - Always untransformed categorical covariates. Several categories per
+%   covariate possible but all need to be numeric and integers.
+% - IIV correlation parameters always 0.1 at the initial guess.
+% - Selection of PRED,RES,WRES outputs dependent on the method that is used
+%   for estimation (in the tables renamed to: XPRED, XRES, XWRES):
+%       - PREDI RESI WRESI if FO
+%       - CPREDI, CRESI, CWRESI if FOCE
+%       - EPRED, ERES, EWRES if SAEM
+% - Default values for add and prop errors: 1 and 0.3
+% - Dataset can contain CMT or (ADM+YTYPE) columns. The output on the
+%   screen of this function will guide the user as to the needed values in
+%   these columns.
+%       - ADM+YTYPE but not CMT 
+%           - YTYPE defines number of output
+%           - ADM used as CMT column
+%
+%       - ADM+CMT but not YTYPE
+%           - YTYPE is inferred based on CMT for observation records (in $ERROR)
+%             But this means that CMT needs to follow the OUTPUTn numbering! 
+%           - CMT will be used as defined for selecting the dosing compartments
+%           - ADM is used to inform potential switchings for NONMEM parameters in the PK section
+%
+% [SYNTAX]
+% [] = createGeneralLinear_MONOLIXprojectIQM(modelinfo,modelinput,modeloutput,data,projectPath)
+% [] = createGeneralLinear_MONOLIXprojectIQM(modelinfo,modelinput,modeloutput,data,projectPath,options)
+%
+% [INPUT]
+% modelinfo:            MATLAB structure with following fields:
+%   modelinfo.nrCompartments:              Number of states/compartments in the model
+%   modelinfo.parameterNames:              Cell-array with names of parameters to be estimated
+%   modelinfo.parameterNamesGeneral:       Cell-array with parameter names of the general linear model to define
+%                                          all others will be kept on 0. 
+%                                          Syntax: 
+%                                               Rate parameter from compartment 1 to compartment 2 is: k1T2 
+%                                               Rate parameter from compartment 3 to compartment 2 is: k3T2 
+%                                               Elimination rate parameter from compartment 2 is: k2T0
+%   modelinfo.parameterExpressionsGeneral: Cell-array linking the parameters to be estimated to the parameters in 
+%                                          the general linear model in terms of expressions.
+%                                          Same order as parameterNamesGeneral. For example, if first element in 
+%                                          parameterNamesGeneral is 'k20' then first element here could be 'CL/Vc',
+%   EXAMPLE:
+%       modelinfo                               = [];
+%       modelinfo.nrCompartments                = 3;
+%       modelinfo.parameterNames                = {'ka' 'CL' 'V' 'FM' 'CLM' 'VM'};
+%       modelinfo.parameterNamesGeneral         = {'k1T2'   'k2T0'              'k2T3'       'k3T0'};
+%       modelinfo.parameterExpressionsGeneral   = {'ka'     'CL*(1-FM)/V'       'CL*FM/V'    'CLM/VM'};
+%
+%       This example realizes a PK model with first order absorption and a
+%       metabolite. Both parent and metabolite are described by a one
+%       compartment model.
+% 
+% modelinput:           Cell-array of cell-arrays. Each inner cell-array
+%                       describes one dosing input and links the data to the model.
+%                       First element: A name for the input.
+%                       Second element: Type of the administration (use
+%                         only 'BOLUS', 'INFUSION' or 'ADMINISTRATION0'
+%                       Third element: Number of the compartment to which
+%                         the dose should be added (match with CMT number in
+%                         dataset)
+%                       Fourth element: String with text to write after
+%                         "F<<compartment number>>" ... this can be an
+%                         expression, allowing simple definition of nonlinear
+%                         bioavailability - can depend on covariates,
+%                         regression parameters etc.
+% 						Fifth element: String with expression (or single parameter)
+% 						  for lag time definition.
+% 						Sixth element: String with expression (or single parameter)
+% 						  for definition of 0 order absorption. In this case it
+% 					      would be good to set the "type" to "ABSORPTION0"
+%   EXAMPLE:
+%       modelinput  = { {'INPUT1', 'BOLUS', 1,'Fabs1'}  {'INPUT2', 'INFUSION', 2,'1', 'Tlag' 'Duration'} };
+% 
+%       This example realizes a bolus administration into the first
+%       compartment with F1=Fabs1. And an infusion into second compartment
+%       with F2=1. Note that the difference between bolus and infusion is
+%       only defined by the value in the RATE column: 0 is bolus, >1 is
+%       infusion. The distinction is only needed later when simulation in
+%       IQM Tools should be done (e.g. VPC).
+%
+% modeloutput:          Cell-array of cell-arrays. Each inner cell-array
+%                       describes one observation output and links the data
+%                       to the model. 
+%                       First element: A name for the output.
+%                       Second element: Number of the compartment to which
+%                         the dose should be added (match with CMT number in
+%                         dataset)
+%                       Third element: String with scaling expression,
+%                         allowing to transform the output to the desired
+%                         units.
+%   EXAMPLE:
+%       modeloutput = { {'CP', 2,'V*495.45/1000000'} {'CM', 3,'VM*435.49/1000000'} };
+%
+%       This example defines an output 'CP' which is measured as the amount
+%       in the second compartment and scaled (divided) by the term
+%       V*495.45/1000000 to obtain concentrations in nmol/L. Similar with
+%       the second output - here measured in the third compartment and
+%       given the name "CM".
+% 
+% data:                 Structure with following fields:
+%   data.dataRelPathFromProject:    path to data file - relative to the
+%                                   projectPath folder.
+%   data.dataFileName:              data file filename
+%   data.dataHeaderIdent:           String with datafile header identifiers (example: 'ID,TIME,Y,MDV,EVID,AMT,TINF,ADM,YTYPE,COV,COV,CAT') 
+%
+% projectPath:          String with the path/foldername to which the project files are to be written (example: 'FIT_01' or 'Models/FITS/FIT_01') 
+%
+% options:              Structure with following fields (all optional with default settings):
+%   options.POPestimate:            Vector with 0 and 1 entries. 1 if pop parameter is estimated, 0 if not. Default or []: => all are estimated
+%   options.POPvalues0:             Vector with pop parameter initial values. Default or []: => all values 1 (does not really make sense)
+%   options.IIVdistribution:        Cell-array with information about parameter distribution. L (lognormal), N (normal), G (logit)
+%                                       Example: {'L' 'L' 'L' 'L' 'N' 'L' 'L' 'L'}. Default or {}: => use lognormal for all
+%   options.IIVestimate:            Vector with 0 and 1 entries. 1 if random effect is estimated, 0 if not. Default or []: => all are estimated
+%                                   0: IIV not estimated (IIVvalues0 not used) 
+%                                   1: IIV estimated (IIVvalues0 as starting guesses)
+%                                   2: IIV not estimated but fixed on IIVvalues0 value
+%   options.IIVvalues0:             Vector with random effect parameter
+%                                   initial values. Default or []: => all set to 0.5
+%                                   If IIV not estimated then defined initial guess not used but replaced by 0
+%   options.errorModels:            String with definition of residual error models, comma separated for each output.
+%                                   Possible values: const,prop,comb1. Example: 'comb1,prop', Default or '': => const for all outputs
+%   options.errorParam0:            Vector allowing to pass initial guesses for error model parameters. Same order as error models. 
+%                                   'const': a, 'prop': b, 'comb1': a,b
+%   options.covarianceModel:        Definition of covariance model. String with cell-array text inside, grouping the parameters to consider having 
+%                                   correlated random effects. Example: '{CL,Vc},{Q,Vp,KM}'. Default: 'diagonal'
+%   options.covariateModel:         Definition of covariate model. Cell-array. Each element is a sub-cell-array. First element in sub-cell-array is the 
+%                                   parameter to which to add the covariate, all following elements define the covariates as named in the dataset.
+%                                   Example: '{CL,BMI0}, {Fsubcut,WT0}, {Vc,SEX,BMI0}'. Default: '' => no covariates
+%                                   By default (and so far not changeable, the continuous covariates are all weighted by their median, determined from the dataset)
+%                                   >>>Covariates can be added to all parameters for which not both IIVestimate and POPestimate are 0.
+%   options.covariateModelValues:   Definition of covariate coefficients for the selected covariate model. 
+%                                   Syntax is similar to options.covariateModel. It is a cell-array containing vectors instead of cell-arrays.
+%                                   Each vector contains values for the covariate coefficients, matching the covariateModel definition order.
+%                                   Example: if options.covariateModel = '{CL,BMI0,AGE0}, {Fsubcut,WT0}, {Vc,SEX,BMI0}'
+%                                   Then: options.covariateModelValues = {[0.5,0], [0.75], [0,0]}
+%                                   Defines the initial guesses for the covariate coefficients for BMI0 on CL to be 0.5, WT0 on Fsubcut to be 0.75, and the other ones are 0.
+%                                   If not defined, all covariate coefficients start from 0 in the estimation.
+%   options.COVestimate:            Same structure as options.covariateModelValues but with entries 0 or 1. 0 means not estimated, 1 means estimated.
+%                                   By default all are estimated.
+%                                   In the example above options.COVestimate = {[0,1], [1], [1,0]}   will estimate AE0 on CL, WT0 on Fsubcut, SEX on Vc.
+%                                   The other coefficients will be kept fixed.
+%   options.COVcentering.covs:      Cell-array with covariates that should be centered around a custom value. 
+%   options.COVcentering.values:    Vector with centering values. 
+%   options.keepProjectFolder:      =0: remover already existing folder, =1: keep it
+%
+% ALGORITHM SETTINGS:
+% ===================
+%
+%   options.algorithm.SEED:                  Seed setting. Defualt: 123456
+%   options.algorithm.K1:                    First iterations. Default: 500
+%   options.algorithm.K2:                    Final iterations. Default: 200
+%   options.algorithm.NRCHAINS:              Number of parallel chains. Default: 1
+%   options.algorithm.LLsetting:             'linearization' (default) or 'importantsampling'
+%   options.algorithm.FIMsetting:            'linearization' (default) or 'stochasticApproximation'
+%   options.algorithm.INDIVparametersetting: 'conditionalMode' (default) ... others not considered for now.
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle variable input arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin<6,
+    options = [];
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Define Default Properties (Never changing)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+projectName            = 'project';
+resultsFolder          = 'RESULTS';
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle some input arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try modelADVAN                  = modelinfo.modelADVAN;                     catch, modelADVAN       = 'ADVAN7';                                     end
+try nrCompartments              = modelinfo.nrCompartments;                 catch, error('Please define modelinfo.nrCompartments,');                 end
+try parameterNames              = modelinfo.parameterNames;                 catch, error('Please define modelinfo.parameterNames,');                end
+try parameterNamesGeneral       = modelinfo.parameterNamesGeneral;          catch, error('Please define modelinfo.parameterNamesGeneral,');         end
+try parameterExpressionsGeneral = modelinfo.parameterExpressionsGeneral;    catch, error('Please define modelinfo.parameterExpressionsGeneral,');   end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check input
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try
+    dataRelPathFromProject = data.dataRelPathFromProject;
+    dataFileName           = data.dataFileName;
+    dataHeaderIdent        = data.dataHeaderIdent;
+catch
+    error('data input argument not defined correctly.');
+end
+
+% Removal of TIMEPOS in dataHeaderIdent: TIMEPOS only needed for NONMEM ...
+dataHeaderIdent         = regexprep(dataHeaderIdent,'\<TIMEPOS\>','IGNORE');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle optional arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try POPestimate                     = options.POPestimate;                      catch, POPestimate = [];                             end
+try POPvalues0                      = options.POPvalues0;                       catch, POPvalues0 = [];                              end
+try IIVdistribution                 = options.IIVdistribution;                  catch, IIVdistribution = {};                         end
+try IIVestimate                     = options.IIVestimate;                      catch, IIVestimate = [];                             end
+try IIVvalues0                      = options.IIVvalues0;                       catch, IIVvalues0 = [];                              end
+try errorModels                     = options.errorModels;                      catch, errorModels = '';                             end
+try errorParam0                     = options.errorParam0;                      catch, errorParam0 = [];                             end
+try covarianceModel                 = options.covarianceModel;                  catch, covarianceModel = 'diagonal';                 end
+try covariateModel                  = options.covariateModel;                   catch, covariateModel = '';                          end
+try covariateModelValues            = options.covariateModelValues;             catch, covariateModelValues = {};                    end
+try COVestimate                     = options.COVestimate;                      catch, COVestimate = {};                             end
+
+try COVcentering_covs               = options.COVcentering.covs;                catch, COVcentering_covs = {};                       end
+try COVcentering_values             = options.COVcentering.values;              catch, COVcentering_values = [];                     end
+
+try SEED                            = options.algorithm.SEED;                   catch, SEED = 123456;                                end
+try K1                              = options.algorithm.K1;                     catch, K1 = 500;                                     end
+try K2                              = options.algorithm.K2;                     catch, K2 = 200;                                     end
+try K1_AUTO                         = options.algorithm.K1_AUTO;                catch, K1_AUTO = 0;                                  end
+try K2_AUTO                         = options.algorithm.K2_AUTO;                catch, K2_AUTO = 0;                                  end
+try NRCHAINS                        = options.algorithm.NRCHAINS;               catch, NRCHAINS = 1;                                 end
+try SILENT                          = options.SILENT;                           catch, SILENT = 0;                                   end
+try INDIVparametersetting           = options.algorithm.INDIVparametersetting;  catch, INDIVparametersetting = 'conditionalMode';    end
+try LLsetting                       = options.algorithm.LLsetting;              catch, LLsetting = 'linearization';                  end
+try FIMsetting                      = options.algorithm.FIMsetting;             catch, FIMsetting = 'linearization';                 end
+try keepProjectFolder               = options.keepProjectFolder;                catch, keepProjectFolder = 0;                        end   
+
+% Handle cell requirements
+if ~iscell(COVcentering_covs),
+    COVcentering_covs = {COVcentering_covs};
+end
+
+options.covariateModel = covariateModel;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle modelinput and modeloutput - cellarray of cellarrays
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~iscell(modelinput{1}),
+    modelinput = {modelinput};
+end
+
+if ~iscell(modeloutput{1}),
+    modeloutput = {modeloutput};
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Convert covariate model into different syntax
+% '{CL,BMI0}, {Fsubcut,WT0}, {Vc,SEX,BMI0}'
+% to
+% {{'CL','BMI0'}, {'Fsubcut','WT0'}, {'Vc','SEX','BMI0'}}
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(covariateModel),
+    terms = explodePCIQM(covariateModel,',','{','}');
+    y = {};
+    for k=1:length(terms),
+        x = strrep(strtrim(terms{k}),' ','');
+        x = strrep(x,'{','{''');
+        x = strrep(x,'}','''}');
+        x = strrep(x,',',''',''');
+        y{k} = eval(x);
+    end
+    covariateModel = y;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check covariateModelValues
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(covariateModel) && ~isempty(covariateModelValues),
+    error('If you define covariateModelValues, you also need to define the covariateModel.');
+end
+
+if isempty(covariateModelValues),
+    % Determine default covariateModelValues
+    covariateModelValues = {};
+    for k=1:length(covariateModel),
+        covariateModelValues{k} = zeros(1,length(covariateModel{k})-1);
+    end
+else
+    % Check correct length of covariateModelValues elements
+    if length(covariateModel) ~= length(covariateModelValues),
+        error('Number of elements in covariateModel and covariateModelValues needs to match.');
+    end
+    for k=1:length(covariateModel),
+        if length(covariateModel{k})-1 ~= length(covariateModelValues{k}),
+            error('Length of single elements in covariateModel and covariateModelValues needs to match (covariateModelValues elements being one shorter).');
+        end            
+    end    
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check COVestimate
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(covariateModel) && ~isempty(COVestimate),
+    error('If you define COVestimate, you also need to define the covariateModel.');
+end
+
+if isempty(COVestimate),
+    % Determine default COVestimate - all are estimates
+    COVestimate = {};
+    for k=1:length(covariateModel),
+        COVestimate{k} = ones(1,length(covariateModel{k})-1);
+    end
+else
+    % Check correct length of COVestimate elements
+    if length(covariateModel) ~= length(COVestimate),
+        error('Number of elements in covariateModel and COVestimate needs to match.');
+    end
+    for k=1:length(covariateModel),
+        if length(covariateModel{k})-1 ~= length(COVestimate{k}),
+            error('Length of single elements in covariateModel and COVestimate needs to match (COVestimate elements being one shorter).');
+        end            
+    end    
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Create project and results folder
+% Change into project path
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+warning off
+oldpath = pwd;
+if ~keepProjectFolder,
+    try rmdir(projectPath,'s'); catch, end
+end
+mkdir(projectPath); cd(projectPath)
+mkdir(resultsFolder);
+warning on
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Load dataset and get column names
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try
+    dataCSV     = IQMloadCSVdataset(fullfile(dataRelPathFromProject,dataFileName));
+catch
+    error('Trouble loading the data file. Please check if data.dataRelPathFromProject has been defined correctly.');
+end
+dataheader  = dataCSV.Properties.VariableNames;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check the NLME dataset for the minimal required columns
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+IQMcheckNLMEdatasetHeader(dataCSV);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Determine medians for covariates
+% Also handle in case custom centering values are defined.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Determine index of COV columns and their names
+terms   = explodePCIQM(dataHeaderIdent);
+ixCOVs  = strmatchIQM('COV',terms,'exact');
+if ~isempty(ixCOVs),
+    covariateMedianNames            = dataheader(ixCOVs);
+
+    % Get median values
+    unique_covs                     = unique(dataCSV(:,{'ID' covariateMedianNames{:}}));
+    covariateMedianValues           = nanmedianIQM(table2array(unique_covs(:,2:end)));
+
+    % Handle custom centering values
+    for k=1:length(COVcentering_covs),
+        ix                          = strmatchIQM(COVcentering_covs{k},covariateMedianNames,'exact');
+        covariateMedianValues(ix)   = COVcentering_values(k);
+    end
+    
+    if ~SILENT, 
+        disp(' ')
+        disp('==================================================================');
+        disp('Analysis of dataset for covariates - determine the centering values  ')
+        disp('These are the median values, if not defined differently by the user.')
+        disp(' Results:');
+        for k=1:length(covariateMedianValues),
+            disp(sprintf('   median(%s) = %g',covariateMedianNames{k},covariateMedianValues(k)));
+        end
+        disp('These values will be used to center the continuous covariates')
+        disp('==================================================================');
+        disp(' ')
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Create MLXTRAN model
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+modelFileName = 'model_MLXTRAN.txt';
+createGeneralLinear_MLXTRANfileIQM(modelinfo,modelinput,modeloutput,data,modelFileName,SILENT);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Info text
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~SILENT,
+    disp(' ')
+    disp('==================================================================');
+    disp('==================================================================');
+    disp('== Start of creation of Monolix project.mlxtran file');
+    disp('==================================================================');
+    disp('==================================================================');
+    disp(' ')
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check if datafile exists and csv file and load some information
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+dataFile = [dataRelPathFromProject '/' dataFileName];
+try
+    dataheader = IQMloadCSVdataset(dataFile,1);
+catch
+    cd(oldpath);
+    error('Please check if the data file "%s" exists.',dataFile)
+end
+% Check if length of header identical to dataHeaderIdent
+if length(explodePCIQM(dataHeaderIdent,',')) ~= length(dataheader),
+    cd(oldpath);
+    error('Please check: The data header identifiers do not have the same length as the number of columns in the dataset.')
+end
+
+% Determine continuous and categorical covariates
+IDs         = explodePCIQM(dataHeaderIdent,',');
+covIDs      = strmatchIQM('COV',upper(IDs));
+covNames    = dataheader(covIDs);
+catIDs      = strmatchIQM('CAT',upper(IDs));
+catNames    = dataheader(catIDs);
+
+% Print table with header names and identifiers
+IDs = explodePCIQM(dataHeaderIdent,',');
+
+if ~SILENT,
+    disp(' ');
+    disp('Please check that the following matches between data header and identifiers do make sense:');
+    for k=1:length(dataheader),
+        fprintf('\t%s%s: %s\n',dataheader{k},char(32*ones(1,8-length(dataheader{k}))),IDs{k})
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check parameter and covariate names ... '_' not allowed
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+parNamesCheck = [parameterNames covNames catNames];
+text_error = '';
+for k=1:length(parNamesCheck),
+    if ~isempty(strfind(parNamesCheck{k},'_')),
+        text_error = sprintf('%sUnderscores "_" are not allowed in parameter and covariate names: "%s".\n',text_error,parNamesCheck{k});
+    end
+end
+if ~isempty(text_error),
+    error(text_error);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check POPestimate thing
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(POPestimate),
+    POPestimate = ones(1,length(parameterNames));
+end
+if length(parameterNames) ~= length(POPestimate),
+    cd(oldpath);
+    error('Please make sure POPestimate is of same length as number of parameters.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check POPvalues0 thing
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(POPvalues0),
+    POPvalues0 = ones(1,length(parameterNames));
+end
+if length(parameterNames) ~= length(POPvalues0),
+    cd(oldpath);
+    error('Please make sure POPvalues0 is of same length as number of parameters.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check IIV distribution things
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(IIVdistribution),
+    IIVdistribution = {};
+    for k=1:length(parameterNames),
+        IIVdistribution{k} = 'L';
+    end
+end
+
+% Check contents
+test = IIVdistribution;
+for k=1:length(IIVdistribution),
+    if ~ismember(test{k},{'L','N','G'}),
+        cd(oldpath);
+        error('Please make sure that only "N", "L", or "G" appear in the "IIVdistribution" variable.');
+    end
+end
+
+% Check length
+if length(IIVdistribution) ~= length(parameterNames),
+    cd(oldpath);
+    error('Please make sure that an equal number of IIVdistribution is defined as parameters in the model.');
+end
+
+% Print table parameter names and IIV distributions
+if ~SILENT,
+    disp(' ');
+    disp('Please check that the following matches between parameters and used IIV distributions are correct:');
+    for k=1:length(parameterNames),
+        if IIVdistribution{k} == 'L', dtext = 'logNormal'; end
+        if IIVdistribution{k} == 'N', dtext = 'Normal'; end
+        if IIVdistribution{k} == 'G', dtext = 'logitNormal'; end
+        fprintf('\t%s%s: %s\n',parameterNames{k},char(32*ones(1,15-length(parameterNames{k}))),dtext)
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check IIV estimation things
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(IIVestimate),
+    IIVestimate = ones(1,length(parameterNames));
+end
+% Check length
+if length(IIVestimate) ~= length(parameterNames),
+    cd(oldpath);
+    error('Please make sure that an equal number of IIVestimate is defined as parameters in the model.');
+end
+% Print table parameter names and IIV esimations
+if ~SILENT,
+    disp(' ');
+    disp('Please check that the following matches between parameters and used estimated IIVs are correct:');
+    for k=1:length(parameterNames),
+        if IIVestimate(k) == 0,
+            fprintf('\t%s%s: IIV NOT ESTIMATED (kept on 0)\n',parameterNames{k},char(32*ones(1,15-length(parameterNames{k}))));
+        elseif IIVestimate(k) == 1,
+            fprintf('\t%s%s: IIV ESTIMATED\n',parameterNames{k},char(32*ones(1,15-length(parameterNames{k}))));
+        elseif IIVestimate(k) == 2,
+            fprintf('\t%s%s: IIV NOT ESTIMATED (kept on initial value)\n',parameterNames{k},char(32*ones(1,15-length(parameterNames{k}))));
+        end
+    end
+    disp(' ');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check IIVvalues0 thing
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(IIVvalues0),
+    IIVvalues0 = 0.5*ones(1,length(parameterNames));
+end
+if length(parameterNames) ~= length(IIVvalues0),
+    cd(oldpath);
+    error('Please make sure IIVvalues0 is of same length as number of parameters.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check residual error things
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(errorModels),
+    errorModels = '';
+    for k=1:length(modeloutput),
+        errorModels = sprintf('%sconst,',errorModels);
+    end
+    errorModels = errorModels(1:end-1);
+end
+test = errorModels;
+test = strtrim(strrep(strrep(strrep(strrep(test,'const',''),'prop',''),'comb1',''),',',''));
+if ~isempty(test),
+    cd(oldpath);
+    error('Please make sure that only "const", "prop", or "comb1" appear in the "errorModels" variable.');
+end
+% Check length
+errors = explodePCIQM(errorModels,',');
+if length(errors) ~= length(modeloutput),
+    cd(oldpath);
+    error('Please make sure that an equal number of errorModels is defined as outputs in the model.');
+end
+% Print table parameter names and IIV distributions
+if ~SILENT,
+    disp(' ');
+    disp('Please check that the following matches between outputs and used residual error models are correct:');
+    for k=1:length(modeloutput),
+        fprintf('\t%s%s: %s\n',modeloutput{k}{1},char(32*ones(1,15-length(modeloutput{k}{1}))),errors{k})
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle empty errorParam0
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(errorParam0),
+    terms = explodePCIQM(errorModels);
+    for k=1:length(terms),
+        if strcmp(lower(terms{k}),'const'),
+            errorParam0(end+1) = 1;
+        elseif strcmp(lower(terms{k}),'prop'),
+            errorParam0(end+1) = 0.3;
+        elseif strcmp(lower(terms{k}),'comb1'),
+            errorParam0(end+1) = 1;
+            errorParam0(end+1) = 0.3;          
+        elseif strcmp(lower(terms{k}),'exp'),
+            errorParam0(end+1) = 1;
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check errorParam0
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+terms = explodePCIQM(errorModels);
+nrneededelements = 0;
+for k=1:length(terms),
+    if strcmpi(terms{k},'const'),
+        nrneededelements = nrneededelements+1;
+    elseif strcmpi(terms{k},'prop'),
+        nrneededelements = nrneededelements+1;
+    elseif strcmpi(terms{k},'comb1'),
+        nrneededelements = nrneededelements+2;
+    elseif strcmpi(terms{k},'exp'),
+        nrneededelements = nrneededelements+1;
+    end
+end
+if length(errorParam0) ~= nrneededelements,
+    error('Incorrect number of elements in options.errorParam0.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check covariance model
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(covarianceModel),
+    covarianceModel = 'diagonal';
+elseif ~strcmp(covarianceModel,'diagonal'),
+    % Need to check that none of the parameters for which no IIV is estimated is used in the covarianceModel
+    param_est_noIIV = parameterNames(find(~IIVestimate));
+    for k=1:length(param_est_noIIV),
+        if ~isempty(regexp(covarianceModel,['\<' param_est_noIIV{k} '\>'])),
+            cd(oldpath);
+            error('Please make sure none of the parameters for which no IIV is estimated/fixed to non zero is used in the covarianceModel settings.');
+        end
+    end
+    % Check that all parameters in the covariance model actually are model parameters
+    param = parameterNames;
+    test  = covarianceModel;
+    for k=1:length(param),
+        test = regexprep(test,['\<' param{k} '\>'],'');
+    end
+    test = strrep(test,'{','');
+    test = strrep(test,'}','');
+    test = strrep(test,',','');
+    test = strtrim(test);
+    if ~isempty(test),
+        cd(oldpath);
+        error('Please make sure that covarianceModel only contains model parameters.');
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check LL setting
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(LLsetting),
+    LLsetting = 'both';
+end
+if isempty(strmatchIQM(LLsetting,{'linearization','importantSampling','both'})),
+    cd(oldpath);
+    error('Please make sure LLsetting has one of the following values: "linearization", "importantSampling", "both"=""');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check FIM setting
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(FIMsetting),
+    FIMsetting = 'linearization';
+end
+if isempty(strmatchIQM(FIMsetting,{'linearization','stochasticApproximation'})),
+    cd(oldpath);
+    error('Please make sure FIMsetting has one of the following values: "linearization" or "stochasticApproximation"');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check covariate model things
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% First check that all first elements are estimated parameters of the model
+param_est = parameterNames;
+for k=1:length(covariateModel),
+    param = covariateModel{k}{1};
+    if isempty(strmatchIQM(param,param_est,'exact')),
+        cd(oldpath);
+        error('Please make sure that all parameters for which covariates are parameters in the model.');
+    end
+end
+% Second check that all defined covariates actually are covariates
+covcatNames = [covNames catNames];
+for k=1:length(covariateModel),
+    for k2=2:length(covariateModel{k}),
+        cov = covariateModel{k}{k2};
+        if isempty(strmatchIQM(cov,covcatNames,'exact')),
+            cd(oldpath);
+            error(sprintf('Please make sure that all covariates, defined in covariateModel, are defined in the dataset\n   This error might be due to a categorical covariate having only single category.'));
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% OPEN File
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fid = fopen([projectName '.mlxtran'],'w');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INFO
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; MLXTRAN PROJECT, created using IQM Tools\r\n');
+fprintf(fid,'; Date: %s\r\n',datestr(now,'yyyy-mmm-DD HH:MM'));
+fprintf(fid,'; By:   %s\r\n',usernameIQM());
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Placeholder for project information
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; ==PROJECT HEADER START===================================================\r\n');
+fprintf(fid,'PROJECT_HEADER_PLACEHOLDER\r\n');
+fprintf(fid,'; ==PROJECT HEADER END=====================================================\r\n');
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DESCRIPTION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; =============================================\r\n');
+fprintf(fid,'DESCRIPTION:\r\n');
+fprintf(fid,'; =============================================\r\n');
+fprintf(fid,'\tmodel\r\n');
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DATA
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; =============================================\r\n');
+fprintf(fid,'DATA:\r\n');
+fprintf(fid,'; =============================================\r\n');
+fprintf(fid,'\tpath = "%%MLXPROJECT%%/%s/",\r\n',dataRelPathFromProject);
+fprintf(fid,'\tfile  ="%s",\r\n',dataFileName);
+fprintf(fid,'\theaders = {%s},\r\n',dataHeaderIdent);
+fprintf(fid,'\tcolumnDelimiter = ","\r\n');
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% VARIABLES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; =============================================\r\n');
+fprintf(fid,'VARIABLES:\r\n');
+fprintf(fid,'; =============================================\r\n');
+% Assume all covariates defined in dataset are used ...
+% Continuous are always log transformed and centered by median
+% Categorical are always kept as they are
+text = '';
+% Write out continuous first
+for k=1:length(covNames),
+    text = sprintf('%s\t%s,\r\n',text,covNames{k});
+    covname = covNames{k};
+    % Scale covariate by median value from dataset
+    ixmedian = strmatchIQM(covname,covariateMedianNames,'exact');
+    covname_weighted = sprintf('%s/%g',covname,covariateMedianValues(ixmedian));
+    text = sprintf('%s\tt_%s = log(%s) [use=cov],\r\n',text,covname,covname_weighted);
+end
+% Write out categorical
+for k=1:length(catNames),
+    text = sprintf('%s\t%s [use=cov, type=cat],\r\n',text,catNames{k});
+end
+% Remove last comma and write text to file
+fprintf(fid,text(1:end-3));
+fprintf(fid,'\r\n');
+fprintf(fid,'\r\n');
+
+% Create BETACOVNAMES and BETACOVTRANS information for header
+BETACOVNAMES = {};
+BETACOVTRANS = {};
+for k=1:length(covariateModel),
+    for k2=2:length(covariateModel{k}),
+        if ~isempty(strmatchIQM(covariateModel{k}{k2},covNames,'exact')),
+            BETACOVNAMES{end+1} = sprintf('beta_%s(%s)',covariateModel{k}{1},covariateModel{k}{k2});
+            ixmedian = strmatchIQM(covariateModel{k}{k2},covariateMedianNames,'exact');
+            BETACOVTRANS{end+1} = sprintf('log(cov/%g)',covariateMedianValues(ixmedian));
+        end
+    end
+end
+
+% Create BETACATNAMES and BETACATREFERENCE information for header
+BETACATNAMES        = {};
+BETACATREFERENCE    = [];
+for k=1:length(covariateModel),
+    for k2=2:length(covariateModel{k}),
+        if ~isempty(strmatchIQM(covariateModel{k}{k2},catNames,'exact')),
+            BETACATNAMES{end+1} = sprintf('beta_%s(%s)',covariateModel{k}{1},covariateModel{k}{k2});
+            BETACATREFERENCE(end+1) = min(unique(dataCSV.(covariateModel{k}{k2})));
+        end
+    end
+end
+
+% Determine all categories for categorical covariates and store them as
+% metadata in the header of the project.mlxtran file
+CAT_CATEGORIES = '';
+for k=1:length(catNames),
+    x = unique(dataCSV.(catNames{k}));
+    x = sprintf('%g,',x);
+    x = ['[' x(1:end-1) ']'];
+    CAT_CATEGORIES{k} = x;
+end
+if ~isempty(CAT_CATEGORIES),
+    CAT_CATEGORIES = sprintf('%s,',CAT_CATEGORIES{:});
+    CAT_CATEGORIES = [CAT_CATEGORIES(1:end-1)];
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INDIVIDUAL
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; =============================================\r\n');
+fprintf(fid,'INDIVIDUAL:\r\n');
+fprintf(fid,'; =============================================\r\n');
+% Write out parameters to estimate. Assume iiv=yes on all of them by default. 
+% If no IIV desired then rather fix omega to 0.01.
+text = '';
+PARAM_TRANSNAME_STRING = {};
+PARAM_INVTRANSNAME_STRING = {};
+
+for k=1:length(parameterNames),
+    if IIVdistribution{k} == 'L', 
+        dtext = 'logNormal'; 
+        PARAM_INVTRANSNAME_STRING{k} = 'log(psi)';
+        PARAM_TRANSNAME_STRING{k} = 'exp(phi)';        
+    end
+    if IIVdistribution{k} == 'N', 
+        dtext = 'Normal';
+        PARAM_INVTRANSNAME_STRING{k} = '(psi)';
+        PARAM_TRANSNAME_STRING{k} = '(phi)';
+    end
+    if IIVdistribution{k} == 'G', 
+        dtext = 'logitNormal'; 
+        PARAM_INVTRANSNAME_STRING{k} = 'log(psi./(1-psi))';
+        PARAM_TRANSNAME_STRING{k} = 'exp(phi)./(1+exp(phi))';        
+    end
+    % check if IIV 
+    if IIVestimate(k) == 0,
+        iiv='no';
+    else
+        iiv='yes';
+    end
+    % check for covariates to use
+    param = parameterNames{k};
+    covs = {};
+    for k2=1:length(covariateModel),
+        if strcmp(param,covariateModel{k2}{1}),
+            covs = covariateModel{k2}(2:end);
+        end
+    end
+    % Attach "t_" to continuous covariate names, keep categorical covariate names same
+    for k2=1:length(covs),
+        if ~isempty(strmatchIQM(covs{k2},covNames,'exact')),
+            covs{k2} = ['t_' covs{k2}];
+        end
+    end
+    % Write it out
+    if isempty(covs),
+        text = sprintf('%s\t%s = {distribution=%s, iiv=%s},\r\n',text,param,dtext,iiv);
+    else
+        % Create cov text
+        covText = '';
+        for k2=1:length(covs),
+            covText = sprintf('%s%s,',covText,covs{k2});
+        end
+        covText = covText(1:end-1);
+        text = sprintf('%s\t%s = {distribution=%s, covariate={%s}, iiv=%s},\r\n',text,param,dtext,covText,iiv);
+        
+
+    end        
+end
+% Remove last comma and write text to file
+fprintf(fid,text(1:end-3));
+fprintf(fid,'\r\n');
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CORRELATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~strcmp(covarianceModel,'diagonal'),
+    fprintf(fid,'; =============================================\r\n');
+    fprintf(fid,'CORRELATION:\r\n');
+    fprintf(fid,'; =============================================\r\n');
+    fprintf(fid,'\tcorrelationIIV = {%s}\r\n',covarianceModel);
+    fprintf(fid,'\r\n');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% STRUCTURAL_MODEL
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; =============================================\r\n');
+fprintf(fid,'STRUCTURAL_MODEL:\r\n');
+fprintf(fid,'; =============================================\r\n');
+fprintf(fid,'\tfile = "mlxt:%s",\r\n',strrep(modelFileName,'.txt',''));
+fprintf(fid,'\tpath = "%%MLXPROJECT%%",\r\n');
+fprintf(fid,'\toutput = {');
+for k=1:length(modeloutput)-1,
+    fprintf(fid,'%s, ',modeloutput{k}{1});
+end
+fprintf(fid,'%s}',modeloutput{end}{1});
+fprintf(fid,'\r\n');
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% OBSERVATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; =============================================\r\n');
+fprintf(fid,'OBSERVATIONS:\r\n');
+fprintf(fid,'; =============================================\r\n');
+% Only consider "continuous" observations with IQM conversion 
+errors = explodePCIQM(errorModels,',');
+text = '';
+for k=1:length(modeloutput),
+    if strcmp(errors{k},'const'), errorModel = 'constant'; end
+    if strcmp(errors{k},'prop'), errorModel = 'proportional'; end
+    if strcmp(errors{k},'comb1'), errorModel = 'combined1'; end
+    if strcmp(errors{k},'exp'), errorModel = 'exponential'; end
+    text = sprintf('%s\ty%d = {type=continuous, prediction=%s, error=%s},\r\n',text,k,modeloutput{k}{1},errorModel);
+end
+% Remove last comma and write text to file
+fprintf(fid,text(1:end-3));
+fprintf(fid,'\r\n');
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% TASKS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; =============================================\r\n');
+fprintf(fid,'TASKS:\r\n');
+fprintf(fid,'; =============================================\r\n');
+fprintf(fid,'\t; settings\r\n');
+fprintf(fid,'\tglobalSettings={\r\n');
+fprintf(fid,'\t\twithVariance=no,\r\n'); % Always estimate standard deviations of IIVs
+% Use default graphics settings
+fprintf(fid,'\t\tsettingsGraphics="%%MLXPROJECT%%/project_graphics.xmlx",\r\n');
+fprintf(fid,'\t\tsettingsAlgorithms="%%MLXPROJECT%%/project_algorithms.xmlx",\r\n');
+fprintf(fid,'\t\tresultFolder="%%MLXPROJECT%%/%s"},\r\n',resultsFolder);
+fprintf(fid,'\t; workflow\r\n');
+fprintf(fid,'\testimatePopulationParameters(\r\n');
+fprintf(fid,'\t\tinitialValues={\r\n');
+% write out population parameter initial values
+for k=1:length(parameterNames),
+    method = '';
+    if POPestimate(k) == 0,
+        method = '[method=FIXED]';
+    end
+    fprintf(fid,'\t\t\tpop_{%s} = %g %s,\r\n',parameterNames{k},POPvalues0(k),method);
+end
+
+% write out covariate coefficient initial guesses
+for k1=1:length(covariateModel),
+    for k2=2:length(covariateModel{k1}),
+        covarvalue = covariateModelValues{k1}(k2-1);
+        if COVestimate{k1}(k2-1),
+            method = '';
+        else
+            method = '[method=FIXED]';
+        end
+        ix = strmatchIQM(covariateModel{k1}{k2},covNames,'exact');
+        if isempty(ix),
+            fprintf(fid,'\t\t\tbeta_{%s,%s} = %g %s,\r\n',covariateModel{k1}{1},covariateModel{k1}{k2},covarvalue,method);
+        else
+            fprintf(fid,'\t\t\tbeta_{%s,t_%s} = %g %s,\r\n',covariateModel{k1}{1},covariateModel{k1}{k2},covarvalue,method);
+        end
+    end
+end
+
+% write out residual error model
+errors = explodePCIQM(errorModels,',');
+count = 1;
+for k=1:length(errors),
+    if strcmp(errors{k},'const'), 
+        fprintf(fid,'\t\t\ta_y%d = %g,\r\n',k,errorParam0(count));
+        count = count + 1;
+    end
+    if strcmp(errors{k},'prop'), 
+        fprintf(fid,'\t\t\tb_y%d = %g,\r\n',k,errorParam0(count));
+        count = count + 1;
+    end
+    if strcmp(errors{k},'comb1'), 
+        fprintf(fid,'\t\t\ta_y%d = %g,\r\n',k,errorParam0(count));
+        count = count + 1;
+        fprintf(fid,'\t\t\tb_y%d = %g,\r\n',k,errorParam0(count));
+        count = count + 1;
+    end
+    if strcmp(errors{k},'exp'), 
+        fprintf(fid,'\t\t\ta_y%d = %g,\r\n',k,errorParam0(count));
+        count = count + 1;
+    end
+end
+
+% write out population parameter initial values
+text = '';
+for k=1:length(parameterNames),
+    if IIVestimate(k)==1,
+        value0 = IIVvalues0(k);
+        text = sprintf('%s\t\t\tomega_{%s} = %g,\r\n',text,parameterNames{k},value0);
+    elseif IIVestimate(k)==2,
+        value0 = IIVvalues0(k);
+        text = sprintf('%s\t\t\tomega_{%s} = %g [method=FIXED],\r\n',text,parameterNames{k},value0);
+    end
+end
+fprintf(fid,text(1:end-3));
+fprintf(fid,'\r\n');
+
+fprintf(fid,'\t\t} ),\r\n');
+if strcmp(FIMsetting,'linearization'),
+    fprintf(fid,'\testimateFisherInformationMatrix( method={linearization} ),\r\n');
+else
+    fprintf(fid,'\testimateFisherInformationMatrix( method={stochasticApproximation} ),\r\n');
+end    
+fprintf(fid,'\testimateIndividualParameters( method={%s} ),\r\n',INDIVparametersetting);
+if strcmp(LLsetting,'linearization'),
+    fprintf(fid,'\testimateLogLikelihood(method={linearization}),\r\n');
+elseif strcmp(LLsetting,'importantSampling'),
+    fprintf(fid,'\testimateLogLikelihood(method={importantSampling}),\r\n');
+elseif strcmp(LLsetting,'both'),
+    fprintf(fid,'\testimateLogLikelihood(method={importantSampling,linearization}),\r\n');
+end
+fprintf(fid,'\tdisplayGraphics()');
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% CLOSE File
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fclose(fid);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Create Project Header with Metadata
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+PROJECT_INFO_TEXT = '';
+
+% Data location
+DATA_info = sprintf('; DATA                = ''%s''\r\n',strrep(fullfile(dataRelPathFromProject,dataFileName),'\','/'));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,DATA_info);
+
+% DOSINGTYPES
+DOSINGTYPES = {};
+for k=1:length(modelinput),
+    DOSINGTYPES{k} = modelinput{k}{2};
+end
+x = sprintf('%s,',DOSINGTYPES{:});
+DOSINGTYPES_info = sprintf('; DOSINGTYPES         = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,DOSINGTYPES_info);
+
+% covNames
+x = sprintf('%s,',covNames{:});
+COVNAMES_info = sprintf('; COVNAMES            = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,COVNAMES_info);
+
+% catNames
+x = sprintf('%s,',catNames{:});
+CATNAMES_info = sprintf('; CATNAMES            = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,CATNAMES_info);
+
+% CATCATEGORIES
+CATCATEGORIES_info = sprintf('; CATCATEGORIES       = ''%s''\r\n',CAT_CATEGORIES);
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,CATCATEGORIES_info);
+
+% Regression parameters
+ix_regress = strmatchIQM('X',explodePCIQM(data.dataHeaderIdent),'exact');
+dataheader = IQMloadCSVdataset(fullfile(data.dataRelPathFromProject,data.dataFileName),1);
+regressors = dataheader(ix_regress);
+x = sprintf('%s,',regressors{:});
+REGRESSNAMES_info = sprintf('; REGRESSIONNAMES     = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,REGRESSNAMES_info);
+
+% Outputs
+x = cell(1,length(modeloutput));
+for k=1:length(modeloutput),
+    on = k;
+    x{on} = modeloutput{k}{1};
+end
+y = '';
+for k=1:length(x),
+    y = sprintf('%s%s,',y,x{k});
+end
+y = y(1:end-1);
+OUTPUTS_info = sprintf('; OUTPUTS             = ''%s''\r\n',y);
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,OUTPUTS_info);
+
+% Error models
+ERRORMODELS_info = sprintf('; ERRORMODELS         = ''%s''\r\n',errorModels);
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,ERRORMODELS_info);
+
+% PARAMNAMES
+x = sprintf('%s,',parameterNames{:});
+PARAMNAMES_info = sprintf('; PARAMNAMES          = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,PARAMNAMES_info);
+
+% PARAMTRANS
+x = sprintf('%s,',PARAM_TRANSNAME_STRING{:});
+PARAMTRANS_info = sprintf('; PARAMTRANS          = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,PARAMTRANS_info);
+
+% PARAMINVTRANS
+x = sprintf('%s,',PARAM_INVTRANSNAME_STRING{:});
+PARAMINVTRANS_info = sprintf('; PARAMINVTRANS       = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,PARAMINVTRANS_info);
+
+% COVARIATENAMES
+COVARIATENAMES = [covNames,catNames];
+x = sprintf('%s,',COVARIATENAMES{:});
+COVARIATENAMES_info = sprintf('; COVARIATENAMES      = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,COVARIATENAMES_info);
+
+% COVARIATESUSED
+COVARIATESUSED = setdiff(explodePCIQM(strrep(strrep(options.covariateModel,'{',''),'}','')),param_est);
+x = sprintf('%s,',COVARIATESUSED{:});
+COVARIATESUSED_info = sprintf('; COVARIATESUSED      = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,COVARIATESUSED_info);
+
+% BETACOVNAMES
+x = sprintf('%s,',BETACOVNAMES{:});
+BETACOVNAMES_info = sprintf('; BETACOVNAMES        = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,BETACOVNAMES_info);
+
+% BETACOVTRANS
+x = sprintf('%s,',BETACOVTRANS{:});
+BETACOVTRANS_info = sprintf('; BETACOVTRANS        = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,BETACOVTRANS_info);
+
+% BETACATNAMES
+x = sprintf('%s,',BETACATNAMES{:});
+BETACATNAMES_info = sprintf('; BETACATNAMES        = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,BETACATNAMES_info);
+
+% BETACATREFERENCE
+x = ''; for k=1:length(BETACATREFERENCE), x=sprintf('%s%g,',x,BETACATREFERENCE(k)); end
+BETACATREFERENCE_info = sprintf('; BETACATREFERENCE    = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,BETACATREFERENCE_info);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Replace PROJECT_HEADER_PLACEHOLDER
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+content = fileread('project.mlxtran');
+content = strrep(content,'PROJECT_HEADER_PLACEHOLDER',strtrim(PROJECT_INFO_TEXT));
+fid = fopen('project.mlxtran','w');
+fprintf(fid,'%s',content);
+fclose(fid);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Do generate the default graphics settings so that 
+% predictions.txt file is generated and included NPDE and meanPWRES
+% Trick is to load project file and to add things and then to save the file
+% again.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+copyfile(which('template_project_graphics.xmlx'),'project_graphics.xmlx')
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Generate project_algorithms.xmlx file
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% only writing out K1, K2, Number of Chains, Seed, and auto settings for K1,K2,Number of chains
+fid = fopen('project_algorithms.xmlx','w');
+fprintf(fid,'<monolix>\n');
+fprintf(fid,'	<algorithms seed="%d">\n',SEED);
+fprintf(fid,'		<populationParameters>\n');
+fprintf(fid,'			<vna value="%d,%d"/>\n',K1,K2);
+fprintf(fid,'			<iop_Kauto value="%d,%d"/>\n',K1_AUTO,K2_AUTO);
+fprintf(fid,'			<nmc value="%d"/>\n',NRCHAINS);
+fprintf(fid,'		</populationParameters>\n');
+fprintf(fid,'	</algorithms>\n');
+fprintf(fid,'</monolix>\n');
+fclose(fid);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Change out of project path
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+cd(oldpath);
\ No newline at end of file
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/14-GeneralLinearNLMEmodel/auxiliary/NONMEM/createGeneralLinear_NONMEMprojectIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/14-GeneralLinearNLMEmodel/auxiliary/NONMEM/createGeneralLinear_NONMEMprojectIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..ddbc6ee21be2db7c55a764dd32ae7a53abb1e19f
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/14-GeneralLinearNLMEmodel/auxiliary/NONMEM/createGeneralLinear_NONMEMprojectIQM.m	
@@ -0,0 +1,1995 @@
+function [] = createGeneralLinear_NONMEMprojectIQM(modelinfo,modelinput,modeloutput,data,projectPath,options)
+% This function allows to generate a general linear model using ADVAN5 or ADVAN7.
+% 
+%  ADVAN5 and ADVAN7 are routines in PREDPP's library which implement the
+%  general linear model.  The general linear model is used for systems in
+%  which a drug is distributed between compartments according  to  linear
+%  processes.   ADVAN7  may be used when the eigenvalues of the rate con-
+%  stant matrix are known to be real (which is true for  many  pharmacok-
+%  inetic  systems  such  as  mammillary models).  It is generally faster
+%  than ADVAN5.
+%
+% Handling the BLOQ Methods M3 and M4:  
+%   M3 or M4 method of BLOQ handling can be used. This requires a CENS
+%   column in the dataset (CENS=0 for >=LLOQ values, CENS=1 for <LLOQ
+%   values and DV=LLOQ in case of CENS=1 (just as in MONOLIX). Since M3 and
+%   M4 requires the use of "LAPLACIAN NUMERICAL SLOW" in the $EST
+%   statements with INTERACTION, the code for M3 or M4 is only added to the
+%   model if the CENS column has non-zero entries - meaning that the model
+%   in this case needs to be generated for each dataset to be run. M3 is
+%   the default method. M4 can be selected in the options by setting
+%   options.algorithm.M4 = 1.
+%
+% ASSUMPTIONS:
+% ============
+% - MU Referencing always used. 
+% - Continuous covariates are always log-transformed, independent
+%   of the distribution of the parameter on which they are added. Centering
+%   by the median (or user defined values) for the covariates. 
+% - Always untransformed categorical covariates. Several categories per
+%   covariate possible but all need to be numeric and integers.
+% - IIV correlation parameters always 0.1 at the initial guess.
+% - Selection of PRED,RES,WRES outputs dependent on the method that is used
+%   for estimation (in the tables renamed to: XPRED, XRES, XWRES):
+%       - PREDI RESI WRESI if FO
+%       - CPREDI, CRESI, CWRESI if FOCE
+%       - EPRED, ERES, EWRES if SAEM
+% - Default values for add and prop errors: 1 and 0.3
+% - Dataset can contain CMT or (ADM+YTYPE) columns. The output on the
+%   screen of this function will guide the user as to the needed values in
+%   these columns.
+%       - ADM+YTYPE but not CMT 
+%           - YTYPE defines number of output
+%           - ADM used as CMT column
+%
+%       - ADM+CMT but not YTYPE
+%           - YTYPE is inferred based on CMT for observation records (in $ERROR)
+%             But this means that CMT needs to follow the OUTPUTn numbering! 
+%           - CMT will be used as defined for selecting the dosing compartments
+%           - ADM is used to inform potential switchings for NONMEM parameters in the PK section
+%
+% [SYNTAX]
+% [] = createGeneralLinear_NONMEMprojectIQM(modelinfo,modelinput,modeloutput,data,projectPath)
+% [] = createGeneralLinear_NONMEMprojectIQM(modelinfo,modelinput,modeloutput,data,projectPath,options)
+%
+% [INPUT]
+% modelinfo:            MATLAB structure with following fields:
+%   modelinfo.modelADVAN:                  'ADVAN5' or 'ADVAN7' (default: 'ADVAN7')
+%   modelinfo.nrCompartments:              Number of states/compartments in the model
+%   modelinfo.parameterNames:              Cell-array with names of parameters to be estimated
+%   modelinfo.parameterNamesGeneral:       Cell-array with parameter names of the general linear model to define
+%                                          all others will be kept on 0. 
+%                                          Syntax: 
+%                                               Rate parameter from compartment 1 to compartment 2 is: k1T2 
+%                                               Rate parameter from compartment 3 to compartment 2 is: k3T2 
+%                                               Elimination rate parameter from compartment 2 is: k2T0
+%   modelinfo.parameterExpressionsGeneral: Cell-array linking the parameters to be estimated to the parameters in 
+%                                          the general linear model in terms of expressions.
+%                                          Same order as parameterNamesGeneral. For example, if first element in 
+%                                          parameterNamesGeneral is 'k20' then first element here could be 'CL/Vc',
+%   EXAMPLE:
+%       modelinfo                               = [];
+%       modelinfo.nrCompartments                = 3;
+%       modelinfo.parameterNames                = {'ka' 'CL' 'V' 'FM' 'CLM' 'VM'};
+%       modelinfo.parameterNamesGeneral         = {'k1T2'   'k2T0'              'k2T3'       'k3T0'};
+%       modelinfo.parameterExpressionsGeneral   = {'ka'     'CL*(1-FM)/V'       'CL*FM/V'    'CLM/VM'};
+%
+%       This example realizes a PK model with first order absorption and a
+%       metabolite. Both parent and metabolite are described by a one
+%       compartment model.
+% 
+% modelinput:           Cell-array of cell-arrays. Each inner cell-array
+%                       describes one dosing input and links the data to the model.
+%                       First element: A name for the input.
+%                       Second element: Type of the administration (use
+%                         only 'BOLUS', 'INFUSION' or 'ADMINISTRATION0'
+%                       Third element: Number of the compartment to which
+%                         the dose should be added (match with CMT number in
+%                         dataset)
+%                       Fourth element: String with text to write after
+%                         "F<<compartment number>>" ... this can be an
+%                         expression, allowing simple definition of nonlinear
+%                         bioavailability - can depend on covariates,
+%                         regression parameters etc.
+% 						Fifth element: String with expression (or single parameter)
+% 						  for lag time definition.
+% 						Sixth element: String with expression (or single parameter)
+% 						  for definition of 0 order absorption. In this case it
+% 					      would be good to set the "type" to "ABSORPTION0"
+%   EXAMPLE:
+%       modelinput  = { {'INPUT1', 'BOLUS', 1,'Fabs1'}  {'INPUT2', 'INFUSION', 2,'1', 'Tlag' 'Duration'} };
+% 
+%       This example realizes a bolus administration into the first
+%       compartment with F1=Fabs1. And an infusion into second compartment
+%       with F2=1. Note that the difference between bolus and infusion is
+%       only defined by the value in the RATE column: 0 is bolus, >1 is
+%       infusion. The distinction is only needed later when simulation in
+%       IQM Tools should be done (e.g. VPC).
+%
+% modeloutput:          Cell-array of cell-arrays. Each inner cell-array
+%                       describes one observation output and links the data
+%                       to the model. 
+%                       First element: A name for the output.
+%                       Second element: Number of the compartment to which
+%                         the dose should be added (match with CMT number in
+%                         dataset)
+%                       Third element: String with scaling expression,
+%                         allowing to transform the output to the desired
+%                         units.
+%   EXAMPLE:
+%       modeloutput = { {'CP', 2,'V*495.45/1000000'} {'CM', 3,'VM*435.49/1000000'} };
+%
+%       This example defines an output 'CP' which is measured as the amount
+%       in the second compartment and scaled (divided) by the term
+%       V*495.45/1000000 to obtain concentrations in nmol/L. Similar with
+%       the second output - here measured in the third compartment and
+%       given the name "CM".
+% 
+% data:                 Structure with following fields:
+%   data.dataRelPathFromProject:    path to data file - relative to the
+%                                   projectPath folder.
+%   data.dataFileName:              data file filename
+%   data.dataHeaderIdent:           String with datafile header identifiers (example: 'ID,TIME,Y,MDV,EVID,AMT,TINF,ADM,YTYPE,COV,COV,CAT') 
+%
+% projectPath:          String with the path/foldername to which the project files are to be written (example: 'FIT_01' or 'Models/FITS/FIT_01') 
+%
+% options:              Structure with following fields (all optional with default settings):
+%   options.POPestimate:            Vector with 0 and 1 entries. 1 if pop parameter is estimated, 0 if not. Default or []: => all are estimated
+%   options.POPvalues0:             Vector with pop parameter initial values. Default or []: => all values 1 (does not really make sense)
+%   options.IIVdistribution:        Cell-array with information about parameter distribution. L (lognormal), N (normal), G (logit)
+%                                       Example: {'L' 'L' 'L' 'L' 'N' 'L' 'L' 'L'}. Default or {}: => use lognormal for all
+%   options.IIVestimate:            Vector with 0 and 1 entries. 1 if random effect is estimated, 0 if not. Default or []: => all are estimated
+%                                   0: IIV not estimated (IIVvalues0 not used) 
+%                                   1: IIV estimated (IIVvalues0 as starting guesses)
+%                                   2: IIV not estimated but fixed on IIVvalues0 value
+%   options.IIVvalues0:             Vector with random effect parameter
+%                                   initial values. Default or []: => all set to 0.5
+%                                   If IIV not estimated then defined initial guess not used but replaced by 0
+%   options.errorModels:            String with definition of residual error models, comma separated for each output.
+%                                   Possible values: const,prop,comb1. Example: 'comb1,prop', Default or '': => const for all outputs
+%   options.errorParam0:            Vector allowing to pass initial guesses for error model parameters. Same order as error models. 
+%                                   'const': a, 'prop': b, 'comb1': a,b
+%   options.covarianceModel:        Definition of covariance model. String with cell-array text inside, grouping the parameters to consider having 
+%                                   correlated random effects. Example: '{CL,Vc},{Q,Vp,KM}'. Default: 'diagonal'
+%   options.covariateModel:         Definition of covariate model. Cell-array. Each element is a sub-cell-array. First element in sub-cell-array is the 
+%                                   parameter to which to add the covariate, all following elements define the covariates as named in the dataset.
+%                                   Example: '{CL,BMI0}, {Fsubcut,WT0}, {Vc,SEX,BMI0}'. Default: '' => no covariates
+%                                   By default (and so far not changeable, the continuous covariates are all weighted by their median, determined from the dataset)
+%                                   >>>Covariates can be added to all parameters for which not both IIVestimate and POPestimate are 0.
+%   options.covariateModelValues:   Definition of covariate coefficients for the selected covariate model. 
+%                                   Syntax is similar to options.covariateModel. It is a cell-array containing vectors instead of cell-arrays.
+%                                   Each vector contains values for the covariate coefficients, matching the covariateModel definition order.
+%                                   Example: if options.covariateModel = '{CL,BMI0,AGE0}, {Fsubcut,WT0}, {Vc,SEX,BMI0}'
+%                                   Then: options.covariateModelValues = {[0.5,0], [0.75], [0,0]}
+%                                   Defines the initial guesses for the covariate coefficients for BMI0 on CL to be 0.5, WT0 on Fsubcut to be 0.75, and the other ones are 0.
+%                                   If not defined, all covariate coefficients start from 0 in the estimation.
+%   options.COVestimate:            Same structure as options.covariateModelValues but with entries 0 or 1. 0 means not estimated, 1 means estimated.
+%                                   By default all are estimated.
+%                                   In the example above options.COVestimate = {[0,1], [1], [1,0]}   will estimate AE0 on CL, WT0 on Fsubcut, SEX on Vc.
+%                                   The other coefficients will be kept fixed.
+%   options.COVcentering.covs:      Cell-array with covariates that should be centered around a custom value. 
+%   options.COVcentering.values:    Vector with centering values. 
+%   options.keepProjectFolder:      =0: remover already existing folder, =1: keep it
+%
+% ALGORITHM SETTINGS:
+% ===================
+%
+%   options.algorithm.METHOD:       'FO','FOCE','FOCEI','SAEM' (default: SAEM)
+%   options.algorithm.MAXEVAL:      Default: 9999
+%   options.algorithm.SIGDIGITS:    Default: 3
+%   options.algorithm.PRINT:        Default: 1
+%
+%   options.algorithm.M4:           Default: 0 (default: M3 method if dataset formated with CENS column and non-zero entries in it.)
+%
+%   options.algorithm.ITS:                  Allow to run an ITS method as first method befor all other methods (METHOD)
+%                                           ITS = 0 or 1 (default: 0 if not FO) - ITS=1 only accepted if not FO!
+%   options.algorithm.ITS_ITERATIONS:       Number of iterations for ITS (default: 10)
+%
+%   options.algorithm.IMPORTANCESAMPLING:   Allow determination of the OFV - only accepted after SAEM
+%                                           Default: 0, If 1 then do the importance sampling
+%   options.algorithm.IMP_ITERATIONS:       Number of iterations for importance sampling (default: 5)
+% 
+%   options.algorithm.SEED:         Seed setting. Defualt: 123456
+%   options.algorithm.K1:           First iterations. Default: 500
+%   options.algorithm.K2:           Final iterations. Default: 200
+%   options.algorithm.NRCHAINS:     Number of parallel chains. Default: 1
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle variable input arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin<6,
+    options = [];
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Define Default Properties (Never changing)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+projectName            = 'project';
+resultsFolder          = 'RESULTS';
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle some input arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try modelADVAN                  = modelinfo.modelADVAN;                     catch, modelADVAN       = 'ADVAN7';                                     end
+try nrCompartments              = modelinfo.nrCompartments;                 catch, error('Please define modelinfo.nrCompartments,');                 end
+try parameterNames              = modelinfo.parameterNames;                 catch, error('Please define modelinfo.parameterNames,');                end
+try parameterNamesGeneral       = modelinfo.parameterNamesGeneral;          catch, error('Please define modelinfo.parameterNamesGeneral,');         end
+try parameterExpressionsGeneral = modelinfo.parameterExpressionsGeneral;    catch, error('Please define modelinfo.parameterExpressionsGeneral,');   end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check input
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try
+    dataRelPathFromProject = data.dataRelPathFromProject;
+    dataFileName           = data.dataFileName;
+    dataHeaderIdent        = data.dataHeaderIdent;
+    
+    % Need to change the data header
+    % TIME => TIME2 (Since it can contain negative times)
+    % TIMEPOS => TIME (The normal NONMEM time ... since it is only positive)
+    dataHeaderIdent         = regexprep(dataHeaderIdent,'\<TIME\>','TIME2');
+    dataHeaderIdent         = regexprep(dataHeaderIdent,'\<TIMEPOS\>','TIME');
+catch
+    error('data input argument not defined correctly.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle optional arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try POPestimate                     = options.POPestimate;                      catch, POPestimate = [];                             end
+try POPvalues0                      = options.POPvalues0;                       catch, POPvalues0 = [];                              end
+try IIVdistribution                 = options.IIVdistribution;                  catch, IIVdistribution = {};                         end
+try IIVestimate                     = options.IIVestimate;                      catch, IIVestimate = [];                             end
+try IIVvalues0                      = options.IIVvalues0;                       catch, IIVvalues0 = [];                              end
+try errorModels                     = options.errorModels;                      catch, errorModels = '';                             end
+try errorParam0                     = options.errorParam0;                      catch, errorParam0 = [];                             end
+try covarianceModel                 = options.covarianceModel;                  catch, covarianceModel = 'diagonal';                 end
+try covariateModel                  = options.covariateModel;                   catch, covariateModel = ''; options.covariateModel = '';  end
+try covariateModelValues            = options.covariateModelValues;             catch, covariateModelValues = {};                    end
+try COVestimate                     = options.COVestimate;                      catch, COVestimate = {};                             end
+
+try COVcentering_covs               = options.COVcentering.covs;                catch, COVcentering_covs = {};                       end
+try COVcentering_values             = options.COVcentering.values;              catch, COVcentering_values = [];                     end
+
+try METHOD                          = options.algorithm.METHOD;                 catch, METHOD = 'SAEM';                              end
+try MAXEVAL                         = options.algorithm.MAXEVAL;                catch, MAXEVAL = 9999;                               end
+try SIGDIGITS                       = options.algorithm.SIGDIGITS;              catch, SIGDIGITS = 3;                                end
+try PRINT                           = options.algorithm.PRINT;                  catch, PRINT = 1;                                    end
+try M4                              = options.algorithm.M4;                     catch, M4 = 0;                                       end
+try SEED                            = options.algorithm.SEED;                   catch, SEED = 123456;                                end
+try K1                              = options.algorithm.K1;                     catch, K1 = 500;                                     end
+try K2                              = options.algorithm.K2;                     catch, K2 = 200;                                     end
+try NRCHAINS                        = options.algorithm.NRCHAINS;               catch, NRCHAINS = 1;                                 end
+try IMPORTANCESAMPLING              = options.algorithm.IMPORTANCESAMPLING;     catch, IMPORTANCESAMPLING = 0;                       end
+try ITS                             = options.algorithm.ITS;                    catch, ITS = 0;                                      end
+try ITS_ITERATIONS                  = options.algorithm.ITS_ITERATIONS;         catch, ITS_ITERATIONS = 10;                          end
+try IMP_ITERATIONS                  = options.algorithm.IMP_ITERATIONS;         catch, IMP_ITERATIONS = 10;                          end
+
+try SILENT                          = options.SILENT;                           catch, SILENT = 0;                                   end
+
+try keepProjectFolder               = options.keepProjectFolder;                catch, keepProjectFolder = 0;                        end   
+
+if ~iscell(COVcentering_covs),
+    COVcentering_covs = {COVcentering_covs};
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle modelinput and modeloutput - cellarray of cellarrays
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~iscell(modelinput{1}),
+    modelinput = {modelinput};
+end
+
+if ~iscell(modeloutput{1}),
+    modeloutput = {modeloutput};
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle methods - some IQM Tools limitations
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if strcmp(METHOD,'FO') && ITS==1,
+   error('The FO method should not be used with ITS=1.');
+end
+
+if ~strcmp(METHOD,'SAEM') && IMPORTANCESAMPLING==1,
+    error('The importance sampling (IMPORTANCESAMPLING=1) should only be used with the SAEM method.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Info text
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~SILENT,
+    disp(' ')
+    disp('==================================================================');
+    [xdummyx,projectFolderName] = fileparts(projectPath);
+    disp(sprintf('== Start of creation of %s/project.nmctl file',projectFolderName));
+    disp('==================================================================');
+    disp(' ')
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Create project and results folder
+% Change into project path
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+warning off
+oldpath = pwd;
+if ~keepProjectFolder,
+    try, rmdir(projectPath,'s'); catch, end
+end
+mkdir(projectPath); cd(projectPath)
+mkdir(resultsFolder);
+warning on
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Load data and get info about data
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+dataModeling = IQMloadCSVdataset([data.dataRelPathFromProject '/' data.dataFileName]);
+% Determine maximum number of data records per ID
+maxDATARECORDS_ID = -Inf;
+allID = unique(dataModeling.ID);
+for k=1:length(allID),
+    datak = dataModeling(dataModeling.ID==allID(k),:);
+    maxDATARECORDS_ID = max(maxDATARECORDS_ID,height(datak));
+end
+maxDATARECORDS = height(dataModeling);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Process data to get the dataheader and the median values for the covariates
+% and the categorical covariate names and their unique values.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[covariateMedianNames,covariateMedianValues,covariateCATNames,covariateCATValues,dataheader,dataCSV] = processDataAndGetMedianValuesIQM(oldpath,dataRelPathFromProject,dataFileName,dataHeaderIdent,SILENT,COVcentering_covs,COVcentering_values);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check data regarding the CMT/ADM/YTYPE thing
+% Allowed combinations:
+%
+%  - ADM+YTYPE but not CMT 
+%       - YTYPE defines number of output
+%       - ADM used as CMT column
+%
+%  - ADM+CMT but not YTYPE
+%       - YTYPE is inferred based on CMT for observation records (in $ERROR)
+%         But this means that CMT needs to follow the OUTPUTn numbering! 
+%       - CMT will be used as defined for selecting the dosing compartments
+%       - ADM is used to inform potential switchings for NONMEM parameters in the PK section
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+dataHeaderIdentAll = explodePCIQM(dataHeaderIdent);
+
+ix_CMT   = strmatchIQM('CMT',dataHeaderIdentAll,'exact');
+ix_ADM   = strmatchIQM('ADM',dataHeaderIdentAll,'exact');
+ix_YTYPE = strmatchIQM('YTYPE',dataHeaderIdentAll,'exact');
+
+%%
+if isempty(ix_CMT) && ~isempty(ix_ADM) && ~isempty(ix_YTYPE),
+    FLAG_CMT = 0;
+elseif ~isempty(ix_CMT) && ~isempty(ix_ADM) && isempty(ix_YTYPE),
+    FLAG_CMT = 1;
+else
+    error('Not allowed ADM/YTYPE/CMT combinations. Allowed: ADM+YTYPE or ADM+CMT (CMT defines dosing compartments and output numbers).');
+end
+
+if ~isempty(ix_CMT),
+    FLAG_CMT = 1;       % Defines that the CMT column is present
+    % Also means that ADM is present and can be accessed in the NONMEM code
+else
+    FLAG_CMT = 0;       % Defines that the CMT column is not present and that ADM and YTYPE are present instead
+    % Need to rename ADM to CMT in dataHeaderIdentAll, dataHeaderIdent, dataheader
+    dataHeaderIdent = regexprep(dataHeaderIdent,'\<ADM\>','CMT');
+    dataheader{strmatchIQM('ADM',dataheader,'exact')} = 'CMT';
+    dataHeaderIdentAll{strmatchIQM('ADM',dataHeaderIdentAll,'exact')} = 'CMT';
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check and update default input arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check POPestimate thing
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(POPestimate),
+    POPestimate = ones(1,length(parameterNames));
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check POPvalues0 thing
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(POPvalues0),
+    POPvalues0 = ones(1,length(parameterNames));
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check IIV distribution things
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(IIVdistribution),
+    IIVdistribution = {};
+    for k=1:length(parameterNames),
+        IIVdistribution{k} = 'L';
+    end
+end
+
+% Check contents
+test = IIVdistribution;
+for k=1:length(IIVdistribution),
+    if ~ismember(test{k},{'L','N','G'}),
+        cd(oldpath);
+        error('Please make sure that only "N", "L", or "G" appear in the "IIVdistribution" variable.');
+    end
+end
+
+% Check length
+if length(IIVdistribution) ~= length(parameterNames),
+    cd(oldpath);
+    error('Please make sure that an equal number of IIVdistribution is defined as estimated parameters in the model.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check IIV estimation things
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(IIVestimate),
+    IIVestimate = ones(1,length(parameterNames));
+end
+% Check length
+if length(IIVestimate) ~= length(parameterNames),
+    cd(oldpath);
+    error('Please make sure that an equal number of IIVestimate is defined as estimated parameters in the model.');
+end
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check IIVvalues0 thing
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(IIVvalues0),
+    IIVvalues0 = ones(1,length(parameterNames));
+end
+if length(parameterNames) ~= length(IIVvalues0),
+    cd(oldpath);
+    error('Please make sure IIVvalues0 is of same length as number of parameters to be estimated.');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Convert covariate model into different syntax
+% '{CL,BMI0}, {Fsubcut,WT0}, {Vc,SEX,BMI0}'
+% to
+% {{'CL','BMI0'}, {'Fsubcut','WT0'}, {'Vc','SEX','BMI0'}}
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(covariateModel),
+    terms = explodePCIQM(covariateModel,',','{','}');
+    y = {};
+    for k=1:length(terms),
+        x = strrep(strtrim(terms{k}),' ','');
+        x = strrep(x,'{','{''');
+        x = strrep(x,'}','''}');
+        x = strrep(x,',',''',''');
+        y{k} = eval(x);
+    end
+    covariateModel = y;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check covariateModelValues
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(covariateModel) && ~isempty(covariateModelValues),
+    error('If you define covariateModelValues, you also need to define the covariateModel.');
+end
+
+if isempty(covariateModelValues),
+    % Determine default covariateModelValues
+    covariateModelValues = {};
+    for k=1:length(covariateModel),
+        covariateModelValues{k} = zeros(1,length(covariateModel{k})-1);
+    end
+else
+    % Check correct length of covariateModelValues elements
+    if length(covariateModel) ~= length(covariateModelValues),
+        error('Number of elements in covariateModel and covariateModelValues needs to match.');
+    end
+    for k=1:length(covariateModel),
+        if length(covariateModel{k})-1 ~= length(covariateModelValues{k}),
+            error('Length of single elements in covariateModel and covariateModelValues needs to match (covariateModelValues elements being one shorter).');
+        end            
+    end    
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check COVestimate
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(covariateModel) && ~isempty(COVestimate),
+    error('If you define COVestimate, you also need to define the covariateModel.');
+end
+
+if isempty(COVestimate),
+    % Determine default COVestimate - all are estimates
+    COVestimate = {};
+    for k=1:length(covariateModel),
+        COVestimate{k} = ones(1,length(covariateModel{k})-1);
+    end
+else
+    % Check correct length of COVestimate elements
+    if length(covariateModel) ~= length(COVestimate),
+        error('Number of elements in covariateModel and COVestimate needs to match.');
+    end
+    for k=1:length(covariateModel),
+        if length(covariateModel{k})-1 ~= length(COVestimate{k}),
+            error('Length of single elements in covariateModel and COVestimate needs to match (COVestimate elements being one shorter).');
+        end            
+    end    
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Reorder estimation parameters to allow for block-diagonal covariance
+% matrix
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if strcmp(covarianceModel,'diagonal') || isempty(covarianceModel),
+    % Keep parameters in the given order
+    POPestimate_trans       = POPestimate;
+    POPvalues0_trans        = POPvalues0;
+    IIVestimate_trans       = IIVestimate;
+    IIVvalues0_trans        = IIVvalues0;
+    parameterNames_trans    = parameterNames;
+    IIVdistribution_trans   = IIVdistribution;    
+else
+    % Need to rearrange
+    % Determine the order of parameters as they appear in the
+    % covarianceModel definition
+    x = strrep(covarianceModel,'{','');
+    x = strrep(x,'}','');
+    terms = explodePCIQM(x);
+    % Check which parameters are missing
+    paramnames_order = terms;
+    for k=1:length(parameterNames),
+        if ~ismember(parameterNames{k},paramnames_order),
+            paramnames_order{end+1} = parameterNames{k};
+        end
+    end
+    % Determine the transformation indices
+    index_trans = [];
+    for k=1:length(paramnames_order),
+        index_trans(k) = strmatchIQM(paramnames_order{k},parameterNames,'exact');
+    end
+    % Ok, we got the new order of the parameters, now we need to change the
+    % order in a couple of things
+    % POPestimate
+    % POPvalues0
+    % IIVdistribution
+    % IIVestimate
+    % IIVvalues0
+    % parameterNames
+    POPestimate_trans       = POPestimate(index_trans);
+    POPvalues0_trans        = POPvalues0(index_trans);
+    IIVestimate_trans       = IIVestimate(index_trans);
+    IIVvalues0_trans        = IIVvalues0(index_trans);
+    parameterNames_trans    = parameterNames(index_trans);
+    IIVdistribution_trans   = IIVdistribution(index_trans);
+end
+% Update the variables to the transformed ones
+POPestimate             = POPestimate_trans;
+POPvalues0              = POPvalues0_trans;
+IIVestimate             = IIVestimate_trans;
+IIVvalues0              = IIVvalues0_trans;
+parameterNames          = parameterNames_trans;
+IIVdistribution         = IIVdistribution_trans;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Do additional checks and write out information
+% Definition of param_est and IIVestimation + reordering needed to be ready
+% before running these checks.
+% Additionally, the names of the covariates are determined and the
+% errorModels default setting is handled here.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%
+% Determine continuous and categorical covariates
+%%%%%%%%%%%%%%%%%%%%%%%
+dataHeaderIDs   = explodePCIQM(dataHeaderIdent,',');
+covIDs          = strmatchIQM('COV',upper(dataHeaderIDs));
+covNames        = dataheader(covIDs);
+catIDs          = strmatchIQM('CAT',upper(dataHeaderIDs));
+catNames        = dataheader(catIDs);
+
+%%%%%%%%%%%%%%%%%%%%%%%
+% Check all headers
+%%%%%%%%%%%%%%%%%%%%%%%
+if ~SILENT,
+    disp(' ');
+    disp('Please check that the following matches between data header and identifiers do make sense:');
+    for k=1:length(dataheader),
+        fprintf('\t%s%s: %s\n',dataheader{k},char(32*ones(1,8-length(dataheader{k}))),dataHeaderIDs{k})
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check residual error things
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(errorModels),
+    errorModels = '';
+    for k=1:length(modeloutput),
+        errorModels = sprintf('%sconst,',errorModels);
+    end
+    errorModels = errorModels(1:end-1);
+end
+test = errorModels;
+test = strtrim(strrep(strrep(strrep(strrep(test,'const',''),'prop',''),'comb1',''),',',''));
+if ~isempty(test),
+    cd(oldpath);
+    error('Please make sure that only "const", "prop", or "comb1" appear in the "errorModels" variable.');
+end
+% Check length
+errors = explodePCIQM(errorModels,',');
+if length(errors) ~= length(modeloutput),
+    cd(oldpath);
+    error('Please make sure that an equal number of errorModels is defined as outputs in the model.');
+end
+% Print table parameter names and IIV distributions
+if ~SILENT,
+    disp(' ');
+    disp('Please check that the following matches between outputs and used residual error models are correct:');
+    for k=1:length(modeloutput),
+        fprintf('\t%s%s: %s\n',modeloutput{k}{1},char(32*ones(1,15-length(modeloutput{k}{1}))),errors{k})
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle empty errorParam0
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(errorParam0),
+    terms = explodePCIQM(errorModels);
+    for k=1:length(terms),
+        if strcmp(lower(terms{k}),'const'),
+            errorParam0(end+1) = 1;
+        elseif strcmp(lower(terms{k}),'prop'),
+            errorParam0(end+1) = 0.3;
+        elseif strcmp(lower(terms{k}),'comb1'),
+            errorParam0(end+1) = 1;
+            errorParam0(end+1) = 0.3;          
+        end
+    end
+end
+
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check errorParam0
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+terms = explodePCIQM(errorModels);
+nrneededelements = 0;
+for k=1:length(terms),
+    if strcmp(lower(terms{k}),'const'),
+        nrneededelements = nrneededelements+1;
+    elseif strcmp(lower(terms{k}),'prop'),
+        nrneededelements = nrneededelements+1;
+    elseif strcmp(lower(terms{k}),'comb1'),
+        nrneededelements = nrneededelements+2;
+    end
+end
+if length(errorParam0) ~= nrneededelements,
+    error('Incorrect number of elements in options.errorParam0.');
+end
+
+
+%%%%%%%%%%%%%%%%%%%%%%%
+% Check covariance model
+%%%%%%%%%%%%%%%%%%%%%%%
+if isempty(covarianceModel),
+    covarianceModel = 'diagonal';
+end
+
+if ~strcmp(covarianceModel,'diagonal'),
+    % Need to check that none of the parameters for which no IIV is estimated is used in the covarianceModel
+    param_est_noIIV = parameterNames(IIVestimate~=1);
+    for k=1:length(param_est_noIIV),
+        if ~isempty(regexp(covarianceModel,['\<' param_est_noIIV{k} '\>'])),
+            cd(oldpath);
+            error('Please make sure none of the parameters for which NO IIV is estimated (IIVestimate 0 and 2) is used in the covarianceModel settings.');
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%
+% Check covariate model things
+%%%%%%%%%%%%%%%%%%%%%%%
+% First check that all first elements are estimated parameters of the model
+for k=1:length(covariateModel),
+    param = covariateModel{k}{1};
+    if isempty(strmatchIQM(param,parameterNames,'exact')),
+        cd(oldpath);
+        error('Please make sure that all parameters for which covariates are defined are defined by <estimate> in the model.');
+    end
+end
+% Second check that all defined covariates actually are covariates
+covcatNames = [covNames catNames];
+for k=1:length(covariateModel),
+    for k2=2:length(covariateModel{k}),
+        cov = covariateModel{k}{k2};
+        if isempty(strmatchIQM(cov,covcatNames,'exact')),
+            error('Please make sure that all covariates, defined in covariateModel, are defined in the dataset.');
+        end
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check for absorption0 presence
+% The user will be warned that RATE needs to be set to -2 for these doses
+% Additionally, the dataset might be updated if RATE column present and 0 order
+% doses present in dataset and RATE not set to -2. The updated dataset then is 
+% saved in the NLME project folder and the dataset name and relative path are 
+% changed accordingly.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+inputTYPES = {};
+for k=1:length(modelinput),
+    inputTYPES{k} = modelinput{k}{2};
+end
+
+if ismember('ABSORPTION0',inputTYPES),
+    % Warn the user about the presence of ABSORPTION0 doses:
+    if ~SILENT,
+        disp(' ');
+        fprintf('==========================================================\n');
+        fprintf('0 order administration present in model:\n');
+        fprintf('If no RATE column present an error will appear!\n');
+        fprintf('If RATE column present but values not -2 for entries of\n');
+        fprintf('0 order absorption doses, then a new dataset will be\n');
+        fprintf('generated with RATE=-2 and saved in the NLME project folder.\n');
+        fprintf('The generated model will then use this updated dataset!\n');      
+        fprintf('==========================================================\n');
+        disp(' ');
+    end
+    
+    % Check if RATE=-2 for the 0 order absorption dose events
+    FIX_dataset_0order_absorption = 0;
+    ix_inputs_0order = strmatchIQM('ABSORPTION0',inputTYPES);
+    for k=1:length(ix_inputs_0order),
+        input_number = ix_inputs_0order(k);
+        datak = dataModeling(dataModeling.ADM==input_number,:);
+        
+        % Only check further if datak is not empty (if empty then model might contain 0th order absorption input(s), 
+        % but data does not contain doses for this/these input(s)
+        fixRATEminus2 = 0;
+        if ~isempty(datak),
+            try
+                RATE = unique(datak.RATE);
+            catch
+                error('Please check if a RATE column is present and that the entries for 0 order absorption doses are set to -2');
+            end
+            if length(RATE)~=1,
+                fixRATEminus2 = 1;
+            else
+                if RATE~=-2,
+                    fixRATEminus2 = 1;
+                end
+            end
+        end
+        
+        % If RATE for 0 order absorption not defined adequately (-2) then fix that and save the fixed dataset in the NLME project folder.
+        if fixRATEminus2,
+            dataModeling.RATE(dataModeling.ADM==input_number) = -2;
+            FIX_dataset_0order_absorption = 1;
+        end
+    end
+    
+    if FIX_dataset_0order_absorption,
+        % Need to save the fixed dataset in the NLME project folder
+        % Define new name
+        [p,f,e] = fileparts(data.dataFileName);
+        FIX_dataset_0order_absorption_NewName = [f '_0orderABS_fix.csv'];
+        IQMexportCSVdataset(dataModeling,FIX_dataset_0order_absorption_NewName);
+        % Update data file information
+        dataRelPathFromProject = '.'; % data file in project folder
+        dataFileName = FIX_dataset_0order_absorption_NewName; % New name
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% OPEN File
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fid = fopen([projectName '.nmctl'],'w');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% INFO
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; NONMEM PROJECT, created using IQM Tools\r\n');
+fprintf(fid,'; Date: %s\r\n',datestr(now,'yyyy-mmm-DD HH:MM'));
+fprintf(fid,'; By:   %s\r\n',usernameIQM());
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Placeholder for project information
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; ==PROJECT HEADER START===================================================\r\n');
+fprintf(fid,'PROJECT_HEADER_PLACEHOLDER\r\n');
+fprintf(fid,'; ==PROJECT HEADER END=====================================================\r\n');
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Define $SIZES
+% Set all LIM1,2,6 to TOTDREC=maxDATARECORDS!
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'$SIZES LIM1=%d\r\n',maxDATARECORDS);
+fprintf(fid,'$SIZES LIM2=%d\r\n',maxDATARECORDS);
+fprintf(fid,'$SIZES LIM6=%d\r\n',maxDATARECORDS);
+fprintf(fid,'$SIZES LTH=XXX\r\n');
+% Define PD as number of columns that are not skipped
+PD = length(explodePCIQM(data.dataHeaderIdent))-length(strfind(data.dataHeaderIdent,'IGNORE'))+5;
+fprintf(fid,'$SIZES PD=%d\r\n',PD);
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $PROBLEM
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[xdummyx,problemName]     = fileparts(projectPath);
+fprintf(fid,'$PROBLEM %s\r\n',problemName);
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $DATA
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'$DATA %s\r\n',strrep(fullfile(dataRelPathFromProject,dataFileName),'\','/'));
+fprintf(fid,'    IGNORE=@\r\n');
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $INPUT
+% Assumption: names for INPUT are used as in the dataset for CAT,COV,X
+% for all others as in dataHeaderIdent.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+dataHeaderIdentAll = explodePCIQM(dataHeaderIdent);
+
+text = '$INPUT';
+for k=1:length(dataheader),
+    col     = dataheader{k};
+    coltype = dataHeaderIdentAll{k};
+    
+    % Check if CAT, COV or X
+    if ismember(coltype,{'CAT','COV','X'}),
+        % Use name as in dataset header
+        text = sprintf('%s %s',text,col);
+    elseif strcmp(coltype,'IGNORE'),
+        % If column set to IGNORE then use SKIP in the $INPUT definition
+        text = sprintf('%s SKIP',text);
+    else
+        % Use name as in dataset ident
+        text = sprintf('%s %s',text,coltype);
+    end
+end
+fprintf(fid,'%s\r\n',wrapRowTextIQM(text,80,7));
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $SUBROUTINE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'$SUBROUTINE %s\r\n\r\n',modelADVAN);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $MODEL
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'$MODEL NCOMP=%d\r\n\r\n',nrCompartments);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $PK - Start
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'$PK\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $PK - PK parameters
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; Parameters\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $PK - Start by THETAs
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+MU_param_text = {};
+for k=1:length(parameterNames)
+    MU_param_text{k} = sprintf('    MU_%d%s = THETA(%d)%sX#X#X    ; %s\r\n',k,char(32*ones(1,2-length(num2str(k)))),k,char(32*ones(1,2-length(num2str(k)))),parameterNames{k});
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $PK - Introduce covariates
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+beta_parameters     = {};
+beta_parameters_cov_project_info     = {};
+beta_parameters_cat_project_info     = {};
+THETA_INDEX_BETA    = [];
+cov_type_continuous = [];
+covparam            = {};
+covcov              = {};
+
+COV_transformation_info = {};
+CAT_reference_info = {};
+CAT_categories_info = {};
+
+COVCATestimate_info = [];
+
+%%%%%%%%%%%%%%%%%%%%
+% Handle the CONTINUOUS covariate definitions and their introduction into
+% the MU referencing.
+%%%%%%%%%%%%%%%%%%%%
+parameter_add_cov   = {};
+cov_add_cov         = {};
+cov_add_median      = [];
+covTrans_text       = {};
+count = 1;
+for kcov=1:length(covariateModel),
+    covParam = covariateModel{kcov}{1};
+    covCOVs  = covariateModel{kcov}(2:end);
+    for k2=1:length(covCOVs),
+        if ismember(covCOVs{k2},covariateMedianNames),
+            beta_parameters{end+1}      = sprintf('beta_%s(%s)',covParam,covCOVs{k2});
+            theta_index                 = length(parameterNames)+count;
+            THETA_INDEX_BETA(end+1)     = theta_index;
+            cov_type_continuous(end+1)  = 1;
+            count                       = count+1;
+            parameter_add_cov{end+1}    = covParam;
+            cov_add_cov{end+1}          = covCOVs{k2};
+            cov_median                  = covariateMedianValues(strmatchIQM(covCOVs{k2},covariateMedianNames,'exact'));
+            cov_add_median(end+1)       = cov_median;
+            
+            COVCATestimate_info(end+1)  = COVestimate{kcov}(k2);
+            
+            % find index of parameter to add covariate to
+            ix                          = strmatchIQM(covParam,parameterNames,'exact');
+            % Get transformation
+            TRANS                       = IIVdistribution{ix};
+            if TRANS=='N',
+                covTrans_text{end+1} = sprintf('+ THETA(%d)*log(%s/%g) ',theta_index,covCOVs{k2},cov_median);
+                COV_transformation_info{end+1} = sprintf('log(cov/%g)',cov_median);
+            elseif TRANS=='L',
+                covTrans_text{end+1} = sprintf('+ THETA(%d)*log(%s/%g) ',theta_index,covCOVs{k2},cov_median);
+                COV_transformation_info{end+1} = sprintf('log(cov/%g)',cov_median);
+            elseif TRANS=='G',
+                covTrans_text{end+1} = sprintf('+ THETA(%d)*log(%s/%g) ',theta_index,covCOVs{k2},cov_median);
+                COV_transformation_info{end+1} = sprintf('log(cov/%g)',cov_median);
+            end
+        end
+    end
+end
+% Aggregate covariate text for each parameter
+cov_add_text_param = cell(1,length(parameterNames));
+cov_add_text_param(1:end) = {''};
+for k=1:length(parameter_add_cov),
+    ix = strmatchIQM(parameter_add_cov{k},parameterNames,'exact');
+    cov_add_text_param{ix} = [cov_add_text_param{ix} covTrans_text{k}];
+end
+% Add continuous covariates into MU_param_text
+for k=1:length(MU_param_text),
+    MU_param_text{k} = strrep(MU_param_text{k},'X#X#X',[strtrim(cov_add_text_param{k}) 'X#X#X']);
+end
+% Save for later
+covparam            = parameter_add_cov;
+covcov              = cov_add_cov;
+
+beta_parameters_cov_project_info     = beta_parameters;
+
+
+%%%%%%%%%%%%%%%%%%%%
+% Handle the categorical covariates
+% 
+% Example:
+% SEX_1 = 0 (can be omitted)
+% SEX_2 = 0
+% SEX_3 = 0
+% IF SEX==1 THEN SEX_1 = 1 (can be omitted)
+% IF SEX==2 THEN SEX_2 = 1
+% IF SEX==3 THEN SEX_3 = 1
+%     
+% MU_3  = THETA(3) + beta_SEX_2_WT*SEX_2 + beta_SEX_3_WT*SEX_3
+% 
+% Assume reference is always the first one with the smallest number
+%%%%%%%%%%%%%%%%%%%%
+
+text_defining_cat_auxiliaries = '';
+cov_text = cell(1,length(parameterNames));
+cov_text(1:end) = {''};
+covs_handled_text_defining_cat_auxiliaries = {};
+for kcov=1:length(covariateModel),
+    covParam = covariateModel{kcov}{1};
+    covCOVs  = covariateModel{kcov}(2:end);
+    for k2=1:length(covCOVs),
+        if ismember(covCOVs{k2},covariateCATNames),
+            cov                         = covCOVs{k2};
+            cov_values                  = covariateCATValues{strmatchIQM(covCOVs{k2},covariateCATNames,'exact')};
+            reference_value             = cov_values(1);
+            other_values                = cov_values(2:end);
+            
+            CAT_reference_info{end+1}   = reference_value;
+            CAT_categories_info{end+1}  = cov_values;
+                        
+            % Define the auxiliary text to be added before the MU thingy
+            if ~ismember(cov,covs_handled_text_defining_cat_auxiliaries),
+                for kaux=1:length(other_values),
+                    text_defining_cat_auxiliaries = sprintf('%s    %s_%d = 0 ; reference: %d\r\n',text_defining_cat_auxiliaries,cov,other_values(kaux),reference_value);
+                end
+                for kaux=1:length(other_values),
+                    text_defining_cat_auxiliaries = sprintf('%s    IF(%s.EQ.%d) %s_%d = 1\r\n',text_defining_cat_auxiliaries,cov,other_values(kaux),cov,other_values(kaux));
+                end
+                % Set cov as handled
+                covs_handled_text_defining_cat_auxiliaries{end+1} = cov;
+            end
+            
+            % Define the rest
+            for kaux=1:length(other_values),
+                COVCATestimate_info(end+1)  = COVestimate{kcov}(k2);
+                
+                covparam{end+1} = covParam;
+                covcov{end+1} = cov;
+                beta_parameters{end+1}      = sprintf('beta_%s(%s_%d)',covParam,cov,other_values(kaux));
+
+                % Check if beta_parameters_cat_project_info already
+                % contains element
+                element_add_check = sprintf('beta_%s(%s)',covParam,cov);
+                if isempty(strmatchIQM(element_add_check,beta_parameters_cat_project_info,'exact')),
+                    % not present => add it
+                    beta_parameters_cat_project_info{end+1} = element_add_check;
+                end
+                
+                if isempty(THETA_INDEX_BETA),
+                    nextindex = length(parameterNames)+1;
+                else
+                    nextindex                   = max(THETA_INDEX_BETA)+1;
+                end
+                THETA_INDEX_BETA(end+1)     = nextindex;
+                cov_type_continuous(end+1)  = 0;
+                ixParam                     = strmatchIQM(covParam,parameterNames,'exact');
+                cov_text{ixParam}           = sprintf('%s + THETA(%d)*%s_%d',cov_text{ixParam},nextindex,cov,other_values(kaux));
+            end
+        end
+    end
+end
+
+% Add continuous covariates into MU_param_text
+for k=1:length(MU_param_text),
+    MU_param_text{k} = strrep(MU_param_text{k},'X#X#X',cov_text{k});
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $PK - Write out the auxiliaries if needed
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~isempty(text_defining_cat_auxiliaries),
+    fprintf(fid,'; Auxiliary definitions for handling categorical covariates\r\n');
+    fprintf(fid,'%s\r\n',text_defining_cat_auxiliaries);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $PK - MU Referencing
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; MU Referencing\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle MU_param_text to wrap lines
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+MAXLENGTHLINE = 80;
+for k=1:length(MU_param_text),
+    if length(MU_param_text{k}) > MAXLENGTHLINE,
+        xxx = MU_param_text{k};
+        % Get first additive element
+        ix = strfind(xxx,' + ');
+        ix = ix(1);
+        text_start = xxx(1:ix(1));
+        text_wrap = xxx(ix(1)+3:end);
+        pieces_wrap = {};
+        while length(text_wrap)>MAXLENGTHLINE,
+            ix = strfind(text_wrap,' + ');
+            ixx = ix(find(ix>MAXLENGTHLINE)-1);
+            if ~isempty(ixx),
+                ix = ixx(1);
+            else
+                ix = ix(end);
+            end
+            pieces_wrap{end+1} = text_wrap(1:ix);
+            text_wrap = text_wrap(ix+3:end);
+        end        
+        pieces_wrap{end+1} = text_wrap;
+        for k2=1:length(pieces_wrap),
+            if k2==1,
+                pieces_wrap{k2} = sprintf('    MU%dWRAP_%d = %s',k,k2,strtrim(pieces_wrap{k2}));
+            else
+                pieces_wrap{k2} = sprintf('    MU%dWRAP_%d = MU%dWRAP_%d + %s',k,k2,k,k2-1,strtrim(pieces_wrap{k2}));
+            end
+        end
+        pieces_wrap{end+1} = sprintf('%s + MU%dWRAP_%d',text_start,k,k2);
+        
+        % Put together
+        xxx = '';
+        for k2=1:length(pieces_wrap),
+            xxx = sprintf('%s%s\r\n',xxx,pieces_wrap{k2});
+        end
+        
+        MU_param_text{k} = xxx;
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $PK - Write out the MU parameter definitions with covariates
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for k=1:length(MU_param_text),
+    fprintf(fid,'%s',MU_param_text{k});
+end
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $PK - Parameter transformations
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; MU+ETA\r\n');
+for k=1:length(parameterNames),
+    fprintf(fid,'    T_%s%s = MU_%d + ETA(%d)\r\n',parameterNames{k},char(32*ones(1,cellmaxlengthIQM(parameterNames)-length(parameterNames{k})+1)),k,k);
+end
+fprintf(fid,'\r\n');
+
+fprintf(fid,'; Parameter transformations\r\n');
+for k=1:length(parameterNames),
+    if IIVdistribution{k} == 'N',
+        fprintf(fid,'    %s%s = T_%s\r\n',parameterNames{k},char(32*ones(1,cellmaxlengthIQM(parameterNames)-length(parameterNames{k})+1)),parameterNames{k});
+    elseif  IIVdistribution{k} == 'L',
+        fprintf(fid,'    %s%s = EXP(T_%s)\r\n',parameterNames{k},char(32*ones(1,cellmaxlengthIQM(parameterNames)-length(parameterNames{k})+1)),parameterNames{k});
+    elseif  IIVdistribution{k} == 'G',
+        fprintf(fid,'    %s%s = EXP(T_%s)/(1+EXP(T_%s))\r\n',parameterNames{k},char(32*ones(1,cellmaxlengthIQM(parameterNames)-length(parameterNames{k})+1)),parameterNames{k},parameterNames{k});
+    else
+        error('Unknown distribution.');
+    end
+end
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $PK - Renaming to match the used ADVAN/TRANS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; Assigning expressions to match %s parameterization\r\n',modelADVAN);
+for k=1:length(parameterNamesGeneral),
+    fprintf(fid,'    %s = %s\r\n',parameterNamesGeneral{k},parameterExpressionsGeneral{k});
+end
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $PK - Compartment assignment, etc.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% F parameters
+for k=1:length(modelinput),
+    inputk = modelinput{k};
+    name = inputk{1};
+    CMTnr = inputk{3};
+    Fexpression = inputk{4};
+    fprintf(fid,'    F%d = %s     ; %s\r\n',CMTnr,Fexpression,name);
+end
+fprintf(fid,'\r\n');
+
+% Lag time
+for k=1:length(modelinput),
+    inputk = modelinput{k};
+    name = inputk{1};
+    CMTnr = inputk{3};
+    try
+        Tlag = inputk{5};
+    catch
+        Tlag = [];
+    end
+    if ~isempty(Tlag),
+        fprintf(fid,'    ALAG%d = %s     ; %s\r\n',CMTnr,Tlag,name);
+    end
+end
+fprintf(fid,'\r\n');
+
+% Duration for zero order absorption
+for k=1:length(modelinput),
+    inputk = modelinput{k};
+    name = inputk{1};
+    CMTnr = inputk{3};
+    try
+        Duration = inputk{6};
+    catch
+        Duration = [];
+    end
+    if ~isempty(Duration),
+        fprintf(fid,'    D%d = %s     ; %s\r\n',CMTnr,Duration,name);
+    end
+end
+fprintf(fid,'\r\n');
+
+% Scaling
+for k=1:length(modeloutput),
+    outputk = modeloutput{k};
+    name = outputk{1};
+    CMTnr = outputk{2};
+    Scaling = outputk{3};
+    fprintf(fid,'    S%d = %s     ; %s\r\n',CMTnr,Scaling,name);
+end
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $ERROR
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'$ERROR\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $ERROR - error models
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Define next index for THETA parameters
+if isempty(THETA_INDEX_BETA),
+    THETA_INDEX_NEXT = length(parameterNames)+1;
+else
+    THETA_INDEX_NEXT = max(THETA_INDEX_BETA)+1;
+end
+THETA_ERROR_MODELS_IX = [];
+THETA_ERROR_MODELS_NAME = {};
+THETA_ERROR_MODELS_VALUE = [];
+error_model = explodePCIQM(errorModels);
+
+% Check if BLOQ data is to be handled in the MODEL (M3 and M4 methods)
+CENS_tobehandled = 0;
+if ~isempty(strfind(data.dataHeaderIdent,',CENS')),
+    if ~isempty(find(dataCSV.CENS==1)),
+        CENS_tobehandled = 1;
+        if ~SILENT,
+            disp(' ');
+            disp('BLOQ - Handling in the NONMEM code:');
+            disp('===================================');
+            if M4,
+                disp('Using the M4 method.');
+            else
+                disp('Using the M3 method.');
+            end
+            disp(' ');
+        end
+    end
+end
+
+fprintf(fid,'; just to avoid a NONMEM warning\r\n');
+if CENS_tobehandled,
+    fprintf(fid,'    CUMD  = 0 ; only needed for M4 method\r\n');
+    fprintf(fid,'    CUMDZ = 0 ; only needed for M4 method\r\n');
+end
+fprintf(fid,'    Y     = 0.1\r\n\r\n');
+  
+output_parameters_project_info = {};
+count = 1;
+for k=1:length(modeloutput),
+    outputk = modeloutput{k};
+    name = outputk{1};
+    CMTk = outputk{2};
+    outputNumber = k;
+    
+    fprintf(fid,'; Error model %s (CMT=%d)\r\n',name,CMTk);
+    
+    textError = '';
+    textError = sprintf('%s        %s     = A(%d)/S%d\r\n',textError,name,CMTk,CMTk);
+    textError = sprintf('%s        IPRED  = %s\r\n',textError,name);
+    textError = sprintf('%s        IRES   = DV - IPRED\r\n',textError);
+    
+    if strcmpi(error_model{k},'const'),
+        textError = sprintf('%s        W      = THETA(%d)\r\n',textError,THETA_INDEX_NEXT); 
+        THETA_ERROR_MODELS_IX(end+1) = THETA_INDEX_NEXT;
+        THETA_ERROR_MODELS_NAME{end+1} = sprintf('Additive error %s',name);
+        THETA_ERROR_MODELS_VALUE(end+1) = errorParam0(count);
+        count = count + 1;
+        THETA_INDEX_NEXT = THETA_INDEX_NEXT+1;
+        output_parameters_project_info{end+1} = sprintf('error_ADD%d',outputNumber);
+    elseif strcmpi(error_model{k},'prop'),
+        textError = sprintf('%s        W      = THETA(%d)*IPRED\r\n',textError,THETA_INDEX_NEXT); 
+        THETA_ERROR_MODELS_IX(end+1) = THETA_INDEX_NEXT;
+        THETA_ERROR_MODELS_NAME{end+1} = sprintf('Proportional error %s',name);
+        THETA_ERROR_MODELS_VALUE(end+1) = errorParam0(count);
+        count = count + 1;
+        THETA_INDEX_NEXT = THETA_INDEX_NEXT+1;
+        output_parameters_project_info{end+1} = sprintf('error_PROP%d',outputNumber);
+    elseif strcmpi(error_model{k},'comb1'),
+        textError = sprintf('%s        W      = SQRT(THETA(%d)**2 + (THETA(%d)*IPRED)**2)\r\n',textError,THETA_INDEX_NEXT,THETA_INDEX_NEXT+1); 
+        THETA_ERROR_MODELS_IX(end+1) = THETA_INDEX_NEXT;
+        THETA_ERROR_MODELS_IX(end+1) = THETA_INDEX_NEXT+1;
+        THETA_ERROR_MODELS_NAME{end+1} = sprintf('Additive error %s',name);
+        THETA_ERROR_MODELS_NAME{end+1} = sprintf('Proportional error %s',name);
+        THETA_ERROR_MODELS_VALUE(end+1) = errorParam0(count);
+        count = count + 1;
+        THETA_ERROR_MODELS_VALUE(end+1) = errorParam0(count);
+        count = count + 1;
+        THETA_INDEX_NEXT = THETA_INDEX_NEXT+2;
+        output_parameters_project_info{end+1} = sprintf('error_ADD%d',outputNumber);
+        output_parameters_project_info{end+1} = sprintf('error_PROP%d',outputNumber);
+    else
+        error('Unknown error model definition.');
+    end
+    textError = sprintf('%s        IWRES  = IRES/W\r\n',textError);
+
+    % Handle different BLOQ methods if CENS column in dataset - only
+    % handled if non zero elements present in CENS column
+    % Reason: handling CENS=1 in M3 and M4 requires LAPLACIAN in the $EST
+    % statement. To be avoided if not needed.
+    
+    if ~CENS_tobehandled,
+        % NO CENS column in the dataset (or no 1 entries in CENS) => just use standard
+        if FLAG_CMT,
+            fprintf(fid,'    IF(CMT.EQ.%d) THEN\r\n',CMTk);
+        else
+            fprintf(fid,'    IF(YTYPE.EQ.%d) THEN\r\n',outputNumber);
+        end
+        fprintf(fid,'%s',textError);
+        fprintf(fid,'        Y      = IPRED + W*ERR(%d)\r\n',k);
+        fprintf(fid,'    ENDIF\r\n');
+    else
+        % CENS column in the dataset 
+        
+        % Handle uncensored values (CENS==0)
+        if FLAG_CMT,
+            fprintf(fid,'    IF(CMT.EQ.%d.AND.CENS.EQ.0) THEN\r\n',CMTk);
+        else
+            fprintf(fid,'    IF(YTYPE.EQ.%d.AND.CENS.EQ.0) THEN\r\n',outputNumber);
+        end
+        fprintf(fid,'%s',textError);
+        fprintf(fid,'        ; Handle data above LLOQ\r\n');
+        fprintf(fid,'        F_FLAG = 0\r\n');
+        fprintf(fid,'        Y      = IPRED + W*ERR(%d)\r\n',k);
+        fprintf(fid,'    ENDIF\r\n');
+        
+        % Handle censored BLOQ values (CENS==1) - assumption that LLOQ in DV
+        
+        if ~M4,
+            % M3 method
+            if FLAG_CMT,
+                fprintf(fid,'    IF(CMT.EQ.%d.AND.CENS.EQ.1) THEN\r\n',CMTk);
+            else
+                fprintf(fid,'    IF(YTYPE.EQ.%d.AND.CENS.EQ.1) THEN\r\n',outputNumber);
+            end
+            fprintf(fid,'%s',textError);
+            fprintf(fid,'        ; Handle data below LLOQ (M3 method - assuming LLOQ in DV and CENS=1)\r\n');
+            fprintf(fid,'        F_FLAG = 1\r\n');
+            fprintf(fid,'        Y      = PHI((DV-IPRED)/W)\r\n');
+            fprintf(fid,'    ENDIF\r\n');
+        else
+            % M4 method
+            if FLAG_CMT,
+                fprintf(fid,'    IF(CMT.EQ.%d.AND.CENS.EQ.1) THEN\r\n',CMTk);
+            else
+                fprintf(fid,'    IF(YTYPE.EQ.%d.AND.CENS.EQ.1) THEN\r\n',outputNumber);
+            end
+            fprintf(fid,'%s',textError);
+            fprintf(fid,'        ; Handle data below LLOQ (M4 method - assuming LLOQ in DV and CENS=1)\r\n');
+            fprintf(fid,'        F_FLAG = 1\r\n');
+            fprintf(fid,'        CUMD   = PHI((DV-IPRED)/W)\r\n');
+            fprintf(fid,'        CUMDZ  = PHI(-IPRED/W)\r\n');
+            fprintf(fid,'        Y      = (CUMD-CUMDZ)/(1-CUMDZ)\r\n');
+            fprintf(fid,'    ENDIF\r\n');
+        end
+    end
+    fprintf(fid,'\r\n');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Assign variables to report in tables
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% ETAs:
+fprintf(fid,'; Assign variables to report in tables\r\n');
+for k=1:length(parameterNames),
+    fprintf(fid,'    ETA_%s%s = ETA(%d)\r\n',parameterNames{k},char(32*ones(1,cellmaxlengthIQM(parameterNames)-length(parameterNames{k})+1)),k);
+end
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $THETA for model parameters
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'$THETA\r\n');
+
+fprintf(fid,'; Model parameters\r\n');
+
+THETA_GUESS0_STRING = {};
+PARAM_TRANSNAME_STRING = {};
+PARAM_INVTRANSNAME_STRING = {};
+initialGuess_noTrans = [];
+for k=1:length(parameterNames),
+    initialGuess = POPvalues0(k);
+    initialGuess_noTrans(k) = POPvalues0(k);
+    if IIVdistribution{k} == 'N',
+        initialGuess = initialGuess;
+        if POPestimate(k),
+            if initialGuess == 0,
+                initialGuess = 0.01;
+            end
+        end
+        PARAM_INVTRANSNAME_STRING{k} = '(psi)';
+        PARAM_TRANSNAME_STRING{k} = '(phi)';
+    elseif IIVdistribution{k} == 'L';
+        initialGuess = log(initialGuess);
+        if POPestimate(k),
+            if initialGuess == 0,
+                initialGuess = 0.01;
+            end
+        end
+        PARAM_INVTRANSNAME_STRING{k} = 'log(psi)';
+        PARAM_TRANSNAME_STRING{k} = 'exp(phi)';
+    elseif IIVdistribution{k} == 'G',
+        initialGuess = log(initialGuess/(1-initialGuess));
+        if POPestimate(k),
+            if initialGuess == 0,
+                initialGuess = 0.01;
+            end
+        end
+        PARAM_INVTRANSNAME_STRING{k} = 'log(psi./(1-psi))';
+        PARAM_TRANSNAME_STRING{k} = 'exp(phi)./(1+exp(phi))';
+    else
+        error('Unknown parameter transformation.');
+    end
+    THETA_GUESS0_STRING{k} = sprintf('%1.3g',initialGuess);
+    % Check if parameter fixed or not
+    if POPestimate(k) == 0,
+        THETA_GUESS0_STRING{k} = [THETA_GUESS0_STRING{k} '  FIX'];
+    end
+end    
+
+for k=1:length(parameterNames),
+    texttext = strrep(PARAM_INVTRANSNAME_STRING{k},'psi',parameterNames{k});
+    fprintf(fid,'    %s%s ; %d %s (%1.3g)\r\n',THETA_GUESS0_STRING{k},char(32*ones(1,cellmaxlengthIQM(THETA_GUESS0_STRING)-length(THETA_GUESS0_STRING{k})+1)),k,texttext,initialGuess_noTrans(k));
+end
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $THETA for continuous covariate parameters
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+THETA_INDEX_BETA_cov = THETA_INDEX_BETA(cov_type_continuous==1);
+beta_parameters_cov  = beta_parameters(cov_type_continuous==1);
+
+if ~isempty(COVestimate) && ~isempty(THETA_INDEX_BETA_cov),
+    fprintf(fid,'; Continuous covariate model parameters\r\n');
+    count = 1;
+    for kparam=1:length(COVestimate),
+        for kcov=1:length(COVestimate{kparam}),
+            estimate = COVestimate{kparam}(kcov);
+            value    = covariateModelValues{kparam}(kcov);
+            cov      = covariateModel{kparam}{kcov+1};
+            if ismember(cov,covNames),
+                % Only handle if covariate member iof continuous covariates
+                index    = THETA_INDEX_BETA_cov(count);
+                param    = beta_parameters_cov{count};
+                count    = count+1;
+                if estimate,
+                    if value==0,
+                        value = 0.01;
+                    end
+                    fprintf(fid,'    %g ; %d %s\r\n',value,index,param);
+                else
+                    fprintf(fid,'    %g FIX ; %d %s\r\n',value,index,param);
+                end
+            end
+        end
+    end
+    fprintf(fid,'\r\n');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $THETA for categorical covariate parameters
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+THETA_INDEX_BETA_cat = THETA_INDEX_BETA(cov_type_continuous==0);
+beta_parameters_cat  = beta_parameters(cov_type_continuous==0);
+covcov_cat           = covcov(cov_type_continuous==0);
+covparam_cat         = covparam(cov_type_continuous==0);
+
+if ~isempty(COVestimate) &&  ~isempty(THETA_INDEX_BETA_cat),
+    fprintf(fid,'; Categorical covariate model parameters\r\n');
+    for k=1:length(THETA_INDEX_BETA_cat),
+        % Get parameter name
+        param = covparam_cat{k};
+        % Get covariate name
+        cov = covcov_cat{k};
+        
+        % Find index of parameter in covariateModel
+        covModelAllParam = {};
+        for k2=1:length(covariateModel),
+            covModelAllParam{end+1} = covariateModel{k2}{1};
+        end
+        ixparam = strmatchIQM(param,covModelAllParam,'exact');
+        
+        % Find index of cov in covariateModel{ixparam}
+        ixcov = strmatchIQM(cov,covariateModel{ixparam},'exact');
+        
+        % Is this covariate estimated?
+        estimate = COVestimate{ixparam}(ixcov-1);
+        
+        % Which is the value
+        value = covariateModelValues{ixparam}(ixcov-1);
+        
+        % Write out
+        if estimate,
+            if value == 0,
+                value = 0.01;
+            end
+            fprintf(fid,'    %g ; %d %s\r\n',value,THETA_INDEX_BETA_cat(k),beta_parameters_cat{k});
+        else
+            fprintf(fid,'    %g FIX ; %d %s\r\n',value,THETA_INDEX_BETA_cat(k),beta_parameters_cat{k});
+        end
+    end
+    fprintf(fid,'\r\n');
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $THETA for error model parameters
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'; Error model parameters\r\n');
+for k=1:length(THETA_ERROR_MODELS_IX),
+    fprintf(fid,'    %g%s ; %d %s\r\n',THETA_ERROR_MODELS_VALUE(k),char(32*ones(1,cellmaxlengthIQM(THETA_GUESS0_STRING)-length('1')+1)),THETA_ERROR_MODELS_IX(k),THETA_ERROR_MODELS_NAME{k});
+end
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $OMEGA
+% Using standard deviations and correlations
+%
+% $OMEGA STANDARD CORRELATION BLOCK(2)
+% 0.8
+% -0.394 0.762
+%
+% or:
+% $OMEGA
+% 0.8 STANDARD
+% 0.5 STANDARD
+%
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+	
+if strcmp(lower(covarianceModel),'diagonal') || isempty(covarianceModel),
+    fprintf(fid,'$OMEGA\r\n');
+    OMEGA_GUESS0_STRING = {};
+    for k=1:length(parameterNames),
+        if IIVestimate(k) == 0,
+            % Set IIV value to 0 and FIX
+            OMEGA_GUESS0_STRING{k} = sprintf('0 STANDARD FIX');
+        elseif IIVestimate(k) == 1,
+            value = IIVvalues0(k);
+            if value == 0,
+                value = 0.1;
+            end
+            % Set IIV value
+%             OMEGA_GUESS0_STRING{k} = sprintf('%1.2g',(value)^2); % Convert IIV values from STD to VAR
+            OMEGA_GUESS0_STRING{k} = sprintf('%1.2g STANDARD',value); % USE STD
+        elseif IIVestimate(k) == 2,
+            % Set IIV value and FIX
+%             OMEGA_GUESS0_STRING{k} = sprintf('%1.2g  FIX',(IIVvalues0(k))^2); % Convert IIV values from STD to VAR
+            OMEGA_GUESS0_STRING{k} = sprintf('%1.2g STANDARD FIX',IIVvalues0(k)); % Convert IIV values from STD to VAR
+        end
+    end
+    for k=1:length(parameterNames),
+        fprintf(fid,'    %s%s ; %d %s\r\n',OMEGA_GUESS0_STRING{k},char(32*ones(1,cellmaxlengthIQM(OMEGA_GUESS0_STRING)-length(OMEGA_GUESS0_STRING{k})+1)),k,parameterNames{k});
+    end
+else
+    % Handle the covariances ... block by block
+    terms = explodePCIQM(covarianceModel,',','{','}');
+    for k=1:length(terms),
+        block = terms{k};
+        block = strrep(block,'{','');
+        block = strrep(block,'}','');
+        block = explodePCIQM(block);
+        ix_parameters = [];
+        for k2=1:length(block),
+            ix_parameters(end+1) = strmatchIQM(block{k2},parameterNames,'exact');
+        end
+        % Need to reorder each block to match the order of the parameters
+        % in param_est.name. It already has been made sure that they are
+        % sequential.
+        ix_parameters_ordered = sort(ix_parameters,'ascend');
+        % Construct the block text
+        blockText = sprintf('$OMEGA STANDARD CORRELATION BLOCK(%d)\r\n',length(block));
+        blockMatrix = 0.1*ones(length(ix_parameters_ordered));
+        for k=1:length(ix_parameters_ordered),
+            value = IIVvalues0(ix_parameters_ordered(k));
+            if value == 0,
+                value = 0.1;
+            end
+            blockMatrix(k,k) = value; % No need to convert, since in STD
+        end
+        for krow=1:length(block),
+            for kcol=1:krow,
+                blockText = sprintf('%s    %1.2g',blockText,blockMatrix(krow,kcol));
+            end
+            blockText = sprintf('%s    ; %d %s',blockText,ix_parameters_ordered(krow),parameterNames{ix_parameters_ordered(krow)});
+            blockText = sprintf('%s\r\n',blockText);
+        end
+        fprintf(fid,'%s\r\n',blockText);
+    end
+    
+    % Finally find the parameters that have not been handled yet by the
+    % block things ...
+    x = strrep(covarianceModel,'{','');
+    x = strrep(x,'}','');
+    terms = explodePCIQM(x);
+    missingParam = setdiff(parameterNames,terms);
+    % These are not in the right order ...
+    ix_parameters = [];
+    for k2=1:length(missingParam),
+        ix_parameters(end+1) = strmatchIQM(missingParam{k2},parameterNames,'exact');
+    end
+    % Need to reorder according to their appearance in the model
+    % It already has been made sure that they are sequential.
+    ix_parameters_ordered = sort(ix_parameters,'ascend');
+    
+    if ~isempty(missingParam),
+        fprintf(fid,'$OMEGA\r\n');
+    end
+    OMEGA_GUESS0_STRING = {};
+    for k=1:length(missingParam),
+        if IIVestimate(ix_parameters_ordered(k)) == 0,
+            % Set IIV value to 0 and FIX
+            OMEGA_GUESS0_STRING{k} = sprintf('0 STANDARD FIX');
+        elseif IIVestimate(ix_parameters_ordered(k)) == 1,
+            value = IIVvalues0(ix_parameters_ordered(k));
+            if value == 0,
+                value = 0.1;
+            end
+            % Set IIV value
+            OMEGA_GUESS0_STRING{k} = sprintf('%1.2g STANDARD',value); % Need to convert from STD to VAR
+        elseif IIVestimate(ix_parameters_ordered(k)) == 2,
+            % Set IIV value and FIX
+            OMEGA_GUESS0_STRING{k} = sprintf('%1.2g STANDARD FIX',IIVvalues0(ix_parameters_ordered(k))); % Need to convert from STD to VAR
+        end
+    end    
+    for k=1:length(missingParam),
+        fprintf(fid,'    %s%s ; %d %s\r\n',OMEGA_GUESS0_STRING{k},char(32*ones(1,cellmaxlengthIQM(OMEGA_GUESS0_STRING)-length(OMEGA_GUESS0_STRING{k})+1)),ix_parameters_ordered(k),parameterNames{ix_parameters_ordered(k)});
+    end
+end
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $SIGMA
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'$SIGMA\r\n');
+for k=1:length(modeloutput),
+    fprintf(fid,'    1 FIX\r\n');
+end   
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $ESTIMATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Need to add 'LAPLACIAN NUMERICAL SLOW' as arguments for $EST definitions
+% with INTERACTION if M3 or M4 method handled (CENS_tobehandled=1).
+if CENS_tobehandled==1,
+    addTEXT_INTERACTION = 'LAPLACIAN NUMERICAL SLOW';
+else
+    addTEXT_INTERACTION = '';
+end
+
+% Check if ITS done as first method
+if ITS,
+    % ITS
+    if strcmp(upper(METHOD),'FO') || strcmp(upper(METHOD),'FOCE'),
+        text = sprintf('$ESTIMATION METHOD=ITS NOINTERACTION NOABORT NITER=%d SIGDIGITS=%d PRINT=%d\r\n',ITS_ITERATIONS,SIGDIGITS,PRINT);
+    else
+        text = sprintf('$ESTIMATION METHOD=ITS INTERACTION %s NOABORT NITER=%d SIGDIGITS=%d PRINT=%d\r\n',addTEXT_INTERACTION,ITS_ITERATIONS,SIGDIGITS,PRINT);
+    end
+    fprintf(fid,'%s\r\n',wrapRowTextIQM(text,80,12));
+end    
+
+% Then the "Main" Method
+if strcmp(upper(METHOD),'FO'),
+    % FO
+    text = sprintf('$ESTIMATION METHOD=ZERO NOINTERACTION NOABORT MAXEVAL=%d CTYPE=4 POSTHOC SIGDIGITS=%d PRINT=%d\r\n',MAXEVAL,SIGDIGITS,PRINT);
+    fprintf(fid,'%s\r\n',wrapRowTextIQM(text,80,12));
+elseif strcmp(upper(METHOD),'FOCE'),
+    % FOCE
+    text = sprintf('$ESTIMATION METHOD=CONDITIONAL NOINTERACTION NOABORT MAXEVAL=%d CTYPE=4 POSTHOC SIGDIGITS=%d PRINT=%d\r\n',MAXEVAL,SIGDIGITS,PRINT);
+    fprintf(fid,'%s\r\n',wrapRowTextIQM(text,80,12));
+elseif strcmp(upper(METHOD),'FOCEI'),
+    % FOCEI
+    text = sprintf('$ESTIMATION METHOD=CONDITIONAL INTERACTION %s NOABORT MAXEVAL=%d CTYPE=4 POSTHOC SIGDIGITS=%d PRINT=%d\r\n',addTEXT_INTERACTION,MAXEVAL,SIGDIGITS,PRINT);
+    fprintf(fid,'%s\r\n',wrapRowTextIQM(text,80,12));
+elseif strcmp(upper(METHOD),'SAEM'),
+    % SAEM
+    text = sprintf('$ESTIMATION METHOD=SAEM INTERACTION %s NOABORT NBURN=%d NITER=%d ISAMPLE=%d CONSTRAIN=1 CTYPE=0 SEED=%d POSTHOC SIGDIGITS=%d PRINT=%d\r\n',addTEXT_INTERACTION,K1,K2,NRCHAINS,SEED,SIGDIGITS,PRINT);
+    fprintf(fid,'%s\r\n',wrapRowTextIQM(text,80,12));
+else
+    error('Unknown estimation method.');
+end
+
+% Then check if importance sampling to be done for objective function evaluation
+if IMPORTANCESAMPLING,
+%     text = sprintf('$ESTIMATION METHOD=IMP NOABORT EONLY=1 ISAMPLE=1000 NITER=%d MAPITER=0 SIGDIGITS=%d PRINT=%d',IMP_ITERATIONS,SIGDIGITS,PRINT);
+    text = sprintf('$ESTIMATION METHOD=IMP INTERACTION %s NOABORT EONLY=1 ISAMPLE=1000 NITER=%d MAPITER=0 SIGDIGITS=%d PRINT=%d',addTEXT_INTERACTION,IMP_ITERATIONS,SIGDIGITS,PRINT);
+    fprintf(fid,'%s\r\n',wrapRowTextIQM(text,80,12));
+end
+
+fprintf(fid,'\r\n');
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $COVARIANCE
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fprintf(fid,'$COVARIANCE UNCONDITIONAL MATRIX=S\r\n');
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Define FORMAT for all TABLEs
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORMAT = 's1PG15.6';
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $TABLE similar to predictions.txt in MONOLIX 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if strcmp(METHOD,'FO'),
+    text = sprintf('$TABLE ID TIME TIME2 YTYPE MDV EVID DV CENS IPRED IRES IWRES NPDE NPRED=XPRED  NRES=XRES  NWRES=XWRES  NOPRINT ONEHEADER NOAPPEND FILE=project.pred FORMAT=%s',FORMAT);
+elseif strcmp(METHOD,'FOCE'), 
+    text = sprintf('$TABLE ID TIME TIME2 YTYPE MDV EVID DV CENS IPRED IRES IWRES NPDE NPRED=XPRED  CRES=XRES  CWRES=XWRES  NOPRINT ONEHEADER NOAPPEND FILE=project.pred FORMAT=%s',FORMAT);
+elseif strcmp(METHOD,'FOCEI'),
+    text = sprintf('$TABLE ID TIME TIME2 YTYPE MDV EVID DV CENS IPRED IRES IWRES NPDE CPREDI=XPRED CRESI=XRES CWRESI=XWRES NOPRINT ONEHEADER NOAPPEND FILE=project.pred FORMAT=%s',FORMAT);
+elseif strcmp(METHOD,'SAEM'),
+    text = sprintf('$TABLE ID TIME TIME2 YTYPE MDV EVID DV CENS IPRED IRES IWRES NPDE EPRED=XPRED  ERES=XRES  EWRES=XWRES  NOPRINT ONEHEADER NOAPPEND FILE=project.pred FORMAT=%s ESAMPLE=1000 SEED=%d',FORMAT,SEED);
+else
+    error('Unknown method');
+end
+text = wrapRowTextIQM(text,80,7);
+% Print out table command
+fprintf(fid,'%s\r\n',text);
+fprintf(fid,'\r\n');
+  
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $TABLE similar to indiv_eta.txt in MONOLIX - include all covariates
+% in the dataset
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+text = 'ID';
+for k=1:length(parameterNames),
+    text = sprintf('%s ETA_%s',text,parameterNames{k});
+end
+% Add covariates
+for k=1:length(covNames),
+    text = sprintf('%s %s',text,covNames{k});
+end
+for k=1:length(catNames),
+    text = sprintf('%s %s',text,catNames{k});
+end
+% Create the full table command
+text = sprintf('$TABLE %s NOPRINT ONEHEADER FIRSTONLY NOAPPEND FILE=project.eta FORMAT=%s',text,FORMAT);
+text = wrapRowTextIQM(text,80,7);
+% Print out table command
+fprintf(fid,'%s\r\n',text);
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% $TABLE similar to indiv_parameters.txt in MONOLIX - include all covariates
+% in the dataset - also include the regression parameters
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+text = 'ID';
+for k=1:length(parameterNames),
+    text = sprintf('%s %s',text,parameterNames{k});
+end
+% Add covariates
+for k=1:length(covNames),
+    text = sprintf('%s %s',text,covNames{k});
+end
+for k=1:length(catNames),
+    text = sprintf('%s %s',text,catNames{k});
+end
+% Create the full table command
+text = sprintf('$TABLE %s NOPRINT ONEHEADER FIRSTONLY NOAPPEND FILE=project.indiv FORMAT=%s',text,FORMAT);
+text = wrapRowTextIQM(text,80,7);
+% Print out table command
+fprintf(fid,'%s\r\n',text);
+fprintf(fid,'\r\n');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Close file and change out of project path
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+fclose(fid);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Construct PROJECT_HEADER_PLACEHOLDER information
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+PROJECT_INFO_TEXT = '';
+
+% Method
+METHOD_ALL = METHOD;
+if ITS,
+    METHOD_ALL = ['ITS,' METHOD_ALL];
+end
+if IMPORTANCESAMPLING,
+    METHOD_ALL = [METHOD_ALL ',IMP'];
+end
+METHOD_info = sprintf('; METHOD              = ''%s''\r\n',METHOD_ALL);
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,METHOD_info);
+
+% Data location
+DATA_info = sprintf('; DATA                = ''%s''\r\n',strrep(fullfile(dataRelPathFromProject,dataFileName),'\','/'));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,DATA_info);
+
+% DOSINGTYPES
+DOSINGTYPES = {};
+for k=1:length(modelinput),
+    DOSINGTYPES{end+1} = modelinput{k}{2};
+end
+x = sprintf('%s,',DOSINGTYPES{:});
+DOSINGTYPES_info = sprintf('; DOSINGTYPES         = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,DOSINGTYPES_info);
+
+% covNames
+x = sprintf('%s,',covNames{:});
+COVNAMES_info = sprintf('; COVNAMES            = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,COVNAMES_info);
+
+% catNames
+x = sprintf('%s,',catNames{:});
+CATNAMES_info = sprintf('; CATNAMES            = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,CATNAMES_info);
+
+% Regression parameters
+REGRESSNAMES_info = sprintf('; REGRESSIONNAMES     = ''''\r\n');
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,REGRESSNAMES_info);
+
+% Outputs
+x = cell(1,length(modeloutput));
+for k=1:length(modeloutput),
+    x{k} = modeloutput{k}{1};
+end
+y = '';
+for k=1:length(x),
+    y = sprintf('%s%s,',y,x{k});
+end
+y = y(1:end-1);
+OUTPUTS_info = sprintf('; OUTPUTS             = ''%s''\r\n',y);
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,OUTPUTS_info);
+
+% Error models
+ERRORMODELS_info = sprintf('; ERRORMODELS         = ''%s''\r\n',errorModels);
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,ERRORMODELS_info);
+
+% ERRORNAMES
+x = sprintf('%s,',output_parameters_project_info{:});
+ERRORNAMES_info = sprintf('; ERRORNAMES          = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,ERRORNAMES_info);
+
+% PARAMNAMES
+x = sprintf('%s,',parameterNames{:});
+PARAMNAMES_info = sprintf('; PARAMNAMES          = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,PARAMNAMES_info);
+
+% PARAMTRANS
+x = sprintf('%s,',PARAM_TRANSNAME_STRING{:});
+PARAMTRANS_info = sprintf('; PARAMTRANS          = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,PARAMTRANS_info);
+
+% PARAMINVTRANS
+x = sprintf('%s,',PARAM_INVTRANSNAME_STRING{:});
+PARAMINVTRANS_info = sprintf('; PARAMINVTRANS       = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,PARAMINVTRANS_info);
+
+% COVARIATENAMES
+COVARIATENAMES = [covariateMedianNames,covariateCATNames];
+x = sprintf('%s,',COVARIATENAMES{:});
+COVARIATENAMES_info = sprintf('; COVARIATENAMES      = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,COVARIATENAMES_info);
+
+% COVARIATESUSED
+COVARIATESUSED = setdiff(explodePCIQM(strrep(strrep(options.covariateModel,'{',''),'}','')),parameterNames);
+x = sprintf('%s,',COVARIATESUSED{:});
+COVARIATESUSED_info = sprintf('; COVARIATESUSED      = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,COVARIATESUSED_info);
+
+% BETACOVNAMES
+x = sprintf('%s,',beta_parameters_cov_project_info{:});
+BETACOVNAMES_info = sprintf('; BETACOVNAMES        = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,BETACOVNAMES_info);
+
+% BETACOVTRANS
+x = sprintf('%s,',COV_transformation_info{:});
+BETACOVTRANS_info = sprintf('; BETACOVTRANS        = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,BETACOVTRANS_info);
+
+% BETACATNAMES
+x = sprintf('%s,',beta_parameters_cat_project_info{:});
+BETACATNAMES_info = sprintf('; BETACATNAMES        = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,BETACATNAMES_info);
+
+% BETACATREFERENCE
+x = ''; for k=1:length(CAT_reference_info), x=sprintf('%s%g,',x,CAT_reference_info{k}); end
+BETACATREFERENCE_info = sprintf('; BETACATREFERENCE    = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,BETACATREFERENCE_info);
+
+% BETACATCATEGORIES
+x = ''; 
+for k=1:length(CAT_categories_info), 
+    x = [x '['];
+    x2 = '';
+    x2 = sprintf('%d ',CAT_categories_info{k});
+    x = [x x2(1:end-1) '],'];
+end
+BETACATCATEGORIES_info = sprintf('; BETACATCATEGORIES   = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,BETACATCATEGORIES_info);
+
+% ALL THETANAMES
+x = [parameterNames beta_parameters output_parameters_project_info];
+y = sprintf('%s,',x{:});
+THETANAMES_info = sprintf('; THETANAMES          = ''%s''\r\n',y(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,THETANAMES_info);
+
+% THETAESTIMATE
+% Add theta for parameters
+PARAM_info = sprintf('%d,',POPestimate);
+% Add theta for covariates
+COVCAT_info = sprintf('%d,',COVCATestimate_info);
+if isempty(COVCATestimate_info),
+    COVCAT_info = [];
+end
+% Add theta for error models
+x = ones(1,length(output_parameters_project_info));
+ERROR_info = sprintf('%d,',x);
+% Combine
+ESTIMATE_info = strtrim([PARAM_info COVCAT_info ERROR_info]);
+% Create text
+THETAESTIMATE_info = sprintf('; THETAESTIMATE       = ''%s''\r\n',ESTIMATE_info(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,THETAESTIMATE_info);
+
+% ALL ETANAMES (should be same as PARAMNAMES)
+x = sprintf('omega(%s),',parameterNames{:});
+ETANAMES_info = sprintf('; ETANAMES            = ''%s''\r\n',x(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,ETANAMES_info);
+
+% ETAESTIMATE
+ETAESTIMATE = sprintf('%d,',IIVestimate); 
+ETAESTIMATE_info = sprintf('; ETAESTIMATE         = ''%s''\r\n',ETAESTIMATE(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,ETAESTIMATE_info);
+
+% ALL CORRNAMES 
+cov = explodePCIQM(covarianceModel,',','{','}');
+text = '';
+for k=1:length(cov),
+    covk = strrep(strrep(cov{k},'{',''),'}','');
+    covk = explodePCIQM(covk);
+    for k1=1:length(covk),
+        for k2=1:k1,
+            if k1~=k2,
+                text = sprintf('%scorr(%s,%s),',text,covk{k2},covk{k1});
+            end
+        end
+    end
+end
+CORR_info = sprintf('; CORRELATIONNAMES    = ''%s''\r\n',text(1:end-1));
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,CORR_info);
+
+% CORRESTIMATE
+if ~isempty(text),
+    CORRestimate = ones(1,length(explodePCIQM(text(1:end-1))));
+    x = sprintf('%d,',CORRestimate); 
+    CORRESTIMATE_info = sprintf('; CORRESTIMATE        = ''%s''\r\n',x(1:end-1));
+else
+    CORRestimate = 0;
+    CORRESTIMATE_info = sprintf('; CORRESTIMATE        = ''''\r\n');
+end
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,CORRESTIMATE_info);
+
+% Get and store number of observations in the data
+% Remove MDV=1 records
+x = dataCSV(dataCSV.MDV==0,:);
+% Remove CMT>nrOUTPUTS or YTYPE>nrOUTPUT
+nrOUTPUTS = 1;
+x(x.YTYPE > nrOUTPUTS,:) = [];
+
+% Write out number of observations
+nOBS = height(x);
+NROBS_info = sprintf('; NROBSERVATIONS      = ''%d''\r\n',nOBS);
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,NROBS_info);
+
+% Determine the number of estimated parameters (THETA and ETA)
+NRPARAMETERS_ESTIMATED = sum(eval(['[' ESTIMATE_info(1:end-1) ']']))+sum(eval(['[' ETAESTIMATE(1:end-1) ']'])==1)+sum(CORRestimate);
+NRPARAMETERS_ESTIMATED_info = sprintf('; NRPARAM_ESTIMATED   = ''%d''\r\n',NRPARAMETERS_ESTIMATED);
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,NRPARAMETERS_ESTIMATED_info);
+
+% Info about residual names depending on the selected method
+RESIDUAL_NAMES_USED = sprintf('; RESIDUAL_NAMES_USED = ''XPRED,XRES,XWRES''\r\n');
+if strcmp(METHOD,'FO'),
+    RESIDUAL_NAMES_ORIG = sprintf('; RESIDUAL_NAMES_ORIG = ''NPRED,NRES,NWRES''\r\n');
+elseif strcmp(METHOD,'FOCE'), 
+    RESIDUAL_NAMES_ORIG = sprintf('; RESIDUAL_NAMES_ORIG = ''NPRED,CRES,CWRES''\r\n');
+elseif strcmp(METHOD,'FOCEI'),
+    RESIDUAL_NAMES_ORIG = sprintf('; RESIDUAL_NAMES_ORIG = ''CPREDI,CRESI,CWRESI''\r\n');
+elseif strcmp(METHOD,'SAEM'),
+    RESIDUAL_NAMES_ORIG = sprintf('; RESIDUAL_NAMES_ORIG = ''EPRED,ERES,EWRES''\r\n');
+end
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,RESIDUAL_NAMES_USED);
+PROJECT_INFO_TEXT = sprintf('%s%s',PROJECT_INFO_TEXT,RESIDUAL_NAMES_ORIG);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Replace PROJECT_HEADER_PLACEHOLDER
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+content = fileread('project.nmctl');
+content = strrep(content,'PROJECT_HEADER_PLACEHOLDER',strtrim(PROJECT_INFO_TEXT));
+x = [parameterNames beta_parameters output_parameters_project_info]; % get theta names
+content = strrep(content,'$SIZES LTH=XXX',sprintf('$SIZES LTH=%d',length(x)));
+fid = fopen('project.nmctl','w');
+fprintf(fid,'%s',content);
+fclose(fid);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Go back to old path
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+cd(oldpath);
diff --git a/IQMtools V1.2.2.2/IQMpro/tools/14-GeneralLinearNLMEmodel/auxiliary/createGeneralLinear_TEXTmodelIQM.m b/IQMtools V1.2.2.2/IQMpro/tools/14-GeneralLinearNLMEmodel/auxiliary/createGeneralLinear_TEXTmodelIQM.m
new file mode 100644
index 0000000000000000000000000000000000000000..671e9df2ccf790bf7b5d04e8fb83621f3a542bc1
--- /dev/null
+++ b/IQMtools V1.2.2.2/IQMpro/tools/14-GeneralLinearNLMEmodel/auxiliary/createGeneralLinear_TEXTmodelIQM.m	
@@ -0,0 +1,324 @@
+function [] = createGeneralLinear_TEXTmodelIQM(modelinfo,modelinput,modeloutput,options,filename)
+% Functions createGeneralLinear_NONMEMprojectIQM and
+% createGeneralLinear_MONOLIXprojectIQM create generalized linear NONMEM
+% and MONOLIX models without the need to a-priori define an IQMmodel or
+% IQMdosing scheme. This function here can use the same input arguments 
+% and generate an IQMmodel and an IQMdosing object for this specific linear
+% model. This is useful for simulation purposes ... but also to check that
+% the generalized linear model definition is correct.
+%
+% [SYNTAX]
+% [] = createGeneralLinear_TEXTmodelIQM(modelinfo,modelinput,modeloutput)
+% [] = createGeneralLinear_TEXTmodelIQM(modelinfo,modelinput,modeloutput,options)
+% [] = createGeneralLinear_TEXTmodelIQM(modelinfo,modelinput,modeloutput,options,filename)
+%
+% [INPUT]
+% modelinfo:            MATLAB structure with following fields:
+%   modelinfo.nrCompartments:              Number of states/compartments in the model
+%   modelinfo.parameterNames:              Cell-array with names of parameters to be estimated
+%   modelinfo.parameterNamesGeneral:       Cell-array with parameter names of the general linear model to define
+%                                          all others will be kept on 0. 
+%                                          Syntax: 
+%                                               Rate parameter from compartment 1 to compartment 2 is: k1T2 
+%                                               Rate parameter from compartment 3 to compartment 2 is: k3T2 
+%                                               Elimination rate parameter from compartment 2 is: k2T0
+%   modelinfo.parameterExpressionsGeneral: Cell-array linking the parameters to be estimated to the parameters in 
+%                                          the general linear model in terms of expressions.
+%                                          Same order as parameterNamesGeneral. For example, if first element in 
+%                                          parameterNamesGeneral is 'k20' then first element here could be 'CL/Vc',
+%   EXAMPLE:
+%       modelinfo                               = [];
+%       modelinfo.nrCompartments                = 3;
+%       modelinfo.parameterNames                = {'ka' 'CL' 'V' 'FM' 'CLM' 'VM'};
+%       modelinfo.parameterNamesGeneral         = {'k1T2'   'k2T0'              'k2T3'       'k3T0'};
+%       modelinfo.parameterExpressionsGeneral   = {'ka'     'CL*(1-FM)/V'       'CL*FM/V'    'CLM/VM'};
+%
+%       This example realizes a PK model with first order absorption and a
+%       metabolite. Both parent and metabolite are described by a one
+%       compartment model.
+% 
+% modelinput:           Cell-array of cell-arrays. Each inner cell-array
+%                       describes one dosing input and links the data to the model.
+%                       First element: A name for the input.
+%                       Second element: Type of the administration (use
+%                         only 'BOLUS', 'INFUSION' or 'ADMINISTRATION0'
+%                       Third element: Number of the compartment to which
+%                         the dose should be added (match with CMT number in
+%                         dataset)
+%                       Fourth element: String with text to write after
+%                         "F<<compartment number>>" ... this can be an
+%                         expression, allowing simple definition of nonlinear
+%                         bioavailability - can depend on covariates,
+%                         regression parameters etc.
+% 						Fifth element: String with expression (or single parameter)
+% 						  for lag time definition.
+% 						Sixth element: String with expression (or single parameter)
+% 						  for definition of 0 order absorption. In this case it
+% 					      would be good to set the "type" to "ABSORPTION0"
+%   EXAMPLE:
+%       modelinput  = { {'INPUT1', 'BOLUS', 1,'Fabs1'}  {'INPUT2', 'INFUSION', 2,'1', 'Tlag' 'Duration'} };
+% 
+%       This example realizes a bolus administration into the first
+%       compartment with F1=Fabs1. And an infusion into second compartment
+%       with F2=1. Note that the difference between bolus and infusion is
+%       only defined by the value in the RATE column: 0 is bolus, >1 is
+%       infusion. The distinction is only needed later when simulation in
+%       IQM Tools should be done (e.g. VPC).
+%
+% modeloutput:          Cell-array of cell-arrays. Each inner cell-array
+%                       describes one observation output and links the data
+%                       to the model. 
+%                       First element: A name for the output.
+%                       Second element: Number of the compartment to which
+%                         the dose should be added (match with CMT number in
+%                         dataset)
+%                       Third element: String with scaling expression,
+%                         allowing to transform the output to the desired
+%                         units.
+%   EXAMPLE:
+%       modeloutput = { {'CP', 2,'V*495.45/1000000'} {'CM', 3,'VM*435.49/1000000'} };
+%
+%       This example defines an output 'CP' which is measured as the amount
+%       in the second compartment and scaled (divided) by the term
+%       V*495.45/1000000 to obtain concentrations in nmol/L. Similar with
+%       the second output - here measured in the third compartment and
+%       given the name "CM".
+% 
+% options:              Structure with following fields (all optional with default settings):
+%   options.POPvalues0:             Vector with pop parameter initial values. Default or []: => values stored in model and dosing scheme
+%
+
+% <<<COPYRIGHTSTATEMENT - IQM TOOLS PRO>>>
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Handle variable input arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if nargin<4,
+    options = [];
+end
+if nargin<5,
+    filename = 'model';
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Get path and filename etc
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[ppp,fff] = fileparts(filename);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Handle some input arguments
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Required parameters
+try nrCompartments              = modelinfo.nrCompartments;                 catch, error('Please define modelinfo.nrCompartments,');                 end
+try parameterNames              = modelinfo.parameterNames;                 catch, error('Please define modelinfo.parameterNames,');                end
+try parameterNamesGeneral       = modelinfo.parameterNamesGeneral;          catch, error('Please define modelinfo.parameterNamesGeneral,');         end
+try parameterExpressionsGeneral = modelinfo.parameterExpressionsGeneral;    catch, error('Please define modelinfo.parameterExpressionsGeneral,');   end
+
+% Optional parameters
+try POPvalues0                  = options.POPvalues0;                       catch, POPvalues0 = ones(1,length(parameterNames));                      end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Handle modelinput and modeloutput - cellarray of cellarrays
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+if ~iscell(modelinput{1}),
+    modelinput = {modelinput};
+end
+
+if ~iscell(modeloutput{1}),
+    modeloutput = {modeloutput};
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Generate TEXT IQMmodel
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Initialize model
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ms = struct(IQMmodel());
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Add parameters
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+for k=1:length(parameterNames),
+    ms.parameters(end+1).name   = parameterNames{k};
+    ms.parameters(end).value  = POPvalues0(k);
+    ms.parameters(end).notes  = ' <estimate>';
+    ms.parameters(end).type = '';
+    ms.parameters(end).compartment = '';
+    ms.parameters(end).unittype = '';
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Add rate parameter variables
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+for k=1:length(parameterNamesGeneral),
+    ms.variables(end+1).name        = parameterNamesGeneral{k};
+    ms.variables(end).formula       = parameterExpressionsGeneral{k};
+    ms.variables(end).notes         = ' General rate definition';
+    ms.variables(end).type = '';
+    ms.variables(end).compartment = '';
+    ms.variables(end).unittype = '';
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Add output variables
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+for k=1:length(modeloutput),
+    ms.variables(end+1).name        = modeloutput{k}{1};
+    ms.variables(end).formula       = sprintf('A%d / (%s)',modeloutput{k}{2},modeloutput{k}{3});
+    ms.variables(end).notes         = ' Output variable definition';
+    ms.variables(end).type = '';
+    ms.variables(end).compartment = '';
+    ms.variables(end).unittype = '';
+end
+for k=1:length(modeloutput),
+    ms.variables(end+1).name        = sprintf('OUTPUT%d',k);
+    ms.variables(end).formula       = sprintf('%s',modeloutput{k}{1});
+    ms.variables(end).notes         = ' Output definition';
+    ms.variables(end).type = '';
+    ms.variables(end).compartment = '';
+    ms.variables(end).unittype = '';
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Add state variables
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+for k=1:nrCompartments,
+    ms.states(k).name = sprintf('A%d',k);
+    ms.states(k).ODE  = '';
+    ms.states(k).initialCondition = 0;
+    ms.states(k).type = '';
+    ms.states(k).compartment = '';
+    ms.states(k).unittype = '';
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Add ODEs 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+for k=1:length(parameterNamesGeneral),
+    param = parameterNamesGeneral{k};
+    % remove the 'k'
+    param = strrep(param,'k','');
+    terms = explodePCIQM(param,'T');
+    % check
+    if length(terms) ~= 2,
+        error('Incorrect definition of general rate parameters. Use "k#T#" where # indicates numbers of compartment.');
+    end
+    % Get numbers
+    start_ix = eval(terms{1});
+    end_ix   = eval(terms{2});
+    % Generate ODE term
+    if start_ix==0,
+        ODEterm = parameterNamesGeneral{k};
+		error('Uncertain if "k0T#" makes sense. Check how MONOLIX and NONMEM deal with it!.');
+    else
+        ODEterm = sprintf('%s*A%d',parameterNamesGeneral{k},start_ix);
+        ms.states(start_ix).ODE = sprintf('%s - %s',ms.states(start_ix).ODE,ODEterm);
+    end
+    if end_ix~=0,
+        ms.states(end_ix).ODE = sprintf('%s + %s',ms.states(end_ix).ODE,ODEterm);
+    end
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Add INPUTs 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+for k=1:length(modelinput),
+    state_ix = modelinput{k}{3};
+    prefix   = modelinput{k}{4};
+    input_text_ODE = sprintf('(%s)*INPUT%d',prefix,k);
+    ms.states(state_ix).ODE = sprintf('%s + %s',ms.states(state_ix).ODE,input_text_ODE);
+end
+    
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Add NAME 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ms.name = fff;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Add NOTES 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ms.notes = sprintf('Automatically generated linear model.');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Generate TEXT IQMdosing
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Initialize dosing
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ds = struct(IQMdosing());
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Add dosings
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+for k=1:length(modelinput),
+    ds.inputs(k).name = sprintf('INPUT%d',k);
+    ds.inputs(k).type = modelinput{k}{2};
+    ds.inputs(k).time = 0;
+    if length(modelinput{k})>4,
+        ds.inputs(k).Tlag = modelinput{k}{5};
+    else
+        ds.inputs(k).Tlag = [];
+    end
+    ds.inputs(k).D = 0;
+    if strcmp(upper(modelinput{k}{2}),'INFUSION'),
+        ds.inputs(k).parameters.name = 'Tinf';
+        ds.inputs(k).parameters.value = 1;
+        ds.inputs(k).parameters.notes = '';
+    elseif strcmp(upper(modelinput{k}{2}),'ABSORPTION0'),
+        ds.inputs(k).parameters.name = 'Tk0';
+        ds.inputs(k).parameters.value = 1;
+        ds.inputs(k).parameters.notes = '';
+    elseif strcmp(upper(modelinput{k}{2}),'ABSORPTION1'),
+        ds.inputs(k).parameters.name = 'ka';
+        ds.inputs(k).parameters.value = 1;
+        ds.inputs(k).parameters.notes = '';
+    end 
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Add NAME 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ds.name = fff;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Add NOTES 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ds.notes = sprintf('Automatically generated dosing description for generalized linear model.');
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Save model and dosing description
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+model       = IQMmodel(ms);
+dosing      = IQMdosing(ds);
+
+% Create path for export if not existing
+if ~isempty(ppp),
+    warning off;
+    mkdir(ppp);
+    warning on;
+end
+
+IQMcreateTEXTBCfile(model,fullfile(ppp,fff));
+IQMcreateDOSfile(dosing,fullfile(ppp,fff));
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Remove INPUT# = 0 definitions in the model text
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+modelfile = [fullfile(ppp,fff) '.txtbc'];
+content   = fileread(modelfile);
+content   = regexprep(content,'(\nINPUT[0-9]+[^\n]+)','');
+fid       = fopen(modelfile,'w');
+fprintf(fid,'%s',content);
+fclose(fid);
diff --git a/IQMtools V1.2.2.2/installIQMtools.m b/IQMtools V1.2.2.2/installIQMtools.m
new file mode 100644
index 0000000000000000000000000000000000000000..c670b36040d3f9bac3286e421fb6c4e9ff39b2bc
--- /dev/null
+++ b/IQMtools V1.2.2.2/installIQMtools.m	
@@ -0,0 +1,54 @@
+% installIQMtools
+% This script installs the LITE and PRO version of the IQM Suite of modeling tools.
+% Basically it assumes that both packages are present in the folder and that 
+% installIQMtoolsInitial has been executed previously to ensure that all libraries
+% have been compiled for your system.
+%
+%       installIQMtools
+%
+% The function will check for a previous version of IQM Lite installed and
+% in this case it will remove this previous version from the path and
+% install the desired version.
+%
+% Additional IQM packages - if present, will be added as well. Each
+% additional package is expected to have a name starting with "IQM" and to
+% have an install.m file in its root folder.
+
+% Try to install IQM Tools Lite
+IQMliteInstalled = 0;
+try
+    cd IQMlite
+    addpath(genpath(pwd));
+    cd ..
+    IQMliteInstalled = 1;
+catch
+    disp('Error installing IQM Tools Lite. You need to run the installation script from the folder it is located in.');
+end
+
+% Try to install IQM Tools Pro
+if IQMliteInstalled,
+    try
+        cd IQMpro
+        addpath(genpath(pwd));
+        cd ..
+    catch
+        disp('Error installing IQM Tools Pro.');
+    end
+end
+
+% Add additional packages if present
+x = dir('IQM*');
+x = x([x.isdir]);
+x = {x.name};
+x = setdiff(x,{'IQMlite'    'IQMpro'});
+for k=1:length(x),
+    cd(x{k});
+    try
+        addpath(genpath(pwd));
+    catch
+        disp(sprintf('Problems installing package "%s".',x{k}));
+    end
+    cd ..
+end
+
+addpath(pwd);
diff --git a/IQMtools V1.2.2.2/installIQMtoolsInitial.m b/IQMtools V1.2.2.2/installIQMtoolsInitial.m
new file mode 100644
index 0000000000000000000000000000000000000000..b7a265c1dbaae57ce4367fd1c6b74c0eaa0a010c
--- /dev/null
+++ b/IQMtools V1.2.2.2/installIQMtoolsInitial.m	
@@ -0,0 +1,53 @@
+% installIQMtoolsInitial
+% This script installs the LITE and PRO version of the IQM Suite of modeling tools.
+% Basically it assumes that both packages are present in the folder and runs 
+% their individual installers.
+%
+%       installIQMtoolsInitial
+%
+% The function will check for a previous version of IQM Lite installed and
+% in this case it will remove this previous version from the path and
+% install the desired version.
+%
+% Additional IQM packages - if present, will be added as well. Each
+% additional package is expected to have a name starting with "IQM" and to
+% have an install.m file in its root folder.
+
+% Try to install IQM Tools Lite
+IQMliteInstalled = 0;
+try
+    cd IQMlite
+    installIQMlite
+    cd ..
+    IQMliteInstalled = 1;
+catch
+    disp('Error installing IQM Tools Lite. You need to run the installation script from the folder it is located in.');
+end
+
+% Try to install IQM Tools Pro
+if IQMliteInstalled,
+    try
+        cd IQMpro
+        installIQMpro
+        cd ..
+    catch
+        disp('Error installing IQM Tools Pro.');
+    end
+end
+
+% Add additional packages if present
+x = dir('IQM*');
+x = x([x.isdir]);
+x = {x.name};
+x = setdiff(x,{'IQMlite'    'IQMpro'});
+for k=1:length(x),
+    cd(x{k});
+    try
+        install
+    catch
+        disp(sprintf('Problems installing package "%s".',x{k}));
+    end
+    cd ..
+end
+
+addpath(pwd);
diff --git a/IQMtools V1.2.2.2/installation.txt b/IQMtools V1.2.2.2/installation.txt
new file mode 100644
index 0000000000000000000000000000000000000000..140fcaf09a706941337a9eb618a8329e060a427c
--- /dev/null
+++ b/IQMtools V1.2.2.2/installation.txt	
@@ -0,0 +1,19 @@
+Installation of IQM Tools Suite
+===============================
+
+When you are reading this document, you already have successfully obtained IQM Tools Suite from somewhere.
+Please perform the following steps to install it:
+
+- Move the IQM Tools Suite folder to a location on your computer where you want to store it
+- Start MATLAB
+- When installing IQM Tools the first time, please read first the "IQMlite/installation.txt" file and handle as instructed,
+  then read the "IQMpro/installation.txt" file and handle accordingly
+- Change into the folder in which "IQMlite" and "IQMpro" folders are located
+- Execute "installIQMtoolsInitial"
+
+Note: The installation of IQM Tools does not save the MATLAB path. This means that everytime you start MATLAB you will need to 
+      execute the "installIQMtools" script. This procedure has been chosen on purpose, for compliance and reproducibility reasons.
+      The "installIQMtools" does the same as the "installIQMtoolsInitial" script, but does not compile the required libraries.
+      It can be used instead of "installIQMtoolsInitial" script after this has been run at least once.
+	  
+ 
\ No newline at end of file
diff --git a/initIQM.m b/initIQM.m
deleted file mode 100644
index b42555307bc3d85d5ca0e0ab9c2ee2bb23793f9f..0000000000000000000000000000000000000000
--- a/initIQM.m
+++ /dev/null
@@ -1,2 +0,0 @@
-run('/home/elin/MATLAB/IQMToolsV121/IQMlite/installIQMlite.m')
-run('/home/elin/MATLAB/IQMToolsV121/IQMpro/installIQMpro.m')
\ No newline at end of file