*! version 2.1.0 09oct2013 MJC

/*
History
MJC 09oct2013: version 2.1.0 - tvc() and texp() added for time-dependent effects in hazard scale PH survival submodels
							 - rcs survival submodel added (splines on log hazard scale)
							 - noshowadapt changed to showadapt, adaptive iterations now not shown by default
							 - bug in predictions missed time interactions in undocumented deriv predictions
							 - bug in exponential submodel when using adaptive quadrature (quick) now fixed
MJC 14jan2013: version 2.0.2 - Gauss-Legendre quadrature added for hazard scale models
							 - assoccovariates() no longer allowed in intassoc and association() linear predictors
							 - knots of rrcs() on _t0 were not passed to _t, now fixed
							 - nolog didn't suppress adaptive log, now fixed
							 - e(BIC) was incorrect, now fixed
							 - atol() changed from 1E-05 to 1E-08
							 - nocoefficient added for intassoc and assoc()
							 - frcs() and rrcs() now allowed with survmodel(fpm)
							 - fixed bug in hazard xb predictions with survm(ww/weibexp), formula was incorrect
MJC 15aug2012: version 2.0.1 - fixed erroneous sort causing fulldata to be invoked when unnecessary
MJC 11aug2012: version 2.0.0 - Adaptive quadrature algorithms improved, now use a convergence scheme
							 - Adaptive iterations shown by default, option noshowadapt suppresses display of log-likelihood, default adaptit() now 5
							 - Added ww/we survival models
							 - ffracpoly()/rfracpoly() renamed to ffp()/rfp()
							 - atol() option added which declares the tolerance used under the adaptive quadrature sub-iterations, default is 1.0E-5
							 - stjm_dmvnorm() Mata function added for PDF of node contributions in adaptive lnl functions
							 - Longitudinal splines have been added, through options frcs() and rrcs()
							 - noxtem option added (default -xtmixed- fit uses emonly option for speed)
MJC 02feb2012: version 1.3.0 - Implemented adaptive GH quadrature which is now the default. timeinteraction, assoccovariates options added.
MJC 20oct2011: version 1.2.0 - Added Gompertz and Exponential survival submodels. Added covariance options consistent with xtmixed.
MJC 14oct2011: version 1.1.0 - Weibull survival submodel now allowed. Delayed entry re-written, now allowing time-varying covariates in survival submodel.
							 - Fixed error when rfracp or ffracp was 0 with min(_t0) = 0
MJC 10oct2011: version 1.0.0
*/

program stjm, eclass sortpreserve properties(st)
	version 12.1
	if replay() {
		if (`"`e(cmd)'"' !="stjm") error 301
		Replay `0'
	}
	else {
		Estimate `0'
		syntax [anything] [if] [in] [, GETBLUPS(string) *]
		if "`getblups'"=="" ereturn local cmdline `"stjm `0'"'
	}
end

