*! version 2.1	19November2020
*! Stephen Nash
*! Katy Morgan	katy.morgan@lshtm.ac.uk
*! Amy Mulick	amy.mulick@lshtm.ac.uk

/*
DESCRIPTION
Sample size and power calculator for slope outcomes using a linear mixed model on
data in memory for estimation of key parameters.

slopepower performs a sample size or power calculation for a proposed randomised
clinical trial, based partly upon data in Stata’s memory and partly on user
input. A linear mixed model is run (using mixed) on the data in memory to
estimate a plausible treatment effect and its variance; the remaining parameters
are specified by the user. The data should come from an observational study or
a similar clinical trial and contain repeated measurements of the outcome in
long format.

The data in memory will not be altered by this program.
*/
cap prog drop slopepower
program define slopepower , rclass
	version 13.0 // Due to use of the -mixed- command, which was introduced in v13
	syntax varname(max=1) [if], SUBJect(varname) TIMe(varname) SCHEDule(numlist ascending integer >=1) ///
		[obs NOCONTrols rct  CASEcon(varname) TReat(varname) SCAle(real 1) ITERate(integer 16000) Alpha(real 0.05) ///
		 POWer(string) n(string) EFFectiveness(string) DROPouts(numlist >=0) noCONTVar USETrt]

		preserve // We're going to change the data - drop rows and create new vars
			capture keep `if' // Get rid of un-needed obs now

			*************************************
			**
			** SYNTAX SECTION - CHECK THE PARAMETERS and CREATE SOME LOCALS
			**
			*************************************
			quietly {
				marksample touse
				local outcome `varlist' // Just to make the code easier to understand

				* Check that we have at least _some_ data
				if _N <1 {
					dis as error "No observations"
					exit 2000
				}
				* CHECK THE OPTIONS ARE VALID
				*
				* MODEL: Check the combinations are valid and assign 1, 2, or 3 to the local model
				if "`obs'"!="" & "`rct'"!="" {
					dis as error "You cannot specify both obs and rct"
					exit 198
				}
				if "`obs'"=="" & "`rct'"=="" {
					dis as error "No model specified: please specify obs or rct"
					exit 198
				}
				if "`obs'"!="" {
					if "`nocontrols'" == "" local model 1
						else local model 2
				}
				else if "`rct'"!="" & "`nocontrols'"=="" local model 3
					else {
						dis as error "You cannot specify nocontrols and rct "
						exit 198
					}
				*
				* ALPHA: Should be between 0 and 1
				if `alpha'<=0 | `alpha'>=1 {
					dis as error "Alpha must be a number greater than 0 and less than 1"
					exit 198
				}
				*POWER AND N
					* Must specify one of power or N: 4 possible cases...
					* 1. 1. Both power an n specified - error
						if "`power'"!="" & "`n'"!="" {
							display as error "Only one of power and n may be specified, not both"
							exit 184
							}
					* 2. Power is specified, n is missing - okay - we'll calculate SAMPLE SIZE (N)
						if "`power'"!="" & "`n'"=="" {
							local given_power=real("`power'")
							if missing(`given_power') { // ...but power isn't a number
								dis as error "Power must be a number greater than 0 and less than 1"
								exit 198
							}
							local power_or_n power
						}
					* 3. Power is absent, n is specified - okay - we'll calculate POWER
						if "`power'"=="" & "`n'"!="" { //
							local given_n=floor(real("`n'"))
							if missing(`given_n') { // ...but n isn't a number
								dis as error "n must be a numerical value"
								exit 198
							}
							if `given_n' != `n' { // The floor of n must be the same as n... ie n cannot be fractional
								dis as error "n must be a whole number greater than or equal to 2"
								exit 198
							}
							if `given_n' < 2 { // N must be at least 2
								dis as error "n must be at least 2"
								exit 198
							}
							local n = ceil(`given_n')
							local power_or_n n
						}
					* 4. Both power and n absent: okay, use default value for power - we'll calculate SAMPLE SIZE (N)
						if "`power'"=="" & "`n'"=="" {
							local given_power = 0.8 // Default power is 80%
							local power_or_n power
						}
				* Check values
					if "`power_or_n'"=="power" { // Power is specified - we already know it's a number.
						if `given_power'>=1 {
							dis as error "Power must be a value strictly less than 1"
							exit 198
						}
						if `given_power'<=0 {
							dis as error "Power must be a value greater than 0"
							exit 198
						}
					}
					if "`power_or_n'" == "n" { // N is specified - we already know it's a number
						* Make sure it's even, or round down
						local actual_n = 2 * floor(`given_n' / 2)
						if `given_n'<2 {
							dis as error "n must be a number greater or equal to 2"
							exit 198
						}
					}
				*
				* CASECON
					if "`casecon'"!="" & `model'!=1 {
						dis as error "WARNING: casecon can only be specified with observational data which has both cases and controls. It will be ignored."
					}
					* If model is 1, then must have a casecontrol variable
						if (`model'==1) & ("`casecon'"=="") {
								display as error _n "You must provide a case-control variable for this model choice, or specify the nocont option"
								exit 198
						}
						if (`model'==1) {
							* First, check that casecon has exactly two levels
								tab `casecon'
								if r(r)!=2 {
									dis as error "Case-control variable (casecon) must have exactly two levels"
									exit 198
								}
							* Check that it's a numeric variable
								capture confirm numeric variable `casecon'
								if _rc!=0 {
									dis as error "Case-control variable (casecon) must be numeric"
									exit 198
							}
							* And that it's coded 0/1
							sum `casecon'
							if `r(min)' !=0 | `r(max)'!=1 {
								dis as error "Case-control variable (casecon) variable must be coded 0/1"
								exit 198
							}
						}
				*
				* EFFECTIVENESS AND USETRT
				* Check which combination of effectiveness and usetrt have been specified
				* First, check usetrt is only specified with Model 3
				if "`usetrt'"!="" & `model'!=3 {
					dis as error "WARNING: The usetrt option can only be specified with RCT data. It will be ignored here."
					local usetrt
				}
					* User cannot specify both usetrt and effectiveness
					* If usetrt is not specified effectiveness is as the user inputs,
					* Unless not specified, in which case default is used (25%)
						if "`usetrt'"!="" & "`effectiveness'"!="" { // Both specified
							dis as error "Only one of usetrt and effectiveness may be specified, not both"
							exit 184
						}
						if "`usetrt'"=="" & "`effectiveness'"=="" local effectiveness 0.25 // Both missing; default effectiveness is 0.25
						* Now check effectivenes is a number >0 and <= 1
							if "`effectiveness'"!="" { // Effectiveness is specified
								capture confirm number `effectiveness'
								if _rc!=0 {
									dis as error "Effectiveness must be a number greater than 0 and less than or equal to 1"
									exit 198
								}
								* So eff is specified and it's a number
								if `effectiveness' > 1 {
									dis as error "Effectiveness must be less than or equal 1"
									exit 198
								}
								if `effectiveness' <=0 {
									dis as error "Effectiveness must be strictly greater than 0"
									exit 198
								}
							} // If statement "eff is specified"
				*
				* TREAT
				* If model is 3 (RCT), then must have a treatment variable
					if (`model'!=3) & ("`treat'"!="") {
						dis as error "Treatment can only be specified with RCT data`. Treatment variable will be ignored."
						}
					if (`model'==3) & ("`treat'"=="") {
							display as error _n "You must provide a treatment variable for this model choice"
							exit 198
						}
					* Check that we have obs in both arms, and that treatment has just two levels
					if (`model'==3) & ("`treat'"!="") {
						tab `treat'
						if r(r)!=2 {
							dis as error "Treatment variable must have exactly two levels"
							exit 198
						}
						* Check that it's a numeric variable
						capture confirm numeric variable `treat'
						if _rc!=0 {
							dis as error "Treatment must be a numeric variable"
							exit 198
						}
						* And that it's coded 0/1
						sum `treat'
						if `r(min)' !=0 | `r(max)'!=1 {
							dis as error "Treatment must be coded 0/1"
							exit 198
						}
					}
				*
				* SCALE
					if `scale' <= 0 {
						dis as error "Scale must be a positive number"
						exit 198
					}
				*
				* NOCONTVAR
				* is only compatible with Model 1
					if "`contvar'"!="" & `model'!=1 {
						dis as error "WARNING: nocontvar can only be set for observational data with controls. This option will be ignored."
					}
				*
				* SCHEDULE
				* Length of schedule list:
					local sched_length = 0
					foreach i of numlist `schedule' {
						local sched_length = `sched_length ' + 1
					}
				* Decant the schedule numlist into locals
					local j = 1 // counter - position number
					foreach i of numlist `schedule' {
						local sched`j++' = `i'
					}
				* Get a nice schedule string with commas for output
					foreach i of numlist `schedule' {
						local sched_string `"`sched_string'`i', "' // Adds commas to the numlist, for use in output
					}
					* Remove the last comma from the schedule string
						local ss = strlen("`sched_string'") - 2
						local sched_string = substr("`sched_string'", 1, `ss')
				*
				* DROPOUTS
				* Is there a dropout list specified?
					local drop_yes = 0
					if "`dropouts'"!="" local drop_yes = 1
				* Decant dropout numlist into locals and calculate people who attend all visits
					local dfrac_complete = 1 // The proportion attending all visits - one unless dropouts specified
					if `drop_yes'==1 {
						local j = 1 // counter - position number
						foreach fr of numlist `dropouts' {
							local dfrac`sched`j'' = `fr'
							local j = `j' + 1
							local dfrac_complete = `dfrac_complete' - `fr'
						}
					* Check the drop matrix adds up to less than 100%
						if `dfrac_complete' < 0 {
							display as error _n "Dropouts cannot exceed 100%"
							exit 198
						}
					* Drop matrix must be same length as Schedule matrix
						* Length of dropout list
						local drop_length = 0
						foreach i of numlist `dropouts' {
							local drop_length = `drop_length ' + 1
						}
						* Is this equal to schedule matrix?
						if `sched_length' != `drop_length' {
							dis as error _n "Dropout list must correspond with visit schedule"
							exit 198
						}
						* Get a nice schedule string with commas for output
							local j = 0 // counter - position in schedule list
							local sched_string ""
							foreach i of numlist `schedule' {
								if `dfrac`i'' != 0 local sched_string `"`sched_string'`i' (0`dfrac`i''), "' // Adds commas to the numlist, for use in output
									else local sched_string `"`sched_string'`i' (0), "' // Adds commas to the numlist, for use in output
							}
							* Remove the last comma from the schedule string
								local ss = strlen("`sched_string'") - 2
								local sched_string = substr("`sched_string'", 1, `ss')
					}
			} // End quietly

			*************************************
			**
			** DATA SECTION
			**
			*************************************
			quietly {
				tempname nmeas first_time
				* Drop if outside the sample to use - shouldn't be necessary
					drop if !`touse'
				* Rescale the data
					replace `time' = `time' / `scale'
				* Drop if no outcome variable - the model will ignore anyway but safest this way
					drop if missing(`outcome')

				* Make the time var start at 0
					gen `first_time' = .
					bysort `subject' (`time') : replace `first_time' = `time'[1]
					bysort `subject' : replace `time' = `time' - `first_time'
					sum `first_time'
					if (r(mean)!=0) | (r(sd)!=0) dis as error "WARNING: time variable did not start at zero for all participants. Times have been adjusted such that the first visit for each person is treated as time zero."

				* Make dummy variables for cases and controls
				if (`model'==1) {
					tempname case control timecase timecontrol
					drop if missing(`casecon')
					gen `case' = (`casecon'!=0)
					gen `control' = (`casecon'==0)
					gen `timecase' = `time'*`case'
					gen `timecontrol' = `time'*`control'
				}

				* If model 3 (RCT), make a placebo var from the treat var
					if (`model'==3) {
						tempname placebo
						drop if missing(`treat')
						gen `placebo' = (`treat'==0)
					}
			} // End quietly

			*************************************
			**
			** MODEL SECTION
			**
			*************************************
			quietly {
				tempname mbeta slope0 slope2 var_slope var_int cov_slopeint var_res var_visit n_in_model people_in_model observed_difference ngroups tte

				*************************
				** MODEL 1 - Cases and controls
				*************************
				if `model'==1 {
					if "`contvar'"=="" { // Controls are allowed a variance parameter
						capture mixed `outcome' `case'##c.`time' , `noconsoption' ///
							|| `subject': `timecase' `case', cov(uns) nocons ///
							|| `subject': `timecontrol' `control', cov(uns) nocons ///
							res(ind, by(`case')) reml iterate(`iterate')
						if _rc!=0 {
							dis as error "Model failure. Try using the nocontvar option, or see error code (below)."
							exit _rc
						}
						if e(converged)==0 {
							dis as error "Model did not converge"
							exit 430
						}
						matrix `mbeta'=e(b) // A 1x14 matrix
						scalar `n_in_model' = e(N)
						matrix `ngroups' = e(N_g)
						scalar `people_in_model' = `ngroups'[1,1]
						scalar `slope0'=`mbeta'[1,3] // fixed time - ie time slope for controls
						scalar `slope2'=`mbeta'[1,3] + `mbeta'[1,5] // time + case#time interaction - ie time slope for cases
						scalar `observed_difference' = `slope2' - `slope0'
						scalar `tte' = -1 * `observed_difference' * `effectiveness'
						scalar `var_slope'=(exp(`mbeta'[1,7]))^2 // Variance of time for  cases
						scalar `var_int'=(exp(`mbeta'[1,8]))^2 // Variance of casepos - var of intercept for CASES
						scalar `cov_slopeint'=tanh(`mbeta'[1,9])*exp(`mbeta'[1,7])*exp(`mbeta'[1,8]) // Covariance of time and casepos = b[1,10] + exp2(b8) + exp2(b9)
						scalar `var_res'=(exp(`mbeta'[1,13]+`mbeta'[1,14]))^2 // Residual variance for cases
					} // end of nested if (for control variance)
					else { // Drop the variance parameter for controls
						capture mixed `outcome' `case'##c.`time' ///
							|| `subject': `timecase' `case', cov(uns) nocons ///
							|| `subject': `control', cov(id) nocons ///
							res(ind, by(`case')) reml iterate(`iterate') coeflegend
						if _rc!=0 {
							dis as error "Model failure. See error code (below)."
							exit _rc
						}
						if e(converged)==0 {
							dis as error "Model did not converge"
							exit 430
						}
						matrix `mbeta'=e(b) // A 1x12 matrix
						scalar `n_in_model' = e(N)
						matrix `ngroups' = e(N_g)
						scalar `people_in_model' = `ngroups'[1,1]
						scalar `slope0'=`mbeta'[1,3] // fixed time - ie time slope for controls
						scalar `slope2'=`mbeta'[1,3] + `mbeta'[1,5] // time + case#time interaction - ie time slope for cases
						scalar `observed_difference' = `slope2' - `slope0'
						scalar `tte' = -1 * `observed_difference' * `effectiveness'
						scalar `var_slope'=(exp(`mbeta'[1,7]))^2 // Variance of time for cases
						scalar `var_int'=(exp(`mbeta'[1,8]))^2 // Variance of casepos - var of intercept for CASES
						scalar `cov_slopeint'=tanh(`mbeta'[1,9])*exp(`mbeta'[1,7])*exp(`mbeta'[1,8]) // Covariance of time and casepos = b[1,10] + exp2(b8) + exp2(b9)
						scalar `var_res'=(exp(`mbeta'[1,11]+`mbeta'[1,12]))^2 // Residual variance for cases
					} // end else (var param for controls)
				} // end Model 1

				*************************
				** 		MODEL 2 - Obs, everyone has the condition
				*************************
				else if `model'==2 { // No controls - assume we can get slope (a fraction of the way) to zero
					capture mixed `outcome' c.`time' || `subject': `time', cov(uns) reml iterate(`iterate')
						if _rc!=0 {
							dis as error "Model failure. See error code (below)."
							exit _rc
						}
						if e(converged)==0 {
							dis as error "Model did not converge"
							exit 430
						}
					matrix `mbeta'=e(b)
					scalar `n_in_model' = e(N)
					matrix `ngroups' = e(N_g)
					scalar `people_in_model' = `ngroups'[1,1]
					scalar `slope0' = 0 // For consistency with other models
					scalar `slope2'=`mbeta'[1,1]
					scalar `observed_difference' = `slope2' - `slope0'
					scalar `tte' = -1 * `observed_difference' * `effectiveness'
					scalar `var_slope'=(exp(`mbeta'[1,3]))^2 // var(time) in subject
					scalar `var_int'=(exp(`mbeta'[1,4]))^2 // var(cons) in subject
					scalar `cov_slopeint'=tanh(`mbeta'[1,5])*exp(`mbeta'[1,3])*exp(`mbeta'[1,4])
					scalar `var_res'=(exp(`mbeta'[1,6]))^2
					} // end Model 2

				*************************
				** 		MODEL 3 - RCT
				*************************
				else if `model'==3 {
					capture mixed `outcome' `time' `placebo'#c.`time' ///
						|| `subject': `time', cov(uns) reml iterate(`iterate')
						if _rc!=0 {
							dis as error "Model failure. See error code (below)."
							exit _rc
						}
						if e(converged)==0 {
							dis as error "Model did not converge"
							exit 430
						}
						* Note we're using a "placebo" variable, hence
						* slope0 is slope of the TREATED (placebo==0)
						* slope2 is slope of the UNTREATED, placebo group (placebo=1)
					matrix `mbeta'=e(b) // A 1x8 matrix
					scalar `n_in_model' = e(N)
					matrix `ngroups' = e(N_g)
					scalar `people_in_model' = `ngroups'[1,1]
					scalar `slope2'=`mbeta'[1,1] + `mbeta'[1,3] // slope over time - ie time slope for placebo group
					scalar `observed_difference' = `slope2' - `mbeta'[1,1] // This is for reporting, so we need the actual value
					scalar `slope0' = 0 // Default option is to ignore the slope for treated
					if "`usetrt'"!="" { // usetrt is specified; use the treatment effect from the RCT
						scalar `slope0'=`mbeta'[1,1] // ie time slope for experimental, treated group (placebo==0)
						local effectiveness = 1
						scalar `tte' =  -1 * `observed_difference'
					 }
					 else scalar `tte' = -1 * `slope2' * `effectiveness'
					scalar `var_slope'=(exp(`mbeta'[1,5]))^2 // Variance of time
					scalar `var_int'=(exp(`mbeta'[1,6]))^2 // Variance of intercept
					scalar `cov_slopeint'=tanh(`mbeta'[1,7])*exp(`mbeta'[1,5])*exp(`mbeta'[1,6]) // Covariance of slopes and intercepts
					scalar `var_res'=(exp(`mbeta'[1,8]))^2 // Residual variance
				} // end Model 3
			} // end of quitely

			*************************************
			**
			** MATRIX SECTION
			**
			*************************************
			quietly {
				tempname V VSTAR X DSTAR XSTAR F1STAR FSTAR visit_matrix COV
				foreach i of numlist `schedule' {
					tempname DROP`i' DROP`i'STAR DROP
				}
				* First, need to make a visit schedule matrix
				* from the user inputted visit schedule, which is just a numlist...

				* What's the biggest number (=number of timepoints), and how many are in the list? (vvv)
					local vvv = 0 // This will count the elements of the numlist
					foreach i of numlist `schedule' { // We want: (i) timepoint of last visit (ii) number of visits and (iii) a nice string of visit times
						local tpoints = `i' + 1
						local vvv = `vvv' + 1
					}
				* Add one to the number in the list to get the number of rows we need visit_matrix to have
					local vplus1 = `vvv' + 1
				* Make a `vplus1' x `tpoints' matrix, all zeros
					matrix `visit_matrix' = J(`vplus1', `tpoints', 0)
				* Make the first row 1, 0, 0...
					matrix `visit_matrix'[1,1] = 1
				* Fill in the (i+1,j+1) element (=1) where j is the value of the ith number
					local i = 2 // We need the +1's because our matric starts with timepoint 0
					foreach j of numlist `schedule' {
						local jjj = `j' + 1
						matrix `visit_matrix'[`i', `jjj'] = 1
						local i = `i' + 1
					}

				* These scalars make a matrix
					local tpminus1 = `tpoints' - 1
				* Do diagonal first
					forvalues i=1/`tpoints' {
						local v_`i'_`i' = (`var_int')+(`var_res')+(((`i'-1)^2)*(`var_slope'))+ (2*(`i'-1)*`cov_slopeint')
					}
				* Then the bottom left corner
					forvalues j=1/`tpminus1' {
						local jplus1 = `j' + 1
						forvalues i=`jplus1' / `tpoints' {
							local v_`i'_`j' = (`var_int') + ( (`j'-1)*(`i'-1)*`var_slope') + ( (`j'-1+`i'-1)*`cov_slopeint' )
						} // i
					} // j
				* Now fill in the top right corner by symmetry
					forvalues i=1 / `tpoints' {
						local iplus1 = `i' + 1
						forvalues j=`iplus1' / `tpoints' {
							local v_`i'_`j' = `v_`j'_`i''
						}
					}
				* This matrix V is constructed in a loop using the above values
					matrix `V' = J(`tpoints', `tpoints', 0) // create a blank matrix of the right size
					forvalues i=1/`tpoints' {
						forvalues j=1 / `tpoints' {
							matrix `V'[`i', `j'] = `v_`i'_`j''
						} // i
					} // j

				* Matrix VSTAR
					* Define bottom-left and top-right matrices (COV)
						matrix `COV' = 0*I(`tpoints') // Zeroes everywhere in a square matrix
					* Vstar
					matrix `VSTAR'=(`V',`COV' \ `COV',`V')

				* Matrix X
					matrix `X' = J(`tpoints', 2, 1)
					forvalues i=1/`tpoints' {
						matrix `X'[`i', 2] = `i' - 1
					}

				* Make dropout matrices: one for each visit (dropping out BEFORE that visit)
				if `drop_yes'==1 {
					* First, make an indicator matrix
					* Start making it the right size, all zeros, then add 1's...
					local j = 1 // row counter = position in schedule numlist
					matrix `DROP`sched1'' = J(1,`tpoints', 0)
					matrix `DROP`sched1''[1,1] = 1
					forvalues i=2/`vvv' {
						local lag = `i' - 1
						matrix `DROP`sched`i''' = `DROP`sched`lag''' \ J(1, `tpoints', 0) // Add one row at a time
						* Get correct column pos'n for the 1
							local ccc = `sched`lag'' + 1
						matrix `DROP`sched`i'''[`i',`ccc'] = 1
					}
					* Matrix DROPSTAR
					foreach nnn of numlist `schedule' {
						matrix `DROP`nnn'STAR'=(`DROP`nnn'', 0*`DROP`nnn'' \ 0*`DROP`nnn'',`DROP`nnn'')
					}
				} // End if drop_yes

				* Make matrix DSTAR
					matrix `DSTAR'=(`visit_matrix',0*`visit_matrix' \ 0*`visit_matrix',`visit_matrix')

				* Make matrix XSTAR
					matrix `XSTAR' = J(2*`tpoints', 3, 1) // So the first colum is done - all 1s
					forvalues j=1/`tpoints' { // Top of the second column
						matrix `XSTAR'[`j', 2] = `j' - 1
					}
					local aa = `tpoints' + 1
					local bb = `tpoints' * 2
					forvalues j=`aa'/`bb' { // Bottom half of second column
						matrix `XSTAR'[`j', 2] = `j' - 1 - `tpoints'
					}
					forvalues j=1/`tpoints' { // Top of the third column
						matrix `XSTAR'[`j', 3] = 0
					}
					forvalues j=`aa'/`bb' { // Bottom half of third column
						matrix `XSTAR'[`j', 3] = `j' - `tpoints' - 1
					}

					* Matrices FDROPiSTAR
					if `drop_yes'==1 {
						foreach nnn of numlist `schedule' {
							if `nnn'==`sched1' continue
							tempname FDROP`nnn'STAR
							matrix `FDROP`nnn'STAR' = inv((`DROP`nnn'STAR'*`XSTAR')' * ///
											  inv(`DROP`nnn'STAR'*`VSTAR'*`DROP`nnn'STAR'') * ///
											  `DROP`nnn'STAR'*`XSTAR')
						}
					} //end if drop_yes

				* Matrix FSTAR
				  matrix `FSTAR' = inv((`DSTAR'*`XSTAR')'* /// That last ' is for "matrix transpose"
									  inv(`DSTAR'*`VSTAR'*`DSTAR'')* ///
									  `DSTAR'*`XSTAR')
			} // End of quietly
*


			*************************************
			**
			** CALCULATE THE POWER / SAMPLE SIZE
			**
			*************************************
			quietly {
				tempname es_slope var1 sampfactor alpha_tail sampsize sampsize_arm power z_power
					* Slope
						scalar `es_slope'=`slope2'-`slope0'
					* Main variance and effect size component
						scalar `var1' = `FSTAR'[3,3] // This is var_tte
						local part_effsize =  `es_slope' / sqrt(`var1') // use this to get an N (below)

					* Dropout variances and effect size components
					if `drop_yes'==1 {
						foreach nnn of numlist `schedule' {
							if `nnn' == `sched1' continue
							tempname var_drop_`nnn'
							scalar `var_drop_`nnn'' = `FDROP`nnn'STAR'[3,3]
							local effsize_drop`nnn' = `es_slope' / sqrt(`var_drop_`nnn'')
						} // End for
					} // end if drop_yes

					* Combine all effect size components into one overall effect size
						local eff_bit = `dfrac_complete' * (`part_effsize')^2
						if `drop_yes'==1 {
							foreach nnn of numlist `schedule' {
								if `nnn' == `sched1' continue
								local eff_bit = `eff_bit' + (`dfrac`nnn'' * (`effsize_drop`nnn'')^2)
								}
							} // end if drop_yes

					* Calculate the EFFECT SIZE
						local effsize=sign(`es_slope') * sqrt(`eff_bit')

					* CALCULATE THE MAIN RESULT: Either sample size or power
						if "`power_or_n'"=="power" { // Calc SAMPLE SIZE
							scalar `alpha_tail' = 1 - (0.5 * `alpha')
							scalar `sampfactor' = ( invnormal(`alpha_tail') + invnormal(`given_power'))^2
							scalar `sampsize_arm' = ceil( ( `sampfactor' / (`effsize')^2) / `effectiveness'^2)
							scalar `sampsize' = 2 * `sampsize_arm'
							scalar `power' = `given_power' // Transferring the local into the scalar...
						}
						else { // Calc POWER
							// Calc the power here
							scalar `sampsize' = `actual_n' // As specified by the user; transferring to output scalar
							scalar `sampsize_arm' = `actual_n' / 2
							scalar `z_power' = ( abs(`effsize')*`effectiveness'*sqrt(`actual_n'/2) ) - invnormal(1-`alpha'/2)
							scalar `power' = normal(`z_power')
						}

				if "`usetrt'"!="" local effectiveness = .

			} // close quietly

			*************************************
			**
			** OUTPUT SECTION
			**
			** Same for all models:
			**		- matrix
			**
			** Separate for each model
			**		- other return values
			**		- on-screen text
			**
			*************************************
				quietly {
					tempname RESULTS
					mat `RESULTS' = J(1, 10 ,.)
					if `model'==1  mat colnames `RESULTS' = alpha power N N1 N2 effectiveness tte var_tte slope_cases slope_controls  // diffnames for diff models
					if `model'==2  mat colnames `RESULTS' = alpha power N N1 N2 effectiveness tte var_tte slope_cases slope_controls
					if `model'==3  mat colnames `RESULTS' = alpha power N N1 N2 effectiveness tte var_tte slope_untreated slope_treated
					mat `RESULTS'[1,1] = `alpha'
					mat `RESULTS'[1,2] = `power'
					mat `RESULTS'[1,3] = `sampsize'
					mat `RESULTS'[1,4] = `sampsize_arm'
					mat `RESULTS'[1,5] = `sampsize_arm'
					mat `RESULTS'[1,6] = `effectiveness'
					mat `RESULTS'[1,7] = `tte'
					mat `RESULTS'[1,8] = `var1'
					if `drop_yes'==1 {
						mat `RESULTS'[1,8] = `sampsize_arm' * (`tte')^2 / (invnormal(1-`alpha'/2)+invnormal(`power'))^2
					}
					mat `RESULTS'[1,9] = `slope2'
					mat `RESULTS'[1,10] = `slope0'
					if `model'==2 mat `RESULTS'[1,10] = .
					if `model'==3 & "`usetrt'"=="" mat `RESULTS'[1,10] = .
					return matrix table = `RESULTS'
				}

				*************************
				** MODEL 1 - Cases and controls
				*************************
				if `model'==1 {

					** ** ** ** ** ** ** **
					**
					** return values
							return scalar slope_controls = `slope0'
							return scalar slope_cases = `slope2'
							if `drop_yes'==1 {
								return scalar var_tte = `sampsize_arm' * (`tte')^2 / (invnormal(1-`alpha'/2)+invnormal(`power'))^2 // if there is dropout get tte variance by inverting sample size formula
							}
							else {
								return scalar var_tte = `var1'
							}
							return scalar tte = `tte'
							return scalar effectiveness = `effectiveness'
							return scalar sampsize = `sampsize'
							return scalar fupvisits = `vvv'
							return scalar power = `power'
							return scalar alpha = `alpha'
							return scalar obs_in_model = `n_in_model'
							return scalar subjects_in_model = `people_in_model'

					** ** ** ** ** ** ** **
					**
					** on-screen text
						display as text _n "Data characteristics:"
						display as text "        number of observations in model = " as result `n_in_model'
						display as text "        number of participants in model = " as result `people_in_model'
						display as text "          observed difference in slopes = " as result %5.3f `observed_difference'
						display as text "                         slope of cases = " as result %5.3f `slope2'
						display as text "              slope of healthy controls = " as result %5.3f `slope0'
						display as text _n "Parameters for planned study:"

						if "`power_or_n'"=="power" { // Power is given, so we're calculating SAMPLE SIZE
							display as text "                                  alpha = " as result %5.3f round(`alpha', 0.001)
							display as text "                                  power = " as result %5.3f round(`power', 0.001)
							display as text "                          effectiveness = " as result %5.3f round(`effectiveness', 0.001)
							display as text "  target treatment difference in slopes = " as result %5.3f round(`tte', 0.001)
							display as text "             number of follow-up visits = " as result `vvv'
							display as text "                schedule (and dropouts) : " as result "`sched_string'"
							display as text "                                  scale = " as result `scale'
							display as text _n "  Estimated sample size:"
							display as text "                                      N = " as result `sampsize'
							display as text "                              N per arm = " as result `sampsize_arm'
						}
						else { // we're calculating POWER
							display as text "                                  alpha = " as result %5.3f round(`alpha', 0.001)
							display as text "                            specified N = " as result `given_n'
							display as text "                               actual N = " as result `actual_n'
							display as text "                              N per arm = " as result `actual_n' / 2
							display as text "                          effectiveness = " as result %5.3f round(`effectiveness', 0.001)
							display as text "  target treatment difference in slopes = " as result %5.3f round(`tte', 0.001)
							display as text "             number of follow-up visits = " as result `vvv'
							display as text "                schedule (and dropouts) = " as result "`sched_string'"
							display as text "                                  scale = " as result `scale'
							display as text "Estimated power:"
							display as text "                                  power = " as result %5.3f round(`power', 0.001)
						}
				} // end model 1

				*************************
				** MODEL 2 - Obs, everyone has the condition
				*************************
				if `model'==2 {

					** ** ** ** ** ** ** **
					**
					** return values
						return scalar slope_controls = .
						return scalar slope_cases = `slope2'
						if `drop_yes'==1 {
							return scalar var_tte = `sampsize_arm' * (`tte')^2 / (invnormal(1-`alpha'/2)+invnormal(`power'))^2 // if there is dropout get tte variance by inverting sample size formula
						}
						else {
							return scalar var_tte = `var1'
						}
						return scalar tte = `tte'
						return scalar effectiveness = `effectiveness'
						return scalar sampsize = `sampsize'
						return scalar fupvisits = `vvv'
						return scalar power = `power'
						return scalar alpha = `alpha'
						return scalar obs_in_model = `n_in_model'
						return scalar subjects_in_model = `people_in_model'


					** ** ** ** ** ** ** **
					**
					** on-screen text
						display as text _n "Data characteristics:"
						display as text "        Number of observations in model = " as result `n_in_model'
						display as text "                  Participants in model = " as result `people_in_model'
						display as text "                         Slope of cases = " as result %5.3f `slope2'
						display as text _n "Parameters for planned study:"

						if "`power_or_n'"=="power" { // Power is given, so we're calculating SAMPLE SIZE
							display as text "                                  alpha = " as result %5.3f round(`alpha', 0.001)
							display as text "                                  power = " as result %5.3f round(`power', 0.001)
							display as text "                          effectiveness = " as result %5.3f round(`effectiveness', 0.001)
							display as text "  target treatment difference in slopes = " as result %5.3f round(`tte', 0.001)
							display as text "             number of follow-up visits = " as result `vvv'
							display as text "                schedule (and dropouts) : " as result "`sched_string'"
							display as text "                                  scale = " as result `scale'
							display as text _n "  Estimated sample size:"
							display as text "                                      N = " as result `sampsize'
							display as text "                              N per arm = " as result `sampsize_arm'
						}
						else { // we're calculating POWER
							display as text "                                  alpha = " as result %5.3f round(`alpha', 0.001)
							display as text "                            specified N = " as result `given_n'
							display as text "                               actual N = " as result `actual_n'
							display as text "                              N per arm = " as result `actual_n' / 2
							display as text "                          effectiveness = " as result %5.3f round(`effectiveness', 0.001)
							display as text "  target treatment difference in slopes = " as result %5.3f round(`tte', 0.001)
							display as text "             number of follow-up visits = " as result `vvv'
							display as text "                schedule (and dropouts) = " as result "`sched_string'"
							display as text "                                  scale = " as result `scale'
							display as text "Estimated power:"
							display as text "                                  power = " as result %5.3f round(`power', 0.0001)
						}
				} // end model 2 display

				*************************
				** MODEL 3 - RCT (need to separate usetrt and effectiveness
				*************************
				if `model'==3 {

					** ** ** ** ** ** ** **
					**
					** return values
						if "`usetrt'" != "" {
							return scalar slope_treated = `slope0'
						}
						else {
							return scalar slope_treated = .
						}
						return scalar slope_untreated = `slope2'
						if `drop_yes'==1 {
							return scalar var_tte = `sampsize_arm' * (`tte')^2 / (invnormal(1-`alpha'/2)+invnormal(`power'))^2 // if there is dropout get tte variance by inverting sample size formula
						}
						else {
							return scalar var_tte = `var1'
						}
						return scalar tte = `tte'
						return scalar effectiveness = `effectiveness'
						return scalar sampsize = `sampsize'
						return scalar fupvisits = `vvv'
						return scalar power = `power'
						return scalar alpha = `alpha'
						return scalar obs_in_model = `n_in_model'
						return scalar subjects_in_model = `people_in_model'

					** ** ** ** ** ** ** **
					**
					** on-screen text
						display as text _n "Data characteristics:"
						display as text "        number of observations in model = " as result `n_in_model'
						display as text "        number of participants in model = " as result `people_in_model'
						if "`usetrt'"!="" display as text "          observed difference in slopes = " as result %5.3f `observed_difference'
						display as text "                   slope of control arm = " as result %5.3f `slope2'
						if "`usetrt'"!="" display as text "              slope of experimental arm = " as result %5.3f `slope0'
						display as text _n "Parameters for planned study:"

						if "`power_or_n'"=="power" { // Power is given, so we're calculating SAMPLE SIZE
							display as text "                                  alpha = " as result %5.3f round(`alpha', 0.001)
							display as text "                                  power = " as result %5.3f round(`power', 0.001)
							display as text "                          effectiveness = " as result %5.3f round(`effectiveness', 0.001)
							display as text "  target treatment difference in slopes = " as result %5.3f round(`tte', 0.001)
							display as text "             number of follow-up visits = " as result `vvv'
							display as text "                schedule (and dropouts) : " as result "`sched_string'"
							display as text "                                  scale = " as result `scale'
							display as text _n "  Estimated sample size:"
							display as text "                                      N = " as result `sampsize'
							display as text "                              N per arm = " as result `sampsize_arm'
						}
						else { // we're calculating POWER
							display as text "                                  alpha = " as result %5.3f round(`alpha', 0.001)
							display as text "                            specified N = " as result `given_n'
							display as text "                               actual N = " as result `actual_n'
							display as text "                              N per arm = " as result `actual_n' / 2
							display as text "                          effectiveness = " as result %5.3f round(`effectiveness', 0.001)
							display as text "  target treatment difference in slopes = " as result %5.3f round(`tte', 0.001)
							display as text "             number of follow-up visits = " as result `vvv'
							display as text "                schedule (and dropouts) = " as result "`sched_string'"
							display as text "                                  scale = " as result `scale'
							display as text "Estimated power:"
							display as text "                                  power = " as result %5.3f round(`power', 0.001)
						}
				} // close model 3
*




		 * FINAL STEP - RESTORE THE DATA BACK TO HOW WE FOUND IT
		restore

end