program Estimate, eclass
		syntax varlist(min=1 numeric) 	[if] [in] ,											///
																							///
													Panel(varname) 							///			-Patient identifier-
													SURVModel(string)						///			-Survival submodel choice-
																							///
													[										///
													/* Longitudinal model options */		///
														FFP(numlist max=5 asc)				///			-Fixed time power variables-
														FRCS(string)						///			-Fixed splines of time-
														RFP(numlist max=5 asc)				///			-Random time power variables-
														RRCS(string)						///			-Random splines of time-
														TIMEINTERACtion(varlist numeric)	///			-Covariates to interact with fixed time variables-
														COVariance(string)					///			-Covariance structure-
																							///
													/* Survival model options */			///
														SURVCov(varlist numeric)			///			-Covariates to include in the survival submodel-
														TVC(varlist numeric)				///			-Time-dependent effects
														TEXP(string)						///			-Multiplier for time-varying covariates; default is texp(_t)-
														DF(string) 		 					///			-Degrees of freedom for FPM-
														KNOTS(numlist) 						///			-Knot locations for baseline hazard function-
														NOORTHog							///			-Do not orthoganalise splines-
																							///
													/* Association options */				///
														ASSOCCOVariates(varlist numeric)	///			-Adjust association parameters by covariates-
														NOCurrent							///			-Assciation not based on current value-
														DERIVASSOCiation					///			-Association based on derivatives-
														INTASSOCiation						///			-Association based on random intercept-
														ASSOCiation(numlist max=5)			///			-Association based on random slope/etc.-
														NOCOEFficient						///			-Do not include fixed component in intassoc or assoc()-
																							///
													/* Results display options */			///
														SHOWINITial							///			-Show output from fitting initial value models-
														VARiance							///			-Display variances-covariances in random effects table-
														SHOWCons							///			-Show spline constraints-
														KEEPCons							///			-Do not drop constraints used in ml routine-
														Level(cilevel)						///			-Statistical significance level-
														EFORM								///			-Exponentiate survival parameters-
																							///
													/* Maximisation options	*/				///
														GH(string) 							///			-Number of Gauss-Hermite nodes-
														GK(string)							///			-Number of Gauss-Kronrod nodes-
														GL(string)							///			-Number of Gauss-Legendre nodes-
														ADAPTIT(string)						///			-Number of adaptive iterations to do-
														SHOWAdapt							///			-Display adaptive log-likelihood-
														ATOL(real 1E-08)					///			-Tolerance for the log-likelihood under adaptive iterations-
														NONADAPT							///			-Use non-adaptive quadrature-
														FULLdata							///			-Use all rows of survival data in estimation-
														NULLAssoc							///			-Initial values for association parameters set to zero-
														NOXTEM								///			-Option for xtmixed initial values-
														NOLOG								///			-Suppress log-likelihood iteration log-
														INITMATSURV(string)					///
														SKIP								///
														* 									///			-ML options-
																							///
													/* Undocumented for use by predict */	///
														GETBLUPS(string)					///			-UNDOCUMENTED-
														REISE								///			-UNDOCUMENTED-
														POSTTOUSE(varname)					///			-UNDOCUMENTED-
														GETBLUPSGH(int 30)					///			-UNDOCUMENTED-
																							///
														condsurv(string)					///
														LEAVE								///
													]

	//===================================================================================================================================================//
	// Error checks //

		local l = length("`survmodel'")
		if substr("exponential",1,max(1,`l'))=="`survmodel'" local smodel "e"
		else if substr("weibull",1,max(1,`l'))=="`survmodel'" local smodel "w"
		else if substr("gompertz",1,max(1,`l'))=="`survmodel'" local smodel "g"
		else if "fpm" == "`survmodel'" local smodel "fpm"
		else if "rcs" == "`survmodel'" local smodel "rcs"
		else if ("ww"=="`survmodel'" | substr("weibweib",1,max(5,`l'))=="`survmodel'") local smodel "ww"
		else if substr("weibexp",1,max(5,`l'))=="`survmodel'" local smodel "we"
		else {
			di as error "Unknown survival submodel"
			exit 198
		}
		local aft = 0

		if "`covariance'"=="" {
			local cov "unstr"
			local covtype "Unstructured"
		}
		else {
			local l = length("`covariance'")
			if substr("independent",1,max(3,`l')) == "`covariance'" {
				local cov "ind"
				local covtype "Independent"
			}
			else if substr("exchangeable",1,max(2,`l')) == "`covariance'" {
				local cov "exch"
				local covtype "Exchangeable"
			}
			else if substr("identity",1,max(2,`l')) == "`covariance'" {
				local cov "iden"
				local covtype "Identity"
			}
			else if substr("unstructured",1,max(2,`l')) == "`covariance'" {
				local cov "unstr"
				local covtype "Unstructured"
			}
			else {
				di as error "Unknown variance-covariance structure"
				exit 198
			}
		}

		if "`weight'" != "" {
			display as err "weights not allowed"
			exit 198
		}
		local wt: char _dta[st_w]
		if "`wt'" != "" {
			display as err "weights not allowed"
			exit 198
		}

		fvexpand `varlist' `survcov' `timeinteraction' `assoccovariates'
		if "`r(fvops)'" != "" {
			display as error "Factor variables not allowed. Create your own dummy variables."
			exit 198
		}

		if "`smodel'"=="fpm" {
			capture which stpm2
			if _rc >0 {
				display in yellow "You need to install the command stpm2. This can be installed using,"
				display in yellow ". {stata ssc install stpm2}"
				exit 198
			}
		}

		if "`smodel'"=="fpm" | "`smodel'"=="rcs" | "frcs"!="" | "`rrcs'"!="" {
			capture which rcsgen
			if _rc >0 {
				display in yellow "You need to install the command rcsgen. This can be installed using,"
				display in yellow ". {stata ssc install rcsgen}"
				exit 198
			}
		}

		if "`smodel'"=="rcs" {
			capture which stgenreg
			if _rc>0 {
				display in yellow "You need to install the command stgenreg. This can be installed using,"
				display in yellow ". {stata ssc install stgenreg}"
				exit 198
			}
			if "`knots'"!="" {
				di as error "knots() not allowed with survmodel(rcs), please use df()"
				exit 198
			}
		}

		if "`smodel'"=="ww" | "`smodel'"=="ww" {
			capture which stmix
			if _rc>0 {
				display in yellow "You need to install the command stmix. This can be installed using,"
				display in yellow ". {stata ssc install stmix}"
				exit 198
			}
		}

		if ("`smodel'"!="fpm" & "`smodel'"!="rcs") & ("`df'"!="" | "`knots'"!="") {
			di as error "Can only specify df()/knots() with survmodel(fpm) or survmodel(rcs)"
			exit 198
		}

		if ("`smodel'"!="fpm" & "`smodel'"!="rcs") & "`noorthog'"!="" {
			di as error "Option noorthog only valid with survmodel(fpm) or survmodel(rcs)"
			exit 198
		}

		if "`rfp'"=="" & "`ffp'"=="" & "`frcs'"=="" {
			di as error "One of rfp()/ffp()/frcs() must be specified"
			exit 198
		}

		if "`rrcs'"!="" & "`derivassociation'"!="" {
			di as error "derivassociation() and rrcs() not currently allowed"
			exit 198
		}

		if ("`nocurrent'"!="" & "`intassociation'"=="" & "`association'"=="" & "`derivassociation'"=="") {
			di as error "No association between submodels has been specified"
			exit 198
		}

		if ("`derivassociation'"!="" & "`rfp'"=="" & "`rrcs'"=="") {
			di as error "Random time variables must be specified for derivative association."
			exit 198
		}

		if ("`association'"!="" & "`rfp'"=="") {
			di as error "Random time variables must be specified for separate association."
			exit 198
		}

		if ("`association'"!="" & "`rrcs'"!="") {
			di as error "rrcs() cannot be used with association()"
			exit 198
		}

		if "`ffp'"!="" | "`rfp'"!="" {
			foreach fe of numlist `ffp' `rfp' {
				if (`fe'!=-5 & `fe'!=-4 & `fe'!=-3 & `fe'!=-2 & `fe'!=-1 & `fe'!=-0.5 & `fe'!=0 & `fe'!=0.5 & `fe'!=1 & `fe'!=2 & `fe'!=3 & `fe'!=4 & `fe'!=5) {
					di as error "ffp()/rfp() powers must be one of -5, -4, -3, -2, -1, -.5, 0, .5, 1, 2, 3, 4, 5"
					exit 198
				}
			}
		}

		local dumcheck = 0
		if "`rfp'"!="" & "`ffp'"!="" {
			foreach re of numlist `rfp' {
				foreach fe of numlist `ffp' {
					if "`re'"=="`fe'" {
						local dumcheck = 1
					}
				}
			}
		}
		if `dumcheck' {
			di as error "You cannot specify both a fixed and random fracpoly with the same power"
			exit 198
		}

		if ("`association'"!="" & "`rfp'"!="") {
			local dumcheck   = 0
			local finalcheck = 0
			foreach a of numlist `association' {
				foreach b of numlist `rfp' {
					if `a'==`b' {
						local dumcheck = 1
					}
				}
				if !`dumcheck' {
					local finalcheck = 1
				}
			}
			if `finalcheck' {
				di as error "Elements of association must be in rfp()"
				exit 198
			}
		}

		if "`showcons'"!="" & "`smodel'"!="fpm" {
			di as error "showcons only allowed when survmodel = fpm"
			exit 198
		}

		if "`gk'"!="" & "`gl'"!="" {
			di as error "gk() and gl() cannot both be specified"
			exit 198
		}

		if "`gk'"!="" {
			if "`gk'"!="15" & "`gk'"!="7" {
				di as error "gk() must be 7 or 15"
				exit 198
			}
		}

		if "`gl'"!="" {
			cap confirm integer number `gl'
			if _rc {
				di as error "gl() must be a positive integer >= 5"
				exit 198
			}
			if `gl'<5 {
				di as error "gl() must be a positive integer >= 5"
				exit 198
			}
		}

		if ("`smodel'"=="fpm" | "`smodel'"=="rcs") & "`df'"=="" & "`knots'"=="" {
			di as error "One of df() or knots() must be specified"
			exit 198
		}

		if ("`smodel'"=="fpm" | "`smodel'"=="rcs" ) {
			if "`df'"!="" & "`knots'"!="" {
				di as error "Only one of df() and knots() can be specified"
				exit 198
			}
		}

		if "`adaptit'"!="" {
			cap confirm integer number `adaptit'
			if _rc>0 {
				di as error "adaptit must be an integer"
				exit 198
			}
			if `adaptit'<0 {
				di as error "adaptit must be >0"
				exit 198
			}
		}
		else if "`nonadapt'"=="" local adaptit 5

		if "`gh'"!="" {
			cap confirm integer number `gh'
			if _rc>0 {
				di as error "gh() must be an integer"
				exit 198
			}
			if `gh'<2 {
				di as error "gh() must be > 1"
				exit 198
			}
		}
		else {
			if "`nonadapt'"=="" local gh 5
			else local gh 15
		}

		if ("`ffp'"!="" | "`rfp'"!="") & ("`rrcs'"!="" | "`frcs'"!="") {
			di as error "ffp()/rfp() cannot be specified with frcs()/rrcs()"
			exit 198
		}

		if "`nonadapt'"!="" & "`adaptit'"!="" {
			di as error "Cannot specify adaptit() with nonadapt"
			exit 198
		}

        if `"`texp'"' != "" & "`tvc'" == "" {
			di as err "texp() only allowed with tvc()"
			exit 198
        }

		if "`tvc'"!="" & (`aft' | "`smodel'"=="fpm" | "`smodel'"=="rcs") {
			di as error "tvc() only allowed with hazard scale PH survival models (except survmodel(rcs))"
			exit 198
		}

		if `aft' & ("`gk'"!="" | "`gl'"!="") {
			di as error "gk()/gl() not allowed with an AFT survival sub model"
			error 198
		}

	//===================================================================================================================================================//
	// Preliminaries //

		if ("`getblups'"!="") local gbquietly quietly

		if "`nonadapt'"=="" {
			local dprolog derivprolog(stjm_prolog())
			local quadtype adapt
			local ghtext "Adaptive Gauss-Hermite quadrature"
		}
		else {
			local nonadapt _na
			local quadtype nonadapt
			local ghtext "Gauss-Hermite quadrature"
		}

		if "`showinitial'"!="" local noisily noisily
		if ("`smodel'"!="fpm" & !`aft' & "`gk'"=="" & "`gl'"=="") local gk 15
		local usegk = "`gk'"!=""

		local emonly emonly
		if "`noxtem'"!="" local emonly

		//set estimation sample
		marksample touse
		markout `touse' `survcov' `timeinteraction' `assoccovariates'
		qui replace `touse' = 0 if _st==0

		//longitudinal variables
		gettoken lhs rhs : varlist

		//parse ml options and extract any extra constraints
		mlopts mlopts , `options'
		local extra_constraints `s(constraints)'

		//panel ID variable
		tempvar _tempid
		qui egen `_tempid' = group(`panel')	if `touse'==1
		//final row per panel indicator
		tempvar surv_ind
		qui bys `_tempid' (_t0): gen byte `surv_ind'= (_n==_N & `touse'==1)
		//# measurements per panel
		tempvar n_meas
		qui bys `_tempid' (_t0): gen `n_meas' = _N if `touse'==1

		//Numbers
		qui count if `touse'==1
		local nmeasures = `r(N)'
		qui count if `surv_ind'==1
		local Npat = `r(N)'
		qui count if _d==1 & `surv_ind'==1
		local Nevents = `r(N)'
		local n_scovs : list sizeof survcov
		local n_lcovs : list sizeof rhs
		if "`frcs'"!="" local n_ftime = `frcs'
		else local n_ftime : list sizeof ffp
		if "`rrcs'"!="" local n_rtime = `rrcs'
		else local n_rtime : list sizeof rfp
		local npows = `n_ftime' + `n_rtime'
		local n_re = `n_rtime' + 1

		if "`frcs'"=="" {
			numlist "`ffp' `rfp'", sort
			local fps `r(numlist)'
			local firstpow : word 1 of `fps'
			if `firstpow' <= 0 {
				qui fracgen _t0 `fps' if `touse',  noscaling nogen
				local shift = `r(shift)'
			}
			else local shift = 0

			tempvar stime basetime
			qui gen double `stime'		= _t + `shift' if `touse'==1
			qui gen double `basetime' 	= _t0 + `shift' if `touse'==1
		}

		//Check time origin for delayed entry models
		tempvar del_surv_ind
		qui bys `_tempid' (_t0): gen byte `del_surv_ind' = (_n==1 & `touse'==1)		//summary passed to below quick/slow check

		local n_time_assoc = 0
		if "`association'"!="" {
			local n_time_assoc : list sizeof association
			tempname timeassoc_fixed_ind
			mat `timeassoc_fixed_ind' = J(`n_time_assoc',1,.)
		}

	//===================================================================================================================================================//
	// Quick or slow //

		if "`fulldata'"=="" {
			if "`survcov'"!="" | "`assoccovariates'"!="" {
				local nvardiffs = 0
				foreach var of varlist `survcov' `assoccovariates' {
					tempvar ind_`var'
					qui bys `_tempid' (_t0): gen byte `ind_`var'' = (`var'[_n]==`var'[_n+1]) if _n<_N & _N>1 & `touse'==1
					qui bys `_tempid' (_t0): replace `ind_`var'' = (`var'[_n]==`var'[_n-1]) if _n==_N & _N>1 & `touse'==1
					qui count if `ind_`var''==0
					local nvardiffs = `nvardiffs' + `r(N)'
				}
				if `nvardiffs'==0 {
					local quick _quick
				}
			}
			else local quick _quick
		}

		if "`quick'"=="" {	// Full data
			local delsurvtouse "`touse'"
			local survtouse "`touse'"
			local Nsurv = `nmeasures'
			di in yellow "Warning -> all rows of data are being used in the survival component of the likelihood."
			di in yellow "        -> care must be taken if missing data is present, see the help file for details."
			di ""
		}
		else {				// quick option
			tempvar quickindex
			qui gen `quickindex' = _n if `touse'==1
			local delsurvtouse "`del_surv_ind'"
			local survtouse "`surv_ind'"
			local Nsurv = `Npat'
		}

		qui summ _t0 if `delsurvtouse'==1, meanonly
		local delentry = 0
		if `r(max)'>0 local delentry = 1

	//======================================================================================================================================================//
	// Handle time-dependent effects //

		if "`tvc'"!="" {
			tempvar foft1
			if `"`texp'"' == "" {
					local texp _t
			}
			local texp: subinstr local texp " " "", all
			cap gen double `foft1' = `texp' if `touse'
			if _rc {
					di as err "{p 0 4 2}texp() invalid{p_end}"
					exit 198
			}
			qui count if `touse' & missing(`foft1')
			if `r(N)' {
				di as err "{p 0 4 2}texp() evaluates to missing for "
				di as err "`r(N)' observations{p_end}"
				exit 459
			}
			//FunctionOfTime `foft1' if `touse'		//!!add later

			// tvc() has a limit of 100 variables
			local Ntvcvars : word count `tvc'
			if `Ntvcvars' > 100 {
				di as err "too many variables specified"
				di as err "option tvc() incorrectly specified"
				exit 198
			}
			//version 11: _rmcoll `tvc', forcedrop

		}


	//======================================================================================================================================================//
	// Create time variables //

		cap drop _time_*
		local ninterac : list sizeof timeinteraction
		scalar ntimecovinterac = `ninterac'

		//====================================================//
		// FP's
		if "`ffp'"!="" | "`rfp'"!="" {
			local longtimeform fps

			tempname rand_ind fp_pows
			mat `rand_ind' = J(1,`npows',0)
			mat `fp_pows'  = J(1,`npows',.)

			// Generate timevars
			local j = 1
			local tfi_ind = 1
			local tassoc_ind = 1
			foreach i of numlist `fps' {
				mat `fp_pows'[1,`j']  = `i'
				tempvar _time_surv_`j'
				if (`i'!=0) {
					qui gen double _time_`j' 			= (`basetime')^(`i') 	if `touse'==1
					qui gen double `_time_surv_`j'' 	= (`stime')^(`i') 		if `touse'==1

					if "`smodel'"=="fpm" | "`derivassociation'"!="" {
						tempvar d1_time_`j' d1_time_surv_`j'
						qui gen double `d1_time_`j''		= `i'*(`basetime')^(`=`i'-1') 	if `touse'==1
						qui gen double `d1_time_surv_`j'' 	= `i'*(`stime')^(`=`i'-1') 		if `touse'==1
						local d1_fe_timevar_names 		`d1_fe_timevar_names' `d1_time_`j''
						local d1_fe_timevar_names_surv 	`d1_fe_timevar_names_surv' `d1_time_surv_`j''
					}

					if "`smodel'"=="fpm" & "`derivassociation'"!="" {
						tempvar d2_time_`j' d2_time_surv_`j'
						if `i'!=1 {
							qui gen double `d2_time_`j'' 		= (`=`i'-1')*(`i')*(`basetime')^(`=`i'-2') 	if `touse'==1
							qui gen double `d2_time_surv_`j'' 	= (`=`i'-1')*(`i')*(`stime')^(`=`i'-2') 	if `touse'==1
						}
						else {
							qui gen byte `d2_time_`j'' 		= 0 if `touse'==1
							qui gen byte `d2_time_surv_`j'' = 0 if `touse'==1
						}
						local d2_fe_timevar_names 		`d2_fe_timevar_names' `d2_time_`j''
						local d2_fe_timevar_names_surv 	`d2_fe_timevar_names_surv' `d2_time_surv_`j''
					}
					n `gbquietly' di in green "-> gen double _time_`j' = X^(`i')"
					label variable _time_`j' "_time_`j' = X^(`i') `xtxt'"
				}
				else {
					qui gen double _time_`j' 					= log(`basetime') 	if `touse'==1
					qui gen double `_time_surv_`j'' 			= log(`stime') 		if `touse'==1
					if "`smodel'"=="fpm" | "`derivassociation'"!="" {
						tempvar d1_time_`j' d1_time_surv_`j'
						qui gen double `d1_time_`j''			= 1/(`basetime') 	if `touse'==1
						qui gen double `d1_time_surv_`j'' 		= 1/(`stime') 		if `touse'==1
						local d1_fe_timevar_names 		`d1_fe_timevar_names' `d1_time_`j''
						local d1_fe_timevar_names_surv 	`d1_fe_timevar_names_surv' `d1_time_surv_`j''
					}
					if "`smodel'"=="fpm" & "`derivassociation'"!="" {
						tempvar d2_time_`j' d2_time_surv_`j'
						qui gen double `d2_time_`j'' 		= -1/((`basetime')^2) 	if `touse'==1
						qui gen double `d2_time_surv_`j'' 	= -1/((`stime')^2) 		if `touse'==1
						local d2_fe_timevar_names 		`d2_fe_timevar_names' `d2_time_`j''
						local d2_fe_timevar_names_surv 	`d2_fe_timevar_names_surv' `d2_time_surv_`j''
					}
					n `gbquietly' di in green "-> gen double _time_`j' = log(X)"
					label variable _time_`j' "_time_`j' = log(X) `xtxt'"
				}

				local fe_timevar_names 			`fe_timevar_names' _time_`j'
				local fe_timevar_names_surv 	`fe_timevar_names_surv' `_time_surv_`j''

				if "`rfp'"!=""{
					foreach re of numlist `rfp' {
						if `re'==`i' {
							mat `rand_ind'[1,`j'] = 1
							local re_timevar_names 			`re_timevar_names' _time_`j'
							local re_timevar_names_surv 	`re_timevar_names_surv' `_time_surv_`j''
							if "`smodel'"=="fpm" | "`derivassociation'"!="" {
								local d1_re_timevar_names 		`d1_re_timevar_names' `d1_time_`j''
								local d1_re_timevar_names_surv 	`d1_re_timevar_names_surv' `d1_time_surv_`j''
							}
							if "`smodel'"=="fpm" & "`derivassociation'"!="" {
								local d2_re_timevar_names 		`d2_re_timevar_names' `d2_time_`j''
								local d2_re_timevar_names_surv 	`d2_re_timevar_names_surv' `d2_time_surv_`j''
							}
						}
					}
				}

				if "`association'"!="" {
					local dumtest = 0
					foreach ass in `association' {
						if `i'==`ass' {
							mat `timeassoc_fixed_ind'[`tfi_ind',1] = `tassoc_ind'
							local `++tfi_ind'
						}
					}
					local `++tassoc_ind'
				}

				// time-covariate interactions
				if "`timeinteraction'"!="" {

					foreach covtime of varlist `timeinteraction' {
						tempvar interac_t_`j'_`covtime'
						qui gen double _time_`j'_`covtime'			= `covtime' * _time_`j' 		if `touse'==1
						qui gen double `interac_t_`j'_`covtime'' 	= `covtime' * `_time_surv_`j'' 	if `touse'==1
						local covinterlist1 	`covinterlist1' _time_`j'_`covtime'
						local covinterlist2 	`covinterlist2' `interac_t_`j'_`covtime''
						n `gbquietly' di in green "-> gen double _time_`j'_`covtime' = `covtime' * _time_`j'"
						label variable _time_`j'_`covtime' "_time_`j'_`covtime' = `covtime' * _time_`j'"
					}
					if "`smodel'"=="fpm" | "`derivassociation'"!="" {
						foreach covtime of varlist `timeinteraction' {
							tempvar  d1_interac_t_`j'_`covtime'
							qui gen double `d1_interac_t_`j'_`covtime'' 	= `covtime' * `d1_time_surv_`j'' 	if `touse'==1
							local d1_covinterlist_surv "`d1_covinterlist_surv' `d1_interac_t_`j'_`covtime''"
							if "`smodel'"=="fpm"{
								tempvar  d1_interac_t0_`j'_`covtime'
								qui gen double `d1_interac_t0_`j'_`covtime'' 	= `covtime' * `d1_time_`j'' 	if `touse'==1
								local d1_covinterlist_long 	`d1_covinterlist_long' `d1_interac_t0_`j'_`covtime''
							}
						}
					}
					if "`smodel'"=="fpm" & "`derivassociation'"!="" {
						foreach covtime of varlist `timeinteraction' {
							tempvar  d2_interac_t_`j'_`covtime'
							qui gen double `d2_interac_t_`j'_`covtime'' 	= `covtime' * `d2_time_surv_`j'' 	if `touse'==1
							local d2_covinterlist_surv 	`d2_covinterlist_surv' `d2_interac_t_`j'_`covtime''
						}
					}

				}

				local `++j'
			}

			if `shift'==0 n `gbquietly' di in green "(where X = _t0)"
			else n `gbquietly' di in green "(where X = _t0 + `shift')"
		}

		//================================================================================//
		// Splines
		else {

			if "`smodel'"=="fpm" | "`derivassociation'"!="" {
				tempvar d1_time d1_time_surv
				local dgen1 dgen(`d1_time'_)
				local dgen2 dgen(`d1_time_surv'_)
			}

			//fixed time rcs
			qui rcsgen _t0 if `touse', df(`frcs') gen(_time_) /*orthog*/ `dgen1'
			local knots_1 `r(knots)'
			/*tempname rmat_frcs
			mat `rmat_frcs' = r(R)*/
			forvalues i=1/`frcs' {
				local fe_timevar_names `fe_timevar_names' _time_`i'
				if "`smodel'"=="fpm" | "`derivassociation'"!="" {
					local d1_fe_timevar_names `d1_fe_timevar_names' `d1_time'_`i'
				}
			}
			`gbquietly' di as txt "-> Spline variables created: `fe_timevar_names'"
			tempvar _time_surv
			qui rcsgen _t if `touse', knots(`knots_1') gen(`_time_surv'_) /*rmat(`rmat_frcs')*/ `dgen2'
			forvalues i=1/`frcs' {
				local fe_timevar_names_surv `fe_timevar_names_surv' `_time_surv'_`i'
				if "`smodel'"=="fpm" | "`derivassociation'"!="" {
					local d1_fe_timevar_names_surv `d1_fe_timevar_names_surv' `d1_time_surv'_`i'
				}
			}

			if "`timeinteraction'"!="" {
				foreach covtime of varlist `timeinteraction' {
					forvalues j=1/`frcs'{
						tempvar interac_t_`j'_`covtime'
						qui gen double _time_`j'_`covtime'			= `covtime' * _time_`j' 		if `touse'==1
						qui gen double `interac_t_`j'_`covtime'' 	= `covtime' * `_time_surv'_`j' 	if `touse'==1
						local covinterlist1 `covinterlist1' _time_`j'_`covtime'
						local covinterlist2 `covinterlist2' `interac_t_`j'_`covtime''
						n `gbquietly' di in green "-> gen double _time_`j'_`covtime' = `covtime' * _time_`j'"
						label variable _time_`j'_`covtime' "_time_`j'_`covtime' = `covtime' * _time_`j'"
					}
				}

				if "`smodel'"=="fpm" | "`derivassociation'"!="" {
					foreach covtime of varlist `timeinteraction' {
						forvalues j=1/`frcs'{
							tempvar  d1_interac_t_`j'_`covtime'
							qui gen double `d1_interac_t_`j'_`covtime'' 	= `covtime' * `d1_time_surv'_`j' 	if `touse'==1
							local d1_covinterlist_surv `d1_covinterlist_surv' `d1_interac_t_`j'_`covtime''
							if "`smodel'"=="fpm"{
								tempvar  d1_interac_t0_`j'_`covtime'
								qui gen double `d1_interac_t0_`j'_`covtime'' 	= `covtime' * `d1_time'_`j' 	if `touse'==1
								local d1_covinterlist_long 	`d1_covinterlist_long' `d1_interac_t0_`j'_`covtime''
							}
						}
					}
				}
			}

			//random time rcs
			if "`rrcs'"!="" {
				if "`rrcs'"!="`frcs'"{
					if "`smodel'"=="fpm" | "`derivassociation'"!="" {
						tempvar d1_re_time d1_re_time_surv
						local dgen3 dgen(`d1_re_time'_)
						local dgen4 dgen(`d1_re_time_surv'_)
					}
					tempvar _re_time
					qui rcsgen _t0, df(`rrcs') gen(_time_re_) /*orthog*/ `dgen3'
					local knots_2 `r(knots)'
					/*tempname rmat_rrcs
					mat `rmat_rrcs' = r(R)*/
					forvalues i=1/`rrcs' {
						local re_timevar_names `re_timevar_names' _time_re_`i'
						if ("`smodel'"=="fpm" | "`derivassociation'"!="") local d1_re_timevar_names 	`d1_re_timevar_names' `d1_re_time'_`i'
					}
					`gbquietly' di as txt "-> Spline variables created: `re_timevar_names'"
					tempvar _re_time_surv
					qui rcsgen _t, knots(`knots_2') gen(`_re_time_surv'_) /*rmat(`rmat_rrcs')*/ `dgen4'
					forvalues i=1/`rrcs' {
						local re_timevar_names_surv `re_timevar_names_surv' `_re_time_surv'_`i'
						if ("`smodel'"=="fpm" | "`derivassociation'"!="") local d1_re_timevar_names_surv 	`d1_re_timevar_names_surv' `d1_re_time_surv'_`i'
					}
				}
				else {
					local knots_2 `knots_1'
					local re_timevar_names `fe_timevar_names'
					if ("`smodel'"=="fpm" | "`derivassociation'"!="") local d1_re_timevar_names `d1_fe_timevar_names'
					local re_timevar_names_surv `fe_timevar_names_surv'
					if ("`smodel'"=="fpm" | "`derivassociation'"!="") local d1_re_timevar_names_surv `d1_fe_timevar_names_surv'
				}
			}

		}

		// Variance ml equation names //
		if "`cov'"=="ind" | "`cov'"=="unstr" {
			forvalues i=1/`n_re' {
				local var_re_eqn_names "`var_re_eqn_names' /lns_`i'"
			}
		}
		else local var_re_eqn_names "/lns_1"

		local eqn_names "(Longitudinal: = `fe_timevar_names' `covinterlist1' `rhs')"				/* Longitudinal ml equation */

	//========================================================================================================================================================================================//
	// Fixed effect design matrices at exit times

		local longparams_surv "`fe_timevar_names_surv' `covinterlist2' `rhs'"

		if "`smodel'"=="fpm" | "`derivassociation'"!="" {
			local ntemp = `n_lcovs' + 1
			local d1_fe_timevar_names "`d1_fe_timevar_names' `d1_covinterlist_long'"
			local d1_fe_timevar_names_surv "`d1_fe_timevar_names_surv' `d1_covinterlist_surv'"
		}

		if "`smodel'"=="fpm" & "`derivassociation'"!="" local d2_fe_timevar_names_surv "`d2_fe_timevar_names_surv' `d2_covinterlist_surv'"

	//========================================================================================================================================================================================//
	// Association parameterisation

		local alpha_ith = 1
		local current 	= 0
		local deriv 	= 0
		local intassoc 	= 0
		local timeassoc = 0
		if "`nocurrent'"=="" {
			local current = 1
			local alphaequation "`alphaequation' (alpha_`alpha_ith': `assoccovariates')"
			local `++alpha_ith'
		}
		if "`derivassociation'"!="" {
			local deriv = 1
			local alphaequation "`alphaequation' (alpha_`alpha_ith': `assoccovariates')"
			local `++alpha_ith'
		}
		if "`intassociation'"!="" {
			local intassoc = 1
			local alphaequation "`alphaequation' /alpha_`alpha_ith'"
			local `++alpha_ith'
		}
		if "`association'"!="" {
			local timeassoc = 1
			foreach assoc of numlist `association' {
				local alphaequation "`alphaequation' /alpha_`alpha_ith'"
				local `++alpha_ith'
			}
		}
		local n_alpha = `alpha_ith' - 1

	//========================================================================================================================================================================================//
	// GK set-up including longitudinal splines and hazard splines

		if "`smodel'"!="fpm" & !`aft' {

			tempname gknodes gkweights
			//GK nodes and weights
			if `usegk' {
				if (`gk'==15) {
					mat `gknodes' 	= 0.991455371120813,-0.991455371120813,0.949107912342759,-0.949107912342759,0.864864423359769,-0.864864423359769,0.741531185599394,-0.741531185599394,0.586087235467691,-0.586087235467691,0.405845151377397,-0.405845151377397,0.207784955007898,-0.207784955007898,0
					mat `gkweights'	= 0.022935322010529,0.022935322010529,0.063092092629979,0.063092092629979,0.104790010322250,0.104790010322250,0.140653259715525,0.140653259715525,0.169004726639267,0.169004726639267,0.190350578064785,0.190350578064785,0.204432940075298,0.204432940075298,0.209482141084728
				}
				else {
					mat `gknodes' 	= 0.949107912342759,-0.949107912342759,0.741531185599394,-0.741531185599394,0.405845151377397,-0.405845151377397,0
					mat `gkweights'	= 0.129484966168870,0.129484966168870,0.279705391489277,0.279705391489277,0.381830050505119,0.381830050505119,0.417959183673469
				}
			}
			else {
				stjm_gaussquad, n(`gl') legendre
				mat `gknodes' = r(nodes)'
				mat `gkweights' = r(weights)'
			}

			if "`quick'"!="" {
				tempvar delt
				qui bys `_tempid' (_t0): gen `delt' = _t0[1] if `touse'==1
				local tvar `delt'
			}
			else local tvar _t0

			//create basis GK node variables
			local gk `gk'`gl'
			forvalues i=1/`gk' {
				tempvar node`i'
				qui gen double `node`i'' =  0.5*(_t - `tvar')*(el(`gknodes',1,`i')) + 0.5*(_t + `tvar') if `survtouse'
			}

			//tvc's
			if "`tvc'"!="" {

				//for hazard function
				foreach tvcvar in `tvc' {
					cap drop `tvcvar'_tvc
					gen double `tvcvar'_tvc = `tvcvar' * `foft1'
					n `gbquietly' di in green "-> gen double `tvcvar'_tvc = `tvcvar' * `texp'"
					local tvcvars `tvcvars' `tvcvar'_tvc							//for ml model
				}
				local tvcmleqn (tvc: `tvcvars',nocons)

				//for quadrature
				local texpcopy `texp'
				forvalues i=1/`gk' {
					local texpfunc : subinstr local texpcopy "_t" "`node`i''", all		//update tdefunc with node tempvar
					tempvar tvcnode`i'
					qui gen double `tvcnode`i'' =  `texpfunc' if `survtouse' 		//needs to include texp()
					local tvcquadvars `tvcquadvars' `tvcnode`i''
				}
				//need separate quad vars for each tvc()
				local tvcind = 1
				foreach tvcvar in `tvc' {
					forvalues i=1/`gk' {
						tempvar tvcnode`tvcvar'`i'
						qui gen double `tvcnode`tvcvar'`i'' = `tvcnode`i'' * `tvcvar'  if `survtouse' 		//needs to include texp()
						local tvcquadvars`tvcind' `tvcquadvars`tvcind'' `tvcnode`tvcvar'`i''
					}
					local tvcind = `tvcind' + 1
				}

			}

			tempvar cons
			qui gen byte `cons' = 1 if `survtouse'
		}

		//getblups and exit
		if "`getblups'"!="" {
			mata: stjm_setup()
			capture mata: rmexternal("`stjm_struct'")
			exit
		}

	//========================================================================================================================================================================================//
	// Initial values

	quietly{

		noisily di
		noisily di as txt "Obtaining initial values:"
		noisily di

		tempname initmat
		// Longitudinal model initial values
		`noisily' xtmixed `lhs' `fe_timevar_names' `covinterlist1' `rhs' if `touse' || `_tempid': `re_timevar_names', cov(`cov') `variance' `emonly'
		matrix `initmat' = e(b)

		// predict RE's and seRE's
		forvalues i=1/`n_re' {
			tempvar blup`i' seblup`i'
			local blupnames "`blupnames' `blup`i''"
			local seblupnames "`seblupnames' `seblup`i''"
		}
		qui predict `blupnames' if `touse', reffects
		qui predict `seblupnames' if `touse', reses

		if "`nocurrent'"=="" {
			tempvar fitvals
			qui predict `fitvals' if `touse', fitted
			if "`assoccovariates'"!="" {
				foreach var of varlist `assoccovariates' {
					tempvar assocint_`var'
					qui gen double `assocint_`var'' = `fitvals'*`var'
					local associntlist1 "`associntlist1' `assocint_`var''"
				}
			}
			local alpha_di_txt "assoc:value"
		}

		if "`intassociation'"!="" | "`association'"!="" | "`derivassociation'"!=""{

			if "`derivassociation'"!="" {
				tempvar deriv_1
				//FP's
				if "`rfp'"!="" {
					qui gen double `deriv_1' = 0
					local stub 		= 1
					local re_stub 	= 1
					foreach pow of numlist `fps' {
						if `pow'!=0 {
							if `rand_ind'[1,`stub']==1 {
								local derivadd "(([`lhs'][_time_`stub'] + `blup`re_stub'')*(`pow')*`basetime'^(`pow'-1))"
								local `++re_stub'
							}
							else local derivadd "([`lhs'][_time_`stub']*(`pow')*`basetime'^(`pow'-1))"
						}
						else {
							if `rand_ind'[1,`stub']==1 {
								local derivadd "(([`lhs'][_time_`stub'] + `blup`re_stub'')/`basetime')"
								local `++re_stub'
							}
							else local derivadd "([`lhs'][_time_`stub']/`basetime')"
						}
						if "`timeinteraction'"!="" {
							foreach var of varlist `timeinteraction' {
								local derivadd2 "`derivadd2' + `derivadd'*`var' "
							}
						}
						replace `deriv_1' = `deriv_1' + (`derivadd') `derivadd2'
						local `++stub'
					}
				}
				//splines -> error check not allowing this
				else {
					tempvar fitvalsd1
					qui predict `fitvalsd1' if `touse', fitted
					qui dydx `fitvalsd1' _t0, gen(`deriv_1')
					qui bys _t0 (`deriv_1'): replace `deriv_1' = `deriv_1'[1]
					cap sort `_tempid' _t0
				}

				if "`assoccovariates'"!="" {
					foreach var of varlist `assoccovariates' {
						tempvar assocderivint_`var'
						qui gen double `assocderivint_`var'' = `deriv_1'*`var'
						local associntlist2 "`associntlist2' `assocderivint_`var''"
					}
				}
				local derivlist "`deriv_1'"

				local alpha_di_txt "`alpha_di_txt' assoc:slope"

			}

			if "`intassociation'"!="" {
				local sepassocnameint "`blup`n_re''"
				local alpha_di_txt "`alpha_di_txt' assoc:int"
			}

			if "`association'"!="" {
				//need to extract random time variables whose coefficients are specified for the association
				//index random time variables
				tempname timeassoc_re_ind
				mat `timeassoc_re_ind' = J(`n_time_assoc',1,.)
				local re  = 1
				local ind = 1
				foreach repow of numlist `rfp' {
					foreach ass of numlist `association' {
						if `repow'==`ass' {
							mat `timeassoc_re_ind'[`ind',1] = `re'
							local `++ind'
						}
					}
					local `++re'
				}
				local ind_row = 1
				foreach a of numlist `association' {
					local ind_re  = 1
					foreach b of numlist `fps' {
						if `a'==`b' {
							local sepassocnames "`sepassocnames' `blup`ind_row''"
							local sepassocpred "`sepassocpred' `ind_re'"
							local alpha_di_txt "`alpha_di_txt' a:_time_`ind_re'"
						}
						local `++ind_re'
					}
					local `++ind_row'
				}
			}
		}
		global alpha_di_txt `alpha_di_txt'

		if "`cov'"=="exch" & `n_re'>1 {
			local corr_eqn_names "/art_1_1"
			local corr_eqn_names2 "art_1_1"
		}
		else if "`cov'"=="unstr" {
			local subind = 1
			while (`subind'<`n_re') {
				forvalues i=`=`subind'+1'/`n_re' {
					local corr_eqn_names  "`corr_eqn_names' /art_`subind'_`i'"
					local corr_eqn_names2 "`corr_eqn_names2' art_`subind'_`i'"
				}
				local `++subind'
			}
		}

		local longequation "`eqn_names' `var_re_eqn_names' `corr_eqn_names' /lns_e"

		local var_corr_eqn_names `var_re_eqn_names' `corr_eqn_names'
		local nvcvparams : list sizeof var_corr_eqn_names

		//================================//
		// Survival model initial values

		local searchopt "search(off)"
		tempname initmatsurv

		// Flexible parametric model
		if "`smodel'"=="fpm" {
			if "`df'"!="" {
				local splines "df(`df')"
			}
			else {
				local splines "knots(`knots')"
				local df : word count `knots'
				local df = `df' + 1
			}

			`noisily' stpm2 `associntlist1' `fitvals' `associntlist2' `derivlist' `associntlist3' `sepassocnameint' `sepassocnames' `survcov' if `touse', `splines' scale(hazard) `noorthog' failconvlininit

			local ln_bhknots `e(ln_bhknots)'

			local nalphacovs : list sizeof assoccovariates
			local n1 = `n_alpha' * (`nalphacovs' +1 ) + `n_scovs' + 2*`df' + 1
			local n2 = `n1' + `n_alpha' * (`nalphacovs' +1 ) + 1

			tempname mat1
			mat `mat1' = e(b)
			mat `initmatsurv' = `mat1'[1,1..`n1']
			mat `initmatsurv' = `initmatsurv',`mat1'[1,`n2'..colsof(`mat1')]
			tempname R_bh
			mat `R_bh' = e(R_bh)

			/* rcs and drcs names */
			local rcsnames "`e(rcsterms_base)'"
			local drcsnames "`e(drcsterms_base)'"

			/* Constraints */
				forvalues i=1/`df' {
					local r`i' : word `i' of `rcsnames'
					local dr`i' : word `i' of `drcsnames'
					constraint free
					constraint `r(free)' [xb][`r`i'']=[dxb][`dr`i'']
					local conslist "`conslist' `r(free)'"
					/* Delayed entry */
					local srcsnames "`srcsnames' _s0_rcs`i'"
					constraint free
					constraint `r(free)' [xb][`r`i'']=[xb0][_s0_rcs`i']
					local conslist "`conslist' `r(free)'"
				}

				local xb0_eqn "(xb0: `survcov' `srcsnames')"
				constraint free
				constraint `r(free)' [xb][_cons]=[xb0][_cons]
				local conslist "`conslist' `r(free)'"

				if "`survcov'"!="" {
					foreach var in `survcov' {
						constraint free
						constraint `r(free)' [xb][`var']=[xb0][`var']
						local conslist "`conslist' `r(free)'"
					}
				}

			local dropconslist `conslist'
			//if further constraints are listed stpm2 then remove this from mlopts and add to conslist
			if "`extra_constraints'" != "" {
				local mlopts : subinstr local mlopts "constraints(`extra_constraints')" "", word
				local conslist `conslist' `extra_constraints'
			}

			local constopts "constraints(`conslist')"

			local collinopt "collinear"																		//pass collinear option as ml can drop spline variables when it shouldn't
			local survequation "(xb: `survcov' `rcsnames') (dxb: `drcsnames', nocons) `xb0_eqn'"			//rcs and drcs equations to pass to ml model

		}
		// Exponential
		else if "`smodel'"=="e" {
			`noisily' streg `associntlist1' `fitvals' `associntlist2' `derivlist' `associntlist3' `sepassocnameint' `sepassocnames' `tvcvars' `survcov' if `touse', dist(exp) nohr 					/* initial values from streg fit */
			mat `initmatsurv' = e(b)
			local survequation "`tvcmleqn' (ln_lambda: `survcov')"
		}
		// Weibull
		else if "`smodel'"=="w" {
			`noisily' streg `associntlist1' `fitvals' `associntlist2' `derivlist' `associntlist3' `sepassocnameint' `sepassocnames' `tvcvars' `survcov' if `touse', dist(weibull) nohr 					/* initial values from streg fit */
			mat `initmatsurv' = e(b)
			local survequation "`tvcmleqn' (ln_lambda: `survcov') /ln_gamma"
		}
		// Gompertz
		else if "`smodel'"=="g" {
			`noisily' streg `associntlist1' `fitvals' `associntlist2' `derivlist' `associntlist3' `sepassocnameint' `sepassocnames' `tvcvars' `survcov' if `touse', dist(gompertz) nohr 					/* initial values from streg fit */
			mat `initmatsurv' = e(b)
			local survequation "`tvcmleqn' (ln_lambda: `survcov') /gamma"
		}
		// Spline hazard model
		else if "`smodel'"=="rcs" {
			if "`df'"!="" {
				local splines "df(`df')"
			}
			else {
				local splines "knots(`knots')"
			}

			//`noisily' strcs `longinitvars' `survcov' if `touse', `splines' `noorthog'
			`noisily' stgenreg if `touse', loghazard([xb]) xb(`associntlist1' `fitvals' `associntlist2' `derivlist' 	///
							`associntlist3' `sepassocnameint' `sepassocnames' `survcov' | #rcs(`splines' `noorthog'))
			mat `initmatsurv' = e(b)
			local bhknots `e(eqn1comp2bhknots)'
			tempname rmat
			mat `rmat' = e(eqn1comp2rcsmat)
			cap drop _rcs*
			forvalues i=1/`df' {
				rename _eq1_cp2_rcs`i' _rcs`i'
				local rcsnames `rcsnames' _rcs`i'
			}
			local survequation (xb: `survcov' `rcsnames')
			local nrcsterms : list sizeof rcsnames

		}
		// Mixture Weibull
		else if "`smodel'"=="ww" {
			`noisily' stmix `associntlist1' `fitvals' `associntlist2' `derivlist' `associntlist3' `sepassocnameint' `sepassocnames' `tvcvars' `survcov' if `touse', dist(ww) nohr
			mat `initmatsurv' = e(b)
			if "`survcov'"!="" | "`tvc'"!="" {
				local ww_eqn `tvcmleqn' (xb: `survcov',nocons)
			}
			local survequation "`ww_eqn' /logit_p_mix /ln_lambda1 /ln_gamma1 /ln_lambda2 /ln_gamma2"
		}
		// Mixture Weibull-exponential
		else if "`smodel'"=="we" {
			`noisily' stmix `associntlist1' `fitvals' `associntlist2' `derivlist' `associntlist3' `sepassocnameint' `sepassocnames' `tvcvars' `survcov' if `touse', dist(we) nohr
			mat `initmatsurv' = e(b)
			if "`survcov'"!="" | "`tvc'"!="" {
				local we_eqn `tvcmleqn' (xb: `survcov',nocons)
			}
			local survequation "`we_eqn' /logit_p_mix /ln_lambda1 /ln_gamma1 /ln_lambda2"
		}

		if ("`nullassoc'"!="" & "`nocurrent'"=="") {
			forvalues i=1/`n_alpha' {
				mat `initmatsurv'[1,`i']=0
			}
		}
		matrix `initmat' = `initmat',`initmatsurv'
	}

	//=======================================================================================================================================================//
	// Maximisation

		//Mata setup
		if "`getblups'"=="" mata: stjm_setup()

		di as txt "Fitting full model:"
		if "`nonadapt'"=="" {
			di
			di in yellow "-> Conducting adaptive Gauss-Hermite quadrature"
		}

		if "`leave'"!="" {
			cap drop _STJM_tb*
			forvalues i=1/`n_re' {
				qui gen double _STJM_tb`i' = 0 if `touse'
			}
			local nop nopreserve
		}

		ml model d0 stjm_d0()											///
								`longequation' 							///
								`alphaequation'							///
								`survequation'							///
								if `touse'								///
								, init(`initmat', copy) 				///
								`options' 								///
								waldtest(0) 							///
								`searchopt'								///
								`collinopt'								///
								`constopts'								///
								`nolog'									///
								userinfo(`stjm_struct')					///
								`dprolog'								///
								`nop'									///
								maximize

		//Tidy up
		capture mata: rmexternal("`stjm_struct'")
		if _rc {
			di as error "Error when removing Mata global object"
			exit 1986
		}

		if "`leave'"!="" {
			forvalues i=1/`n_re' {
				qui bys `_tempid': replace _STJM_tb`i' = _STJM_tb`i'[_N] if `touse'
			}
		}

		ereturn local predict stjm_pred
		ereturn local title "Joint model estimates"
		ereturn local cmd stjm
		ereturn local survmodel "`smodel'"
		ereturn local longdepvar "`lhs'"
		ereturn local survdepvar "_t _d"
		ereturn local longtimeform "`longtimeform'"
		ereturn local rcsterms_base `rcsnames'
		ereturn local drcsterms_base `drcsnames'
		ereturn local long_varlist `rhs'
		ereturn local surv_varlist `survcov'
		ereturn local tvc `tvc'
		ereturn local texp `texp'
		ereturn local tvcvars `tvcvars'
		ereturn local panel `panel'
		ereturn local Npat `Npat'
		ereturn local Nobs `nmeasures'
		ereturn local Nevents `Nevents'
		ereturn local intmethod "`ghtext'"
		ereturn scalar dev = -2*e(ll)
		ereturn scalar AIC = -2*e(ll) + 2 * e(rank)
		qui count if `touse' == 1 & _d == 1
		ereturn scalar BIC = -2*e(ll) + ln(r(N)) * e(rank)

		//Stuff for predictions
		ereturn local delentry `delentry'
		ereturn local fpind = "`frcs'"==""
		ereturn local fixed_time `ffp'`frcs'
		ereturn local random_time `rfp'`rrcs'
		ereturn local frcs_knots `knots_1'
		ereturn local rrcs_knots `knots_2'
		ereturn local current `current'
		ereturn local deriv `deriv'
		ereturn local intassoc `intassoc'
		ereturn local timeassoc `timeassoc'
		ereturn local sepassoc_timevar_index `sepassocpred'
		ereturn local sepassoc_timevar_pows `association'
		ereturn local nocoefficient = "`nocoefficient'"!=""
		ereturn local npows `npows'
		ereturn local rand_timevars `re_timevar_names'
		ereturn local n_re = `n_re'
		ereturn local df `df'
		ereturn local shift `shift'
		ereturn local fps_list `fps'
		ereturn local nassoc `n_alpha'
		ereturn local ln_bhknots `ln_bhknots'
		ereturn local bhknots `bhknots'
		ereturn local northog `northog'
		ereturn local gh `gh'
		if `usegk' {
			ereturn local gk `gk'
		}
		else {
			ereturn local gl `gl'
		}
		ereturn local timecovvars `covinterlist1'
		ereturn local timeinteraction `timeinteraction'
		ereturn local assoccovariates `assoccovariates'
		ereturn local nvcvparams = `nvcvparams'
		ereturn local covtype `covtype'
		ereturn local nftime `n_ftime'
		ereturn local nrtime `n_rtime'

		if "`ffp'"!="" | "`rfp'"!="" {
			ereturn matrix fp_pows = `fp_pows'
			ereturn matrix rand_ind = `rand_ind'
		}
		if ("`smodel'"=="fpm") ereturn matrix rmatrix = `R_bh'
		if ("`smodel'"=="rcs") ereturn matrix rmatrix = `rmat'

		if "`association'"!="" {
			ereturn matrix timeassoc_re_ind = `timeassoc_re_ind'
			ereturn matrix timeassoc_fixed_ind = `timeassoc_fixed_ind'
		}

		tempname tempvcv
		matrix `tempvcv' = J(`n_re',`n_re',0)
		if "`covtype'"=="Independent" | "`covtype'"=="Unstructured" {
			forvalues i=1/`n_re' {
				mat `tempvcv'[`i',`i'] 	= exp([lns_`i'][_cons])^2
			}
		}
		else {
			forvalues i=1/`n_re' {
				mat `tempvcv'[`i',`i'] 	= exp([lns_1][_cons])^2
			}
		}
		if "`covtype'"=="Exchangeable" & `n_re'>1 {
			local test=1
			while (`test'<`n_re') {
				forvalues i=`=`test'+1'/`n_re' {
					mat `tempvcv'[`test',`i'] 	 = tanh([art_1_2][_cons])*exp([lns_1][_cons])^2
					mat `tempvcv'[`i',`test'] 	 = `tempvcv'[`test',`i']
				}
				local `++test'
			}
		}
		else if "`covtype'"=="Unstructured" {
			local test=1
			while (`test'<`n_re') {
				forvalues i=`=`test'+1'/`n_re' {
					mat `tempvcv'[`test',`i'] 	 = exp([lns_`test'][_cons])*exp([lns_`i'][_cons])*tanh([art_`test'_`i'][_cons])
					mat `tempvcv'[`i',`test'] 	 = `tempvcv'[`test',`i']
				}
				local `++test'
			}
		}
		ereturn matrix vcv = `tempvcv'

		if "`keepcons'" == "" constraint drop `dropconslist'
		else ereturn local sp_constraints `dropconslist'

		Replay, level(`level') `showcons' `variance'
end

program Replay
		syntax [, Level(cilevel) SHOWCons VARiance EFORM]
		Display, level(`level') `showcons' `variance' `form'
end


program Display
	syntax [, Level(cilevel) VARiance EFORM]

	tempname ests vars ses lci uci pvals zvals results
	mat `ests' = e(b)'
	mat `vars' = e(V)
	local nparams = colsof(`vars')

	mat `ses' = J(`nparams',1,0)
	forvalues i=1/`nparams' {
		mat `ses'[`i',1] = sqrt(`vars'[`i',`i'])
	}

	tempname siglev
	scalar `siglev' = abs(invnormal((100-`level')/200))

	mat `lci' = `ests' - `siglev' * `ses'
	mat `uci' = `ests' + `siglev' * `ses'

	mat `zvals' = J(`nparams',1,0)
	mat `pvals' = J(`nparams',1,0)
	forvalues i=1/`nparams' {
		mat `zvals'[`i',1] = `ests'[`i',1]/`ses'[`i',1]
		mat `pvals'[`i',1] = (1-normal(abs(`zvals'[`i',1])))*2
	}

	mat `results' = `ests',`ses',`zvals',`pvals',`lci',`uci'

	local k = length("`level'")

	if "`variance'"=="" {
		local sdtxt "sd"
		local corrtxt "corr"
	}
	else {
		local sdtxt "var"
		local corrtxt "cov"
	}

	di
	di as txt "Joint model estimates"											///
				as txt _col(50) "Number of obs.     = "							///
				as res _col(`=79-length("`e(Nobs)'")') `e(Nobs)'
	di as txt "Panel variable: " as res abbrev("`e(panel)'",12) 				///
				as txt _col(50) "Number of panels   = "							///
				as res _col(`=79-length("`e(Npat)'")') `e(Npat)'
	di as txt _col(50) "Number of failures = "									///
				as res _col(`=79-length("`e(Nevents)'")') `e(Nevents)'

		di
	di as txt "Log-likelihood = " as res e(ll)
		di

	/*Show constraints if asked */
	if "`showcons'"=="" {
		local nocnsreport nocnsreport
	}

		local labind = 1
		if `e(nftime)'>0 {
			forvalues i=1/`e(nftime)' {
				local `++labind'
			}
		}
		if `e(nrtime)'>0 & "`e(longtimeform)'"=="fps" {
			forvalues i=1/`e(nrtime)' {
				local `++labind'
			}
		}

		/* time covariate interactions */
		if "`e(timecovvars)'"!="" {
			foreach var of varlist `e(timecovvars)' {
				local `++labind'
			}
		}

		if "`e(long_varlist)'"!="" {
			foreach var of varlist `e(long_varlist)' {																			//fixed covariates in longitudinal model (rhs)
				local `++labind'
			}
		}
		ml di, neq(1) noheader showeqn nofootnote plus `nocnsreport' nolstretch
		local `++labind'
		local labind = `labind' + `e(nvcvparams)' + 1

	/* Association parameters */
	di as res "Survival" as txt _col(14) "{c |}"

		forvalues i = 1/`e(nassoc)' {
			local lab : word `i' of $alpha_di_txt
			local p = 13 - length("`lab'")
			di as res _col(`p') "`lab'" as txt _col(14) "{c |}"
			if "`e(assoccovariates)'"!="" {
				foreach cov in `e(assoccovariates)' {
					forvalues j = 1/6 {
						local coef`j' = `results'[`labind',`j']
					}
					local cov = abbrev("`cov'",12)
					Di_param, label(`cov') coef1(`coef1') coef2(`coef2') coef3(`coef3') coef4(`coef4') coef5(`coef5') coef6(`coef6')
					local `++labind'
				}
			}
			_diparm alpha_`i', label("_cons")
			local `++labind'
		}

	/* Survival parameters */
	if "`e(survmodel)'"=="fpm" | "`e(survmodel)'"=="rcs" {

		di as res _col(11) "xb" as txt _col(14) "{c |}"
		local scovs_names "`e(surv_varlist)' `e(rcsterms_base)'"
		foreach var of local scovs_names {																			//fixed covariates in survival model (survcov)
			forvalues i = 1/6 {
				local coef`i' = `results'[`labind',`i']
			}
			local var = abbrev("`var'",12)
			Di_param, label(`var') coef1(`coef1') coef2(`coef2') coef3(`coef3') coef4(`coef4') coef5(`coef5') coef6(`coef6')
			local `++labind'
		}
		_diparm xb, label("_cons")
		local `++labind'

	}
	else if "`e(survmodel)'"=="e" {

				di as res _col(4) "ln_lambda" as txt _col(14) "{c |}"
				local scovs_names "`e(tvcvars)' `e(surv_varlist)'"
				foreach var of local scovs_names {																			//fixed covariates in survival model (survcov)
					forvalues i = 1/6 {
						local coef`i' = `results'[`labind',`i']
					}
					local var = abbrev("`var'",12)
					Di_param, label(`var') coef1(`coef1') coef2(`coef2') coef3(`coef3') coef4(`coef4') coef5(`coef5') coef6(`coef6')
					local `++labind'
				}
				_diparm ln_lambda, label("_cons")		/*ln_lambda baseline */
				local `++labind'

	}
	else if "`e(survmodel)'"=="w" {

		di as res _col(4) "ln_lambda" as txt _col(14) "{c |}"
		local scovs_names "`e(tvcvars)' `e(surv_varlist)'"
		foreach var of local scovs_names {																			//fixed covariates in survival model (survcov)
			forvalues i = 1/6 {
				local coef`i' = `results'[`labind',`i']
			}
			local var = abbrev("`var'",12)
			Di_param, label(`var') coef1(`coef1') coef2(`coef2') coef3(`coef3') coef4(`coef4') coef5(`coef5') coef6(`coef6')
			local `++labind'
		}
		_diparm ln_lambda, label("_cons")		/*ln_lambda baseline */
		local `++labind'
		local p = 13 - length("ln_gamma")
		di as res _col(`p') "ln_gamma" as txt _col(14) "{c |}"
		_diparm ln_gamma, label("_cons")
		local `++labind'

	}
	else if "`e(survmodel)'"=="g" {

		di as res _col(4) "ln_lambda" as txt _col(14) "{c |}"
		local scovs_names "`e(tvcvars)' `e(surv_varlist)'"
		foreach var of local scovs_names {																			//fixed covariates in survival model (survcov)
			forvalues i = 1/6 {
				local coef`i' = `results'[`labind',`i']
			}
			local var = abbrev("`var'",12)
			Di_param, label(`var') coef1(`coef1') coef2(`coef2') coef3(`coef3') coef4(`coef4') coef5(`coef5') coef6(`coef6')
			local `++labind'
		}
		_diparm ln_lambda, label("_cons")		/*ln_lambda baseline */
		local `++labind'
		local p = 13 - length("gamma")
		di as res _col(`p') "gamma" as txt _col(14) "{c |}"
		_diparm gamma, label("_cons")
		local `++labind'

	}
	else if "`e(survmodel)'"=="ww" {

		local scovs_names "`e(tvcvars)' `e(surv_varlist)'"
		if "`scovs_names'"!="" {
			di as res _col(11) "xb" as txt _col(14) "{c |}"
			foreach var of local scovs_names {																			//fixed covariates in survival model (survcov)
				forvalues i = 1/6 {
					local coef`i' = `results'[`labind',`i']
				}
				local var = abbrev("`var'",12)
				Di_param, label(`var') coef1(`coef1') coef2(`coef2') coef3(`coef3') coef4(`coef4') coef5(`coef5') coef6(`coef6')
				local `++labind'
			}
		}
		local p = 13 - length("logit_p_mix")
		di as res _col(`p') "logit_p_mix" as txt _col(14) "{c |}"
		_diparm logit_p_mix, label("_cons")
		local `++labind'
		local p = 13 - length("ln_lambda1")
		di as res _col(`p') "ln_lambda1" as txt _col(14) "{c |}"
		_diparm ln_lambda1, label("_cons")
		local `++labind'
		local p = 13 - length("ln_gamma1")
		di as res _col(`p') "ln_gamma1" as txt _col(14) "{c |}"
		_diparm ln_gamma1, label("_cons")
		local `++labind'
		local p = 13 - length("ln_lambda2")
		di as res _col(`p') "ln_lambda2" as txt _col(14) "{c |}"
		_diparm ln_lambda2, label("_cons")
		local `++labind'
		local p = 13 - length("ln_gamma2")
		di as res _col(`p') "ln_gamma2" as txt _col(14) "{c |}"
		_diparm ln_gamma2, label("_cons")
		local `++labind'
	}
	else if "`e(survmodel)'"=="we" {

		local scovs_names "`e(tvcvars)' `e(surv_varlist)'"
		if "`scovs_names'"!="" {
			di as res _col(11) "xb" as txt _col(14) "{c |}"
			foreach var of local scovs_names {																			//fixed covariates in survival model (survcov)
				forvalues i = 1/6 {
					local coef`i' = `results'[`labind',`i']
				}
				local var = abbrev("`var'",12)
				Di_param, label(`var') coef1(`coef1') coef2(`coef2') coef3(`coef3') coef4(`coef4') coef5(`coef5') coef6(`coef6')
				local `++labind'
			}
		}
		local p = 13 - length("logit_p_mix")
		di as res _col(`p') "logit_p_mix" as txt _col(14) "{c |}"
		_diparm logit_p_mix, label("_cons")
		local `++labind'
		local p = 13 - length("ln_lambda1")
		di as res _col(`p') "ln_lambda1" as txt _col(14) "{c |}"
		_diparm ln_lambda1, label("_cons")
		local `++labind'
		local p = 13 - length("ln_gamma1")
		di as res _col(`p') "ln_gamma1" as txt _col(14) "{c |}"
		_diparm ln_gamma1, label("_cons")
		local `++labind'
		local p = 13 - length("ln_lambda2")
		di as res _col(`p') "ln_lambda2" as txt _col(14) "{c |}"
		_diparm ln_lambda2, label("_cons")
		local `++labind'
	}
	else if "`e(survmodel)'"=="llogistic" {

		di as res _col(9) "beta" as txt _col(14) "{c |}"
		local scovs_names "`e(tvcvars)' `e(surv_varlist)'"
		foreach var of local scovs_names {																			//fixed covariates in survival model (survcov)
			forvalues i = 1/6 {
				local coef`i' = `results'[`labind',`i']
			}
			local var = abbrev("`var'",12)
			Di_param, label(`var') coef1(`coef1') coef2(`coef2') coef3(`coef3') coef4(`coef4') coef5(`coef5') coef6(`coef6')
			local `++labind'
		}
		_diparm beta, label("_cons")		/*ln_lambda baseline */
		local `++labind'
		local p = 13 - length("ln_gamma")
		di as res _col(`p') "ln_gamma" as txt _col(14) "{c |}"
		_diparm ln_gamma, label("_cons")
		local `++labind'

	}
	else if "`e(survmodel)'"=="lnormal" {

		di as res _col(11) "mu" as txt _col(14) "{c |}"
		local scovs_names "`e(tvcvars)' `e(surv_varlist)'"
		foreach var of local scovs_names {																			//fixed covariates in survival model (survcov)
			forvalues i = 1/6 {
				local coef`i' = `results'[`labind',`i']
			}
			local var = abbrev("`var'",12)
			Di_param, label(`var') coef1(`coef1') coef2(`coef2') coef3(`coef3') coef4(`coef4') coef5(`coef5') coef6(`coef6')
			local `++labind'
		}
		_diparm mu, label("_cons")		/*ln_lambda baseline */
		local `++labind'
		local p = 13 - length("ln_sigma")
		di as res _col(`p') "ln_sigma" as txt _col(14) "{c |}"
		_diparm ln_sigma, label("_cons")
		local `++labind'

	}
	else if "`e(survmodel)'"=="gamma" {

		di as res _col(11) "mu" as txt _col(14) "{c |}"
		local scovs_names "`e(tvcvars)' `e(surv_varlist)'"
		foreach var of local scovs_names {																			//fixed covariates in survival model (survcov)
			forvalues i = 1/6 {
				local coef`i' = `results'[`labind',`i']
			}
			local var = abbrev("`var'",12)
			Di_param, label(`var') coef1(`coef1') coef2(`coef2') coef3(`coef3') coef4(`coef4') coef5(`coef5') coef6(`coef6')
			local `++labind'
		}
		_diparm mu, label("_cons")		/*ln_lambda baseline */
		local `++labind'
		local p = 13 - length("ln_sigma")
		di as res _col(`p') "ln_sigma" as txt _col(14) "{c |}"
		_diparm ln_sigma, label("_cons")
		local `++labind'
		local p = 13 - length("kappa")
		di as res _col(`p') "kappa" as txt _col(14) "{c |}"
		_diparm kappa, label("_cons")
		local `++labind'

	}

	di as txt "{hline 13}{c BT}{hline 64}"

	/* Random effects table title*/
		di
		di as txt "{hline 29}{c TT}{hline 48}"
		di as txt _col(3) "Random effects Parameters" _col(30) "{c |}" _col(34) "Estimate" _col(45) "Std. Err." _col(`=61-`k'') ///
		`"[`=strsubdp("`level'")'% Conf. Interval]"'
		di as txt "{hline 29}{c +}{hline 48}"
		if "`e(n_re)'"!="1"{
			local labtextvcv `e(covtype)'
		}
		else local labtextvcv "Independent"
		di as res abbrev("`e(panel)'",12) as txt ": `labtextvcv'" _col(30) "{c |}"

	/* Std. dev./Variances of random effects */
		local retimelabelnames2 `e(rand_timevars)' _cons
		if ("`labtextvcv'"=="Independent" | "`labtextvcv'"=="Unstructured") {
			local test = 1
			forvalues i=1/`e(n_re)' {
				local lab : word `test' of `retimelabelnames2'
				Var_display, param("lns_`i'") label("`sdtxt'(`lab')") `variance'
				local `++test'
			}
		}
		else {
			local name = abbrev(trim("`retimelabelnames2'"),19)
			local n2 = length("`retimelabelnames2'")
			if `n2'>19 {
				local n1 "(1)"
			}
			Var_display, param("lns_1") label("`sdtxt'(`name')`n1'") `variance'
		}

	/* Corrs/Covariances of random effects */
		if ("`labtextvcv'"=="Unstructured" & `e(n_re)'>1) {
			local firstindex = 1
			local txtindex = 1
			while (`firstindex'<`e(n_re)') {
				local test = `firstindex' + 1
				local test2 = 1
				forvalues i=`test'/`e(n_re)' {
					local ind2 = `i'-1
					local lab1 : word `txtindex' of `retimelabelnames2'
					local lab2 : word `=`txtindex'+`test2'' of `retimelabelnames2'
					if "`variance'"=="" {
						Covar_display, param1("art_`firstindex'_`test'") label("`corrtxt'(`lab1',`lab2')") `variance'
					}
					else {
						Covar_display, param1("art_`firstindex'_`test'") param2("lns_`firstindex'") param3("lns_`test'") label("`corrtxt'(`lab1',`lab2')") `variance'
					}
					local `++test'
					local `++test2'
				}
				local `++firstindex'
				local `++txtindex'
			}
		}
		else if ("`labtextvcv'"=="Exchangeable" & `e(n_re)'>1) {
			local name = abbrev(trim("`retimelabelnames2'"),19)
			local n2 = length("`retimelabelnames2'")
			if `n2'>19 {
				local n1 "(1)"
			}
			if "`variance'"=="" {
				Covar_display, param1("art_1_1") label("`corrtxt'(`name')`n1'") `variance'
			}
			else {
				Covar_display, param1("art_1_1") param2("lns_1") param3("lns_1") label("`corrtxt'(`name')`n1'") `variance'
			}
		}

	/* Residual variance */
		di as txt "{hline 29}{c +}{hline 48}"
		Var_display, param(lns_e) label("`sdtxt'(Residual)") `variance'
		di as txt "{hline 29}{c BT}{hline 48}"

	local l = length(trim("`retimelabelnames2'"))
	if `l'>19 & ("`labtextvcv'"=="Exchangeable" | "`labtextvcv'"=="Identity") {
		di in green "(1) `retimelabelnames2'"
	}

	/* Summary text */

	if "`e(survmodel)'"=="w" {
		local smodeltxt "Weibull proportional hazards model"
	}
	else if "`e(survmodel)'"=="e" {
		local smodeltxt "Exponential proportional hazards model"
	}
	else if "`e(survmodel)'"=="g" {
		local smodeltxt "Gompertz proportional hazards model"
	}
	else if "`e(survmodel)'"=="rcs" {
		local smodeltxt "Restricted cubic spline hazard model"
	}
	else if "`e(survmodel)'"=="ww" {
		local smodeltxt "Mixture Weibull-Weibull hazard model"
	}
	else if "`e(survmodel)'"=="we" {
		local smodeltxt "Mixture Weibull-exponential hazard model"
	}
	else if "`e(survmodel)'"=="llogistic" {
		local smodeltxt "Log-logistic AFT model"
	}
	else if "`e(survmodel)'"=="lnormal" {
		local smodeltxt "Log normal AFT model"
	}
	else if "`e(survmodel)'"=="gamma" {
		local smodeltxt "Generalised gamma AFT model"
	}
	else {
		local smodeltxt "Flexible parametric model"
	}

	di ""
	di in green " Longitudinal submodel: Linear mixed effects model"
	di in green "     Survival submodel: `smodeltxt'"
	di in green "    Integration method: `e(intmethod)' using `e(gh)' nodes"
	if "`e(survmodel)'"!="fpm" & "`e(survmodel)'"!="llogistic" & "`e(survmodel)'"!="lnormal" & "`e(survmodel)'"!="gamma" {
		if "`e(gk)'"!="" di in green "     Cumulative hazard: Gauss-Kronrod quadrature using `e(gk)' nodes"
		if "`e(gl)'"!="" di in green "     Cumulative hazard: Gauss-Legendre quadrature using `e(gl)' nodes"
	}

end

program Var_display
	syntax, PARAM(string) LABEL(string) [VARiance]
	if "`variance'"=="" {
		_diparm `param', exp notab
	}
	else {
		_diparm `param', f(exp(2*@)) d(2*exp(2*@)) notab
	}
	Di_re_param, label("`label'")
end

program Covar_display
	syntax, param1(string) [PARAM2(string) PARAM3(string) LABEL(string) VARiance]
	if "`variance'"=="" {
		_diparm `param1', tanh notab
	}
	else {
		_diparm `param1' `param2' `param3', f(tanh(@1)*exp(@2)*exp(@3)) d((1-(tanh(@1)^2))*exp(@2+@3) tanh(@1)*exp(@2+@3) tanh(@1)*exp(@2+@3)) notab
	}
	Di_re_param, label("`label'")
end

program Di_re_param
	syntax, LABEL(string)
	local p = 29 - length("`label'")
	di as txt _col(`p') "`label'" _col(30) "{c |}" ///
			as res _col(33) %9.0g r(est) ///
			as res _col(44) %9.0g r(se)  ///
			as res _col(58) %9.0g cond(missing(r(se)),.,r(lb))  ///
			as res _col(70) %9.0g cond(missing(r(se)),.,r(ub))
end

program Di_param
	syntax, LABEL(string) COEF1(string) COEF2(string) COEF3(string) COEF4(string) COEF5(string) COEF6(string)
	local p = 13 - length("`label'")
	di as txt _col(`p') "`label'" _col(14) "{c |}" 	///
				as res _col(17) %9.0g `coef1' 		///
				as res _col(28) %9.0g `coef2'		///
				as res _col(38) %8.2f `coef3'		///
				as res _col(49) %4.3f `coef4'		///
				as res _col(58) %9.0g `coef5'		///
				as res _col(70) %9.0g `coef6'
end