*! runmlwin.ado, George Leckie and Chris Charlton, 23Apr2024 program runmlwin, eclass if c(stata_version) >= 15 local user user if _caller() >= 12 version 12.0, `user' if _caller() <= 9 version 9.0, `user' display " " // display an empty line between the model command and the model output if replay() { // replay the results if ("`e(cmd)'" ~= "runmlwin") error 301 syntax [, Level(cilevel) CFORMAT(string) PFORMAT(string) SFORMAT(string) noHEADer noGRoup noCONTrast noFETable noRETable SD CORrelations OR IRr RRr MOde MEdian Zratio *] runmlwin_display, level(`level') cformat(`cformat') pformat(`pformat') sformat(`sformat') `header' `group' `contrast' `fetable' `retable' `sd' `correlations' `or' `irr' `rrr' `mode' `median' `zratio' // display the results makecns, displaycns } else { // fit the model syntax anything [if] [in], [Level(cilevel) CFORMAT(string) PFORMAT(string) SFORMAT(string) noHEADer noGRoup noCONTrast noFETable noRETable SD CORrelations OR IRr RRr MOde MEdian Zratio *] timer clear 99 timer on 99 Estimates `0' if "`e(mcmcnofit)'" == "1" { // If the user specifies the nofit option in MCMC then runmlwin needs to exit, but without error exit } timer off 99 quietly timer list ereturn scalar time = r(t99) timer clear 99 runmlwin_display, level(`level') cformat(`cformat') pformat(`pformat') sformat(`sformat') `header' `group' `contrast' `fetable' `retable' `sd' `correlations' `or' `irr' `rrr' `mode' `median' `zratio' // display the results } end program Estimates, eclass sortpreserve if _caller() >= 12 version 12.0 if _caller() <= 9 version 9.0 * Locate and record highest level local runmlwin_cmdline `0' * Separate off options local maxlevels 1 gettoken comma tmpstr : 0, parse(",") bind while strpos(`"`tmpstr'"', "level") != 0 { local tmpstr = substr(`"`tmpstr'"', strpos(`"`tmpstr'"', "level") + 5, .) local lev = substr(`"`tmpstr'"', 1, strpos(`"`tmpstr'"', "(") - 1) * Check this really is a level option if `=real("`lev'")' != . { if `lev' > `maxlevels' { local maxlevels `lev' } } } if ("`verbose'"~="") display as text "Highest level: `maxlevels'" local levargs forvalues l = 2/`maxlevels' { local levargs LEVEL`l'(string) `levargs' } #delimit ; syntax anything(name=eqlist id="equations" equalok) [if] [in], [ `levargs' // min=2 as first var is id, second var is, e.g., cons ] LEVEL1(string) // min = 1 as in discrete response models no variables are specified at level 1. Also in multivariate response models there are no covariates with random effects at level 1. [ Weights(string) Constraints(numlist >0 integer) IGLS RIGLS TOLerance(numlist >0 integer min=1 max=1) MAXIterations(numlist >0 integer min=1 max=1) FPSandwich RPSandwich INITSPrevious INITSB(namelist min=1 max=1) INITSV(namelist min=1 max=1) INITSModel(namelist min=1 max=1) // Initial values matrix DISCRETE(string) MCMC(string) SEED(numlist integer min=1 max=1) SIMulate(namelist min=1 max=1) MLWINPATH(string) MLWINSCRIPTPATH(string) VIEWMacro SAVEMacro(string) SAVEWorksheet(string) SAVEStata(string) USEWorksheet(string) Level(cilevel) CFORMAT(string) PFORMAT(string) SFORMAT(string) OR IRr RRr SD CORrelations MOde MEdian Zratio noHEADer noGRoup noCONTrast noFETable noRETable noDrop FORCESort FORCERecast noMLWIN noPause noVERSIONCHECK BATCh noSORT PLUGIN Verbose VIEWFULLMacro SAVEFULLMacro(string) SAVEEQuation(string) MLWINSETTINGS(string) ] ; #delimit cr local doublevar 1 if c(mode) == "batch" local batch = c(mode) if "`mlwinpath'" == "" & "`mlwinscriptpath'" ~= "" & "`batch'" ~= "" local mlwinpath `mlwinscriptpath' if "`mlwinpath'" == "" & "$MLwiNScript_path" ~= "" & "`batch'" ~= "" local mlwinpath $MLwiNScript_path if "`mlwinpath'" == "" & "$MLwiN_path" ~= "" local mlwinpath $MLwiN_path // will need to allow for fact that users store MLwiN in different locations. User can put global in profile.do to allow this // slightly unfortunate that the installation folder changes with each update from 2.20 to 2.21 etc at user has to keep on changing this to run this command if "`mlwin'"~="nomlwin" & "`mlwinpath'" ~= "" { capture confirm file "`mlwinpath'" if _rc == 601 { display as error "`mlwinpath' does not exist." _n exit 198 } if "`versioncheck'" ~= "noversioncheck" { quietly capture runmlwin_verinfo `mlwinpath' if _rc == 198 { display as error "`mlwinpath' is not a valid version of MLwiN" exit 198 } local majorver `r(ver1)' local minorver : display %02.0f `r(ver2)' local versionok = 1 local versionold = 0 if (`majorver' < 2) | (`majorver' == 2 & `minorver' < 36) local versionok = 0 if (`majorver' < 3) | (`majorver' == 3 & `minorver' < 05) local versionold = 1 if `versionok' == 0 { display as error "runmlwin assumes MLwiN version 2.36 or higher. You can download the latest version of MLwiN at:" _n "https://www.bristol.ac.uk/cmm/software/mlwin/download/upgrades.html." _n "If you want to ignore this warning and attempt to continue anyway you can use the noversioncheck option" exit 198 } if `versionold' == 1 display as error "WARNING: Your version of MLwiN is out of date. You can download the latest version of MLwiN at:" _n "https://www.bristol.ac.uk/cmm/software/mlwin/download/upgrades.html" } local mlwinversion `majorver'.`minorver' capture confirm number `mlwinversion' // Check version number is valid if _rc { // if not replace with missing local mlwinversion . } if `mlwinversion' < 3 { local doublevar 0 } } * Mark the sample (Defines a 0/1 to-use variable that records which observations are to be used in subsequent code) marksample touse, novarlist // This gives the full sample which is sent to MLwiN. Not a listwise delete sample. * Discrete syntax if ("`discrete'"~="") { local 0 , `discrete' syntax , Distribution(string) [Link(namelist min=1 max=1) DEnominator(varlist numeric) Extra Offset(varname numeric) Proportion(varname) Basecategory(numlist integer min=1 max=1) MQL1 MQL2 PQL1 PQL2] local validdistributions normal binomial poisson nbinomial multinomial local checkdistribution :list distribution & validdistributions if "`checkdistribution'"=="" { display as error "Invalid distribution(). Valid distributions are: normal, binomial, poisson, nbinomial, multinomial" exit 198 } * Method of linearization if ("`mql2'"=="" & "`pql1'"=="" & "`pql2'"=="") local linearization MQL1 if ("`mql2'"~="") local linearization MQL2 if ("`pql1'"~="") local linearization PQL1 if ("`pql2'"~="") local linearization PQL2 * Check that the link function is correctly specified. if "`link'"=="" { if ("`distribution'"=="binomial") { di as error "You must specify the link() function. Valid link functions for the binomial distribution are: logit, probit and cloglog." exit 198 } if ("`distribution'"=="multinomial") { di as error "You must specify the link() function. Valid link functions for the multinomial distribution are: mlogit, ologit, oprobit, ocloglog." exit 198 } if ("`distribution'"=="poisson" | "`distribution'"=="nbinomial") local link log } if "`link'" ~= "" { local 0 , `link' syntax , [Identity Logit Probit Cloglog Mlogit OLogit OProbit OCloglog LOG] if ("`distribution'"=="binomial") { if ~inlist("`link'","logit","probit","cloglog") { display as error "Invalid link() function. Valid link functions for the binomial distribution are: logit, probit and cloglog." _n exit 198 } } if ("`distribution'"=="multinomial") { if ~inlist("`link'","mlogit","ologit","oprobit","ocloglog") { display as error "Invalid link() function. Valid link functions for the multinomial distribution are: mlogit, ologit, oprobit, ocloglog." _n exit 198 } } if ("`distribution'"=="poisson") { if ~inlist("`link'","log") { display as error "Invalid link() function. Valid link functions for the poisson distribution are: log." _n exit 198 } } if "`identity'" ~= "" local link identity if "`logit'" ~= "" local link logit if "`probit'" ~= "" local link probit if "`cloglog'" ~= "" local link cloglog if "`mlogit'" ~= "" local link mlogit if "`ologit'" ~= "" local link ologit if "`oprobit'" ~= "" local link oprobit if "`ocloglog'" ~= "" local link ocloglog if "`log'" ~= "" local link log } } else { local link identity } ****************************************************************************** * (1A) PARSE RESPONSE AND FIXED PART PREDICTOR LIST ****************************************************************************** tempname o .`o' = ._eqlist.new, eqopts(NOConstant) eqargopts(EQ) numdepvars(1) noneedvarlist // For properties of this class see C:\Program Files (x86)\Stata11\ado\base\_eqspec.class .`o'.parse `eqlist' local numstataeqns = `.`o'.eq count' if ("`verbose'"~="") display as text "number of eqns: `numstataeqns'" * Derive model type if (`numstataeqns'==1 & "`distribution'" ~= "multinomial") local mtype univariate if ("`distribution'" == "multinomial") local mtype multinomial if (`numstataeqns'>1 & "`distribution'" ~= "multinomial") local mtype multivariate assert"`mtype'"~="" local response local fp if "`mtype'"=="multivariate" { // Count the number of responses local nummlwineqns = 0 local valideqns forvalues e = 1/`numstataeqns' { local 0 , `.`o'.eq options `e'' syntax [, EQuation(numlist integer)] local eq `equation' if `:list sizeof eq' == 1 { local valideqns `valideqns' `eq' local name`eq' `.`o'.eq name `e'' local response`eq' `.`o'.eq depvars `e'' // Add to complete list local response `response' `response`eq'' local ++nummlwineqns } } * Reserve the first nummlwineqns for separate coefficients local numfpbrackets = `nummlwineqns' forvalues e = 1/`numstataeqns' { local 0 , `.`o'.eq options `e'' syntax [, EQuation(numlist integer)] local eq `equation' if "`eq'" == "" { display as error "equation option not set for `e'" exit 198 } if `:list sizeof eq' == 1 { if ("`verbose'"~="") display as text "Separate coefficients" local fp`eq' `.`o'.eq indepvars `e'' local numfpvars`eq' :list sizeof fp`e' local dups :list dups fp`eq' if "`dups'" ~= "" { display as error "`dups' are duplicated in the fixed part equation `eq'" exit 198 } foreach var of local fp`eq' { local fpname`eq' `fpname`eq'' `var'.`eq' } local pat forvalues a = 1/`nummlwineqns' { if `:list a in eq' local pat `pat' 1 else local pat `pat' 0 } local rpat`eq' `pat' } else { if ("`verbose'"~="") display as text "Common coefficients" // NOTE: This may give unnecessary errors if the common equation comes before a corresponding separate one if "`:list eq - valideqns'" ~= "" { display as error "invalid equation(s) specified" exit 198 } local ++numfpbrackets local fp`numfpbrackets' `.`o'.eq depvars `e'' `.`o'.eq indepvars `e'' local numfpvars`numfpbrackets' :list sizeof fp`e' local dups :list dups fp`numfpbrackets' if "`dups'" ~= "" { display as error "`dups' are duplicated in the fixed part equation `eq'" exit 198 } foreach var of local fp`e' { local fpname`numfpbrackets' `fpname`numfpbrackets'' `var'.`=subinstr("`eq'", " ", "", .)' } local pat forvalues a = 1/`nummlwineqns' { if `:list a in eq' local pat `pat' 1 else local pat `pat' 0 } local rpat`numfpbrackets' `pat' } } forvalues e = 1/`numfpbrackets' { // Add to complete list local fp `fp' `fp`e'' } local numfpvars :list sizeof fp } * Multinomial response if "`mtype'"=="multinomial" { local response1 `.`o'.eq depvars 1' capture tab `response1' local nummlwineqns `=`r(r)' - 1' local numfpbrackets = `nummlwineqns' local valideqns forvalues e = 1/`nummlwineqns' { local valideqns `valideqns' `e' } if ("`verbose'"~="") display as text "Valid Equations: `valideqns'" forvalues e = 2/`numstataeqns' { local 0 , `.`o'.eq options `e'' syntax [, CONtrast(numlist integer)] local cat `contrast' if ("`verbose'"~="") display as text "`cat'" if "`cat'" == "" { display as error "cat option not set for `e'" exit 198 } if "`:list cat - valideqns'" ~= "" { display as error "Invalid contrast(s) specified. The contrast(s) specified in contrasts() must tally with the contrast(s) in the model, in this case: 1,2,...,`nummlwineqns'" _n exit 198 } if `:list sizeof cat' == 1 { if ("`verbose'"~="") display as text "Separate coefficients" local fp`cat' `.`o'.eq depvars `e'' `.`o'.eq indepvars `e'' local dups :list dups fp`cat' if "`dups'" ~= "" { display as error "`dups' are duplicated in the fixed part contrast `contrast'" exit 198 } } else { if ("`verbose'"~="") display as text "Common coefficients" local ++numfpbrackets local fp`numfpbrackets' `.`o'.eq depvars `e'' `.`o'.eq indepvars `e'' local numfpvars`numfpbrackets' :list sizeof fp`numfpbrackets' local fpname`numfpbrackets' local dups :list dups fp`numfpbrackets' if "`dups'" ~= "" { display as error "`dups' are duplicated in the fixed part contrast `contrast'" exit 198 } capture levelsof `response1', local(responsecats) local catvals local respnum = 1 foreach catn of local responsecats { if "`catn'" ~= "`basecategory'" { if `:list respnum in cat' local catvals `catvals' `catn' local ++respnum } } foreach var of local fp`numfpbrackets' { local fpname`numfpbrackets' `fpname`numfpbrackets'' `var'.`=subinstr("`catvals'", " ", "", .)' } local pat forvalues a = 1/`nummlwineqns' { if `:list a in cat' local pat `pat' 1 else local pat `pat' 0 } local rpat`numfpbrackets' `pat' } } // Check there are at least nummlwineqns equations capture levelsof `response1', local(responsecats) local e = 1 foreach cat of local responsecats { if "`cat'" ~= "`basecategory'" { // Add to complete list local response`e' `response1' local response `response' `response`e'' local fp`e' `.`o'.eq indepvars 1' `fp`e'' local numfpvars`e' :list sizeof fp`e' local dups :list dups fp`e' if "`dups'" ~= "" { display as error "`dups' are duplicated in the fixed part" exit 198 } local fpname`e' foreach var of local fp`e' { local fpname`e' `fpname`e'' `var'.`cat' } local pat forvalues a = 1/`nummlwineqns' { if `:list a in e' local pat `pat' 1 else local pat `pat' 0 } local rpat`e' `pat' local ++e } } forvalues e = 1/`numfpbrackets' { // Add to complete list local fp `fp' `fp`e'' } local numfpvars :list sizeof fp } if "`mtype'" == "univariate" { local numfpbrackets = `numstataeqns' local nummlwineqns = `numstataeqns' * Parse each equation forvalues e = 1/`numfpbrackets' { local name`e' `.`o'.eq name `e'' local response`e' `.`o'.eq depvars `e'' if _caller() >= 11 { local 0 `.`o'.eq indepvars `e'' syntax varlist(fv) fvexpand `varlist' local fpname`e' `r(varlist)' fvrevar `r(varlist)' local fp`e' `r(varlist)' local newvars :list fp`e' - varlist capture _rmcoll `fp`e'', noconstant local fp`e' `r(varlist)' if "`newvars'" ~= "" { quietly compress `newvars' } local i = 1 foreach x in `fp`e'' { local xname :word `i' of `fpname`e'' if substr("`x'", 1, 2) == "o." { local fp`e' : list fp`e' - x local fpname`e' : list fpname`e' - xname display as text "note: `xname' omitted because of collinearity" } else { if "`:type `x''" == "double" & `:list x in newvars' & `doublevar' == 0{ quietly recast float `x', force display as error "`xname' has more precision that MLwiN can handle, forcing to float" } local ++i } } } else { local fpname`e' `.`o'.eq indepvars `e'' local fp`e' `.`o'.eq indepvars `e'' } local dups :list dups fp`e' if "`dups'" ~= "" { display as error "`dups' are duplicated in the fixed part" exit 198 } local numfpvars`e' :list sizeof fp`e' // Add to complete list local response `response' `response`e'' local fp `fp' `fp`e'' } local numfpvars :list sizeof fp } local fpname forvalues e = 1/`numfpbrackets' { local fpname `fpname' `fpname`e'' } forvalues e = 1/`numfpbrackets' { if ("`=word("`distribution'", `e')'"=="binomial") { if ("`extra'" ~= "") { capture assert (`denominator' == 1) & (`response' == 1 | `response' == 0) if ~_rc { display as error "Extra option applies to binomial responses, not binary" exit 198 } } } } if ("`verbose'"~="") { * Check that the syntax has been parsed properly display _n as result "MODEL " as text "Num. of responses: `numfpbrackets' " as text "Model type: `mtype'" _n forvalues e = 1/`numfpbrackets' { display as result "FP EQUATION `e' " as text "Name: `name`e'', Response: `response`e'', Predictors: `fp`e'', Num. of predictors: `numfpvars`e'', Options: `opts`e''" _n } } ****************************************************************************** * (1B) PARSE LEVELS ****************************************************************************** * Level parsing (Level X identifier, random part covariates and options) local residualsall local factorson = 0 * Total number of random part variables (not total number of random part parameters) local numrpvars = 0 local emptylevels forvalues l = `maxlevels'(-1)1 { if "`level`l''"~="" { gettoken lev`l'id 0 : level`l', parse(":") // get everything before colon and put in lev`l'id, put rest of string in 0 if `:list sizeof lev`l'id' > 1 { // if you have specified more than one variable before the colon then issue an error message display as error "Only one level `l' ID is allowed; a colon should appear after the level `l' ID and before the variable list" _n exit 198 } gettoken colon rp`l': 0, parse(":") // Put : in colon and the variable list and any options in rp`l' if strpos("`rp`l''", ",") > 0 { // If there is a comma is the variable list and option list (i.e. options have been specified after a comma as expected) then ... gettoken rp`l' options : rp`l', parse(",") bind // put the true var list in rp`l' and put the comma and the options in options if "`rp`l''" == "," local rp`l' "" // No RP variables specified else gettoken comma options: options, parse(",") // Put , in comma and the true option list in options } local 0 `rp`l'', lev`l'id(`lev`l'id') `options' // Define new local called 0 which has contents in "". We can prob remove `varlist' but need to check. if "`l'" ~= "1" { // If level is level 2,3,4,5,... // syntax interpret whatever is in `0' #delimit ; syntax [anything(name=rpeqlist id="equations" equalok)], [LEV`l'id(varname)] [Diagonal] [ELements(namelist min=1 max=1)] [DESIGN(string)] [RESET(namelist min=1 max=1)] [Residuals(string)] [Weightvar(varname)] [MMIds(varlist)] [MMWeights(varlist)] [CARIds(varlist)] [CARWeights(varlist)] [PAREXpansion] [FLInits(string)] [FLConstraints(string)] [FVInits(string)] [FVConstraints(string)] [FScores(string)]; #delimit cr } else { // If level is level 1 #delimit ; syntax [anything(name=rpeqlist id="equations" equalok)], LEV`l'id(varname) [Diagonal] [ELements(namelist min=1 max=1)] [DESIGN(string)] [RESET(namelist min=1 max=1)] [Residuals(string)] [Weightvar(varname)] [MMIds(varlist)] [MMWeights(varlist)] [CARIds(varlist)] [CARWeights(varlist)] [FLInits(string)] [FLConstraints(string)] [FVInits(string)] [FVConstraints(string)] [FScores(string)]; #delimit cr } * Parse the random part equations and variable specification tempname o .`o' = ._eqlist.new, eqopts(NOConstant) eqargopts(EQ) numdepvars(1) noneedvarlist // For properties of this class see C:\Program Files (x86)\Stata11\ado\base\_eqspec.class .`o'.parse `rpeqlist' // capture because in some models we may choose to include no predictors in the random part at a particular level (e.g. a bivariate normal response model fitted as a univariate response model has no random part at level 1) local numstataeqns`l' = `.`o'.eq count' local numrpbrackets`l' = `nummlwineqns' if ("`verbose'"~="") display as text "Valid Equations: `valideqns'" forvalues e = 1/`numstataeqns`l'' { // loop over the equations local 0 , `.`o'.eq options `e'' syntax [, EQuation(numlist integer) CONtrast(numlist integer) *] if ("`contrast'" ~= "") local eq `contrast' else local eq `equation' if ("`verbose'"~="") display as text "`eq'" if "`mtype'" == "univariate" { local rp`l'_`e' `.`o'.eq depvars `e'' `.`o'.eq indepvars `e'' local rp`l'name`e' `rp`l'_`e'' local dups :list dups rp`l'_`e' if "`dups'" ~= "" { display as error "`dups' are duplicated in the random part level `l' equation `e'" exit 198 } } else { if "`eq'" == "" { if `e' == 1 { forvalues a = 1/`nummlwineqns' { local name`a' `.`o'.eq name `e'' local rp`l'_`a' `.`o'.eq depvars `e'' `.`o'.eq indepvars `e'' local rpeq`l'_`a' `a' local dups :list dups rp`l'_`a' if "`dups'" ~= "" { display as error "`dups' are duplicated in the random part level `l' contrast `a'" exit 198 } } } else { display as error "equation option not set for `e'" exit 198 } } else { if "`:list eq - valideqns'" ~= "" { display as error "invalid contrast(s) or equation(s) specified" exit 198 } if `:list sizeof eq' == 1 { // Separate local name`eq' `name`eq'' `.`o'.eq name `e'' local rp`l'_`eq' `rp`l'_`eq'' `.`o'.eq depvars `e'' `.`o'.eq indepvars `e'' local rpeq`l'_`eq' `eq' local dups :list dups rp`l'_`eq' if "`dups'" ~= "" { display as error "`dups' are duplicated in the random part level `l' equation `eq'" exit 198 } } else { // Common local ++numrpbrackets`l' local name`numrpbrackets`l'' `.`o'.eq name `e'' local rp`l'_`numrpbrackets`l'' `.`o'.eq depvars `e'' `.`o'.eq indepvars `e'' local numrpvars`numrpbrackets`l'' :list sizeof rp`l'_`numrpbrackets`l'' local rpeq`l'_`numrpbrackets`l'' `eq' local rp`l'name`numrpbrackets`l'' local dups :list dups rp`l'_`numrpbrackets`l'' if "`dups'" ~= "" { display as error "`dups' are duplicated in the random part level `l' equation `eq'" exit 198 } if "`mtype'" == "multivariate" { foreach var of local rp`l'_`numrpbrackets`l'' { local rp`l'name`numrpbrackets`l'' `rp`l'name`numrpbrackets`l'' ' `var'.`=subinstr("`eq'", " ", "", .)' } } if "`mtype'" == "multinomial" { capture levelsof `response1', local(responsecats) local eqvals local respnum = 1 foreach cat of local responsecats { if "`cat'" ~= "`basecategory'" { if `:list respnum in eq' local eqvals `eqvals' `cat' local ++respnum } } foreach var of local rp`l'_`numrpbrackets`l'' { local rp`l'name`numrpbrackets`l'' `rp`l'name`numrpbrackets`l'' ' `var'.`=subinstr("`eqvals'", " ", "", .)' } } local pat forvalues a = 1/`nummlwineqns' { if `:list a in eq' local pat `pat' 1 else local pat `pat' 0 } local rppat`l'_`numrpbrackets`l'' `pat' } } } } if "`mtype'" == "multivariate" { forvalues eq = 1/`nummlwineqns' { if `l' == 1 & "`discrete'" ~= "" & "`=word("`distribution'", `eq')'"=="binomial" local rp`l'_`eq' bcons //_`eq' local numrpvars`eq' :list sizeof rp`l'_`eq' local rp`l'name`eq' foreach var of local rp`l'_`eq' { local rp`l'name`eq' `rp`l'name`eq'' `var'.`=subinstr("`eq'", " ", "", .)' } } } if "`mtype'" == "multinomial" { capture levelsof `response1', local(responsecats) local eq = 1 foreach cat of local responsecats { if "`cat'" ~= "`basecategory'" { local numrpvars`eq' :list sizeof rp`l'_`eq' local rp`l'name`eq' foreach var of local rp`l'_`eq' { local rp`l'name`eq' `rp`l'name`eq'' `var'.`=subinstr("`cat'", " ", "", .)' } local ++eq } } } if "`mtype'" == "multivariate" || "`mtype'" == "multinomial" { forvalues eq = 1/`nummlwineqns' { local pat forvalues a = 1/`nummlwineqns' { if `:list a in eq' local pat `pat' 1 else local pat `pat' 0 } local rppat`l'_`eq' `pat' } } local rp`l' forvalues e = 1/`numrpbrackets`l'' { // loop over the equations local rp`l' `rp`l'' `rp`l'_`e'' if "`mtype'" == "univariate" local rp`l'name`e' `rp`l'_`e'' } // * Add in extra binomial variation parameters etc // if `l' == 1 & "`discrete'" ~= "" & "`mtype'" ~= "multivariate"{ // if "`distribution'" == "multinomial" & "`link'"=="mlogit" local rp`l'name1 `rp`l'name1' P -P // //forvalues a = 1/`nummlwineqns' { // // if "`=word("`distribution'", `a')'" == "binomial" local rp`l'name`a' `rp`l'name`a'' bcons.`a' // // if "`=word("`distribution'", `a')'" == "poisson" local rp`l'name`a' `rp`l'name`a'' bcons.`a' // // if "`=word("`distribution'", `a')'" == "nbinomial" local rp`l'name`a' `rp`l'name`a'' bcons.`a' bcons2.`a' // //} // //if "`distribution'" == "multinomial" & "`link'"=="mlogit" local rp`l'name1 `rp`l'name1' P -P bcons.1 // //if "`distribution'" == "multinomial" & ("`link'"=="ologit" | "`link'"=="oprobit" | "`link'"=="ocloglog") local rp`l'name1 `rp`l'name1' bcons.1 // } forvalues e = 1/`numrpbrackets`l'' { // loop over the equations * Ensure random part names are in the correct order local origrp`l'name `origrp`l'name ' `rp`l'name`e'' local tmpname `rp`l'name`e'' local rp`l'name `rp`l'name' `:list fpname & tmpname' local tmpname `:list tmpname - fpname' forvalues lev = `maxlevels'(-1)`=`e'+1' { local rp`l'name `rp`l'name' `:list rp`lev'name & tmpname' local tmpname `:list tmpname - rp`lev'name' } local rp`l'name `rp`l'name' `tmpname' } // NOTE: The following lines probably aren't needed if "`numfpbrackets'" == "1"{ local rp`l'_1 `.`o'.eq depvars 1' `.`o'.eq indepvars 1' local rp`l' `rp`l'_1' } if ("`verbose'"~="") { display as result "LEVEL `l'" forvalues e = 1/`numfpbrackets' { display as result "RP EQUATION `e', " as text "Name: `name`e'', " as text "Predictors: `rp`l'_`e'', " as text "Num. of predictors: `numrpvars`e'', " as text "Options: `opts`e''" _n } } local numrp`l'vars :list sizeof rp`l' local numrpvars = `numrpvars' + `numrp`l'vars' if `numrp`l'vars' == 0 { if "`diagonal'"~="" | "`elements'"~="" | ("`weightvar'"~="" & `l' > 1) | "`mmids'"~="" | "`mmweights'"~="" | "`carids'"~="" | "`carweights'"~="" || "`parexpansion'"~="" { display as error "Cannot specify random part options at level `l' unless random part predictor variables are specified" exit 198 } if "`reset'"~="" | "`residuals'"~="" { if ~(`l' == 1 & inlist("`distribution`e''","binomial","poisson","nbinomial")) { display as error "Cannot specify reset or residual options at level `l', as no random part predictor variables are specified" exit 198 } } if `l' == 1 & "`mtype'" == "univariate" & "`discrete'" == "" { display as error "WARNING: In univariate continuous models, one or more variables should generally be included in the random part at level 1" } } * Residuals option local numresi`l' 0 if ("`residuals'"~="") { local 0 `residuals' syntax name(name = residname) [, VARiances STANDardised LEVerage INFluence DELetion SAMPling REFlated noRECODE RPAdjust noAdjust SAVEChains(string)] if "`residname'" ~= "" { // If a variable stub has been given for the residual options, then... if "`variances'" ~= "" & ("`leverage'" ~= "" | "`influence'" ~= "" | "`deletion'" ~= ""){ display as error "variances option cannot be used with leverage, deletion or influence" exit 198 } if "`:list residname & residualsall'"~="" { display as error "The new residual variables stub `residname' is defined at more than one level. Specify unique stubs at each level." _n exit 198 } local resivars`l' `rp`l'' if `l' == 1 & "`discrete'" ~= "" { // Note, this does not currently handle multinomial if "`mtype'"=="multinomial" { if "`link'"=="mlogit" local resivars`l' bcons.1 bcons.2 else local resivars`l' bcons.1 } else { forvalues a = 1/`nummlwineqns' { local resivars`l' `resivars`l'' bcons.`a' if "`=word("`distribution'", `a')'" == "nbinomial" local resivars`l' `resivars`l'' bcons2.`a' } } } local numresi`l' :list sizeof resivars`l' forvalues q = 0/`=`:list sizeof resivars`l''-1' { capture confirm variable `residname'`q', exact if !_rc { display as error "The new residual variables stub `residname' is attempting to generate a new variable `residname'`q', but this variable already exists." _n exit 198 } capture confirm variable `residname'`q'se, exact if !_rc { display as error "The new residual variables stub `residname' is attempting to generate a new variable `residname'`q'se, but this variable already exists." _n exit 198 } } if "`rpadjust'" ~= "" & "`adjust'" == "noadjust" { display as error "Cannot specify both RPAdjust and NOAjust at level `l'" exit 198 } local residuals`l' `residname' local residstd`l' `standardised' local residlever`l' `leverage' local residinfl`l' `influence' local residdel`l' `deletion' local residsamp`l' `sampling' local residref`l' `reflated' local residvar`l' `variances' local residrpadj`l' `rpadjust' local residnoadj`l' `adjust' local residrecode`l' `recode' local residualsall :list residualsall | residname } local saveresiduals`l' `savechains' } if "`flinits'" ~= "" | "`flconstraints'" ~= "" | "" ~= "`fvinits'" | "`fvconstraints'" ~= "" | "`fscores'" ~= "" local factorson = 1 if `factorson' == 1 { if "`mtype'" ~= "multivariate" | "`mcmc'" == "" | "`diagonal'" == "" { display as error "Factors can only be specified for multivariate MCMC models with a diagonal covariance matrix" exit 198 } if "`flinits'" == "" | "`flconstraints'" == "" | "" == "`fvinits'" | "`fvconstraints'" == "" { display as error "flinits, flconstraints, fvinits and fvconstraints must all be specified for factor models" exit 198 } if rowsof(`flinits') ~= `:list sizeof rp`l'' | rowsof(`flconstraints') ~= `:list sizeof rp`l'' | colsof(`flinits') ~= colsof(`flconstraints') | colsof(`flinits') ~= rowsof(`fvinits') | colsof(`flinits') ~= colsof(`fvinits') | colsof(`flinits') ~= rowsof(`fvconstraints') | colsof(`flinits') ~= colsof(`fvconstraints') { display as error "Factor matrices are wrong dimensions" exit 198 } tempname fvtempmat capture mat `fvtempmat' = cholesky(`fvinits') if c(rc) == 506 { display as error "Factor variance matrix is not positive definite" exit 198 } local flinit`l' `flinits' local flconstraint`l' `flconstraints' local fvinit`l' `fvinits' local fvconstraint`l' `fvconstraints' local fscores`l' `fscores' } if ("`weightvar'"~="") { if "`mtype'" ~= "univariate" | "`mcmc'" ~= "" { display as error "Weights are only valid for univariate models estimated using (R)IGLS" exit 198 } local weight`l' `weightvar' } if ("`mmids'" ~= "" & "`carids'" ~= "") | ("`mmweights'" ~= "" & "`carweights'" ~= "") | ("`mmids'" ~= "" & "`carweights'" ~= "") | ("`mmweights'" ~= "" & "`carwids'" ~= ""){ display as error "MM and CAR cannot both be specified at the same level" exit 198 } local car if "`carids'" ~= "" | "`carweights'" ~= "" { local mmids `carids' local mmweights `carweights' local car car } if ("`mmids'" ~= "") { //if "`mcmc'" == "" | "`mtype'" ~= "univariate" { // display as error "Multiple membership is only allowed in Univariate MCMC models" // exit 198 //} //else local mmids`l' `mmids' } if ("`mmweights'" ~= "") { if "`mcmc'" == "" | "`mmids`l''" == ""{ display as error "Multiple membership weights are only allowed in MCMC models where multiple membership has been defined" exit 198 } else { local mmweights`l' `mmweights' // This is checked later //if :list sizeof mmids ~= :list sizeof mmweights { // display as error "Number of multiple membership weight variables does not match number of ID variables" // exit 198 //} } } if "`car'" ~= "" { if "`mmids'" == "" | "`mmweights'" == "" { display as error "CAR is only valid for multiple membership models" exit 198 } else local car`l' `car' } if "`parexpansion'" ~= "" { if "`mcmc'" == "" { display as error "Parameter expansion is only valid for MCMC estimation" exit 198 } local parexpansion`l' `parexpansion' local parexpansion } * Diagonal option if ("`diagonal'"~="" & "`elements'"~="") { // If an on/off vector has been given for the elements options, then... display as error "Specify either diagonal or elements(), but not both options." _n exit 198 } if ("`diagonal'"~="") local diagonal`l' `diagonal' // If an on/off vector has been given for the elements options, then... * Elements option if ("`elements'"~="") local elements`l' `elements' // If an on/off vector has been given for the elements options, then... * Reset option if ("`reset'"~="") { // If reset has been specified, then ... local 0 , `reset' syntax , [ALL VARiances NONE] if "`all'" == "" & "`variances'" == "" & "`none'" == "" { display as error "The reset() option must be one of: all, variances, none." _n exit 198 } if "`all'" ~= "" local reset`l' all if "`variances'" ~= "" local reset`l' variances if "`none'" ~= "" local reset`l' none } * Design option if ("`design'"~="") { local 0 `design' syntax using [, FILE(string) Keep(string)] preserve use "`using'", clear if "`keep'"~="" { keep `keep' order `keep' // note that we sort the variables by the order that they are specified in the keep() option. } unab vars: * if "`file'"=="" tempfile file saveold "`file'", nolabel replace restore local filedesign`l' `file' local design`l' `vars' local numdesign`l' :list sizeof vars if ("`verbose'"~="") display as text "Number of DESIGN vectors at level `l': `numdesign`l'' (`design`l'')" } else local numdesign`l' = 0 if `l' > 1 & `numrp`l'vars' == 0 local emptylevels `emptylevels' `l' } else { local numrp`l'vars 0 local emptylevels `emptylevels' `l' } } if ("`linearization'" == "MQL2" | "`linearization'" == "PQL1" | "`linearization'" == "PQL2" ) & "`emptylevels'" ~= "" { display as error "Only MQL1 can be specified if there are empty higher levels" exit 198 } * Generate an indicator for whether any design matrices have been specified at any levels forvalues l = 1/`maxlevels' { if ("`design`l''"~="") local anydesign yes } * Total number of variables (not total number of parameters) (not total number of columns used in MLwiN either as we have denom columns for example) local numvars = `numfpvars' + `numrpvars' * Level order local levelorder forvalues l = 1/`maxlevels' { if "`lev`l'id'"~="" local levelorder `lev`l'id' `levelorder' } * Number of levels local numlevels :list sizeof levelorder ****************************************************************************** * (1C) PARSE GENERAL OPTIONS ****************************************************************************** local hasweights = 0 forvalues l = 1/`maxlevels' { if "`weight`l''" ~= "" local hasweights = 1 } if "`weights'" ~= "" { if `hasweights' == 0 { display as error "weights options specified but no weights defined" exit 198 } local 0, `weights' syntax , [noStandardisation noFPSandwich noRPSandwich] if "`standardisation'" == "" local weighttype standardised else local weighttype raw } // Default weight type is standardised if "`weighttype'" == "" & `hasweights' == 1 local weighttype standardised // Is this check correct? if "`weighttype'" == "standardised" { forvalues l = 2/`maxlevels' { if "`weight`l''" ~= "" & "`weight`=`l'-1''" == ""{ display as error "Standardised weights have been requested for level `l', this requires non-equal standardised weights for all levels below `l'. Please define weights for these levels" exit 198 } } } * Assert that tolerance is integer local iglstolerance `tolerance' * If special option plugin is specified then do macro quietly (i.e. without pauses) if ("`plugin'"~="") local pause no * If savemacro option is specified then check the file extension if ("`savemacro'"~="") { local 0 `savemacro' syntax anything(name=savemacro), [REPLACE] if "`replace'"=="" confirm new file "`savemacro'" } * If savefullmacro option is specified then check the file extension if ("`savefullmacro'"~="") { local 0 `savefullmacro' syntax anything(name=savefullmacro), [REPLACE] if "`replace'"=="" confirm new file "`savefullmacro'" } if ("`saveequation'"~="") { if ("`plugin'" ~= "") { display as error "Cannot capture equation image in plugin mode" exit 198 } local 0 `saveequation' syntax anything(name=saveequation), [REPLACE] if "`replace'"=="" confirm new file "`saveequation'" } * If saveworksheet option is specified then check the file extension if ("`saveworksheet'"~="") { local 0 `saveworksheet' syntax anything(name=saveworksheet), [REPLACE] if length("`saveworksheet'") < 5 local saveworksheet `saveworksheet'.wsz else if lower(substr("`saveworksheet'", -4, .)) ~= ".wsz" local saveworksheet `saveworksheet'.wsz if "`replace'"=="" confirm new file "`saveworksheet'" } if "`initsmodel'" ~= "" { quietly estimates dir local savedmodels `r(names)' if `:list initsmodel in savedmodels' { tempname currentmodel // NOTE: capture in case there is no current model (is there a better check?) quietly capture estimates store `currentmodel', nocopy quietly estimates restore `initsmodel' tempname matPREVIOUS_b matrix `matPREVIOUS_b' = e(b) local inits `matPREVIOUS_b' tempname matPREVIOUS_V matrix `matPREVIOUS_V' = e(V) local initsV `matPREVIOUS_V' quietly capture estimates restore `currentmodel' quietly capture estimates drop `currentmodel' } else { display as error "saved model `initsmodel' not found" exit 198 } } if "`initsv'"~="" & "`initsb'" == "" { display as error "initsb must be specified if initsv is used" exit 198 } * Parse initial values if ("`initsprevious'"~="" & "`initsb'"~="") { display as error "Specify either initsprevious or initsb() and/or initsv(), but not both options." _n exit 198 } if ("`initsprevious'"~="") { tempname matPREVIOUS_b matrix `matPREVIOUS_b' = e(b) local inits `matPREVIOUS_b' tempname matPREVIOUS_V matrix `matPREVIOUS_V' = e(V) local initsV `matPREVIOUS_V' } if ("`initsb'"~="") { local inits `initsb' if rowsof(`inits')~=1 { display as error "The initsb() option expects a row vector as the first argument." _n exit 198 } } if ("`initsv'"~="") local initsV `initsv' if ("`seed'"~="") local standardseed = `seed' if "`mlwinsettings'" ~= "" { local 0, `mlwinsettings' syntax , [Size(numlist >0 integer min=1 max=1) Levels(numlist >=3 integer min=1 max=1) Columns(numlist >=1500 integer min=1 max=1) Variables(numlist >=1 integer min=1 max=1) TEMPMAT OPTIMAT RNGVersion(integer 10)] if "`verbose'" ~= "" display "Worksheet size (KCells): `size', Maximum number of levels: `levels', Number of columns: `columns', Maximum number of modelled variables: `variables'" if "`levels'" ~= "" local toplevel `levels' if "`columns'" ~= "" local numwscolumns `columns' if "`variables'" ~= "" local maxexpl `variables' if "`size'" ~= "" local worksize `size' } ****************************************************************************** * (1D) PARSE DISCRETE SUBOPTIONS ****************************************************************************** * Response type if ("`discrete'"=="") { local distribution forvalues e = 1/`nummlwineqns' { local distribution `distribution' normal } } else { if ("`nummlwineqns'" == "1" & "`distribution'" == "normal") { display as error "The discrete option is unnecessary for univariate normal models" exit 198 } } * Discrete moved higher from here if ("`verbose'"~="") { if ("`mtype'" == "multinomial") { // NOTE: This assumes that the values coming out of levelsof is in the same order as the value labels, is this always true? capture levelsof `response1', local(responsecats) display as text "Response names:" local count = 1 foreach cat of local responsecats { if "`count'" ~= "`basecategory'" display as text "`:label (`response1') `cat''" local ++count } } if ("`mtype'" == "multivariate") { display as text "Response names:" forvalues a = 1/`nummlwineqns' { display as text "`response`a''" } } } if ("`discrete'"~="") { local tmpbin = "binomial" * Check that the denom function is correctly specified. if "`denominator'"=="" { if `:list tmpbin in distribution' { di as error "You must specify the denominator() function for the binomial distribution." exit 198 } if inlist("`distribution'","multinomial") { di as error "You must specify the denominator() function for the multinomial distribution." exit 198 } } else { if ~`:list tmpbin in distribution' & "`distribution'" ~= "multinomial" { display as error "Remove denominator(). denominator() is only valid for the binomial and multinomial distributions." _n exit 198 } } * Check that the offset function is correctly specified. if "`offset'" ~= "" { local tmppois "poisson nbinomial" if "`:list tmppois & distribution'" == "" { display as error "Remove offset(). offset() is only valid for the Poisson or negative binomial distribution." _n exit 198 } } } if ("`mtype'" ~= "multinomial") { if (`:list sizeof distribution' != `nummlwineqns') { display as error "Incorrect number of distributions specified." _n exit 198 } local tmpbin = "binomial" if ((`:list tmpbin in distribution') & (`:list sizeof denominator' != `nummlwineqns')) { display as error "Incorrect number of denominators specified." _n exit 198 } local e = 0 foreach var of local distribution { local ++e local distribution`e' `var' } local e = 0 foreach var of local denominator { local ++e local denominator`e' `var' } * Assert that the response is well behaved forvalues e = 1/`nummlwineqns' { if ("`distribution`e''"=="binomial") { capture assert (`response`e''>=0 & `response`e''<=1) | `response`e''>=. if _rc~=0 { di as error "Binary response variables must take the value 0 or 1. If you have a proportion response variable, then it must lie between 0 and 1." exit 198 } } if ("`distribution`e''"=="poisson") { capture assert `response`e''>=0 if _rc~=0 { di as error "The count response variable must be 0 or a positive integer." exit 198 } } if ("`distribution`e''"=="nbinomial") { capture assert `response`e''>=0 if _rc~=0 { di as error "The count response variable must be 0 or a positive integer." exit 198 } } if ~inlist("`distribution`e''","normal","binomial","poisson","nbinomial") { display as error "The `distribution`e'' response distribution is not recognised by MLwiN." _n exit 198 } } * Check that no level 1 variables have been specified if inlist("`distribution`e''","binomial","poisson","nbinomial") & "`rp1'"~="" { display as error "You cannot make covariates random at level 1 when using the `distribution`e'' response distribution." _n exit 198 } * Check that the denominator has been specified if inlist("`distribution`e''","binomial") & "`denominator`e''"=="" { display as error "You must specify a denominator variable when using the `distribution`e'' response distribution. See the denom() option." _n exit 198 } } else { qui inspect `response1' if r(N_unique)<=1 { display as error "In multinomial response models, the response must have two or more categories" _n exit 198 } * Check that no level 1 variables have been specified if "`rp1'" ~= "" { display as error "You cannot make covariates random at level 1 when using the multinomial response distribution." _n exit 198 } * Check that the denominator has been specified if "`denominator'"=="" { display as error "You must specify a denominator variable when using the multinomial response distribution. See the denom() option." _n exit 198 } * Check that the base category has been specified if "`basecategory'"=="" { display as error "You must specify a (numeric) base category when using the multinomial response distribution. See the basecategory() option." _n exit 198 } * Check that a valid base category has been specified for models with unordered response variables qui levelsof `response1', local(responsevalues) local responsevalues = subinstr("`responsevalues'"," ",",",.) if ~inlist(`basecategory',`responsevalues') { display as error "The base category `basecategory' does not exist for the response variable `response1'. See the basecategory() option." _n exit 198 } } ****************************************************************************** * (1E) PARSE MCMC SUBOPTIONS ****************************************************************************** * Estimation model if ("`mcmc'"=="" & "`rigls'"=="") local emode IGLS if ("`mcmc'"=="" & "`rigls'"~="") local emode RIGLS if ("`mcmc'"~="") local emode MCMC if ("`mcmc'"~="") { if "`initsprevious'"=="" & "`initsb'"=="" & "`initsmodel'" == "" { display as error "When fitting models using MCMC, initial values must be specified; see initsprevious, initsmodel and initsb()/initsv() options." exit 198 } * The syntax for the burn-in is as follows: * * MCMC 0 * burn in for iterations, * use adaptation method , * scale factor , * %acceptance , * tolerance * {residual starting values in C1, * s.e. residual starting values) in C2} * {priors in C3} * fixed effect method * residual method * level 1 variance method * other levels variance method * default prior * model type . local 0 , `mcmc' #delimit ; syntax , [ ON LOGformulation CC MSUBScripts CORResiduals(namelist min=1 max=1) ME(string) PRIORMatrix(namelist min=1 max=1) RPPriors(string) SAVEWinbugs(string) Burnin(integer 500) Chain(integer 5000) Thinning(integer 1) Refresh(integer 50) SCALE(real 5.8) noADAPTation ACCEPTance(real 0.5) TOLerance(real 0.1) CYCLES(integer 1) FEMethod(namelist min=1 max=1) REMethod(namelist min=1 max=1) LEVELONEVARMETHOD(namelist min=1 max=1) HIGHERLEVELSVARMETHOD(namelist min=1 max=1) SMCMC SMVN ORTHogonal HCentring(numlist min=1 max=1 >0 integer) CARCentre SEED(integer 1) noDIAGnostics SAVEChains(string) SIMRESiduals /* Undocumented option. The default is to calculate starting values for higher level residuals using the residuals window. This is a potential alternative which simulates residual starting values from the MVN residual differences (i.e. a drawnorm). */ IMPUTEIterations(numlist >0 integer ascending) IMPUTESummaries ]; #delimit cr if `thinning' > 0.5*`chain' { display as error "Thinning must be less than half the chain length." exit 198 } if ("`fpsandwich'"=="fpsandwich" | ("`weighttype'"~="" & "`fpsandwich'"=="")) | ("`rpsandwich'"=="rpsandwich" | ("`weighttype'"~="" & "`rpsandwich'"=="")){ display as error "Sandwich estimates are not available for MCMC" exit 198 } if "`hcentring'" ~= "" { if `:list hcentring in emptylevels' { display as error "Hierarchical centring cannot be specified for empty levels" exit 198 } if `hcentring' < 2 | `hcentring' > `maxlevels' { display as error "Hierarchical centring must be at one of levels 2 to `maxlevels'" exit 198 } if ("`mtype'"=="multivariate" | "`mtype'"=="multinomial") local ++hcentring } if "`imputeiterations'" ~= "" { foreach val of local imputeiterations { if mod(`val', `refresh') ~= 0 { display as error "`val' is not a valid iteration to impute at" exit 198 } } } if ("`me'"~="") { if "`mtype'" == "multivariate" { display as error "Measurement error not implemented for multivariate in MLwiN." _n exit 198 } local 0 `me' syntax varlist(min=1), variances(numlist min=1 >=0) if `:list sizeof varlist' != `:list sizeof variances' { display as error "incorrect number of measurement error variances" exit 198 } local mevars `varlist' } if ("`discrete'"=="") local temp gibbs if ("`discrete'"~="") local temp univariatemh // univariate MH // NOTE SOMETIMES THIS WILL NEET TO BE MULTIVARITE MH if ("`femethod'"=="") local femethod `temp' if ("`remethod'"=="") local remethod `temp' if ("`levelonevarmethod'"=="") local levelonevarmethod `remethod' // Looks like the GUI does this as well if ("`higherlevelsvarmethod'"=="") local higherlevelsvarmethod gibbs macro drop temp if ("`savechains'"~="") { local 0 `savechains' syntax anything(name=savechains), [REPLACE] // Add .dta extension if this has been omitted if lower(substr("`savechains'", -4, .)) ~= ".dta" { local savechains `savechains'.dta } if "`replace'" == "" confirm new file "`savechains'" } else { tempfile savechains //tempname fh //file open `fh' using "`savechains'", write //file close `fh' } forvalues l = 1/`maxlevels' { if "`saveresiduals`l''" ~= "" { local 0 `saveresiduals`l'' syntax anything(name=saveresiduals`l'), [REPLACE] // Add .dta extension if this has been omitted if lower(substr("`saveresiduals`l''", -4, .)) ~= ".dta" { local saveresiduals`l' `saveresiduals`l''.dta } if "`replace'" == "" confirm new file "`saveresiduals`l''" } } local defaultprior 1 local gama 0.001 local gamb 0.001 if "`rppriors'" ~= "" { local 0 , `rppriors' syntax , [Uniform Gamma(numlist min=2 max=2 >=0)] if "`uniform'" ~= "" & "`gamma'" ~= "" { display as error "Cannot specify both uniform and gamma prior" exit 198 } if "`uniform'" == "" & "`gamma'" == "" { display as error "You must specify uniform or gamma(a b) for priors" exit 198 } if "`uniform'" ~= "" local defaultprior 0 if "`gamma'" ~= "" { local defaultprior 1 local gama :word 1 of `gamma' local gamb :word 2 of `gamma' } } if "`corresiduals'" ~= "" { local 0 , `corresiduals' syntax , [UNstructured EXchangeable AREQvars EQCORRSINDEPvars ARINDEPvars] if "`unstructured'"=="" & "`exchangeable'"=="" & "`areqvars'"=="" & "`eqcorrsindepvars'"=="" & "`arindepvars'"=="" { display as error "Invalid level 1 residual correlation structure specified." exit 198 } } // really we want method(femethod(string) remethod(string) scale(real 5.8) adaptive(acceptance(integer 50) tolerance(integer 10)) cycles(integer 1)) local mcmc_burnin = `burnin' // MLwiN MCMC command option 1 if "`adaptation'" == "noadaptation" local mcmc_adaptation = 0 // MLwiN MCMC command option 2 else local mcmc_adaptation = 1 local mcmc_scale = `scale' // MLwiN MCMC command option 3 if `acceptance' < 0 | `acceptance' > 1 { display as error "Acceptance rate must be between zero and one inclusive" exit 198 } local mcmc_acceptance = ceil(`acceptance'*100) // MLwiN MCMC command option 4 if `tolerance' < 0 | `tolerance' > 1 { display as error "Tolerance rate must be between zero and one inclusive" exit 198 } local mcmc_tolerance = ceil(`tolerance'* 100) // MLwiN MCMC command option 5 local 0 , `femethod' syntax , [GIBBS UNIvariatemh MULTIvariatemh] if "`gibbs'" ~= "" local mcmc_femethod = 1 // 1 = gibbs if "`univariatemh'" ~= "" local mcmc_femethod = 2 // 2 = univariate MH if "`multivariatemh'" ~= "" local mcmc_femethod = 3 // 3 = multivariate MH if "`gibbs'" == "" & "`univariatemh'" == "" & "`multivariatemh'" == "" { display as error "`femethod' is not valid" exit 198 } local 0 , `remethod' syntax , [GIBBS UNIvariatemh MULTIvariatemh] if "`gibbs'" ~= "" local mcmc_remethod = 1 // 1 = gibbs if "`univariatemh'" ~= "" local mcmc_remethod = 2 // 2 = univariate MH if "`multivariatemh'" ~= "" local mcmc_remethod = 3 // 3 = multivariate MH if "`gibbs'" == "" & "`univariatemh'" == "" & "`multivariatemh'" == "" { display as error "`remethod' is not valid" exit 198 } * Looks like you can't set this through the GUI local 0 , `levelonevarmethod' syntax , [GIBBS UNIvariatemh MULTIvariatemh] if "`gibbs'" ~= "" local mcmc_levelonevarmethod = 1 // 1 = gibbs if "`univariatemh'" ~= "" local mcmc_levelonevarmethod = 2 // 2 = univariate MH if "`multivariatemh'" ~= "" local mcmc_levelonevarmethod = 3 // 3 = multivariate MH if "`gibbs'" == "" & "`univariatemh'" == "" & "`multivariatemh'" == "" { display as error "`levelonevarmethod' is not valid" exit 198 } local 0 , `higherlevelsvarmethod' syntax , [GIBBS UNIvariatemh MULTIvariatemh] if "`gibbs'" ~= "" local mcmc_higherlevelsvarmethod = 1 // 1 = gibbs if "`univariatemh'" ~= "" local mcmc_higherlevelsvarmethod = 2 // 2 = univariate MH if "`multivariatemh'" ~= "" local mcmc_higherlevelsvarmethod = 3 // 3 = multivariate MH if "`gibbs'" == "" & "`univariatemh'" == "" & "`multivariatemh'" == "" { display as error "`higherlevelsvarmethod' is not valid" exit 198 } local mcmc_defaultprior = `defaultprior' // MLwiN MCMC command option 10 // MCMC doesn't allow neg binomial if "`mtype'" == "univariate" & "`distribution'"=="normal" local mcmc_modeltype = 1 // Normal models if "`mtype'" == "univariate" & "`distribution'"=="binomial" local mcmc_modeltype = 2 // Binomial models if "`mtype'" == "univariate" & "`distribution'"=="poisson" local mcmc_modeltype = 3 // Poisson models if "`mtype'" == "univariate" & "`distribution'"=="nbinomial" local mcmc_modeltype = 8 // Poisson models if "`mtype'" == "multivariate" & "`discrete'" == "" local mcmc_modeltype = 4 // Multivariate normal models if "`mtype'" == "multivariate" & "`discrete'" ~= "" local mcmc_modeltype = 5 // Multivariate mixed models (must be normal/binomial with probit link) if "`mtype'" == "multinomial" & "`link'"=="mlogit" local mcmc_modeltype = 6 // Unordered multinomial models if "`mtype'" == "multinomial" & ("`link'"=="ologit"|"`link'"=="oprobit"|"`link'"=="ocloglog") local mcmc_modeltype = 7 // Ordered multinomial models capture assert inlist(`mcmc_modeltype',1,2,3,4,5,6,7,8) if _rc { display as error "The selected distribution is not available for MCMC" exit 198 } if "`verbose'"~="" { local i = 1 foreach option in mcmc_burnin mcmc_adaptation mcmc_scale mcmc_acceptance mcmc_tolerance mcmc_femethod mcmc_remethod mcmc_levelonevarmethod mcmc_higherlevelsvarmethod mcmc_defaultprior mcmc_modeltype { di "MLwiN MCMC command option `i': ``option''" _col(50) "(`option')" local ++i } } local resptype local mixed 0 if "`distribution'" == "binomial" local resptype 0 if "`distribution'" == "poisson" local resptype 1 if "`distribution'" == "nbinomial" local resptype 2 if "`distribution'" == "normal" local resptype 3 if "`mtype'" == "multinomial" & "`link'"=="mlogit" local resptype 4 if "`mtype'" == "multinomial" & ("`link'"=="ologit"|"`link'"=="oprobit"|"`link'"=="ocloglog") local resptype 5 if "`mtype'" == "multivariate" { local resptype 3 local firstdist :word 1 of `distribution' foreach dist in `distribution' { // If one of the response is nonlinear set response type to this if "`dist'" ~= "`firstdist'" local mixed 1 if "`dist'" == "binomial" { local resptype 0 if "`link'" ~= "probit" { display as error "Only the probit link is allowed for binomial responses in multivariate models for MCMC estimation" exit 198 } } if "`dist'" == "poisson" { local resptype 1 display as error "Poisson is currently unavailable in multivariate models for MCMC estimation" exit 198 } if "`dist'" == "nbinomial" { local resptype 2 display as error "Poisson is currently unavailable in multivariate models for MCMC estimation" exit 198 } } } //if "`resptype'" == "2" { // display as error "Negative binomial is currently unavailable for MCMC estimation" // exit 198 //} local allnormal 1 local resptypes `distribution' forvalues n = 1/`:list sizeof resptypes' { if "`=word("`resptypes'", `n')'" != "normal" local allnormal 0 } local mcmc_chain = `chain' local mcmc_thinning = `thinning' local mcmc_refresh = `refresh' local mcmc_seed = `seed' forvalues l = 2/`maxlevels' { if "`mmids`l''"~="" |"`mmweights`l''"~="" { if `:list sizeof mmweights`l'' ~= `:list sizeof mmids`l'' { display as error "Number of variables in mmids`l'() must equal number of variables in mmweights`l'()." exit 198 } mata: checkmm("`mmids`l''", "`mmweights`l''") local numweights`l' = `:list sizeof mmwewights`l'' local cc on local mm on } } /* Valid MCMC options: smcmc smvn orth hcen parexpansion 1 0 0 0 0 0 1 0 0 0 0 0 1 1 1 */ local anyparexpansion = 0 forvalues l = 2/`maxlevels' { if "`parexpansion`l''" ~= "" local anyparexpansion = 1 } if "`smcmc'" ~= "" & ("`smvn'" ~= "" | "`orthogonal'" ~= "" | "`hcentring'" ~= "" | `anyparexpansion' > 0) { display as error "SMCMC is exclusive to SMVN, ORTHogonal, HCEN and PAREXpansion" exit 198 } if "`smvn'" ~= "" & ("`smcmc'" ~= "" | "`orthogonal'" ~= "" | "`hcentring'" ~= "" | `anyparexpansion' > 0) { display as error "SMVN is exclusive to SMCMC, ORTHogonal, HCEN and PAREXpansion" exit 198 } if "`smcmc'" ~= "" & ("`mtype'" ~= "univariate" | "`discrete'" ~= "" | "`numrp1vars'" ~= "1" | "`maxlevels'" ~= "2") { display as error "SMCMC is only valid for two-level normal response models with no complex level 1." exit 198 } } local carlev = 0 forvalues l = 1/`maxlevels' { if ("`car`l''"~="" & "`carcentre'"=="") { if `carlev' ~= 0 { display as error "CAR can only be specified at one level" exit 198 } else local carlev = `l' } } ****************************************************************************** * (2) GENERATE THE EMPTY VECTOR OF PARAMETER ESTIMATES ****************************************************************************** * Fixed part parameter vector(s) forvalues r = 1/`numfpbrackets' { tempname FP_b`r' mat `FP_b`r'' = J(1,`numfpvars`r'',.) mat coleq `FP_b`r'' = FP`r' local fname foreach name of local fpname`r' { if _caller() >= 11 { local fname `fname' `=strtoname("`name'")' } else { mata: st_local("name", validname("`name'")) local fname `fname' `=abbrev("`name'", 32)' } } mat colnames `FP_b`r'' = `fname' //`fp`r'' } tempname matFP_b forvalues r = 1/`numfpbrackets' { mat `matFP_b' = (nullmat(`matFP_b'),`FP_b`r'') } * Random part parameter vector (some terms may still need to be deleted) forvalues l = `maxlevels'(-1)1 { tempname RP`l'_b // define matrix names as locals if `:list sizeof rp`l'name'>=1 { runmlwin_rplpars , rpname(`rp`l'name') local rp`l'pars `r(rplong)' runmlwin_rplpars , rpname(`origrp`l'name') local origrp`l'pars `r(rplong)' // if "`mtype'"=="multinomial" & "`link'"=="mlogit" { // * Remove non-existant parameter from multinomial model // // local tmpname var(P) var(_P) // cov(P\bcons_1) cov(_P\bcons_1) // // //if "`mcmc'" ~= "" local tmpname `tmpname' var(bcons_1) // This isn't included for MCMC models // // if "`mcmc'" ~= "" local tmpname `tmpname' cov(P\_P) // This isn't included for MCMC models // if "`mcmc'" ~= "" local tmpname OD:bcons_2 // local rp`l'pars `:list rp`l'pars - tmpname' // } * Remove non-existant parameter from negative-binomial model // local tmpname cov(bcons_1\bcons2_1) // if "`distribution'"=="nbinomial" local rp`l'pars `:list rp`l'pars - tmpname' local numrp`l'pars: word count `rp`l'pars' if `numrp`l'pars' > 0 { mat `RP`l'_b' = J(1,`numrp`l'pars',.) mat coleq `RP`l'_b' = RP`l' mat colnames `RP`l'_b' = `rp`l'pars' } * Remove parameters from the variance-covariance matrices if "`elements`l''"~="" { * Assert that length of `elements`l'' is same as length of `rp`l'pars' if colsof(`elements`l'')~=`numrp`l'pars' { display as error "The matrix `elements`l'' should contain `numrp`l'pars' elements (i.e. one for each parameter in the level `l' var-cov matrix)" _n exit 198 } * Assert that the elements of `elements`l'' are 0 or 1 local names : colfullnames `elements`l'' local c = 1 foreach p of local names { if ~inlist(`elements`l''[1,`c'],0,1) { display as error "All elements in matrix `elements`l'' should be 0 (= remove parameter from model) or 1 (= retain parameter in model)" _n exit 198 } local ++c } * Remove elements from RP_b tempname matTEMP local names : colnames `RP`l'_b' local keepnames forvalues i = 1/`=colsof(`elements`l'')' { if (`elements`l''[1,`i']==1) local keepnames `keepnames' `:word `i' of `origrp`l'pars'' } foreach p of local names { if `:list p in keepnames' matrix `matTEMP' = (nullmat(`matTEMP'), `RP`l'_b'[1,"RP`l':`p'"]) } mat `RP`l'_b' = `matTEMP' } if "`diagonal`l''"~="" { * Work out what the diagonal matrix will look like, then convert the lower diagonal to a vector tempname matTEMP1 matTEMP2 mat `matTEMP1' = I(`numrp`l'vars') local C = `numrp`l'vars' local R = `numrp`l'vars' forvalues r=1/`R' { forvalues c=1/`C' { if `c'<=`r' mat `matTEMP2' = (nullmat(`matTEMP2'), `matTEMP1'[`r',`c']) } } * Remove elements from RP_b // This code is same as that in the elements`l' statement above. Code could be made more efficient tempname matTEMP3 local c = 1 local names : colfullnames `RP`l'_b' foreach p of local names { if (`matTEMP2'[1,`c']==1) matrix `matTEMP3' = (nullmat(`matTEMP3'), `RP`l'_b'[1,"`p'"]) local ++c } mat `RP`l'_b' = `matTEMP3' } } } tempname matRP_b forvalues l = `maxlevels'(-1)1 { if `:list sizeof rp`l'name'>=1 { if `numrp`l'pars' > 0 { mat `matRP_b' = (nullmat(`matRP_b'), `RP`l'_b') } } } if "`distribution'" == "binomial" | "`distribution'" == "poisson" | "`distribution'" == "nbinomial" | "`distribution'" == "multinomial"{ tempname mat_OD if "`distribution'" == "nbinomial" local odvars bcons_1 bcons2_1 else local odvars bcons_1 if "`distribution'" == "multinomial" & "`link'"=="mlogit" & "`mcmc'" == "" local odvars `odvars' bcons_2 mat `mat_OD' = J(1, `:list sizeof odvars', .) mat colnames `mat_OD' = `odvars' mat coleq `mat_OD' = OD mat `matRP_b' = (nullmat(`matRP_b'), `mat_OD') } * Random part design forvalues l = `maxlevels'(-1)1 { if "`design`l''"~="" { mat `RP`l'_b'design = J(1,`numdesign`l'',.) mat coleq `RP`l'_b'design = RP`l'D mat colnames `RP`l'_b'design = `design`l'' mat `matRP_b' = (nullmat(`matRP_b'), `RP`l'_b'design) } } * Factors tempname mat_RP_b_fact forvalues l = `maxlevels'(-1)1 { if "`flinit`l''"~="" { tempname matTEMP forvalues fact = 1/`=colsof(`flinit`l'')' { local factnames forvalues resp = 1/`=rowsof(`flinit`l'')' { local factnames `factnames' f`fact'_`resp' } mat `matTEMP' = J(1, rowsof(`flinit`l''), .) mat coleq `matTEMP' = RP`l'FL mat colnames `matTEMP' = `factnames' mat `mat_RP_b_fact' = (nullmat(`mat_RP_b_fact'), `matTEMP') } } } tempname mat_RP_b_factvar forvalues l = 1/`maxlevels' { if "`flinit`l''" ~= "" { tempname matTEMP local factvarnames forvalues fact1 = 1/`=colsof(`flinit`l'')' { forvalues fact2 = 1/`fact1' { if `fact1' == `fact2' local factvarnames `factvarnames' var(f`fact1') else local factvarnames `factvarnames' cov(f`fact1'\f`fact2') } } mat `matTEMP' = J(1, `:list sizeof factvarnames', .) mat coleq `matTEMP' = RP`l'FV mat colnames `matTEMP' = `factvarnames' mat `mat_RP_b_factvar' = (nullmat(`mat_RP_b_factvar'), `matTEMP') } } local C = colsof(`matFP_b') local namesV : colfullnames `matFP_b' tempname matFP_V mat `matFP_V' = J(`C',`C',0) matrix rownames `matFP_V' = `namesV' matrix colnames `matFP_V' = `namesV' * Put MLwiN values back into RP_V local C = colsof(`matRP_b') local namesV : colfullnames `matRP_b' tempname matRP_V mat `matRP_V' = J(`C',`C',0) matrix rownames `matRP_V' = `namesV' matrix colnames `matRP_V' = `namesV' * Full parameter matrix (this is what Stata expects MLwiN to return) * Create matb with the correct dimensions tempname matb mat `matb' = (`matFP_b',`matRP_b', nullmat(`mat_RP_b_fact'), nullmat(`mat_RP_b_factvar')) mat rowname `matb' = `response1' local names : colfullnames `matb' tempname matV mat `matV' = J(colsof(`matb'), colsof(`matb'), 0) local namesV : colfullnames `matb' mat rownames `matV' = `namesV' mat colnames `matV' = `namesV' if ("`constraints'"~="") { * Parse contraint(s) local C = colsof(`matb') forvalues c=1/`C' { mat `matb'[1,`c'] = 0 } ereturn post `matb' // Need to create e(b) for the current model in order to set constraints tempname matb mat `matb' = e(b) if ("`verbose'"~="") mat list e(b) forvalues c=1/`C' { mat `matb'[1,`c'] = . } tempname consT tempname consa tempname consC makecns `constraints', displaycns matcproc `consT' `consa' `consC' if "`verbose'" ~= "" display "Constraints:" if "`verbose'" ~= "" mat list `consC' * Extract the fixed part constraint submatrix (note that some rows will refer to random part constraints, we delete these below) tempname FPCtemp mat `FPCtemp' = (`consC'[.,1..`numfpvars'],`consC'[.,`=colsof(`consC')'..`=colsof(`consC')']) * Extract the random part constraint submatrix (note that some rows will refer to fixed part constraints, we delete these below) local temp = `numfpvars' + 1 tempname RPCtemp mat `RPCtemp' = (`consC'[.,`temp'...]) if "`verbose'" ~= "" display "FPCtemp" if "`verbose'" ~= "" mat list `FPCtemp' if "`verbose'" ~= "" display "RPCtemp" if "`verbose'" ~= "" mat list `RPCtemp' local numconstraints = rowsof(`consC') * Work out which constraints and how many constraints are FP constraints tempname isFPconstraint mat `isFPconstraint' = J(`numconstraints',1,.) forvalues r=1/`=rowsof(`FPCtemp')'{ local flag = 0 forvalues c=1/`=colsof(`FPCtemp')-1' { if `FPCtemp'[`r',`c'] ~= 0 local flag = 1 } mat `isFPconstraint'[`r',1]==`flag' } tempname mat_sum mat `mat_sum' = J(1,`numconstraints',1)*`isFPconstraint' local numFPconstraints = `mat_sum'[1,1] * Work out which constraints and how many constraints are RP constraints tempname isRPconstraint mat `isRPconstraint' = J(`numconstraints',1,.) forvalues r=1/`=rowsof(`RPCtemp')' { local flag = 0 forvalues c=1/`=colsof(`RPCtemp')-1' { if `RPCtemp'[`r',`c'] ~= 0 local flag = 1 } mat `isRPconstraint'[`r',1]==`flag' } mat `mat_sum' = J(1,`numconstraints',1)*`isRPconstraint' local numRPconstraints = `mat_sum'[1,1] if "`verbose'" ~= "" display "num fp vars: `numfpvars', num rp vars: `numrpvars'" if "`verbose'" ~= "" display "isFPconstraint:" if "`verbose'" ~= "" mat list `isFPconstraint' if "`verbose'" ~= "" display "isRPconstraint:" if "`verbose'" ~= "" mat list `isRPconstraint' if "`verbose'" ~= "" display "num constraints: `numconstraints', num FP constraints: `numFPconstraints', num RP constraints: `numRPconstraints'" * Check that each constraint relates to only the fixed part or only the random part tempname matTEMP mat `matTEMP' = `isFPconstraint' + `isRPconstraint' forvalues r=1/`numconstraints' { if (`matTEMP'[`r',1]>1) { mat list `consC' display as error "Row `r' of the constraint matrix is invalid as it involves both fixed part and random part parameters." _n exit 198 } } * Strip out redundant rows of the fixed part constraint matrix (these relate to the random part) tempname FPC if `numFPconstraints'>0 { forvalues r=1/`numconstraints' { if (`isFPconstraint'[`r',1]==1) mat `FPC' = (nullmat(`FPC') \ `FPCtemp'[`r',1...]) } local fpconstraints `FPC' } * Strip out redundant rows of the random part constraint matrix (these relate to the fixed part) tempname RPC if `numRPconstraints'>0 { forvalues r=1/`numconstraints' { if (`isRPconstraint'[`r',1]==1) mat `RPC' = (nullmat(`RPC') \ `RPCtemp'[`r',1...]) } local rpconstraints `RPC' } ereturn clear // As we don't want an e(b) kicking around } * Store the fixed part constraint(s) as strings in locals ready to insert into MLwiN macro if ("`fpconstraints'"~="") { local numfpconstraints = rowsof(`fpconstraints') forvalues r = 1/`numfpconstraints' { local C = colsof(`fpconstraints') local fpconstraint`r' = `fpconstraints'[`r',1] // put first element of constraint into the string forvalues c=2/`C' { local temp = `fpconstraints'[`r',`c'] local fpconstraint`r' `fpconstraint`r'' `temp' // put second, third,... elements of constraint into the string } } if "`verbose'" ~= "" display("Fixed part constraints:") if "`verbose'" ~= "" mat list `fpconstraints' } * Store the random part constraint(s) as strings in locals ready to insert into MLwiN macro if "`rpconstraints'"~="" { local numrpconstraints = rowsof(`rpconstraints') forvalues r = 1/`numrpconstraints' { local C = colsof(`rpconstraints') local rpconstraint`r' = `rpconstraints'[`r',1] // put first element of constraint into the string forvalues c=2/`C' { local temp = `rpconstraints'[`r',`c'] local rpconstraint`r' `rpconstraint`r'' `temp' // put second, third,... elements of constraint into the string } } if "`verbose'" ~= "" display("Random part constraints:") if "`verbose'" ~= "" mat list `rpconstraints' } * Substitute initial values into the parameter vector if "`inits'"~="" | "`initsmodel'" ~= "" { if "`initsprevious'"~="" | "`initsmodel'" ~= "" { tempname srcrowidx tempname srccolidx tempname destrowidx tempname destcolidx matrix `srcrowidx' = J(1,1,1) matrix `destrowidx' = J(1,1,1) local match 0 foreach p of local names { local idx = colnumb(`inits',"`p'") if "`idx'" ~= "." { local match 1 matrix `srccolidx' = (nullmat(`srccolidx'), `idx') matrix `destcolidx' = (nullmat(`destcolidx'), `=colnumb(`matb',"`p'")') } } if `match' == 1 { mata: copymatrix("`inits'", "`srcrowidx'", "`srccolidx'", "`matb'", "`destrowidx'", "`destcolidx'"); } else { if "`initsprevious'"~="" display as error "The initsprevious option is invalid: No parameters in the previous model match those specified in the current model" if "`initsmodel'" ~= "" display as error "The initsmodel option is invalid: No parameters in the stored model match those specified in the current model" exit 198 } matrix drop `srcrowidx' matrix drop `destrowidx' matrix drop `srccolidx' matrix drop `destcolidx' local match 0 foreach p1 of local namesV { local cidx = colnumb(`initsV',"`p1'") local ridx = rownumb(`initsV',"`p1'") if "`ridx'" ~= "." && "`cinx'" ~= "." { local match 1 matrix `srcrowidx' = (nullmat(`srcrowidx'), `ridx') matrix `destrowidx' = (nullmat(`destrowidx'), `=rownumb(`matV', "`p1'")') matrix `srccolidx' = (nullmat(`srccolidx'), `cidx') matrix `destcolidx' = (nullmat(`destcolidx'), `=colnumb(`matV', "`p1'")') } } if `match' == 1 { mata: copymatrix("`initsV'", "`srcrowidx'", "`srccolidx'", "`matV'", "`destrowidx'", "`destcolidx'"); } else { if "`initsprevious'"~="" display as error "The initsprevious option is invalid: No parameters in the previous model match those specified in the current model" if "`initsmodel'" ~= "" display as error "The initsmodel option is invalid: No parameters in the stored model match those specified in the current model" exit 198 } matrix drop `srcrowidx' matrix drop `destrowidx' matrix drop `srccolidx' matrix drop `destcolidx' } if "`initsb'"~="" { if colsof(`inits') ~= `=colsof(`matFP_b')+colsof(`matRP_b')' { display as error "The row vector `inits' of initial values in initsb() is of length `=colsof(`inits')', but -runmlwin- expects the row vector to be of length `=colsof(`matFP_b')+colsof(`matRP_b')'." exit 198 } matrix `matb'[1,1] = `inits' * Note this is not currently used as we always check there are two inits matrices if "`initsV'" == "" { forvalues i = 1/`=colsof(`matb')' { matrix `matV'[`i', `i'] = (`inits'[1,`i']/2)*(`inits'[1,`i']/2) } } } if "`initsv'"~="" { if colsof(`initsV') ~= `=colsof(`matFP_b')+colsof(`matRP_b')' | rowsof(`initsV') ~= `=colsof(`matFP_b')+colsof(`matRP_b')' { display as error "The matrix of initial variance values in initsv() is of a different length to that expected by -runmlwin-." exit 198 } matrix `matV'[1,1] = `initsV' } } if "`mlwin'" == "nomlwin" { ereturn clear ereturn matrix matb = `matb' ereturn matrix matV = `matV' //ereturn post `matb' `matV' } ****************************************************************************** * (3) PREPARE DATA FOR MLWIN ****************************************************************************** * Preserve the data preserve * Remove data label label data * Generate unique identifier variable label var `_sortindex' "Observation number in the current Stata data set" * Keep the estimation sample qui keep if `touse' local _nobs = _N * List of values of the response variable if ("`mtype'"=="multinomial") { qui levelsof `response1', local(responsecats) if "`proportion'" ~= "" { capture assert `proportion' >= 0 & `proportion' <= 1 if _rc { display as error "Values in the multinomial proportion variable should lie between zero and one" exit 198 } tempvar propsum if ("`cc'"~="") local hier `lev1id' else { local hier local levelused = 0 forvalues l = `maxlevels'(-1)2 { if `numrp`l'vars' > 0 local levelused = 1 if `levelused' == 1 local hier `hier' `lev`l'id' } local hier `hier' `lev1id' } bysort `hier': egen `propsum' = total(`proportion') capture assert inrange(`propsum',0.995,1.005) // >= 0 & `propsum' <= 1 if _rc { display as error "The sum of multinomial proportions for each unit should equal one" exit 198 } drop `propsum' sort `_sortindex' drop `_sortindex' quietly reshape wide `proportion', i(`lev1id') j(`response1') gen `_sortindex' = _n gen `response1' = 1 local propvars local propvarnames local i = 1 foreach r of local responsecats { if `r' ~= `basecategory' local propvars `propvars' `proportion'`r' if `r' ~= `basecategory' local propvarnames `propvarnames' '`proportion'`r'' quietly replace `response1' = `r' in `i' local ++i } } tempname newvaluelabel foreach r of local responsecats { label define `newvaluelabel' `r' "`: label (`response1') `r''", add } label values `response1' `newvaluelabel' if "`link'"=="ologit"|"`link'"=="oprobit"|"`link'"=="ocloglog" { local firstvalue = real(word("`responsecats'",1)) local lastvalue = real(word("`responsecats'",-1)) if ~inlist(`basecategory', `firstvalue',`lastvalue') { di as error "The basecategory must be either the first value (`response1' = `firstvalue') or last value (`response1' = `lastvalue') of the ordered response variable." _n exit 198 } } } * List of ID variables local idvars forvalues l = `maxlevels'(-1)1 { local idvars `idvars' `lev`l'id' // MM IDs are added consecutively in case MM IDs share variables with level IDs (what if ID is used in more than one level?) if "`mmids`l''" ~= "" local idvars `idvars' `mmids`l'' } * List of variables which appear in the random part of the model local rp forvalues l = `maxlevels'(-1)1 { local rp `rp' `rp`l'' } * List of variable which appear as denominators in discrete response models local denomvars if "`mtype'" == "multivariate" { forvalues e = 1/`nummlwineqns' { local denomvars `denomvars' `denominator`e'' } } else { local denomvars `denominator' } * List of multiple membership weight variables local mmweightvars forvalues l = 2/`maxlevels' { if "`mmweights`l''" ~= "" local mmweightvars `mmweightvars' `mmweights`l'' } * List of multiple membership ID variables //local mmweightids //forvalues l = 2/`maxlevels' { // if "`mmids`l''" ~= "" { // local mmweightids `mmweightids' `mmids`l'' // } //} * List of (R)IGLS sampling weight variables local weightvars forvalues l = 1/`maxlevels' { if "`weight`l''" ~= "" local weightvars `weightvars' `weight`l'' } * Keep variables that appear in model local allvarsformlwin /// `idvars' /// `response' /// `fp' /// `rp' /// `denomvars' `offset' `fpconst' `rpconst' `mmweightvars' `mmweightids' `weightvars' `_sortindex' `propvars' local data_has_missing_values = 0 foreach var of local allvarsformlwin { if "`var'" ~= "bcons" { quietly count if missing(`var') if r(N) > 0 { if "`mtype'" == "multinomial" { display as error "For multinomial response models (i.e. ordered and unordered categorical responses), the data must be manually listwise deleted (i.e. cases with missing values for one or more variables included in the model must be dropped) prior to calling runmlwin." exit 198 } local data_has_missing_values = 1 } } } * If a multivariate response model, create and add bcons variable to the list of variables sent to MLwiN if "`mtype'" == "multivariate" gen byte bcons = 1 * Keep variables if "`drop'"=="" keep `allvarsformlwin' order `allvarsformlwin' * Strip off the value labels of all fixed or random part covariates local temp `fp' `rp' foreach var of local temp { label values `var' } * Calculate number of columns that will be used in the worksheet qui describe local numcolumns = r(k) local N = r(N) local explvars forvalues e = 1/`numfpbrackets' { local explvars `:list explvars | fpname`e'' } forvalues l = `maxlevels'(-1)1 { forvalues e = 1/`numrpbrackets`l'' { local explvars `:list explvars | rp`l'name`e'' } } local numrpparam = colsof(`matRP_b') if "`mtype'" == "multivariate" & "`discrete'" ~= "" { // Account for adding bcons parameters with SETV in multivariate (i.e. add off-diagonal) local numrpparam = `numrpparam' + (((`nummlwineqns' * (`nummlwineqns'+1)) /2) - `nummlwineqns') } local numexpl = max(`:list sizeof explvars', `numrpparam') * Allow for bcons.1 if "`distribution'" == "binomial" | "`distribution'" == "poisson" | "`distribution'" == "nbinomial" | "`mtype'" == "multinomial" local ++numexpl * Allow for bcons2.1 if "`distribution'" == "nbinomial" local ++numexpl * Allow for P parameter if "`mtype'" == "multinomial" local ++numexpl if "`maxexpl'" == "" local maxexpl = `numexpl' + 1 // MLwiN appears to allow one fewer than specified if "`toplevel'" == "" { local toplevel `maxlevels' if ("`mtype'"=="multivariate" | "`mtype'"=="multinomial") local ++toplevel local ++toplevel // Add an extra level, as NLEV command gives the wrong answer if all available levels are in use and this can cause the discrete/multicat macros to give the wrong answers if `toplevel' < 3 local toplevel = 3 } if "`numwscolumns'" == "" local numwscolumns 1500 * Attempt to estimate how large the data will be after expansion if "`worksize'" == "" { local worksize = 10000 } if ("`verbose'"~="") display as text "Expanded variables: Count: `numexpand', Length: `longN' Estimated sheet size: `sheetsize'" qui compress * Assert that the data is sorted according to the model hierarchy if "`cc'"=="" && "`sort'" == "" { if "`mtype'" == "univariate" local bottomlev 1 else local bottomlev 0 if `maxlevels'>`bottomlev' { local idvars2andhigher local levelused = 0 forvalues l = `maxlevels'(-1)`=`bottomlev' + 1' { if `numrp`l'vars' > 0 local levelused = 1 if `levelused' == 1 local idvars2andhigher `idvars2andhigher' `lev`l'id' } * Check whether correct sort order is set, otherwise examine the data if `=strpos("`:sortedby'", "`idvars2andhigher'")' ~= 1 { tempvar sortorder1 tempvar sortorder2 quietly gen `sortorder1' = _n sort `idvars2andhigher' `sortorder1' quietly gen `sortorder2' = _n capture assert `sortorder2'==`sortorder1' if _rc { if "`forcesort'" ~= "" { display as error "Warning: The data have been resorted in the order of the model hierarchy: `idvars2andhigher' `lev1id'." _n } else { display as error "The data must be sorted according to the order of the model hierarchy: `idvars2andhigher' `lev1id'." _n exit 198 } } drop `sortorder1' `sortorder2' } } } foreach var of varlist * { if "`:type `var''" == "double" & `doublevar' == 0 { if "`forcerecast'" ~= "" { recast float `var', force display as error "Warning: `var' has been recast to float, this has reduced precision" } else { display as error in smcl "`var' is held to more precision than MLwiN can handle, to reduce the precision use {stata recast float `var', force}" exit 198 } } if "`:type `var''" == "long" { if `doublevar' == 0 { capture recast float `var' } else { capture recast double `var' } if `r(N)' > 0 { if "`forcerecast'" ~= "" { if `doublevar' == 0 { recast float `var', force display as error "Warning: `var' has been recast to float, if this is an ID variable its meaning may have changed" } else { recast double `var', force display as error "Warning: `var' has been recast to double, if this is an ID variable its meaning may have changed" } } else { display as error "`var' is held to more precision than MLwiN can handle, it must be recoded so that values lie in the range +/- 16,777,215" exit 198 } } } } tempfile filedata qui saveold "`filedata'", replace ****************************************************************************** * (4) WRITE MLWIN SUB MACRO TO FIT MODEL ****************************************************************************** tempname macro1 if "`savemacro'" ~= "" local filemacro1 `savemacro' else tempfile filemacro1 if "`batch'" ~= "" local pause nopause qui file open `macro1' using "`filemacro1'", write replace if ("`pause'"=="nopause" | "`plugin'" ~= "") file write `macro1' "ECHO 0" _n * Give details about runmlwin and date and time stamp the macro file write `macro1' "NOTE ***********************************************************************" _n file write `macro1' "NOTE MLwiN macro created by runmlwin Stata command: `c(current_date)', `c(current_time)'" _n file write `macro1' "NOTE See: www.bristol.ac.uk/cmm/runmlwin for help" _n file write `macro1' "NOTE ***********************************************************************" _n(2) if "`verbose'" ~= "" display as text "Estimated worksheet size: `worksize'" if "`verbose'" ~= "" display as text "Number of levels: `toplevel'" if "`verbose'" ~= "" display as text "Number of explanatory variables/random parameters: `maxexpl' (`explvars')" if "`verbose'" ~= "" file write `macro1' "ECHO 1" _n file write `macro1' "NOTE Initialise MLwiN storage" _n "INIT `toplevel' `worksize' `numwscolumns' `maxexpl' 30" _n(2) if "`optimat'" == "" file write `macro1' "OPTS 0" _n else file write `macro1' "OPTS 1" _n if "`tempmat'" == "" file write `macro1' "NOTE Don't use worksheet for matrix storage" _n "MEMS 1" _n(2) else file write `macro1' "NOTE Use worksheet for matrix storage" _n "MEMS 0" _n(2) file write `macro1' "MARK 0" _n if "`batch'" ~= "" { file write `macro1' "NOTE divert error messages to a file" _n "ERRO 0" _n tempfile errlog //tempname fh //file open `fh' using "`errlog'", write //file close `fh' file write `macro1' "LOGO '`errlog'' 1" _n(2) } * Open the equations window if ("`pause'"=="") { file write `macro1' "NOTE Open the equations window" _n file write `macro1' "WSET 15 1" _n // open the equations window file write `macro1' "EXPA 2" _n // expand from response equation to include first model equation then random effects equations file write `macro1' "ESTM 1" _n(2) // switch from black symbols to coloured symbols (but not point estimates) } if "`useworksheet'" ~= "" { file write `macro1' "NOTE Load previously saved model state into MLwiN" _n "ZRET '`useworksheet''" _n(2) } else { * Load the data set file write `macro1' "NOTE Import the Stata data set into MLwiN" _n "RSTA '`filedata''" _n(2) if "`rngversion'" ~= "" file write `macro1' "NOTE Set the random number generator version" _n "RNGV `rngversion'" _n * Load design vectors if specified forvalues l = `maxlevels'(-1)1 { if "`design`l''"~="" { file write `macro1' "NOTE Load the design matrix for the random part at level `l'" _n file write `macro1' "LINK `numdesign`l'' G21" _n "GSTA '`filedesign`l''' G21" _n "LINK 0 G21" _n(2) } } * Convergence tolerance if "`iglstolerance'" ~= "" file write `macro1' "NOTE Specify the (R)IGLS convergence tolerance" _n "TOLE `iglstolerance'" _n(2) * Specify the univariate response variable file write `macro1' "NOTE Specify the response variable(s)" _n if ("`mtype'"~="multivariate" & "`mtype'"~="multinomial") file write `macro1' "RESP '`response1''" _n * Specify the multivariate response variable local responsenames forvalues e = `nummlwineqns'(-1)1 { if "response`e'"~="" local responsenames '`response`e''' `responsenames' } if ("`mtype'"=="multivariate") file write `macro1' "MVAR 1 `responsenames'" _n * Specify the multinomial response variable // assert that response is categorical if ("`distribution'"=="multinomial") { local cresp = `numcolumns' + 1 local cresp_indicator = `numcolumns' + 2 * Expand the data file write `macro1' "NAME c`cresp' 'resp' c`cresp_indicator' 'resp_indicator'" _n if "`link'" == "mlogit" file write `macro1' "MNOM 0 '`response1'' 'resp' 'resp_indicator' `basecategory'" _n else file write `macro1' "MNOM 1 '`response1'' 'resp' 'resp_indicator' `basecategory'" _n file write `macro1' "RESP 'resp'" _n if ("`link'"=="mlogit") file write `macro1' "RDIS 1 4" _n if ("`link'"=="ologit"|"`link'"=="oprobit"|"`link'"=="ocloglog") file write `macro1' "RDIS 1 5" _n if "`link'"=="ologit" | "`link'"=="mlogit" file write `macro1' "LFUN 0" _n if "`link'"=="oprobit" file write `macro1' "LFUN 1" _n if "`link'"=="ocloglog" file write `macro1' "LFUN 2" _n file write `macro1' "DOFF 1 '`denominator''" _n if ("`extra'" ~= "") file write `macro1' "EXTR 1" _n } if "`proportion'" ~= "" file write `macro1' "VECT `=`:list sizeof responsecats'-1' `propvarnames' 'resp'" _n if ("`pause'"=="") file write `macro1' "PAUS 1" _n file write `macro1' _n * Loop over responses (equations) forvalues e = 1/`numfpbrackets' { * Binary response // assert that response lies in the interval [0,1] if ("`distribution`e''"=="binomial") { file write `macro1' "NOTE Response distribution, link function and denominator" _n file write `macro1' "RDIS `e' 0" _n if ("`link'"=="probit") file write `macro1' "LFUN 1" _n if ("`link'"=="cloglog") file write `macro1' "LFUN 2" _n if ("`link'"=="logit" | "`link'"=="") file write `macro1' "LFUN 0" _n file write `macro1' "DOFF `e' '`denominator`e'''" _n if ("`extra'" ~= "") file write `macro1' "EXTR 1" _n if ("`pause'"=="") file write `macro1' "PAUS 1" _n file write `macro1' _n } * Poison response // assert that response is positive integer? if ("`distribution'"=="poisson") { file write `macro1' "NOTE Response distribution, link function and denominator" _n file write `macro1' "RDIS `e' 1" _n "LFUN 3" _n if ("`extra'" ~= "") file write `macro1' "EXTR 1" _n if ("`offset'"~="") file write `macro1' "DOFF `e' '`offset''" _n if ("`pause'"=="") file write `macro1' "PAUS 1" _n file write `macro1' _n } * Negative binomial response // assert that response is positive integer? if ("`distribution'"=="nbinomial") { file write `macro1' "NOTE Response distribution, link function and denominator" _n file write `macro1' "RDIS `e' 2" _n "LFUN 3" _n if ("`extra'" ~= "") file write `macro1' "EXTR 1" _n if ("`offset'"~="") file write `macro1' "DOFF `e' '`offset''" _n if ("`pause'"=="") file write `macro1' "PAUS 1" _n file write `macro1' _n } } * Levels/Classification identifiers file write `macro1' "NOTE Specify the level identifier(s)" _n forvalues l = `maxlevels'(-1)1 { local ll = `l' if ("`mtype'"=="multivariate" | "`mtype'"=="multinomial") local ++ll if ("`lev`l'id'"~="") file write `macro1' "IDEN `ll' '`lev`l'id''" _n } if ("`mtype'"=="multivariate" | "`mtype'"=="multinomial") file write `macro1' "IDEN 1 'resp_indicator'" _n if ("`pause'"=="") file write `macro1' "PAUS 1" _n file write `macro1' _n * Specify covariate(s) used anywhere in the model file write `macro1' "NOTE Specify covariate(s) used anywhere in the model" _n local allvars :list uniq fp forvalues l = `maxlevels'(-1)1 { local allvars :list allvars|rp`l' } * Remove duplicates (for example in Multivariate) local allvars :list uniq allvars if ("`mtype'"=="multinomial" | "`mtype'"=="multivariate") { forvalues e = 1/`numfpbrackets' { if "`mtype'"=="multivariate" & "`=word("`distribution'", `e')'" == "binomial" { // Take out and put back in bcons.* so they appear in the correct position in the terms file write `macro1' "NOTE Ensure bcons is in the correct place for output" _n "NEXP 0 'bcons.`e''" _n "ERAS 'bcons.`e''" _n } if "`fp`e''" ~= "" { file write `macro1' "RPAT `rpat`e''" _n foreach var of varlist `fp`e''{ file write `macro1' "ADDT '`var''" _n } file write `macro1' "RPAT" _n } if `e' <= `nummlwineqns' { forvalues l = `maxlevels'(-1)1 { if "`rp`l'_`e''" ~= "" { file write `macro1' "RPAT `rppat`l'_`e'' " _n forvalues n = 1/`:list sizeof rp`l'name`e'' { if `:list posof "`=word("`rp`l'name`e''", `n')'" in fpname' == 0 { file write `macro1' "ADDT '`=word("`rp`l'_`e''", `n')''" _n "FPAR 0 '`=word("`rp`l'name`e''", `n')''" _n } } file write `macro1' "RPAT" _n } } } } forvalues l = `maxlevels'(-1)1 { forvalues e = `=`nummlwineqns'+1'/`numrpbrackets`l'' { if "`rp`l'_`e''" ~= "" { file write `macro1' "RPAT `rppat`l'_`e'' " _n forvalues n = 1/`:list sizeof rp`l'name`e'' { if `:list posof "`=word("`rp`l'name`e''", `n')'" in fpname' == 0 { file write `macro1' "ADDT '`=word("`rp`l'_`e''", `n')''" _n "FPAR 0 '`=word("`rp`l'name`e''", `n')''" _n } } file write `macro1' "RPAT" _n } } } } if ("`mtype'"=="univariate") { forvalues e = 1/`numfpbrackets' { foreach var of varlist `fp`e''{ file write `macro1' "ADDT '`var''" _n } } * Add to the model any variables in the random part which are not in the fixed part * Then remove from the fixed part of the model (but not entirely from the model itself!) any variables which are only in the random part local nonfp :list allvars - fp if "`nonfp'"~="" { foreach var of varlist `nonfp' { file write `macro1' "ADDT '`var''" _n } foreach var of varlist `nonfp' { file write `macro1' "FPAR 0 '`var''" _n } } } if ("`pause'"=="") file write `macro1' "PAUS 1" _n file write `macro1' _n forvalues l = `maxlevels'(-1)1 { local ll = `l' if ("`mtype'"=="multivariate" | "`mtype'"=="multinomial") local ++ll * Level `l' random part covariates if "`rp`l''"~="" { file write `macro1' "NOTE Specify level `l' random part covariate(s)" _n forvalues e = 1/`numrpbrackets`l'' { if "`rp`l'_`e''" != "" { foreach var of local rp`l'name`e' { if ("`diagonal`l''"=="" & "`elements`l''"=="") { file write `macro1' "SETV `ll' '`var''" _n } if ("`diagonal`l''"~="") { file write `macro1' "SETE `ll' '`var'' '`var''" _n } } } } * Add/Remove terms from variance covariance matrices if "`elements`l''"~="" { local elenames :colnames `RP`l'_b' foreach p of local rp`l'pars { // for each var specified as random at level `l' if regexm("`p'", "(cov)[\(]([a-zA-Z0-9_~]+)[\\]([a-zA-Z0-9_~]+)[\)]") == 1 { local partype `=regexs(1)' local rowvar `=regexs(2)' local colvar `=regexs(3)' capture unab rowvar: `rowvar' capture unab colvar: `colvar' } if regexm("`p'", "(var)[\(]([a-zA-Z0-9_]+)[\)]") == 1 { local partype `=regexs(1)' local rowvar `=regexs(2)' local colvar `=regexs(2)' capture unab rowvar: `rowvar' capture unab colvar: `colvar' } assert inlist("`partype'","var","cov") if `:list p in elenames' { if "`mtype'" == "multivariate" { local rowvar = reverse(subinstr(reverse("`rowvar'"), "_", ".", 1)) local colvar = reverse(subinstr(reverse("`colvar'"), "_", ".", 1)) } file write `macro1' "SETE `ll' '`rowvar'' '`colvar''" _n } } } if ("`pause'"=="") file write `macro1' "PAUS 1" _n file write `macro1' _n } } * Apply random part design matrix if set forvalues l = `maxlevels'(-1)1 { if "`design`l''"~="" { file write `macro1' "NOTE Apply the design matrix for the random part at level `l'" _n foreach alphaname of local design`l' { file write `macro1' "SETD `l' '`alphaname''" _n } file write `macro1' _n } } * Need to fit the ordered model for at least two iterations before we can impose starting values //if ("`mcmc'"~="" & "`cc'" == "") | ("`inits'"~="" & ("`link'"=="ologit" | "`link'"=="oprobit" | "`link'"=="ocloglog" | "`link'"=="mlogit")) { // CMJC added check for mlogit to get model in the correct state for lowest level residuals (e.g. adds P/-P parameter which will then be removed later) if ("`mcmc'"~="" & "`cc'" == "") | ("`link'"=="ologit" | "`link'"=="oprobit" | "`link'"=="ocloglog" | "`link'"=="mlogit") { // CMJC added check for mlogit to get model in the correct state for lowest level residuals (e.g. adds P/-P parameter which will then be removed later) file write `macro1' "NOTE Fit model for two iterations to correctly setup the model (this is only required for the multilevel ordered multinomial model)" _n if "`linearization'"=="MQL1" file write `macro1' "LINE 0 1" _n if "`linearization'"=="MQL2" file write `macro1' "LINE 0 2" _n if "`linearization'"=="PQL1" file write `macro1' "LINE 1 1" _n if "`linearization'"=="PQL2" file write `macro1' "LINE 1 2" _n //file write `macro1' "MAXI 2" _n "BATCH 1" _n "STAR" _n "ITNU 0" _n(2) file write `macro1' "MAXI 2" _n "BATCH 1" _n "STAR" _n(2) // set the maximum iterations back to the default if not set if "`maxiterations'" == "" local maxiterations 20 local modelstarted 1 } * Fixed part constraint(s) if "`fpconstraints'"~="" { file write `macro1' "NOTE Specify fixed part constraint(s)" _n file write `macro1' "FCON b1001" _n forvalues r = 1/`numfpconstraints' { file write `macro1' "JOIN cb1001 `fpconstraint`r'' cb1001" _n //file write `macro1' "JOIN c1001 `fpconstraint`r'' c1001" _n } //file write `macro1' "FCON c1001" _n(2) // note that this column will not be free if multinomial or multivariate has been specified } * Random part constraint(s) if "`rpconstraints'"~="" { file write `macro1' "NOTE Specify random part constraint(s)" _n file write `macro1' "RCON b1002" _n forvalues r = 1/`numrpconstraints' { file write `macro1' "JOIN cb1002 `rpconstraint`r'' cb1002" _n //file write `macro1' "JOIN c1002 `rpconstraint`r'' c1002" _n } //file write `macro1' "RCON c1002" _n(2) // note that this column will not be free if multinomial or multivariate has been specified } } * Edit vector of initial values if "`inits'"~="" { runmlwin_setinit, fpb(`matFP_b') fpv(`matFP_V') rpb(`matRP_b') rpv(`matRP_V') initb(`matb') initv(`matV') mtype(`mtype') link(`link') mcmc(`mcmc') macro1(`macro1') } if "`inits'"~="" | "`useworksheet'" ~= "" { file write `macro1' "ESTM 2" _n // switch from coloured symbols to point estimates if ("`pause'"=="") file write `macro1' "PAUS 1" _n // update equations window file write `macro1' _n } ************************* * Fit model using (R)IGLS ************************* if "`mcmc'"=="" { // i.e. (R)IGLS if "`useworksheet'" == "" { * Specify estimation method (R)IGLS if "`rigls'"~="" { file write `macro1' "NOTE Set estimation method to be RIGLS" _n "METH 0" _n(2) } else { file write `macro1' "NOTE Set estimation method to be IGLS" _n "METH 1" _n(2) } * Specify maximum number of iterations if "`maxiterations'"~="" { file write `macro1' "NOTE Set maximum number of (R)IGLS iterations" _n "MAXI `maxiterations'" _n(2) } // Why is MQL2 the default in MLwiN for poisson models? // What about negbin is there the same problem? if "`distribution'"=="poisson" & "`linearization'"=="MQL1" file write `macro1' "NOTE Set estimation method to be MQL1" _n "LINE 0 1" _n(2) if "`linearization'"=="MQL2" file write `macro1' "NOTE Set estimation method to be MQL2" _n "LINE 0 2" _n(2) if "`linearization'"=="PQL1" file write `macro1' "NOTE Set estimation method to be PQL1" _n "LINE 1 1" _n(2) if "`linearization'"=="PQL2" file write `macro1' "NOTE Set estimation method to be PQL2" _n "LINE 1 2" _n(2) * Allow negative variances local reseton = 0 forvalues l = `maxlevels'(-1)1 { if "`reset`l''"~="" local reseton = 1 } if `reseton' == 1 { file write `macro1' "NOTE Specify element reset options for variance-covariance matrices" _n forvalues l = `maxlevels'(-1)1 { local ll = `l' if ("`mtype'"=="multivariate" | "`mtype'"=="multinomial") local ++ll if "`reset`l''"=="all" file write `macro1' "RESE `ll' 0" _n if "`reset`l''"=="variances" file write `macro1' "RESE `ll' 1" _n if "`reset`l''"=="none" file write `macro1' "RESE `ll' 2" _n } file write `macro1' "" _n } * Weights forvalues l = `maxlevels'(-1)1 { if "`weight`l''" ~= "" | "`weighttype'" ~= "" { if "`weight`l''" ~= "" { file write `macro1' "NOTE Specify sampling weights at level `l'" _n "WEIG `l' 1 '`weight`l'''" _n(2) } else { file write `macro1' "NOTE Specify equal weights at level `l'" _n "WEIG `l' 1" _n(2) } if "`weighttype'" == "standardised" { file write `macro1' "NOTE Standardised weighting" _n file write `macro1' "LINK 1 G21" _n file write `macro1' "FILL G21" _n file write `macro1' "WEIG `l' 2 G21[1]" _n file write `macro1' "LINK 0 G21" _n file write `macro1' "WEIG 2" _n(2) } if "`weighttype'" == "raw" { file write `macro1' "NOTE Raw weighting" _n // MLwiN appears to require this to be set, even if raw weights are used (I think this is a bug) file write `macro1' "LINK 1 G21" _n file write `macro1' "FILL G21" _n file write `macro1' "WEIG `l' 2 G21[1]" _n file write `macro1' "LINK 0 G21" _n file write `macro1' "WEIG 1" _n(2) } } } if "`weighttype'"~="" { // if weights have been specified if "`weighttype'"=="standardised" { file write `macro1' "NOTE Create the standardised weights" _n "WEIG" _n(2) } } if "`fpsandwich'"=="fpsandwich" | ("`weighttype'"~="" & "`fpsandwich'"==""){ file write `macro1' "NOTE Turn on sandwich estimators for the fixed part parameter standard errors" _n "FSDE 2" _n(2) } if "`rpsandwich'"=="rpsandwich" | ("`weighttype'"~="" & "`rpsandwich'"==""){ file write `macro1' "NOTE Turn on sandwich estimators for the random part parameter standard errors" _n "RSDE 2" _n(2) } } * Pause if ("`pause'"=="") { file write `macro1' "NOTE Pause the macro to allow the user to examine the model specification" _n "PAUS" _n(2) } * Fit the model file write `macro1' "NOTE Fit the model" _n if "`inits'"=="" & "`useworksheet'" == "" & "`modelstarted'" == "" file write `macro1' "STAR" _n // do one iteration as batch 1 not yet set (this is to get sensible numbers for the equations window) else { if ("`initsprevious'"~="") display as text "Model fitted using initial values specified as parameter estimates from previous model" _n if ("`initsmodel'"~="") display as text "Model fitted using initial values specified as parameter estimates from saved estimates in `initsmodel'" _n if ("`initsb'"~=""|"`initsv'"~="") display as text "Model fitted using initial values specified in matrices: " as result "`initsb' `initsv'" _n if ("`useworksheet'"~="") display as text "Model fitted using state from previously saved worksheet" _n } if ("`pause'"=="") { file write `macro1' "ESTM 2" _n // switch from coloured symbols to point estimates file write `macro1' "PAUS 1" _n // update equations window } file write `macro1' "BATC 1" _n if ("`inits'"~="" & ("`link'"=="ologit"|"`link'"=="oprobit"|"`link'"=="ocloglog")) file write `macro1' "SUMM" _n // This is a fix as the ordered model forgets its structure when initial values have been specified file write `macro1' "NEXT" _n file write `macro1' "ITNU 0 b21" _n file write `macro1' "CONV b22" _n if ("`pause'"=="") file write `macro1' "PAUS 1" _n file write `macro1' _n } ********************** * Fit model using MCMC ********************** if ("`mcmc'"~="") { // i.e. MCMC if "`useworksheet'" == "" { * Model specification: Cross-classifications file write `macro1' "NOTE Set estimation method to MCMC" _n file write `macro1' "EMODe 3" _n if ("`pause'"=="") file write `macro1' "EXPA 3" _n // Expand to show priors file write `macro1' _n * MM Weights if "`carcentre'" ~= "" file write `macro1' "CARC 1" _n forvalues l = 2/`maxlevels' { local ll = `l' if ("`mtype'"=="multivariate" | "`mtype'"=="multinomial") local ++ll if "`mmweights`l''" ~= "" { file write `macro1' "NOTE Declare weights at level `l'" _n if "`car`l''"~="" { file write `macro1' "MULM `ll' `:list sizeof mmweights`l'' '`=word("`mmweights`l''", 1)'' '`=word("`mmids`l''", 1)''" _n "CARP `ll' 1" _n } else { if "`=word("`mmids`l''", 1)'" ~= "`lev`l'id'" { display as error "The first var in mmids`l'() must match the level `l' ID specified in level`l'()." exit 198 } if "`mtype'"~="multivariate" { file write `macro1' "MULM `ll' `:list sizeof mmweights`l'' '`=word("`mmweights`l''", 1)''" _n } else { file write `macro1' "MULM `ll' `:list sizeof mmweights`l'' '`=word("`mmweights`l''", 1)'' '`=word("`mmids`l''", 1)''" _n } } } } * Cross-classified models if ("`cc'"~="") { file write `macro1' "NOTE Declare model to be a cross-classifed model and switch to classification notation" _n "XCLA 1" _n /* switch on cross-classifications */ "INDE 1" _n(2) /* switch on classification notation */ } * Define measurement error if defined if "`me'"~="" { * measurement error file write `macro1' "NOTE Specify measurement error" _n local mecols local i = 1 foreach p of local mevars { local mecols `mecols' '`p'' `:word `i' of `variances'' local ++i } file write `macro1' "MERR `:list sizeof mevars' `mecols'" _n file write `macro1' _n } * Correlated residuals if "`corresiduals'" ~= "" { file write `macro1' "NOTE Set up correlated residuals" _n //if "`corresiduals'" == "full" { // default // file write `macro1' "NOTE full covariance matrix" _n // file write `macro1' "MCCO 0" _n //} if "`corresiduals'" == "exchangeable" file write `macro1' "NOTE all correlations equal and all variances equal" _n "MCCO 1" _n if "`corresiduals'" == "areqvars" file write `macro1' "NOTE an AR1 structure with all variances equal" _n "MCCO 2" _n if "`corresiduals'" == "eqcorrsindepvars" file write `macro1' "NOTE all correlations equal but independent variances" _n "MCCO 3" _n if "`corresiduals'" == "arindepvars" file write `macro1' "NOTE an AR1 structure with independent variances" _n "MCCO 4" _n } * Use multiple subscripts notation if ("`msubscripts'"~="") { file write `macro1' "NOTE Use multiple subscripts notation" _n file write `macro1' "INDE 1" _n(2) } * Set MCMC seed file write `macro1' "NOTE Set MCMC seed" _n "MCRS `mcmc_seed'" _n(2) if "`smcmc'" ~= "" { file write `macro1' "NOTE Turn on structured MCMC" _n file write `macro1' "SMCM 1" _n(2) } if "`smvn'" ~= "" { file write `macro1' "NOTE Turn on structured MVN" _n file write `macro1' "SMVN 1" _n(2) } if "`orthogonal'" ~= "" { file write `macro1' "NOTE Turn on orthogonal parameterisation" _n file write `macro1' "ORTH 1" _n(2) } if "`hcentring'" ~= "" { file write `macro1' "NOTE Turn on hierarchical centring" _n file write `macro1' "HCEN 1 `hcentring'" _n(2) } if "`logformulation'" ~= "" { file write `macro1' "NOTE Use log formulation" _n file write `macro1' "LCLO 1" _n(2) } if `defaultprior' == 1 { file write `macro1' "NOTE Set prior distribution parameters" _n file write `macro1' "GAMP `gama' `gamb'" _n(2) } forvalues l = 2/`maxlevels' { local ll = `l' if ("`mtype'"=="multivariate" | "`mtype'"=="multinomial") local ++ll if "`parexpansion`l''" ~= "" { file write `macro1' "NOTE Turn on parameter expansion at level `l'" _n file write `macro1' "PAEX `ll' 1" _n(2) } } * Informative priors if "`priormatrix'" ~= "" { local priorcol c1092 runmlwin_writepriors, maxlevels(`maxlevels') priormat(`priormatrix') fpb(`matFP_b') rpb(`matRP_b') macro1(`macro1') priorcol(`priorcol') } * Add factors if specified local numfact = 0 local numcorr = 0 forvalues l = 1/`maxlevels' { if "`flinit`l''" ~= "" { local numfact = `numfact' + colsof(`flinit`l'') forvalues i = 1/`=colsof(`flinit`l'')' { forvalues j = 1/`=`i'-1' { if `fvinit`l''[`i',`j'] ~= . { local ++numcorr } } } } } local factstr "" forvalues l = 1/`maxlevels' { if "`flinit`l''" ~= "" { forvalues fact = 1/`=colsof(`flinit`l'')' { local factstr `factstr' `=`l'+1' forvalues resp = 1/`=rowsof(`flinit`l'')' { local factstr `factstr' `=`flinit`l''[`resp',`fact']' `=`flconstraint`l''[`resp', `fact']' } local factstr `factstr' `=`fvinit`l''[`fact', `fact']' `=`fvconstraint`l''[`fact', `fact']' } } } forvalues l = 1/`maxlevels' { if "`flinit`l''" ~= "" { forvalues fact1 = 1/`=colsof(`flinit`l'')' { forvalues fact2 = 1/`=`fact1'-1' { if `fvinit`l''[`fact1', `fact2'] ~= . { local factstr `factstr' `fact1' `fact2' `=`fvinit`l''[`fact1', `fact2']' `=`fvconstraint`l''[`fact1', `fact2']' } } } } } if "`factstr'" ~= "" { file write `macro1' "NOTE set up factors" _n file write `macro1' "FACT `nummlwineqns' `numfact' `numcorr' `factstr'" _n } local useresid "1" // Use IGLS residuals as starting values local residcol local residsecol // Simulate residuals from the covariance matrix if "`simresiduals'" ~= "" { file write `macro1' "LINK 2 G27" _n // Starting residuals columns file write `macro1' "FILL G27" _n local hasres = 0 local residcol G27[1] local residsecol G27[2] local useresid = "" forvalues l = 1/`maxlevels' { local ll = `l' if ("`mtype'"=="multivariate" | "`mtype'"=="multinomial") local ++ll file write `macro1' "LINK 1 G22" _n file write `macro1' "LINK `numresi`l'' G23" _n if "`numrp`l'pars'" ~= "" { file write `macro1' "OMEGa `ll' G22[1]" _n file write `macro1' "CALC G22[1] = HSYM(G22[1])" _n file write `macro1' "NOBS `ll' b31 b32" _n file write `macro1' "MRAN b31 G22[1] G23" _n forvalues i = 1/`numresi`l'' { if `hasres' == 0 { // remove zero that fill command has put into this column file write `macro1' "ERAS G27" _n local hasres = 1 } file write `macro1' "JOIN G27[1] G23 G27[1]" _n } } file write `macro1' "ERASe G22" _n file write `macro1' "ERASe G23" _n file write `macro1' "LINK 0 G22" _n "LINK 0 G23" _n } file write `macro1' "CALC G27[2] = G27[1] * 0" _n } if "`useresid'" ~= "" & "`cc'" == "" & (`maxlevels' > 1 | "`mtype'" == "multivariate" | ("`mtype'" == "multinomial" & "`link'"=="mlogit")){ * Calculate MCMC starting values for level `l' residuals // set up PRE and POST file if `allnormal' == 1 { file write `macro1' "PREF 0" _n file write `macro1' "POST 0" _n } else { local path `mlwinpath' local revpath `=reverse("`path'")' local revpath `=substr("`revpath'", `=strpos("`revpath'", "\")+1' , .)' local path `=reverse("`revpath'")' if "`mtype'"=="multinomial" { capture confirm file `"`path'\multicat\PRE"' if !_rc file write `macro1' "FPAT '`path'\multicat'" _n else { local revpath `=reverse("`path'")' local revpath `=substr("`revpath'", `=strpos("`revpath'", "\")+1' , .)' local path `=reverse("`revpath'")' capture confirm file `"`path'\multicat\PRE"' if !_rc file write `macro1' "FPAT '`path'\multicat'" _n } } else{ capture confirm file `"`path'\discrete\PRE"' if !_rc file write `macro1' "FPAT '`path'\discrete'" _n else { local revpath `=reverse("`path'")' local revpath `=substr("`revpath'", `=strpos("`revpath'", "\")+1' , .)' local path `=reverse("`revpath'")' capture confirm file `"`path'\discrete\PRE"' if !_rc file write `macro1' "FPAT '`path'\discrete'" _n } } file write `macro1' "PREF 'PRE'" _n file write `macro1' "POST 'POST'" _n file write `macro1' "PREF 1" _n file write `macro1' "POST 1" _n if "`mtype'" == "multinomial" { file write `macro1' "SETV 1 'bcons.1'" _n } if "`linearization'" == "PQL2" & "`maxlevels'" == "1" { forvalues lev = `maxlevels'/5 { file write `macro1' "OFFS `lev'" _n } display as error "can not apply PQL or 2nd order to single level models, switching to MQL/1" local linearization MQL1 } // NOTE at this point MLwiN sets EXTR 0, LINE 0 1 if these are not set if "`linearization'" == "" | "`linearization'" == "MQL1" file write `macro1' "LINE 0 1" _n // cmjc added for poisson if "`linearization'"=="MQL2" file write `macro1' "LINE 0 2" _n if "`linearization'"=="PQL1" file write `macro1' "LINE 1 1" _n if "`linearization'"=="PQL2" file write `macro1' "LINE 1 2" _n // Extra is not valid for MCMC estimation file write `macro1' "EXTR 0" _n // cmjc added for poisson local llev = 1 if "`mtype'"=="multivariate" | "`mtype'"=="multinomial" local ++llev forvalues lev = `llev'/`maxlevels' { file write `macro1' "OFFS `lev'" _n } if "`mtype'" ~= "multivariate" { // i.e. univariate response models local b foreach var of local rp1name { if "`var'" ~= "P" & "`var'" ~= "-P" local b `b' '`var'' } if "`distribution'" == "nbinomial" local b 'bcons.1' 'bcons2.1' else local b 'bcons.1' if `:list sizeof b' == 0 & "`mtype'" ~= "multinomial" display as error "Level 1 random structure must be specified for discrete response models" if `:list sizeof b' ~= 0 file write `macro1' "LINK `b' g9" _n if "`mtype'"=="multinomial" & ~inlist("`link'","mlogit","ologit","oprobit","ocloglog") { display as error "link function must be mlogit, ologit, oprobit or ocloglog" exit 198 } if "`mtype'"=="multinomial" { if "`link'"=="mlogit" file write `macro1' "SET b10 0" _n if "`link'"=="ologit"|"`link'"=="oprobit"|"`link'"=="ocloglog" file write `macro1' "SET b10 1" _n } else file write `macro1' "SET b10 `resptype'" _n // i.e. a univariate response which is not multinomial file write `macro1' "SET b15 1" _n file write `macro1' "SET b16 0" _n } else { // i.e. multivariate response models local b local c forvalues eq = 1/`nummlwineqns' { foreach var of local rp1name`eq' { if "`=word("`distribution'", `eq')'" ~= "normal" local b `b' '`var'' else local c `c' '`var'' } foreach var of local fpname`eq' { if "`=word("`distribution'", `eq')'" == "normal" local c `c' '`var'' } } if "`b'" == "" display as error Level 2 random structure must be specified for discrete responses" file write `macro1' "LINK `b' g9" _n file write `macro1' "SET b10 `resptype'" _n file write `macro1' "SET b15 2" _n if `mixed' == 0 file write `macro1' "SET b16 0" _n else { file write `macro1' "SET b16 1" _n file write `macro1' "LINK `c' g11" _n } } // LINK file write `macro1' "LINK -5 g19 1" _n file write `macro1' "LINK 0 g18" _n file write `macro1' "CALC g18=g19" _n file write `macro1' "ITNU 1 2" _n // Set R(IGLS) iteration to 2 so that residuals are calculated correctly } file write `macro1' "MISR 0" _n // Don't set small residuals to system missing file write `macro1' "LINK 2 G27" _n // Starting residuals columns file write `macro1' "FILL G27" _n local hasres = 0 local residcol G27[1] local residsecol G27[2] forvalues l = 1/`maxlevels' { local ll = `l' if "`mtype'"=="multivariate" | "`mtype'"=="multinomial" local ++ll local numresi = `numrp`l'vars' if "`mtype'"=="multinomial" & "`link'"=="mlogit" & `l' == 1 local numresi = `numresi' + 2 if (`numresi'>=1 & `ll' != 1) { file write `macro1' "LINK `numresi' G22" _n file write `macro1' "FILL G22" _n file write `macro1' "LINK 1 G23" _n file write `macro1' "FILL G23" _n file write `macro1' "NOTE Calculate MCMC starting values for level `l' residuals" _n file write `macro1' "RLEV `ll'" _n file write `macro1' "RFUN" _n file write `macro1' "RCOV 2" _n file write `macro1' "ROUT G22 G23" _n file write `macro1' "RESI" _n if `hasres' == 0 { // remove zero that fill command has put into this column file write `macro1' "ERAS G27" _n local hasres 1 } file write `macro1' "JOIN G27[1] G22 G27[1]" _n file write `macro1' "JOIN G27[2] G23 G27[2]" _n file write `macro1' "ERAS G22 G23" _n file write `macro1' "LINK 0 G22" _n "LINK 0 G23" _n(2) } } file write `macro1' "MISR 1" _n if `allnormal' != 1 { // UNLINK file write `macro1' "CALC g19=g18" _n file write `macro1' "ERASe g18" _n file write `macro1' "LINK 0 g18" _n } } } * Pause // AT THIS POINT THE MULTIVARIATE WISHART DATA INFORMED PRIOR FOR THE LEVEL 2 MATRIX OF A TWO-LEVEL RANDOM SLOPES MODEL HAS NOT BEEN SET if ("`pause'"=="") { file write `macro1' "NOTE Pause the macro to allow the user to examine the model specification" _n file write `macro1' "PAUS" _n(2) } * MCMC Estimation algorithm if ("`distribution'"=="normal") file write `macro1' "NOTE Fit the model in MCMC using Gibbs algorithm (response is normal)" _n // But probit is fit with GIBBS if ("`distribution'"~="normal") file write `macro1' "NOTE Fit the model in MCMC using Metropolis Hastings algorithm (response is discrete)" _n if ("`savewinbugs'"~="") { local 0 , `savewinbugs' syntax , Model(string) Inits(string) Data(string) [noFit] local 0 `inits' syntax anything(name=inits), [REPLACE] if "`replace'" == "" confirm new file "`inits'" local 0 `data' syntax anything(name=data), [REPLACE] if "`replace'" == "" confirm new file "`data'" local 0 `model' syntax anything(name=model), [REPLACE] if "`replace'" == "" confirm new file "`model'" local linkcode 0 // needs to be set (0 for logit, 1 for probit, 2 for complementary log-log and 3 for log link) if "`link'" == "logit" local linkcode 0 if "`link'" == "probit" local linkcode 1 if "`link'" == "cloglog" local linkcode 2 if "`link'" == "log" local linkcode 3 if "`mtype'" == "multivariate" local linkcode 0 if "`mcmc_modeltype'" == "5"{ display as error "WinBUGS in unable to estimate multivariate models with responses other than normal" exit 198 } file write `macro1' "BUGO 6 `mcmc_modeltype' `linkcode' `residcol' `priorcol' '`model'' '`inits'' '`data''" _n // MCMC chains } local chaincols 0 forvalues l = 1/`maxlevels' { if "`saveresiduals`l''" ~= "" local ++chaincols } if "`factstr'" ~= "" local chaincols = `chaincols' + 2 if `chaincols' > 0 file write `macro1' "LINK `chaincols' G22" _n local i = 1 forvalues l = 1/`maxlevels' { local ll = `l' if ("`mtype'"=="multivariate" | "`mtype'"=="multinomial") local ++ll if "`saveresiduals`l''" ~= "" { file write `macro1' "NOTE store residual chain for level `l'" _n file write `macro1' "NAME G22[`i'] 'RESID_CHAIN_LEVEL`l''" _n file write `macro1' "DESC G22[`i'] '\Value'" _n file write `macro1' "SMRE `ll' 'RESID_CHAIN_LEVEL`l''" _n(2) local ++i } } if "`factstr'" ~= "" { file write `macro1' "NAME G22[`i'] '_FACT_LOAD_CHAIN'" _n local ++i file write `macro1' "NAME G22[`i'] '_FACT_VAR_CHAIN'" _n local ++i file write `macro1' "SMFA 1 '_FACT_LOAD_CHAIN'" _n file write `macro1' "SMFA 2 '_FACT_VAR_CHAIN'" _n file write `macro1' "LINK 0 G22" _n(2) } if "`fit'" ~= "nofit" { if "`useworksheet'" == "" { if "`mtype'" == "multinomial" file write `macro1' "CLRV 2" _n // I'm not sure why this is needed file write `macro1' "MTOT `mcmc_chain'" _n file write `macro1' "MCMC 0 `mcmc_burnin' `mcmc_adaptation' `mcmc_scale' `mcmc_acceptance' `mcmc_tolerance' `residcol' `residsecol' `priorcol' `mcmc_femethod' `mcmc_remethod' `mcmc_levelonevarmethod' `mcmc_higherlevelsvarmethod' `mcmc_defaultprior' `mcmc_modeltype'" _n if "`residcol'" ~= "" file write `macro1' "ERAS G27" _n if "`residcol'" ~= "" file write `macro1' "LINK 0 G27" _n } local total_stored = ceil(`mcmc_chain' / `mcmc_thinning') if ("`batch'"=="") { // split MCMC chain into 50 (stored) iterations at a time then update file write `macro1' _n local curriter 0 // Unthinned iterations if "`imputeiterations'" ~= "" { local nextimpute `:word 1 of `imputeiterations'' local imputeiterations `:list imputeiterations - nextimpute' } while `curriter' + (`mcmc_refresh' * `mcmc_thinning') <= `mcmc_chain' { local curriter = `curriter' + (`mcmc_refresh' * `mcmc_thinning') if "`nextimpute'" ~= "" { local impiter = `curriter' - (`mcmc_refresh' * `mcmc_thinning') while (`nextimpute' > `curriter' - (`mcmc_refresh' * `mcmc_thinning')) & (`nextimpute' <= `curriter') { local nextstop = (`nextimpute' / `mcmc_thinning') - ceil(`impiter' / `mcmc_thinning') local impiter = `impiter' + (`nextstop' * `mcmc_thinning') file write `macro1' "MCMC 1 `nextstop' `mcmc_thinning' c1090 c1091 c1003 c1004 1 `mcmc_modeltype'" _n file write `macro1' "LINK 1 G21" _n file write `macro1' "DAMI 0 G21[1]" _n // Impute file write `macro1' "LINK `nummlwineqns' G22" _n file write `macro1' "SPLI G21[1] 'resp_indicator' G22" _n forvalues e = 1/`nummlwineqns' { file write `macro1' "NAME G22[`e'] '_mi_`response`e'''" _n } tempfile impfile //tempname fh //file open `fh' using "`impfile'", write //file close `fh' file write `macro1' "PSTA '`impfile'' '`_sortindex'' G22" _n local imputefiles `" `imputefiles' "`impfile'" "' file write `macro1' "ERAS G21 G22" _n file write `macro1' "LINK 0 G21" _n "LINK 0 G22" _n file write `macro1' "PUPN c1003 c1004" _n file write `macro1' "AVER c1091 b99 b100" _n file write `macro1' "PAUS 1" _n(2) local nextimpute `:word 1 of `imputeiterations'' local imputeiterations `:list imputeiterations - nextimpute' if "`nextimpute'" == "" continue, break } local nextstop = ceil((`curriter' - `impiter') / `mcmc_thinning') if `nextstop' ~= 0 { file write `macro1' "MCMC 1 `nextstop' `mcmc_thinning' c1090 c1091 c1003 c1004 1 `mcmc_modeltype'" _n file write `macro1' "PUPN c1003 c1004" _n "AVER c1091 b99 b100" _n "PAUS 1" _n(2) } } else { file write `macro1' "MCMC 1 `mcmc_refresh' `mcmc_thinning' c1090 c1091 c1003 c1004 1 `mcmc_modeltype'" _n file write `macro1' "PUPN c1003 c1004" _n "AVER c1091 b99 b100" _n "PAUS 1" _n(2) } } if `mcmc_chain' - `curriter' ~= 0 { local remainder = ceil((`mcmc_chain' - `curriter') / `mcmc_thinning') file write `macro1' "MCMC 1 `remainder' `mcmc_thinning' c1090 c1091 c1003 c1004 1 `mcmc_modeltype'" _n file write `macro1' "PUPN c1003 c1004" _n "AVER c1091 b99 b100" _n "PAUS 1" _n(2) } } else { if "`imputeiterations'" ~= "" { local curriter 0 // Thinned iterations while "`imputeiterations'" ~= "" { local nextimpute `:word 1 of `imputeiterations'' local imputeiterations `:list imputeiterations - nextimpute' local nextstop = (`nextimpute' / `mcmc_thinning') - `curriter' local curriter = `curriter' + `nextstop' file write `macro1' "MCMC 1 `nextstop' `mcmc_thinning' c1090 c1091 c1003 c1004 1 `mcmc_modeltype'" _n(2) file write `macro1' "LINK 1 G21" _n file write `macro1' "DAMI 0 G21[1]" _n // Impute file write `macro1' "LINK `nummlwineqns' G22" _n file write `macro1' "SPLI G21[1] 'resp_indicator' G22" _n forvalues e = 1/`nummlwineqns' { file write `macro1' "NAME G22[`e'] 'imp`response`e'''" _n } tempfile impfile //tempname fh //file open `fh' using "`impfile'", write //file close `fh' file write `macro1' "PSTA '`impfile'' '`_sortindex'' G22" _n local imputefiles `" `imputefiles' "`impfile'" "' file write `macro1' "ERAS G21 G22" _n file write `macro1' "LINK 0 G21" _n "LINK 0 G22" _n file write `macro1' "PUPN c1003 c1004" _n file write `macro1' "AVER c1091 b99 b100" _n(2) } local nextstop = `total_stored' - `curriter' if `nextstop' ~= 0 { file write `macro1' "MCMC 1 `nextstop' `mcmc_thinning' c1090 c1091 c1003 c1004 1 `mcmc_modeltype'" _n(2) file write `macro1' "PUPN c1003 c1004" _n file write `macro1' "AVER c1091 b99 b100" _n(2) } } else { file write `macro1' "MCMC 1 `total_stored' `mcmc_thinning' c1090 c1091 c1003 c1004 1 `mcmc_modeltype'" _n(2) file write `macro1' "PUPN c1003 c1004" _n file write `macro1' "AVER c1091 b99 b100" _n(2) } } if ("`pause'"=="") file write `macro1' "PAUS 1" _n(2) } } if "`fit'" ~= "nofit" { if "`imputesummaries'" ~= "" { file write `macro1' "LINK 2 G21" _n file write `macro1' "DAMI 2 G21[1] G21[2]" _n // Impute file write `macro1' "LINK `nummlwineqns' G22" _n file write `macro1' "SPLI G21[1] 'resp_indicator' G22" _n forvalues e = 1/`nummlwineqns' { file write `macro1' "NAME G22[`e'] '_simean_`response`e'''" _n } file write `macro1' "LINK `nummlwineqns' G23" _n file write `macro1' "SPLI G21[2] 'resp_indicator' G23" _n forvalues e = 1/`nummlwineqns' { file write `macro1' "NAME G23[`e'] '_sisd_`response`e'''" _n } tempfile imputesummaries //tempname fh //file open `fh' using "`imputesummaries'", write //file close `fh' file write `macro1' "PSTA '`imputesummaries'' '`_sortindex'' G22 G23" _n file write `macro1' "ERAS G21 G22 G23" _n file write `macro1' "LINK 0 G21" _n "LINK 0 G22" _n "LINK 0 G23" _n } if "`batch'" == "" { * Open the equations window if ("`pause'"=="nopause") { file write `macro1' "NOTE Open the equations window" _n file write `macro1' "WSET 15 1" _n // open the equations window to indicate that the model has finished iterating but don't display anything file write `macro1' "EXPA 3" _n file write `macro1' "ESTM 2" _n } * If any random part design matrices have been specified then open the output window and display the random part parameters if "`anydesign'"=="yes"{ file write `macro1' "WSET 20 1" _n file write `macro1' "ECHO 1" _n file write `macro1' "FIXE" _n file write `macro1' "RAND" _n file write `macro1' "ECHO 0" _n } } ******************* * Calculate Residuals ******************* forvalues l = `maxlevels'(-1)1 { if ("`residuals`l''"~=""){ tempfile residfile`l' //tempname fh //file open `fh' using "`residfile`l''", write //file close `fh' local lids forvalues lev = `maxlevels'(-1)1 { local lids `lids' lev`lev'id(`lev`lev'id') } runmlwin_calcresiduals , level(`l') levxid(`lev`l'id') numrpxvars(`numresi`l'') rpxvars(`resivars`l'') residualsx(`residuals`l'') mtype(`mtype') `residstd`l'' `residlever`l'' `residinfl`l'' `residdel`l'' `residsamp`l'' `residref`l'' `residvar`l'' `residrecode`l'' `residrpadj`l'' `residnoadj`l'' macro(`macro1') mcmc(`mcmc') residfile(`residfile`l'') cc(`cc') maxlevels(`maxlevels') mmid(`mmids`l'') `lids' } } ******************* * Calculate Factor values ******************* if `factorson' == 1 { file write `macro1' "LINK 3 G21" _n file write `macro1' "JOIN 1 G21[3] G21[3]" _n file write `macro1' "NOBS 2 b33 b34" _n file write `macro1' "DAFA G21[1] G21[2]" _n file write `macro1' "SET b35 1" _n forvalues l = 1/`maxlevels' { if ("`fscores`l''"~=""){ tempfile fscoresfile`l' //tempname fh //file open `fh' using "`fscoresfile`l''", write //file close `fh' local count = `=colsof(`flinit`l'')' * 2 file write `macro1' "LINK `count' G22" _n } local i = 1 forvalues fact = 1/`=colsof(`flinit`l'')' { { if ("`fscores`l''"~=""){ file write `macro1' "NOBS `=`l'+1' b31 b32" _n file write `macro1' "NAME G22[`i'] '`fscores`l''`fact''" _n file write `macro1' "CALC b36 = b35 + b31 - 1" _n file write `macro1' "PICK b35 b36 G21[1] G22[`i']" _n local ++i file write `macro1' "NAME G22[`i'] '`fscores`l''`fact'sd'" _n file write `macro1' "PICK b35 b36 G21[2] G22[`i']" _n local ++i } file write `macro1' "CALC b35=b35+b33" _n } if ("`fscores`l''"~=""){ file write `macro1' "GENErate 1 b31 1 G21[3]" _n file write `macro1' "NAME G21[3] '_fscoreid'" _n file write `macro1' "PSTA '`fscoresfile`l''' '_fscoreid' G22" _n file write `macro1' "ERASE '_fscoreid' G22" _n file write `macro1' "LINK 0 G22" _n } } file write `macro1' "ERASE G21" _n file write `macro1' "LINK 0 G21" _n } ********************** * Set Seed ********************** if ("`standardseed'"~="") { // Note if user does not specify seed option then seed is set to zero and runmlwin does not write the seed command to the macro // If the user specifies the seed option then runmlwin will write the seed command to the macro (unless that is if the user specifies the seed to be 0!) file write `macro1' "NOTE Set seed" _n file write `macro1' "SEED `standardseed'" _n(2) } ********************** * Simulate new response variable ********************** if ("`simulate'"~="") { tempfile simfile runmlwin_simresp, simfile(`simfile') simulate(`simulate') simfile(`simfile') macro1(`macro1') } **************** * Save the model **************** if "`saveworksheet'" ~= "" { file write `macro1' "NOTE Save the MLwiN worksheet" _n file write `macro1' "ZSAV '`saveworksheet''" _n(2) } * Pause if ("`pause'"=="") { file write `macro1' "NOTE Pause the macro to allow the user to examine the model results" _n file write `macro1' "PAUS" _n(2) } if "`saveequation'" ~= "" { file write `macro1' "NOTE Save an image of the equations window" _n file write `macro1' "WCAP 15 0 '`saveequation''" _n } } file write `macro1' "NOTE ***********************************************************************" _n(2) file close `macro1' if ("`viewmacro'"~="") view "`filemacro1'" ****************************************************************************** ****************************************************************************** * MLwiN sub macro to export model results ****************************************************************************** ****************************************************************************** // GENERATE COLUMNS TO HOLD MCMC CHAINS AND STATISTICS // MCMC chains for parameters can be stored here // MCMC chains for residuals can be stored here tempname macro2 tempfile filemacro2 qui file open `macro2' using "`filemacro2'", write replace * Export the model results and exit file write `macro2' "NOTE ***********************************************************************" _n file write `macro2' "NOTE Export the model results to Stata" _n file write `macro2' "NOTE ***********************************************************************" _n if "`fit'" ~= "nofit" { file write `macro2' "LINK 1 G30" _n * Store number of cases and number in use //file write `macro2' "NOBS 1 b31 b32" _n //file write `macro2' "EDIT 1 G30[1] b31" _n // Total Cases //file write `macro2' "EDIT 2 G30[1] b32" _n // Cases in use * Put deviance in c1300 file write `macro2' "NAME G30[1] '_Stats'" _n if ("`discrete'"=="" & "`mcmc'"=="") { //if ("`mcmc'"=="") { file write `macro2' "LIKE b100" _n file write `macro2' "EDIT 3 G30[1] b100" _n // Deviance } if ("`mcmc'"~="" & "`me'"=="" & `factorson' == 0 & ("`mtype'" ~= "multivariate" | "`discrete'" == "")) { // BDIC doesn't work for models with measurement error or mixed responses file write `macro2' "BDIC b1 b2 b3 b4" _n file write `macro2' "EDIT 3 G30[1] b1" _n // DIC file write `macro2' "EDIT 4 G30[1] b2" _n // pD - effective number of parameters file write `macro2' "EDIT 5 G30[1] b3" _n // Mean deviance Dbar file write `macro2' "EDIT 6 G30[1] b4" _n // Deviance at mean parameter values D(thetabar) } file write `macro2' "EDIT 7 G30[1] b21" _n // Number of iterations file write `macro2' "EDIT 8 G30[1] b22" _n // Converged * Store number of units in higher levels //local nextrownum = 9 //forvalues l = `maxlevels'(-1)2 { // file write `macro2' "NOBS `l' b33 b34" _n // file write `macro2' "EDIT `nextrownum' G30[1] b33" _n // Total Cases // local ++nextrownum // file write `macro2' "EDIT `nextrownum' G30[1] b34" _n // Cases in use // local ++nextrownum //} file write `macro2' "NAME c1098 '_FP_b'" _n file write `macro2' "NAME c1099 '_FP_v'" _n file write `macro2' "NAME c1096 '_RP_b'" _n file write `macro2' "NAME c1097 '_RP_v'" _n file write `macro2' "NAME c1094 '_esample'" _n file write `macro2' "SUM '_esample' b1" _n file write `macro2' "EDIT 9 G30[1] b1" _n // Number of missing rows if `factorson' == 1 { file write `macro2' "LINK 4 G29" _n file write `macro2' "NAME G29[1] '_FACT_b'" _n file write `macro2' "NAME G29[2] '_FACT_v'" _n file write `macro2' "DAFL G29[1] G29[2]" _n file write `macro2' "NAME G29[3] '_FACTVAR_b'" _n file write `macro2' "NAME G29[4] '_FACTVAR_v'" _n file write `macro2' "DAFV G29[3] G29[4]" _n } if "`savestata'" == "" { tempfile fileresults //tempname fh //file open `fh' using "`fileresults'", write //file close `fh' } else { local 0 `savestata' syntax anything(name=savestata), [REPLACE] if "`replace'" == "" confirm new file "`savestata'" local fileresults `savestata' } if `factorson' == 1 { file write `macro2' "PSTA '`fileresults'' '_FP_b' '_FP_v' '_RP_b' '_RP_v' '_Stats' '_FACT_b' '_FACT_v' '_FACTVAR_b' '_FACTVAR_v'" _n file write `macro2' "ERAS '_Stats' '_FACT_b' '_FACT_v' '_FACTVAR_b' '_FACTVAR_v'" _n file write `macro2' "LINK 0 G29" _n } else { file write `macro2' "PSTA '`fileresults'' '_FP_b' '_FP_v' '_RP_b' '_RP_v' '_Stats'" _n file write `macro2' "ERAS '_Stats'" _n } file write `macro2' "LINK 0 G30" _n tempfile fileesample runmlwin_saveesample, fileesample(`fileesample') nummlwineqns(`nummlwineqns') sortindex(`_sortindex') macro2(`macro2') if "`mcmc'" ~= "" { file write `macro2' "LINK 0 G21" _n /* Residuals */ "LINK 0 G22" _n /* Factors */ "LINK 0 G23" _n /* Factor variances */ local paramlength = colsof(`matFP_b') + colsof(`matRP_b') // numvars is 4 here //local chainlength =`mcmc_chain'/`mcmc_thinning' local chainnames `:colfullnames `matFP_b'' `:colfullnames `matRP_b'' if "`mtype'"=="multinomial" & ("`link'"=="ologit"|"`link'"=="oprobit"|"`link'"=="ocloglog") { local paramlength = `paramlength' - 1 //local tmp RP1:var(bcons_1) //display "`chainnames'" local tmp OD:bcons_1 local chainnames `:list chainnames - tmp' } // Export parameter chains file write `macro2' "NOTE export parameter chain" _n file write `macro2' "NAME c1091 'deviance'" _n file write `macro2' "NAME c1090 'mcmcchains'" _n file write `macro2' "COUNt 'deviance' b40" _n // Thinned iterations file write `macro2' "CALC b41 = b40 * `thinning'" _n // Unthinned iterations local i = 1 file write `macro2' "LINK `:list sizeof chainnames' G21" _n file write `macro2' "FILL G21" _n foreach var of local chainnames { if _caller() >= 11 { file write `macro2' "NAME G21[`i'] '`=strtoname("`var'")''" _n } else { mata: st_local("tmpname", validname("`var'")) file write `macro2' "NAME G21[`i'] '`=abbrev("`tmpname'", 32)''" _n } file write `macro2' "DESC G21[`i'] '`var''" _n local ++i } file write `macro2' "LINK 2 G25" _n file write `macro2' "NAME G25[1] 'parnum'" _n file write `macro2' "NAME G25[2] 'iteration'" _n file write `macro2' "DESC G25[2] '\Iteration'" _n file write `macro2' "LINK 0 G25" _n file write `macro2' "CODE `paramlength' 1 b40 'parnum'" _n file write `macro2' "GENE 1 b41 `thinning' 'iteration'" _n file write `macro2' "SPLIt 'mcmcchains' 'parnum' G21" _n if "`mtype'"=="multinomial" & ("`link'"=="ologit"|"`link'"=="oprobit"|"`link'"=="ocloglog") { file write `macro2' "LINK 1 G25" _n file write `macro2' "PUT b40 1 G25[1]'" _n if _caller() >= 11 { //file write `macro2' "NAME G25[1] '`=strtoname("RP1:var(bcons_1)")''" _n file write `macro2' "NAME G25[1] '`=strtoname("OD:bcons_1")''" _n } else { //mata: st_local("tmpname", validname("RP1:var(bcons_1)")) mata: st_local("tmpname", validname("OD:bcons_1")) file write `macro2' "NAME G25[1] '`tmpname''" _n } //file write `macro2' "DESC G25[1] 'RP1:var(bcons_1)'" _n file write `macro2' "DESC G25[1] 'OD:bcons_1'" _n file write `macro2' "GSET 2 G21 G25 G21" _n file write `macro2' "LINK 0 G25" _n } if `factorson' == 1 { file write `macro2' "LINK 2 G25" _n file write `macro2' "NAME G25[1] 'factnum'" _n file write `macro2' "NAME G25[2] 'factvarnum'" _n file write `macro2' "CODE `=`numfact'*`nummlwineqns'' 1 b40 'factnum'" _n file write `macro2' "CODE `=(`numfact'*(`numfact'+1))/2' 1 b40 'factvarnum'" _n file write `macro2' "LINK 0 G25" _n local count = 0 forvalues l = 1/`maxlevels' { if "`flinit`l''" ~= "" { local count = `count' + (`=colsof(`flinit`l'')' * `=rowsof(`flinit`l'')') } } file write `macro2' "LINK `count' G25" _n local i = 1 forvalues l = 1/`maxlevels' { if "`flinit`l''" ~= "" { forvalues fact = 1/`=colsof(`flinit`l'')' { forvalues resp = 1/`=rowsof(`flinit`l'')' { file write `macro2' "NAME G25[`i'] 'RP`l'FL_f`fact'_`resp''" _n file write `macro2' "DESC G25[`i'] 'RP`l'FL:f`fact'_`resp''" _n local ++i } } } } file write `macro2' "SPLIt '_FACT_LOAD_CHAIN' 'factnum' G25" _n file write `macro2' "GSET 2 G21 G25 G21" _n file write `macro2' "LINK 0 G25" _n local count = 0 local basefact = 0 forvalues l = 1/`maxlevels' { if "`flinit`l''" ~= "" { forvalues fact1 = 1/`=colsof(`flinit`l'')' { local count = `count' + `basefact' + `fact1' } local basefact = `basefact' + colsof(`flinit`l'') } } file write `macro2' "LINK `count' G25" _n local i = 1 local basefact = 0 forvalues l = 1/`maxlevels' { if "`flinit`l''" ~= "" { forvalues fact1 = 1/`=colsof(`flinit`l'')' { local i = `i' + `basefact' forvalues fact2 = 1/`fact1' { if `fact1' == `fact2' { file write `macro2' "NAME G25[`i'] 'RP`l'FV_var_f`fact1'_'" _n file write `macro2' "DESC G25[`i'] 'RP`l'FV:var(f`fact1')'" _n } else { file write `macro2' "NAME G25[`i'] 'RP`l'FV_cov_f`fact1'_f`fact2'_'" _n file write `macro2' "DESC G25[`i'] 'RP`l'FV:cov(f`fact1',f`fact2')'" _n } local ++i } } local basefact = `basefact' + colsof(`flinit`l'') } } file write `macro2' "SPLIt '_FACT_VAR_CHAIN' 'factvarnum' G25" _n file write `macro2' "GSET 2 G21 G25 G21" _n file write `macro2' "LINK 0 G25" _n file write `macro2' "ERAS 'factnum' 'factvarnum'" _n } if ("`savechains'"=="") { tempfile savechains //tempname fh //file open `fh' using "`savechains'", write //file close `fh' } file write `macro2' "PSTA '`savechains'' 'iteration' 'deviance' G21" _n file write `macro2' "ERAS 'parnum' 'iteration' G21" _n file write `macro2' "LINK 0 G21" _n // Export residual chains forvalues l = 1/`maxlevels' { if "`saveresiduals`l''" ~= "" { file write `macro2' "NOTE export residual chain for level `l'" _n local ll = `l' if ("`mtype'"=="multivariate" | "`mtype'"=="multinomial") local ++ll //local numresi = `numrp`l'vars' //if `numresi' == 0 local numresi = 1 file write `macro2' "NOBS `ll' b31 b32" _n file write `macro2' "CALC b33 = b31 * `numresi`l''" _n file write `macro2' "CALC b34 = b31 * b40" _n file write `macro2' "LINK 4 G25" _n // Generate ID column the same length as the residuals if ("`cc'"=="") { local hier forvalues lev = `l'/`maxlevels' { local hier '`lev`l'id'' `hier' } file write `macro2' "COMB `hier' G25[4]" _n file write `macro2' "TAKE G25[4] '`lev`l'id'' G25[3] G25[2]" _n file write `macro2' "ERAS G25[3] G25[4]" _n } if "`mmids`l''" ~= "" { file write `macro2' "ERAS G25[1]" _n foreach varname of varlist `mmids`l'' { file write `macro2' "APPE G25[1] '`varname'' G25[1]" _n } file write `macro2' "UNIQ G25[1] G25[2]" _n file write `macro2' "OMIT 0 G25[2] G25[2]" _n } else file write `macro2' "UNIQ '`lev`l'id'' G25[2]" _n file write `macro2' "ERAS G25[1]" _n file write `macro2' "REPE `numresi`l'' G25[2] G25[3]" _n file write `macro2' "ERAS G25[2]" _n file write `macro2' "CODE G25[3] 1 b40 G25[1]" _n file write `macro2' "ERAS G25[3]" _n // Temporary rename level ID column so there isn't a duplicate file write `macro2' "NAME '`lev`l'id'' '_`lev`l'id''" _n file write `macro2' "NAME G25[1] '`lev`l'id''" _n file write `macro2' "DESC G25[1] '\\`:variable label `lev`l'id'''" _n file write `macro2' "CODE b40 b33 1 G25[2]" _n // iteration number file write `macro2' "CALC G25[2] = ((G25[2] - 1) * `thinning') + 1" _n file write `macro2' "NAME G25[2] 'iteration'" _n file write `macro2' "DESC G25[2] '\Iteration'" _n file write `macro2' "CODE `numresi`l'' 1 b34 G25[3]" _n // residual number file write `macro2' "CALC G25[3] = G25[3] - 1" _n // Renumber to start at zero file write `macro2' "NAME G25[3] 'residual'" _n file write `macro2' "DESC G25[3] '\Residual'" _n file write `macro2' "CODE b31 `numresi`l'' b40 G25[4]" _n // id number file write `macro2' "NAME G25[4] 'idnum'" _n file write `macro2' "DESC G25[4] 'Unit number'" _n file write `macro2' "NAME 'RESID_CHAIN_LEVEL`l'' 'value'" _n file write `macro2' "PSTA '`saveresiduals`l''' 'iteration' 'residual' 'idnum' '`lev`l'id'' 'value'" _n file write `macro2' "ERAS 'iteration' 'residual' 'idnum' '`lev`l'id'' 'value'" _n file write `macro2' "LINK 0 G25" _n // Restore level ID column name file write `macro2' "NAME '_`lev`l'id'' '`lev`l'id''" _n } } } } if ("`plugin'"=="") file write `macro2' "EXIT" _n file close `macro2' * MLwiN macro (appends macro1 and macro2 together) tempname macro3 if "`savefullmacro'" ~= "" local filemacro3 `savefullmacro' else tempfile filemacro3 qui file open `macro3' using "`filemacro3'", write replace file open `macro1' using "`filemacro1'", read file open `macro2' using "`filemacro2'", read file read `macro1' temp file write `macro3' "`temp'" _n while r(eof)==0 { file read `macro1' temp file write `macro3' "`temp'" _n } file read `macro2' temp file write `macro3' "`temp'" _n while r(eof)==0 { file read `macro2' temp file write `macro3' "`temp'" _n } file close `macro1' file close `macro2' file close `macro3' if ("`viewfullmacro'"~="") view "`filemacro3'" if "`mlwin'"=="nomlwin" { di as error "The nomlwin option caused runmlwin to end prematurely" exit 198 } * Call either MLwiN.exe or MLwiN.plugin if "`plugin'"~="" quietly mlncommand OBEY '`filemacro3'' else { if "`mlwinpath'"=="" { di as error "You must specify the file address for MLwiN.exe using either:" _n(2) di as error "(1) the mlwinpath() option; for example mlwinpath(C:\Program Files\MLwiN v3.07\mlwin.exe)" _n di as error "(2) a global called MLwiN_path; for example: . global MLwiN_path C:\Program Files\MLwiN v3.07\mlwin.exe" _n(2) di as error "We recommend (2) and that the user places this global macro command in profile.do, see help profile." _n(2) di as error "IMPORTANT: Make sure that you are using the latest version of MLwiN. This is available at: https://www.bristol.ac.uk/cmm/MLwiN/index.shtml" _n exit 198 } if "`batch'" == "" quietly runmlwin_qshell "`mlwinpath'" /run "`filemacro3'" else { quietly runmlwin_qshell "`mlwinpath'" /nogui /run "`filemacro3'" display as text " --- Begin MLwiN error log --- " type `errlog' display as text " --- End MLwiN error log --- " _n } } if "`fit'" == "nofit" { di as txt "The savewinbugs nofit option caused runmlwin to end prematurely." ereturn scalar mcmcnofit = 1 exit } ****************************************************************************** * IMPORT MLWIN MODEL RESULTS BACK INTO STATA ****************************************************************************** capture use "`fileresults'", clear if _rc { if ("`pause'"=="") display as error "The model did not run properly in MLwiN. You most likely clicked the 'Abort Macro' button in MLwiN, rather than the 'Resume Macro' button." _n if ("`pause'"=="nopause") display as error "The model did not run properly in MLwiN. Re-run the model without the nopause option to debug the model in MLwiN." _n exit 198 } local missrows = _Stats[9] qui gen _FP_name = "" qui gen _RP_name = "" order _FP_name _FP_b _FP_v _RP_name _RP_b _RP_v * Check the MLwiN columns are the expected length qui sum _FP_b capture assert r(N)==colsof(`matFP_b') if _rc~=0 { di as error "runmlwin has encountered an error importing the model results from MLwiN. Check that the model has run properly in MLwiN." _n exit 198 } qui sum _RP_b capture assert r(N)==colsof(`matRP_b') if _rc~=0 { di as error "runmlwin has encountered an error importing the model results from MLwiN. Check that the model has run properly in MLwiN." _n exit 198 } * Put MLwiN values back into FP_b forvalues c = 1/`=colsof(`matFP_b')' { mat `matb'[1,`c'] = _FP_b[`c'] } local startrow = colsof(`matFP_b') * Put MLwiN values back into RP_b forvalues c = 1/`=colsof(`matRP_b')' { mat `matb'[1,`=`startrow'+`c''] = _RP_b[`c'] } if `factorson' == 1 { local startrow = `startrow' + colsof(`matRP_b') forvalues c = 1/`=`numfact'*`nummlwineqns'' { mat `matb'[1,`=`startrow'+`c''] = _FACT_b[`c'] } local i = 1 local startrow = `startrow' + `=`numfact'*`nummlwineqns'' local basefact = 0 forvalues l = 1/`maxlevels' { if "`flinit`l''" ~= "" { forvalues fact1 = 1/`=colsof(`flinit`l'')' { forvalues fact2 = 1/`fact1' { mat `matb'[1,`=`startrow'+`i''] = _FACTVAR_b[`=((`basefact'+`fact1' - 1) * `basefact'+`fact1' / 2) + `basefact'+`fact2''] local ++i } } local basefact = `basefact' + colsof(`flinit`l'') } } } * Stack b // MLwiN has precision problems with constraints so round covariance matrix to 6s.f local sf = 6 * Put MLwiN values back into FP_V local i = 1 forvalues r = 1/`=colsof(`matFP_b')' { forvalues c = 1/`r' { if ("`constraints'"=="") local val = _FP_v[`i'] else local val = round(_FP_v[`i'], 1/10^(`sf'-trunc(log10(abs(_FP_v[`i']))))) if `val' == . local val = 0 mat `matV'[`r',`c'] = `val' mat `matV'[`c',`r'] = `val' local ++i } } local startrow = colsof(`matFP_b') * Put MLwiN values back into RP_V local i = 1 forvalues r = 1/`=colsof(`matRP_b')' { forvalues c = 1/`r' { if ("`constraints'"=="") local val = _RP_v[`i'] else local val = round(_RP_v[`i'], 1/10^(`sf'-trunc(log10(abs(_RP_v[`i']))))) if `val' == . local val = 0 mat `matV'[`=`startrow'+`r'',`=`startrow'+`c''] = `val' mat `matV'[`=`startrow'+`c'',`=`startrow'+`r''] = `val' local ++i } } if `factorson' == 1 { local startrow = `startrow' + colsof(`matRP_b') forvalues c = 1/`=`numfact'*`nummlwineqns'' { mat `matV'[`=`startrow'+`c'',`=`startrow'+`c''] = (_FACT_v[`c'])^2 } local i = 1 local startrow = `startrow' + `=`numfact'*`nummlwineqns'' local basefact = 0 forvalues l = 1/`maxlevels' { if "`flinit`l''" ~= "" { forvalues fact1 = 1/`=colsof(`flinit`l'')' { forvalues fact2 = 1/`fact1' { mat `matV'[`=`startrow'+`i'',`=`startrow'+`i''] = (_FACTVAR_v[`=((`basefact'+`fact1' - 1) * `basefact'+`fact1' / 2) + `basefact'+`fact2''])^2 local ++i } } local basefact = `basefact' + colsof(`flinit`l'') } } } * Stack V * List MLwiN model results ereturn clear if ("`verbose'"~="") display "b and V matrices imported from MLwiN:" if ("`verbose'"~="") mat list `matb' if ("`verbose'"~="") mat list `matV' if "`consC'" == "" capture noisily ereturn post `matb' `matV' else capture noisily ereturn post `matb' `matV' `consC' if ("`verbose'"~="") display "ereturn error code was: " _rc if _rc { display as error "Warning - runmlwin has experienced difficulties importing the standard errors, all standard errors have been set to zero" tempname zeromat mat `zeromat' = J(rowsof(`matV'), rowsof(`matV'), 0) mat rowname `zeromat' = `:rowfullnames `matV'' mat colname `zeromat' = `:colfullnames `matV'' if "`consC'" == "" ereturn post `matb' `zeromat' else ereturn post `matb' `zeromat' `consC' } tempname rptmp mat `rptmp' = e(b) forvalues l = `maxlevels'(-1)1 { if `:list sizeof rp`l'name' > 0 { mat RP`l' = J(`:list sizeof rp`l'name', `:list sizeof rp`l'name', 0) local matnames = subinstr("`rp`l'name'", ".", "_", .) mat rownames RP`l' = `matnames' mat colnames RP`l' = `matnames' local r = 1 local c = 1 foreach row of local rp`l'name { if _caller() < 11 mata: st_local("row", validname("`row'")) foreach col of local rp`l'name { if _caller() < 11 { mata: st_local("col", validname("`col'")) } if `c' < `r' { if _caller() >= 11 { local pname RP`l':cov(`=abbrev(strtoname("`col'"),13)'\\`=abbrev(strtoname("`row'"),13)') } else { local pname RP`l':cov(`=abbrev("`col'",13)'\\`=abbrev("`row'",13)') } if `:list pname in names' { mat RP`l'[`r', `c'] = `rptmp'[1, "`pname'"] mat RP`l'[`c', `r'] = `rptmp'[1, "`pname'"] } } if `c'==`r' { if _caller() >= 11 { local pname RP`l':var(`=abbrev(strtoname("`row'"), 27)') } else { local pname RP`l':var(`=abbrev("`row'", 27)') } if `:list pname in names' mat RP`l'[`r', `c'] = `rptmp'[1, "`pname'"] } local ++c } local ++r local c = 1 } ereturn matrix RP`l' = RP`l' } } ereturn scalar numlevels = `maxlevels' ereturn scalar k_f = colsof(`matFP_b') ereturn scalar k_r = colsof(`matRP_b') ereturn scalar k = colsof(`matFP_b') + colsof(`matRP_b') ereturn local cmd runmlwin ereturn local cmdline `e(cmd)' `runmlwin_cmdline' ereturn local version `mlwinversion' ereturn scalar size = `worksize' ereturn scalar maxlevels = `toplevel' ereturn scalar columns = `numwscolumns' ereturn scalar variables = `maxexpl' if "`tempmat'" == "" ereturn scalar tempmat = 0 else ereturn scalar tempmat = 1 if ("`cc'"~="") local classtype "(cross-classified)" else local classtype "(hierarchical)" if ("`distribution'"~="multinomial") ereturn local depvars `response' if ("`distribution'"=="multinomial") ereturn local depvars :list uniq response ereturn local distribution =rtrim(ltrim("`distribution'")) ereturn local link `link' ereturn local denominators `denominator' ereturn local offsets `offset' ereturn local properties b V ereturn local method `emode' ereturn local linearization `linearization' if "`extra'" ~= "" ereturn scalar extrabinomial = 1 else ereturn scalar extrabinomial = 0 if "`mtype'" == "multinomial" { ereturn local basecategory `basecategory' ereturn local respcategories `responsecats' } if ("`e(distribution)'"=="normal") ereturn local title Normal response model `classtype' if ("`e(distribution)'"=="binomial") ereturn local title Binomial `e(link)' response model `classtype' if ("`e(distribution)'"=="multinomial" & ("`e(link)'"=="mlogit")) ereturn local title Unordered multinomial logit response model `classtype' if ("`e(distribution)'"=="multinomial" & ("`e(link)'"=="ologit")) ereturn local title Ordered multinomial logit response model `classtype' if ("`e(distribution)'"=="multinomial" & ("`e(link)'"=="oprobit")) ereturn local title Ordered multinomial probit response model `classtype' if ("`e(distribution)'"=="multinomial" & ("`e(link)'"=="ocloglog")) ereturn local title Ordered multinomial cloglog response model `classtype' if ("`e(distribution)'"=="poisson") ereturn local title Poisson response model `classtype' if ("`e(distribution)'"=="nbinomial") ereturn local title Negative binomial response model `classtype' if (wordcount("`e(distribution)'")>1) ereturn local title Multivariate response model `classtype' * Level IDs ereturn local level1var `lev1id' local ivars forvalues l = `maxlevels'(-1)2 { local ivars `ivars' `lev`l'id' } ereturn local ivars `ivars' // * Number of units at each level // if `maxlevels'>1 { // matrix N_g = J(1, `=`maxlevels'-1', .) // local nextrownum = 9 // forvalues l = `maxlevels'(-1)2 { // matrix N_g[1, `=`maxlevels' -`l'+1'] = _Stats[`nextrownum'] // local nextrownum = `nextrownum' + 2 // } // ereturn matrix N_g = N_g // } * (R)IGLS Weighting options local weightvar local weighttype forvalues l = `maxlevels'(-1)1 { if "`weight`l''" ~= "" local weightvar `weightvar' `weight`l'' else local weightvar `weightvar' . if "`weighttype`l''" ~= "" local weighttype `weighttype' `weighttype`l'' else local weighttype `weighttype' standardised } ereturn local weightvar `weightvar' ereturn local weighttype `weighttype' * Model fit //if ("`mcmc'"=="") ereturn scalar ll = -_Stats[3]/2 //if ("`mcmc'"=="") ereturn scalar deviance = _Stats[3] if ("`discrete'"=="" & "`mcmc'"=="") ereturn scalar ll = -_Stats[3]/2 if ("`discrete'"=="" & "`mcmc'"=="") ereturn scalar deviance = _Stats[3] ereturn scalar iterations = _Stats[7] if ("`mcmc'"=="") { ereturn scalar converged = (_Stats[8]==1) } * Save MCMC chains and calculate 95% credible interval and ESS and store as matrices if ("`mcmc'" ~= "") { ereturn scalar burnin = `mcmc_burnin' ereturn scalar chain = `mcmc_chain' ereturn scalar thinning = `mcmc_thinning' ereturn scalar dic = _Stats[3] // DIC ereturn scalar pd = _Stats[4] // pD - effective number of parameters ereturn scalar dbar = _Stats[5] // Dbar - Mean deviance ereturn scalar dthetabar = _Stats[6] // D(thetabar) - Deviance at mean parameter values ereturn scalar converged = 1 ereturn scalar mcmcdiagnostics = ("`diagnostics'"~="nodiagnostics") if ("`diagnostics'"~="nodiagnostics") { local chainnames `:colfullnames `matFP_b'' `:colfullnames `matRP_b'' if `factorson' == 1 { local chainnames `chainnames' `:colfullnames `mat_RP_b_fact'' `:colfullnames `mat_RP_b_factvar'' } //ereturn local parnames "`chainnames'" local temp = `:list sizeof chainnames' runmlwin_savechains, parnames(`chainnames') chainresults(`savechains') local savechainnames foreach parname of local chainnames { if _caller() >= 11 { local savechainnames `savechainnames' `=strtoname("`parname'")' } else { mata: st_local("tmpname", validname("`parname'")) local savechainnames `savechainnames' `=abbrev("`tmpname'", 32)' } } use `savechainnames' using "`savechains'", clear foreach stat in meanmcse sd mode ess lb ub rl1 rl2 bd pvalmean pvalmedian pvalmode { matrix `stat' = J(1, `temp', .) matrix colnames `stat' = `chainnames' } local acfpoints = 100 local pacfpoints = 10 local mcsepoints = 1000 local kdpoints = 1000 matrix ACF = J(`acfpoints', `=1 + `temp'', .) matrix colnames ACF = point `chainnames' tempname tmpacf matrix PACF = J(`pacfpoints', `=1 + `temp'', .) matrix colnames PACF = point `chainnames' tempname tmppacf matrix quantiles = J(9, `=1 + `temp'', .) matrix colnames quantiles = quant `chainnames' tempname tmpquantiles tempname mataMCSE mata: `mataMCSE' = J(`mcsepoints',`=1 + `temp'',.) tempname mataKD1 mata: `mataKD1' = J(`kdpoints',`temp',.) tempname mataKD2 mata: `mataKD2' = J(`kdpoints',`temp',.) local i = 1 foreach par of local savechainnames { // set posit(1) for the variance parameters local posit = 0 if regexm("`par'", "RP[0-9]+_var_([a-zA-Z0-9_]+)_") == 1 local posit = 1 quietly runmlwin_mcmcdiag `par', level(`level') thinning(`thinning') posit(`posit') acfpoints(`acfpoints') pacfpoints(`pacfpoints') mcsepoints(`mcsepoints') kernalpoints(`kdpoints') `eform' // Need to add prior option matrix meanmcse[1,`i'] = r(meanmcse) matrix sd[1,`i'] = r(sd) matrix mode[1,`i'] = r(mode) matrix ess[1,`i'] = r(ESS) matrix lb[1,`i'] = r(lb) matrix ub[1,`i'] = r(ub) matrix rl1[1,`i'] = r(RL1) matrix rl2[1,`i'] = r(RL2) matrix bd[1,`i'] = r(BD) matrix pvalmean[1,`i'] = r(pvalmean) matrix pvalmedian[1,`i'] = r(pvalmedian) matrix pvalmode[1,`i'] = r(pvalmode) matrix `tmpacf' = r(ACF) if `i' == 1 matrix ACF[1, 1] = `tmpacf'[1..., 2] matrix ACF[1, `=1 + `i''] = `tmpacf'[1..., 1] matrix `tmppacf' = r(PACF) if `i' == 1 matrix PACF[1, 1] = `tmppacf'[1..., 2] matrix PACF[1, `=1 + `i''] = `tmppacf'[1..., 1] matrix `tmpquantiles' = r(quantiles) if `i' == 1 matrix quantiles[1, 1] = `tmpquantiles'[1..., 1] matrix quantiles[1, `=1 + `i''] = `tmpquantiles'[1..., 2] if `i' == 1 mata: `mataMCSE'[1..., 1] = st_matrix("r(MCSE)")[1..., 2] mata: `mataMCSE'[1..., `=1 + `i''] = st_matrix("r(MCSE)")[1..., 1] mata: `mataKD1'[1..., `i'] = st_matrix("r(KD)")[1..., 1] mata: `mataKD2'[1..., `i'] = st_matrix("r(KD)")[1..., 2] local ++i } ereturn scalar level = `level' mata: st_matrix("MCSE", `mataMCSE') mata: mata drop `mataMCSE' matrix colnames MCSE = point `chainnames' mata: st_matrix("KD1", `mataKD1') mata: mata drop `mataKD1' matrix colnames KD1 = `chainnames' mata: st_matrix("KD2", `mataKD2') mata: mata drop `mataKD2' matrix colnames KD2 = `chainnames' ereturn local chains "runmlwin_chains" foreach stat in meanmcse sd mode ess lb ub rl1 rl2 bd pvalmean pvalmedian pvalmode { ereturn matrix `stat' = `stat' } ereturn matrix ACF = ACF ereturn matrix PACF = PACF ereturn matrix quantiles = quantiles ereturn matrix MCSE = MCSE ereturn matrix KD1 = KD1 ereturn matrix KD2 = KD2 } } * Multiple Imputation - remove _mi_ prefix from response if `:list sizeof imputefiles' ~= 0 { foreach impfile of local imputefiles { use "`impfile'", clear if _caller() >= 12 rename _mi_* * else renpfix "_mi_" quietly saveold "`impfile'", replace } } * Restore the original data set restore * Merge in esample if `missrows' > 0 { if _caller() >= 11 quietly merge m:1 `_sortindex' using "`fileesample'", assert(master match) nogenerate else { quietly merge `_sortindex' using "`fileesample'", uniqusing sort assert inlist(_merge,1,3) drop _merge } qui recode _esample (.=0) } else qui gen _esample = `touse' ereturn repost, esample(_esample) * Calculate the sample size qui count if e(sample) ereturn scalar N = r(N) * Calculate the min, mean and max number of units at each level if `maxlevels' > 1 & "`sort'" == "" { matrix N_g = J(1, `=`maxlevels'-1', .) matrix g_min = J(1, `=`maxlevels'-1', .) matrix g_avg = J(1, `=`maxlevels'-1', .) matrix g_max = J(1, `=`maxlevels'-1', .) local hier forvalues l = `maxlevels'(-1)2 { if ("`cc'"=="") local hier `hier' `lev`l'id' if ("`cc'"~="") local hier `lev`l'id' tempvar esample temp1 temp2 quietly gen `esample' = (e(sample)==1) qui bysort `hier' `esample': gen byte `temp1' = 1 if _n==1 & `esample'==1 qui bysort `hier' `esample': gen `temp2' = _N if `esample'==1 qui sum `temp2' if `temp1'==1 & `esample'==1 drop `esample' `temp1' `temp2' matrix N_g[1, `=`maxlevels' -`l'+1'] = r(N) matrix g_min[1, `=`maxlevels' -`l'+1'] = r(min) matrix g_avg[1, `=`maxlevels' -`l'+1'] = r(mean) matrix g_max[1, `=`maxlevels' -`l'+1'] = r(max) } sort `_sortindex' ereturn matrix N_g = N_g ereturn matrix g_min = g_min ereturn matrix g_avg = g_avg ereturn matrix g_max = g_max } * Merge residuals at each level into the original data set forvalues l = `maxlevels'(-1)1 { local hier forvalues t = `maxlevels'(-1)`l' { local hier `hier' `lev`t'id' } local ll = `l' if ("`mtype'"=="multivariate" | "`mtype'"=="multinomial") local ++ll if ("`residuals`l''"~="") runmlwin_mergeresiduals , numlevels(`ll') touse(`touse') hier(`hier') cc(`cc') levelid(`lev`l'id') residfile(`residfile`l'') sort(`sort') mmid(`mmids`l'') if ("`fscores`l''"~="") runmlwin_mergefscores , numlevels(`ll') touse(`touse') hier(`hier') cc(`cc') levelid(`lev`l'id') fscoresfile(`fscoresfile`l'') sort(`sort') } * Merge simulated response into the original data set if ("`simulate'"~="") runmlwin_mergesimresp, simfile(`simfile') if "`imputesummaries'" ~= "" { if _caller() >= 11 qui merge m:1 `_sortindex' using "`imputesummaries'", assert(match) nogenerate else { quietly merge `_sortindex' using "`imputesummaries'", uniqusing sort assert inlist(_merge,3) drop _merge } } * Append multiple imputed data sets if `:list sizeof imputefiles' ~= 0 { if _caller() >= 11 { mi import flongsep tmpimpfile, using(`imputefiles') id(`_sortindex') imputed(`response') clear mi convert mlong quietly mi erase tmpimpfile } else { tempvar tag gen `tag' = 1 if missing(`=subinstr("`response'"," ",",",.)') foreach resp of local response { rename `resp' `resp'_mi_m0 } local i = 1 foreach imputedfile of local imputefiles { merge `_sortindex' using `imputedfile', unique sort drop _merge foreach resp of local response { rename `resp' `resp'_mi_m`i' } local ++i } quietly reshape long `=subinstr("`response' "," ","_mi_m ",.)', i(`_sortindex') j(_mi_m) foreach resp of local response { rename `resp'_mi_m `resp' } quietly drop if `tag'~=1 & _mi_m>0 drop `tag' gen _mi_id = `_sortindex' quietly gen _mi_miss = 1 if missing(`=subinstr("`response'"," ",",",.)') unab vars : * local mivar _mi_m local vars `:list vars - mivar' local vars `vars' _mi_m order `vars' } } * Sort the data by original sort order if `: list sizeof imputefiles' ~= 0 { // Because data set has extra rows! sort `_sortindex' _mi_m quietly replace `_sortindex' = _n // :sortorder should still be okay, as the data is sorted the same as before, but expanded upwards by the imputed data sets } end ****************************************************************************** * CREATES PARAMETER NAMES FOR RP_B (I.E. SIGMA2_U0, SIGMA_U01, SIGMA2_U1, SIGMA2_E) ****************************************************************************** // Note we can't use "," in for example c(cons,standlrt). Doing so causes problems with estimates table when you try to display more than one model // The "(" and ")" will prob also be problematic // What we need is to display c(cons,standlrt) in the output window but to store the parameter with different notation without the ",", "(" and ")" // A separate problem is that instead of c(cons,standlrt) we have c(standlrt,cons) capture program drop runmlwin_rplpars program define runmlwin_rplpars, rclass if _caller() >= 12 version 12.0 if _caller() <= 9 version 9.0 syntax , RPName(string) local rplong local r = 1 local c = 1 foreach row of local rpname { if _caller() < 11 { mata: st_local("row", validname("`row'")) } foreach col of local rpname { if _caller() < 11 { mata: st_local("col", validname("`col'")) } if `c' < `r' { if _caller() >= 11 { local rplong `rplong' cov(`=abbrev(strtoname("`col'"),13)'\\`=abbrev(strtoname("`row'"),13)') // Note that `col' and `row' are deliberately the wrong way around in order to follow MLwiN convention } else { local rplong `rplong' cov(`=abbrev("`col'",13)'\\`=abbrev("`row'",13)') // Note that `col' and `row' are deliberately the wrong way around in order to follow MLwiN convention } local ++c } if `c'==`r' { if _caller() >= 11 { local rplong `rplong' var(`=abbrev(strtoname("`row'"), 27)') } else { local rplong `rplong' var(`=abbrev("`row'", 27)') } local ++c } } local ++r local c = 1 } return local rplong `rplong' end capture program drop runmlwin_saveesample program define runmlwin_saveesample if _caller() >= 12 version 12.0 if _caller() <= 9 version 9.0 syntax, FILEESAMPLE(string) NUMMLWINEQNS(string) SORTINDEX(string) MACRO2(string) local _sortindex `sortindex' tempname fh file open `fh' using "`fileesample'", write file close `fh' file write `macro2' "NOTE generate esample for Stata if there a missing values" _n file write `macro2' "SWIT b1" _n file write `macro2' "CASE 0:" _n file write `macro2' "LEAVE" _n file write `macro2' "CASE:" _n file write `macro2' "CALC '_esample' = abso('_esample' - 1)" _n // Because in MLwiN 1 = not in estimation sample if `nummlwineqns'>1 { file write `macro2' "NOTE unexpand esample for multinomial/multivariate" _n file write `macro2' "LINK 1 G21" _n file write `macro2' "COUNT '`_sortindex'' b1" _n file write `macro2' "CODE b1 `nummlwineqns' 1 G21[1]" _n file write `macro2' "MLAV G21[1] '_esample' '_esample'" _n file write `macro2' "TAKE G21[1] '_esample' G21[1] '_esample'" _n file write `macro2' "CALC '_esample' = '_esample' > 0" _n file write `macro2' "ERAS G21[1]" _n file write `macro2' "LINK 0 G21" _n } file write `macro2' "PSTA '`fileesample'' '`_sortindex'' '_esample'" _n file write `macro2' "ENDS" _n end capture program drop runmlwin_simresp program define runmlwin_simresp if _caller() >= 12 version 12.0 if _caller() <= 9 version 9.0 syntax, SIMFILE(string) SIMULATE(string) SIMFILE(string) MACRO1(string) tempname fh file open `fh' using "`simfile'", write file close `fh' file write `macro1' "NOTE Simulate new response variable" _n file write `macro1' "LINK 2 G21" _n file write `macro1' "SIMU G21[1]" _n file write `macro1' "NAME G21[1] '`simulate''" _n file write `macro1' "COUN G21[1] b30" _n file write `macro1' "GENE 1 b30 1 G21[2]" _n file write `macro1' "NAME G21[2] '_simprespid'" _n file write `macro1' "PSTA '`simfile'' '`simulate'' '_simprespid'" _n file write `macro1' "ERAS '`simulate'' '_simprespid'" _n file write `macro1' "LINK 0 G21" _n end capture program drop runmlwin_setinit program define runmlwin_setinit if _caller() >= 12 version 12.0 if _caller() <= 9 version 9.0 syntax , FPB(string) FPV(string) RPB(string) RPV(string) INITB(string) INITV(string) MTYPE(string) LINK(string) [MCMC(string)] MACRO1(string) local matFP_b `fpb' local matFP_V `fpv' local matRP_b `rpb' local matRP_V `rpv' local matb `initb' local matV `initv' tempname matINIT * Fixed part initial values file write `macro1' "NOTE Specify fixed part initial values" _n local names : colfullnames `matFP_b' local i = 1 foreach p of local names { file write `macro1' "NOTE `p'" _n mat `matINIT' = `matb'[1,"`p'"] file write `macro1' "EDIT `i' c1098 `=`matINIT'[1,1]'" _n local ++i } file write `macro1' _n * Fixed part initial values sampling (co)variances file write `macro1' "NOTE Specify fixed part initial sampling (co)variances values" _n local names : colfullnames `matFP_V' local i = 1 local e = 1 file write `macro1' "PUT `=(`=rowsof(`matFP_V')'*(`=rowsof(`matFP_V')' + 1))/2' 0 c1099" _n foreach p1 of local names { local j = 1 foreach p2 of local names { if `i' >= `j' { file write `macro1' "NOTE `p1', `p2'" _n mat `matINIT' = `matV'["`p1'","`p2'"] file write `macro1' "EDIT `e' c1099 `=`matINIT'[1,1]'" _n local ++e } local ++j } local ++i } file write `macro1' _n * Random part initial values // Need to check that the correct number of initial values have been specified // what if no random part e.g. single level logit file write `macro1' "NOTE Specify random part initial values" _n local names : colfullnames `matRP_b' local P = colsof(`matRP_b') local i = 1 foreach p of local names { if `i'<=`P' { file write `macro1' "NOTE `p'" _n mat `matINIT' = `matb'[1,"`p'"] file write `macro1' "EDIT `i' c1096 `=`matINIT'[1,1]'" _n local ++i } } //if "`mtype'"=="multinomial" & "`link'"=="mlogit" file write `macro1' "EDIT `i' c1096 1" _n file write `macro1' _n * Random part initial values standard errors // Need to check that the correct number of initial values have been specified // what if no random part e.g. single level logit file write `macro1' "NOTE Specify random part initial sampling (co)variances values" _n local names : colfullnames `matRP_V' local P = colsof(`matRP_V') if ("`mtype'"=="multinomial" & "`link'"=="mlogit") local P = `P' - 1 // Note we might have to add unordered to the if statement as I think ordered models do not have this problem local i = 1 local e = 1 file write `macro1' "PUT `=(`=rowsof(`matRP_V')'*(`=rowsof(`matRP_V')' + 1))/2' 0 c1097" _n foreach p1 of local names { local j = 1 foreach p2 of local names { if `i' >= `j' & `i'<=`P' & `j' <= `P' { file write `macro1' "NOTE `p1', `p2'" _n mat `matINIT' = `matV'["`p1'","`p2'"] file write `macro1' "EDIT `e' c1097 `=`matINIT'[1,1]'" _n local ++e } local ++j } local ++i } if "`mtype'"=="multinomial" & "`link'"=="mlogit" & "`mcmc'" ~= "" file write `macro1' "EDIT `e' c1097 0" _n end capture program drop runmlwin_writepriors program define runmlwin_writepriors if _caller() >= 12 version 12.0 if _caller() <= 9 version 9.0 syntax , MAXLevels(integer) PRIORMAT(string) FPB(string) RPB(string) MACRO1(string) PRIORCOL(string) local priormatrix `priormat' local matFP_b `fpb' local matRP_b `rpb' tempname matprior tempname matpriorSD tempname mateq if rowsof(`priormatrix')~=2 { display "The prior matrix must have two rows. The 1st row is for the means. The 2nd row is for the SDs." exit 198 } local r = 1 local names :colfullnames `matFP_b' foreach var of local names { mat `matprior' = `priormatrix'[1, "`var'"] mat `matpriorSD' = `priormatrix'[2, "`var'"] local prior = `matprior'[1,1] local priorsd = `matpriorSD'[1,1] file write `macro1' "NOTE fixed part prior for `var'" _n if `prior' ~= . { file write `macro1' "EDIT `r' `priorcol' 1" _n local ++r file write `macro1' "EDIT `r' `priorcol' `prior'" _n local ++r file write `macro1' "EDIT `r' `priorcol' `priorsd'" _n local ++r } else { file write `macro1' "EDIT `r' `priorcol' 0" _n local ++r } } forvalues l = `maxlevels'(-1)1 { local hasprior = 0 local eqnames : coleq `matRP_b' local levname "RP`l'" local match : list levname in eqnames if `l' == 1 & `match' == 0 { local levname "OD" local match : list levname in eqnames } if `match' == 1 { matrix `mateq' = `matRP_b'[1, "`levname':"] local names :colfullnames `mateq' local first = 1 foreach var of local names { mat `matprior' = `priormatrix'[1, "`var'"] mat `matpriorSD' = `priormatrix'[2, "`var'"] if (`matprior'[1,1] == . & `matpriorSD'[1,1] ~= .) | (`matprior'[1,1] ~= . & `matpriorSD'[1,1] == .) { display as error "Either both mean and SD have to be specified, nor neither" exit 198 } if `first' ~= 1 { if (`hasprior' == 1 & `matprior'[1,1] == .) | (`hasprior' == 0 & `matprior'[1,1] ~= .) { display as error "Whole matrix must be specified for random part priors" exit 198 } if `priorsd' ~= `matpriorSD'[1,1] { display as error "Inconsistent sample size" exit 198 } } else { local priorsd = `matpriorSD'[1,1] } if `matprior'[1,1] ~= . local hasprior = 1 local first = 0 } file write `macro1' "NOTE random part prior for level `l'" _n if `hasprior' == 1 { file write `macro1' "EDIT `r' `priorcol' 1" _n local ++r foreach var of local names { mat `matprior' = `priormatrix'[1, "`var'"] local prior = `matprior'[1,1] file write `macro1' "EDIT `r' `priorcol' `prior'" _n local ++r } // Check this is a positive integer if floor(`priorsd') ~= `priorsd' | `priorsd' < 0 { display as error "Sample size must be a positive integer" exit 198 } file write `macro1' "EDIT `r' `priorcol' `priorsd'" _n local ++r } else { file write `macro1' "EDIT `r' `priorcol' 0" _n local ++r } } } file write `macro1' "PRIO `priorcol'" _n end ****************************************************************************** * CALCULATE RESIDUALS IN MLWIN ****************************************************************************** capture program drop runmlwin_calcresiduals program define runmlwin_calcresiduals if _caller() >= 12 version 12.0 if _caller() <= 9 version 9.0 syntax , LEVEL(integer) LEVXID(string) NUMRPXVARS(string) RPXVARS(string) RESIDUALSX(string) MTYPE(string) [STANDardised LEVerage INFluence DELetion SAMPling REFlated VARiances noRECode RPAdjust noAdjust MCMC(string) CC(string) MMID(string) *] MACRO1(string) RESIDFile(string) MAXLEVELS(integer) local lids forvalues lev = `maxlevels'(-1)1 { local lids `lids' lev`lev'id(string) } local 0 ,`options' syntax, `lids' //if "`numrpxvars'" == "0" | "`mcmc'" ~= "" local numrpxvars "1" if "`numrpxvars'" == "0" local numrpxvars "1" file write `macro1' "NOTE Store level `level' residuals" _n if "`recode'" ~= "" { file write `macro1' "MISR 0" _n } file write `macro1' "LINK 0 G21" _n // Residual Estimates file write `macro1' "LINK 0 G22" _n // Residual Standard Errors/Variance file write `macro1' "LINK 0 G23" _n // Standardised Residual Estimates file write `macro1' "LINK 0 G24" _n // Leverage Residuals file write `macro1' "LINK 0 G25" _n // Reflated Residuals file write `macro1' "LINK 0 G26" _n // Deletion Residuals file write `macro1' "LINK 0 G27" _n // Influence Residuals file write `macro1' "LINK 0 G28" _n // Sampling Residuals file write `macro1' "LINK 0 G29" _n // Temp file write `macro1' "LINK 0 G30" _n // Temp file write `macro1' "LINK `numrpxvars' G21" _n file write `macro1' "FILL G21" _n file write `macro1' "LINK `numrpxvars' G22" _n file write `macro1' "FILL G22" _n forvalues i = 1/`numrpxvars' { * Name the columns of residual estimates file write `macro1' "NAME G21[`i'] '`residualsx'`=`i' - 1''" _n file write `macro1' "DESC G21[`i'] '`residualsx'`=`i' - 1' residual estimate'" _n } if "`variances'" == "" { forvalues i = 1/`numrpxvars' { * Name the columns of residual standard errors file write `macro1' "NAME G22[`i'] '`residualsx'`=`i' - 1'se'" _n file write `macro1' "DESC G22[`i'] '`residualsx'`=`i' - 1'se residual standard error'" _n } } else { local residual_var forvalues i = 1/`numrpxvars' { * Name the columns of residual standard errors file write `macro1' "NAME G22[`i'] '`residualsx'`=`i' - 1'var'" _n file write `macro1' "DESC G22[`i'] '`residualsx'`=`i' - 1'var residual variance'" _n } } file write `macro1' "RFUN" _n if "`variances'" == "" file write `macro1' "ROUT G21 G22" _n // Designate column c300 for residuals and column C301 for their associated variances else file write `macro1' "ROUT G21 G22" _n // Designate column c300 for residuals and column C301 for their associated variances local ll = `level' if ("`mtype'"=="multivariate" | "`mtype'"=="multinomial") local ++ll file write `macro1' "RLEV `ll'" _n // Specify the level at which variances are to be calculated file write `macro1' "RCOV 1" _n // Output residuals and their variances if "`standardised'" ~= "" | "`deletion'" ~= "" | "`leverage'" ~= ""{ // deletion requires standardised to be calculated, leverage requires standard error calculated here file write `macro1' "LINK `numrpxvars' G23" _n file write `macro1' "FILL G23" _n forvalues i = 1/`numrpxvars' { * Name the columns of standardised residual estimates file write `macro1' "NAME G23[`i'] '`residualsx'`=`i' - 1'std'" _n file write `macro1' "DESC G23[`i'] '`residualsx'`=`i' - 1'std standardised residual'" _n } file write `macro1' "RTYP 0" _n // Compute diagnostic variances if "`mcmc'" ~= "" { file write `macro1' "MCRE" _n // Save the residuals and the variances } else { file write `macro1' "RESI" _n // Save the residuals and the variances } local ccount = 1 //if "`standardised'" ~= "" { forvalues i = 1/`numrpxvars' { file write `macro1' "CALC G23[`i'] = G21[`i']/sqrt(G22[`i'])" _n // Convert the variances to standard errors } //} } // NOTE leverage depends on residuals with rtype 0 if "`leverage'" ~= "" | "`influence'" ~= "" { // influence requires leverage to be calculated file write `macro1' "LINK `numrpxvars' G24" _n file write `macro1' "FILL G24" _n forvalues i = 1/`numrpxvars' { * Name the columns of leverage residual estimates file write `macro1' "NAME G24[`i'] '`residualsx'`=`i' - 1'lev'" _n file write `macro1' "DESC G24[`i'] '`residualsx'`=`i' - 1'lev leverage residual'" _n } forvalues i = 1/`numrpxvars' { file write `macro1' "LINK 1 G30" _n file write `macro1' "OMEGa `ll' '`=word("`rpxvars'", `i')'' G30[1]" _n // retrieve variance for corresponding random parameter file write `macro1' "PICK 1 G30[1] b50" _n file write `macro1' "ERASe G30[1]" _n file write `macro1' "LINK 0 G30" _n file write `macro1' "CALC G24[`i'] = 1 - sqrt(G22[`i']) / sqrt(b50)" _n } if "`standardised'" == "" & "`deletion'" == "" { file write `macro1' "ERASE G23" _n file write `macro1' "LINK 0 G23" _n } } if "`adjust'" == "noadjust" { file write `macro1' "RTYP 4" _n // No adjustment } else if "`rpadjust'" ~= "" { file write `macro1' "RTYP 2" _n // Fixed and Random part adjustment } else { file write `macro1' "RTYP 1" _n // Fixed part adjustment } if "`mcmc'" ~= "" { file write `macro1' "MCRE" _n // Save the residuals and the variances } else { file write `macro1' "RESI" _n // Save the residuals and the variances } if "`reflated'" ~= "" { file write `macro1' "LINK `numrpxvars' G25" _n file write `macro1' "FILL G25" _n forvalues i = 1/`numrpxvars' { * Name the columns of reflated residual estimates file write `macro1' "NAME G25[`i'] '`residualsx'`=`i' - 1'ref'" _n file write `macro1' "DESC G25[`i'] '`residualsx'`=`i' - 1' reflated residual estimate'" _n } } if "`reflated'" ~= "" { file write `macro1' "REFLate G21 G25" _n } if "`variances'" == "" { forvalues i = 1/`numrpxvars' { file write `macro1' "CALC G22[`i'] = sqrt(G22[`i'])" _n // Convert the variances to standard errors } } if "`deletion'" ~= "" | "`influence'" ~= "" { // influence requires deletion to be calculated forvalues i = 1/`numrpxvars' { file write `macro1' "LINK `numrpxvars' G26" _n file write `macro1' "FILL G26" _n * Name the columns of deletion residual estimates file write `macro1' "NAME G26[`i'] '`residualsx'`=`i' - 1'del'" _n file write `macro1' "DESC G26[`i'] '`residualsx'`=`i' - 1'del deletion residual'" _n } file write `macro1' "NOBS `ll' b31 b32" _n forvalues i = 1/`numrpxvars' { file write `macro1' "CALC G26[`i'] = G23[`i'] / sqrt((b31 - 1 - G23[`i'] ^2)/(b31 - 2))" _n } if "`standardised'" == "" & "`leverage'" == ""{ file write `macro1' "ERASE G23" _n file write `macro1' "LINK 0 G23" _n } } if "`influence'" ~= "" { forvalues i = 1/`numrpxvars' { file write `macro1' "LINK `numrpxvars' G27" _n file write `macro1' "FILL G27" _n * Name the columns of influence residual estimates file write `macro1' "NAME G27[`i'] '`residualsx'`=`i' - 1'inf'" _n file write `macro1' "DESC G27[`i'] '`residualsx'`=`i' - 1'inf influence residual'" _n } forvalues i = 1/`numrpxvars' { file write `macro1' "SUM G24[`i'] b50" _n file write `macro1' "CALC G27[`i'] = G24[`i'] / b50" _n file write `macro1' "CALC G27[`i'] = sqrt(G27[`i'] / (1 - G27[`i'])) * abso(G26[`i'])" _n } if "`deletion'" == "" { file write `macro1' "ERASE G26" _n file write `macro1' "LINK 0 G26" _n } if "`leverage'" == "" { file write `macro1' "ERASE G24" _n file write `macro1' "LINK 0 G24" _n } } if "`sampling'" ~= "" { file write `macro1' "LINK `=(`numrpxvars'*(`numrpxvars'+1))/2' G28" _n local numcombs = 0 forvalues i = 1/`numrpxvars' { forvalues j = 1/`i' { local ++numcombs if `i' == `j' { file write `macro1' "NAME G28[`numcombs'] '`residualsx'`=`j'-1'var'" _n file write `macro1' "DESC G28[`numcombs'] '`residualsx'`=`j'-1'var sampling variance'" _n } else { file write `macro1' "NAME G28[`numcombs'] '`residualsx'`=`j'-1'`residualsx'`=`i'-1'cov'" _n file write `macro1' "DESC G28[`numcombs'] '`residualsx'`=`j'-1'`residualsx'`=`i'-1'cov sampling covariance'" _n } } } file write `macro1' "LINK `numrpxvars' G29" _n file write `macro1' "FILL G29" _n file write `macro1' "LINK 2 G30" _n file write `macro1' "FILL G30" _n file write `macro1' "RFUN " _n file write `macro1' "ROUT G29 G30[2]" _n file write `macro1' "RCOV 2" _n file write `macro1' "RESI" _n // NOTE: This is square rooted, as the residual covariances are sometimes negative file write `macro1' "NOBS `ll' b31 b32" _n file write `macro1' "CODE `numcombs' 1 b31 G30[1]" _n file write `macro1' "SPLIt G30[2] G30[1] G28" _n file write `macro1' "ERAS G30" _n file write `macro1' "LINK 0 G30" _n file write `macro1' "ERAS G29" _n file write `macro1' "LINK 0 G29" _n } file write `macro1' _n file write `macro1' "LINK 1 G30" _n file write `macro1' "NOBS `ll' b30 b31" _n file write `macro1' "GENE 1 b30 1 G30[1]" _n file write `macro1' "NAME G30[1] '_residualid'" _n file write `macro1' "LINK 4 G29" _n // Generate ID column the same length as the residuals if ("`cc'"=="") { local hier forvalues lev = `level'/`maxlevels' { local hier '`lev`level'id'' `hier' } file write `macro1' "COMB `hier' G29[4]" _n file write `macro1' "TAKE G29[4] '`lev`level'id'' G29[3] G29[2]" _n file write `macro1' "ERAS G29[3] G29[4]" _n } else if "`mmid'" ~= "" { file write `macro1' "ERAS G29[1]" _n foreach varname of varlist `mmid' { file write `macro1' "APPE G29[1] '`varname'' G29[1]" _n } file write `macro1' "UNIQ G29[1] G29[2]" _n file write `macro1' "OMIT 0 G29[2] G29[2]" _n } else file write `macro1' "UNIQ '`lev`level'id'' G29[2]" _n file write `macro1' "OMIT missing G29[2] G29[2]" _n // Temporary rename level ID column so there isn't a duplicate file write `macro1' "NAME '`lev`level'id'' '_`lev`level'id''" _n file write `macro1' "NAME G29[2] '`lev`level'id''" _n file write `macro1' "DESC G29[2] '\\`:variable label `lev`level'id'''" _n if ("`cc'"~="") { // Ensure the data is sorted by ID variable, as the residual ID is based on it this should already be the case file write `macro1' "SORT 1 '`lev`level'id'' '_residualid' G21 G22 G23 G24 G25 G26 G27 G28 '`lev`level'id'' '_residualid' G21 G22 G23 G24 G25 G26 G27 G28" _n } file write `macro1' "PSTA '`residfile'' '_residualid' '`lev`level'id'' G21 G22 G23 G24 G25 G26 G27 G28" _n file write `macro1' "ERAS '_residualid' G21 G22 G23 G24 G25 G26 G27 G28 G29" _n file write `macro1' "LINK 0 G21" _n file write `macro1' "LINK 0 G22" _n file write `macro1' "LINK 0 G23" _n file write `macro1' "LINK 0 G24" _n file write `macro1' "LINK 0 G25" _n file write `macro1' "LINK 0 G26" _n file write `macro1' "LINK 0 G27" _n file write `macro1' "LINK 0 G28" _n file write `macro1' "LINK 0 G29" _n // Restore level ID column name file write `macro1' "NAME '_`lev`level'id'' '`lev`level'id''" _n if "`recode'" ~= "" { file write `macro1' "MISR 1" _n } end ****************************************************************************** * MERGE THE SAVED MLWIN RESIDUALS BACK TO THE ORIGINAL STATA DATA SET ****************************************************************************** capture program drop runmlwin_mergeresiduals program define runmlwin_mergeresiduals, sortpreserve if _caller() >= 12 version 12.0 if _caller() <= 9 version 9.0 syntax , NUMLevels(int) TOUSE(string) HIER(string) [CC(string) LEVELID(string) SORT(string) MMID(string)] RESIDFile(string) if "`sort'" ~= "" & "`cc'" == "" & `numlevels' > 1 { display as error "Residuals cannot be reliably merged back when nosort is specified" exit 198 } local levXid_and_higher_levels `hier' // use this if hierarchical model local levXid `levelid' // Use this if XC model if `numlevels'==1 { // In single level models the observation/row number is the unique ID quietly gen _residualid = _n if `touse' == 1 if _caller() >= 11 { qui merge m:1 _residualid using "`residfile'", assert(master match) nogenerate noreport } else { mata: setsortorder("`residfile'", "_residualid") sort _residualid quietly merge _residualid using "`residfile'", uniqusing //sort assert inlist(_merge,1,3) drop _merge } drop _residualid } else { if ("`cc'"~="") { // cross-classified models in MCMC can have non-nested IDs in which case user must specify unique IDs //tempvar temp //gen `temp' = `levXid' //replace `temp' = `c(minfloat)' if `levXid'==. //quietly egen _residualid = group(`temp') if `touse' == 1, missing if "`mmid'" ~= "" { local mmnum 1 foreach var of varlist `mmid' { rename `levelid' _`levelid' if "`levelid'" == "`var'" { gen `levelid' = _`levelid' } else { gen `levelid' = `var' } unab oldvars: * if _caller() >= 11 { qui merge m:1 `levelid' using "`residfile'", keep(master match) nogenerate noreport } else { mata: setsortorder("`residfile'", "`levelid'") sort `levelid' quietly merge `levelid' using "`residfile'", uniqusing nokeep //sort drop _merge } drop _residualid unab allvars: * local newvars :list allvars - oldvars if _caller() >= 12 { rename (`newvars') (=_`mmnum') } else { foreach newvar of varlist `newvars' { rename `newvar' `newvar'_`mmnum' } } local ++mmnum drop `levelid' rename _`levelid' `levelid' } } else { if _caller() >= 11 { qui merge m:1 `levelid' using "`residfile'", assert(master match) nogenerate noreport } else { //mata: setsortorder("`residfile'", "`levelid'") sort `levelid' preserve use "`residfile'", clear quietly sort `levelid' // Make sure using data set is sorted quietly compress quietly save, replace restore quietly merge `levelid' using "`residfile'", uniqusing assert inlist(_merge,1,3) drop _merge } drop _residualid } } else { // hierarchical models quietly egen _residualid = group(`levXid_and_higher_levels') if `touse' == 1, missing if _caller() >= 11 { qui merge m:1 _residualid using "`residfile'", assert(master match) nogenerate noreport } else { mata: setsortorder("`residfile'", "_residualid") sort _residualid quietly merge _residualid using "`residfile'", uniqusing //sort assert inlist(_merge,1,3) drop _merge } drop _residualid } } end ****************************************************************************** * MERGE THE SAVED MLWIN FACTOR VALUES BACK TO THE ORIGINAL STATA DATA SET ****************************************************************************** capture program drop runmlwin_mergefscores program define runmlwin_mergefscores, sortpreserve if _caller() >= 12 version 12.0 if _caller() <= 9 version 9.0 syntax , NUMLevels(int) TOUSE(string) HIER(string) [CC(string) LEVELID(string) SORT(string)] FSCORESFile(string) if "`sort'" ~= "" & "`cc'" == "" & `numlevels' > 1 { display as error "Factor scores cannot be reliably merged back when nosort is specified" exit 198 } local levXid_and_higher_levels `hier' // use this if hierarchical model local levXid `levelid' // Use this if XC model if `numlevels'==1 { // In single level models the observation/row number is the unique ID quietly gen _fscoreid = _n if `touse' == 1 } else { if ("`cc'"~="") { // cross-classified models in MCMC can have non-nested IDs in which case user must specify unique IDs quietly egen _fscoreid = group(`levXid') if `touse' == 1, missing } else { // hierarchical models quietly egen _fscoreid = group(`levXid_and_higher_levels') if `touse' == 1, missing } } if _caller() >= 11 { qui merge m:1 _fscoreid using "`fscoresfile'", assert(master match) nogenerate } else { mata: setsortorder("`fscoresfile'", "_fscoreid") sort _fscoreid quietly merge _fscoreid using "`fscoresfile'", uniqusing //sort assert inlist(_merge,1,3) drop _merge } drop _fscoreid end ****************************************************************************** * MERGE THE SAVED MLWIN SIMULATED RESPONSE BACK TO THE ORIGINAL STATA DATA SET ****************************************************************************** capture program drop runmlwin_mergesimresp program define runmlwin_mergesimresp if _caller() >= 12 version 12.0 if _caller() <= 9 version 9.0 syntax , SIMFile(string) quietly gen _simprespid = _n if _caller() >= 11 { qui merge m:1 _simprespid using "`simfile'", assert(match) nogenerate } else { quietly merge _simprespid using "`simfile'", uniqusing sort assert inlist(_merge,3) drop _merge } drop _simprespid end ****************************************************************************** * SAVE THE MCMC CHAIN RESIDUALS AT EACH LEVEL TO STATA DATA SETS ****************************************************************************** capture program drop runmlwin_savechains program define runmlwin_savechains if _caller() >= 12 version 12.0 if _caller() <= 9 version 9.0 syntax , PARNames(string) CHAINResults(string) use "`chainresults'", clear local colnames foreach var of local parnames { if _caller() >= 11.1 { local colnames `colnames' `=strtoname("`var'")' } else { mata: st_local("tmpname", validname("`var'")) local colnames `colnames', "`=abbrev("`tmpname'", 32)'" } } if _caller() >= 11.1 { qui putmata runmlwin_chains = (iteration `colnames' deviance), replace } else { mata: runmlwin_chains = st_data(., ("iteration" `colnames', "deviance")) } end ****************************************************************************** * DISPLAY MODEL RESULTS ****************************************************************************** capture program drop runmlwin_display program runmlwin_display if _caller() >= 12 version 12.0 if _caller() <= 9 version 9.0 syntax [, OR IRr RRr SD CORrelations level(cilevel) CFORMAT(string) PFORMAT(string) SFORMAT(string) noHEADer noGRoup noCONTrast noFETable noRETable MOde MEdian ZRatio * ] if "`or'" ~= "" & !inlist("`e(link)'", "logit", "ologit") { display as error "Odds ratio options is only valid for univariate logit models" exit 198 } if "`rrr'" ~= "" & "`e(link)'" ~= "mlogit" { display as error "Relative-rate ratio options is only valid for univariate unordered multinomial logit models" exit 198 } local tmppois "poisson" local tmpnbin "nbinomial" local distribution `e(distribution)' if "`irr'" ~= "" & ~`:list tmppois in distribution' & ~`:list tmpnbin in distribution' { display as error "Incidence-rate ratio options is only valid for univariate poisson or negative binomial models" exit 198 } if "`mode'" ~= "" & "`median'" ~= "" { display as error "Only specify one of mode or median" exit 198 } if "`mode'" ~= "" { local esttype mode } else if "`median'" ~= "" { local esttype median } else { local esttype mean } local eform = 0 if "`or'" ~= "" | "`irr'" ~= "" | "`rrr'" ~= "" local eform = 1 * Univariate or Multinomial model local mtype univariate if "`e(distribution)'" == "multinomial" { local mtype multinomial local respcats `e(respcategories)' } local responses `e(depvars)' if `:list sizeof responses' > 1 local mtype multivariate * Check whether all the responses in a multivariate response model are normal or not local allnormal 1 local resptypes `e(distribution)' forvalues n = 1/`:list sizeof resptypes' { if "`=word("`resptypes'", `n')'" != "normal" { local allnormal 0 } } * Info required for both the FP and RP tables local multiplier = invnormal(1 - ((100 - `level')/2)/100) // returns 1.96 if 95% confidence intervals are requested local kk = length("`level'") // as in 95 is two characters but 7 is only 1 character * Numeric formatting if `"`cformat'"' == "" { local cformat `c(cformat)' } if `"`cformat'"' == "" { local cformat %9.0g } if fmtwidth(`"`cformat'"') > 9 { local cformat %9.0g display as text "note: invalid cformat(), using default" } if `"`pformat'"' == "" { local pformat `c(pformat)' } if `"`pformat'"' == "" { local pformat %5.3f } if fmtwidth(`"`pformat'"') > 5 { local pformat %5.3f display as text "note: invalid pformat(), using default" } if `"`sformat'"' == "" { local sformat `c(sformat)' } if `"`sformat'"' == "" { local sformat %8.2f } if fmtwidth(`"`sformat'"') > 8 { local sformat %8.2f display as text "note: invalid sformat(), using default" } * Header if "`header'" == "" { * Display estimation algorithm quietly runmlwin_verinfo $MLwiN_path // This may be inaccurate if the user changes version between estimation and display (or uses the plugin) display as text "MLwiN `e(version)' multilevel model" _c display _col(49) as text "Number of obs" _col(68) "=" _col(70) as result %9.0g e(N) di as txt "`e(title)'" display as text "Estimation algorithm: " as result "`e(method)'" _c if ("`e(linearization)'"~="" & "`e(method)'"~="MCMC") display as text ", " as result "`e(linearization)'" _c if "`group'" == "" { display "" * Display number of units at each level of the model hierarchy if e(numlevels)>1 { if "`e(N_g)'" == "" | "`e(g_min)'" == "" | "`e(g_avg)'" == "" | "`e(g_max)'" == "" { display as error "Grouping information is not available when nosort option is specified" } else { local ivars `e(ivars)' local levels : list uniq ivars tempname Ng min avg max mat `Ng' = e(N_g) mat `min' = e(g_min) mat `avg' = e(g_avg) mat `max' = e(g_max) di di as txt "{hline 16}{c TT}{hline 42} di as txt _col(17) "{c |}" _col(21) "No. of" _continue di as txt _col(34) "Observations per Group" di as txt _col(2) "Level Variable" _col(17) "{c |}" _continue di as txt _col(21) "Groups" _col(31) "Minimum" _continue di as txt _col(42) "Average" _col(53) "Maximum" di as txt "{hline 16}{c +}{hline 42}" local i 1 foreach k of local levels { local lev = abbrev("`k'",12) local p = 16 - length("`lev'") di as res _col(`p') "`lev'" _continue di as txt _col(17) "{c |}" _continue di as res _col(19) %8.0g `Ng'[1,`i'] _continue di as res _col(29) %9.0g `min'[1,`i'] _continue di as res _col(40) %9.1f `avg'[1,`i'] _continue di as res _col(51) %9.0g `max'[1,`i'] local ++i } di as txt "{hline 16}{c BT}{hline 42}" } } } * Weights // 1 2 3 4 5 6 7 //123456789012345678901234567890123456789012345678901234567890123456789012345678 //------------------------------------------- // | Weights // Level Variable | Variable Type //----------------+-------------------------- // Unit ID | ############ standardised //------------------------------------------- local maxlevels = e(numlevels) local hasweights = 0 forvalues l = `maxlevels'(-1)1 { if "`e(weighttype`l')'" ~= "" { local hasweights = 1 } } if "`hasweights'" == "1" { local ivars `e(ivars)' local levels : list uniq ivars di di as txt "{hline 16}{c TT}{hline 26} di as txt _col(17) "{c |}" _col(29) "Weights" di as txt _col(2) "Level Variable" _col(17) "{c |}" _col(23) "Variable" _col(40) "Type" di as txt "{hline 16}{c +}{hline 26}" forvalues l = `maxlevels'(-1)1 { if "`e(weighttype`l')'" ~= "" { if "`l'" ~= "1" { local lev = abbrev(word("`levels'", `=`l'-1') ,12) } else { local lev `e(level1var)' } local weightvar = abbrev("`e(weightvar`l')'",12) local p1 = 16 - length("`lev'") local p2 = 31 - length("`weightvar'") local p3 = 44 - length("`e(weighttype`l')'") di as res _col(`p1') "`lev'" as txt _col(17) "{c |}" as txt _col(`p2') "`weightvar'" _col(`p3') "`e(weighttype`l')'" } } di as txt "{hline 16}{c BT}{hline 26}" } * Key for the contrasts in multinomial models if "`contrast'" == "" { if "`e(distribution)'"=="multinomial" { display "" local respcategories `e(respcategories)' local basecategory `e(basecategory)' local num_respcategories = wordcount("`respcategories'") tokenize "`respcategories'" local p = length("`respcategories'") + 4 if (`p'<20) local p = 20 di as txt "{hline 13}{c TT}{hline `p'} di as txt _col(5) "Contrast" _col(14) "{c |}" /// _col(16) "Log-odds" di as txt "{hline 13}{c +}{hline 20}" * Unordered if "`e(link)'"=="mlogit" { local contrast_denom = `basecategory' local contrast_numers : list respcategories - contrast_denom forvalues contrast = 1/`=`num_respcategories' - 1' { local respcategory : word `contrast' of `contrast_numers' //= word("`contrast_numers'",`contrast') local p = 13 - length("`contrast'") di as res _col(`p') "`contrast'" as txt _col(14) "{c |}" _c di as res " `respcategory'" as txt " vs. " as res "`basecategory'" } } * Ordered if "`e(link)'"=="ologit"|"`e(link)'"=="oprobit"|"`e(link)'"=="ocloglog" { local first "" forvalues contrast = 1/`=`num_respcategories' - 1' { local first `first' `1' macro shift local rest `*' * Lowest response value is basecategory if (`basecategory'==real(word("`respcategories'",1))) { local contrast_numer `rest' local contrast_denom `first' } * Highest response value is basecategory if (`basecategory'==real(word("`respcategories'",-1))) { local contrast_numer `first' local contrast_denom `rest' } local p = 13 - length("`contrast'") di as res _col(`p') "`contrast'" as txt _col(14) "{c |}" _c di as res " `contrast_numer'" as txt " vs. " as res "`contrast_denom'" } } di as txt "{hline 13}{c BT}{hline 20}" } } * Display model fit statistics if e(method)=="IGLS" | e(method)=="RIGLS" { display "" if e(method)=="IGLS" & `allnormal'==1 { display as text "Run time (seconds)" _col(22) "= " as result %10.2f e(time) display as text "Number of iterations" _col(22) "= " as result %10.0f e(iterations) if `e(ll)' == . { display as error "Caution. MLwiN was unable to calculate the log likelihood, there may be a problem with your model" } display as text "Log likelihood" _col(22) "= " as result %10.0g e(ll) display as text "Deviance" _col(22) "= " as result %10.0g -2*e(ll) } if e(method)=="RIGLS" & `allnormal'==1 { display as text "Run time (seconds)" _col(27) "= " as result %10.2f e(time) display as text "Number of iterations" _col(27) "= " as result %10.0f e(iterations) if `e(ll)' == . { display as error "Caution. MLwiN was unable to calculate the log likelihood, there may be a problem with your model" } display as text "Log restricted-likelihood" _col(27) "= " as result %10.0g e(ll) display as text "Restricted-deviance" _col(27) "= " as result %10.0g -2*e(ll) } if `allnormal'==0 { display as text "Run time (seconds)" _col(22) "= " as result %10.2f e(time) display as text "Number of iterations" _col(22) "= " as result %10.0f e(iterations) } } if e(method)=="MCMC" { display "" display as text "Burnin" _col(28) "= " as result %10.0f e(burnin) display as text "Chain" _col(28) "= " as result %10.0f e(chain) display as text "Thinning" _col(28) "= " as result %10.0f e(thinning) display as text "Run time (seconds)" _col(28) "= " as result %10.3g e(time) display as text "Deviance (dbar)" _col(28) "= " as result %10.2f e(dbar) display as text "Deviance (thetabar)" _col(28) "= " as result %10.2f e(dthetabar) display as text "Effective no. of pars (pd)" _col(28) "= " as result %10.2f e(pd) display as text "Bayesian DIC" _col(28) "= " as result %10.2f e(dic) } } * FE table // IGLS FP // 1 2 3 4 5 6 7 //123456789012345678901234567890123456789012345678901234567890123456789012345678 //------------------------------------------------------------------------------ // normexam | Coef. Std. Err. z P>|z| [95% Conf. Interval] //-------------+---------------------------------------------------------------- // cons | ######### ######### ######## ###### ######### ######### //------------------------------------------------------------------------------ // MCMC FP // 1 2 3 4 5 6 7 //123456789012345678901234567890123456789012345678901234567890123456789012345678 //------------------------------------------------------------------------------ // normexam | Mean Std. Dev. z ESS [95% Cred. Interval] //-------------+---------------------------------------------------------------- // cons | ######### ######### ######## ###### ######### ######### //------------------------------------------------------------------------------ if "`fetable'" == "" { * Display fixed part of the model display as txt "{hline 13}{c TT}{hline 64} if ("`mtype'"=="univariate") { local p = 13 - length("`=abbrev("`e(depvars)'", 12)'") if e(method)~="MCMC" { display as txt _col(`p') "`=abbrev("`e(depvars)'", 12)'" _continue display as txt _col(14) "{c |}" _continue if "`or'" ~= "" display as txt _col(16) "Odds Ratio" _continue if "`irr'" ~= "" display as txt _col(23) "IRR" _continue if "`rrr'" ~= "" display as txt _col(23) "RRR" _continue if "`or'" == "" & "`irr'" == "" & "`rrr'" == "" display as txt _col(21) "Coef." _continue display as txt _col(29) "Std. Err." _continue display as txt _col(44) "z" _continue display as txt _col(49) "P>|z|" _continue display as txt _col(`=61 -`kk'') `"[`=strsubdp("`level'")'% Conf. Interval]"' } if e(method)=="MCMC" { display as txt _col(`p') "`=abbrev("`e(depvars)'", 12)'" _continue display as txt _col(14) "{c |}" _continue if "`or'" ~= "" display as txt _col(16) "Odds Ratio" _continue if "`irr'" ~= "" display as txt _col(23) "IRR" _continue if "`rrr'" ~= "" display as txt _col(23) "RRR" _continue if "`or'" == "" & "`irr'" == "" & "`rrr'" == "" { if "`esttype'" == "mode" { display as txt _col(21) "Mode" _continue } else if "`esttype'" == "median" { display as txt _col(19) "Median" _continue } else { display as txt _col(21) "Mean" _continue } } display as txt _col(29) "Std. Dev." _continue if "`zratio'" ~= "" { display as txt _col(44) "z" _continue display as txt _col(49) "P>|z|" _continue } else { display as txt _col(43) "ESS" _continue display as txt _col(51) "P" _continue } display as txt _col(`=61 -`kk'') `"[`=strsubdp("`level'")'% Cred. Interval]"' } } else { if e(method)~="MCMC" { display as txt _col(14) "{c |}" _continue if "`or'" ~= "" display as txt _col(16) "Odds Ratio" _continue if "`irr'" ~= "" display as txt _col(23) "IRR" _continue if "`rrr'" ~= "" display as txt _col(23) "RRR" _continue if "`or'" == "" & "`irr'" == "" & "`rrr'" == "" display as txt _col(21) "Coef." _continue display as txt _col(29) "Std. Err." _continue display as txt _col(44) "z" _continue display as txt _col(49) "P>|z|" _continue display as txt _col(`=61 -`kk'') `"[`=strsubdp("`level'")'% Conf. Interval]"' } if e(method)=="MCMC" { display as txt _col(14) "{c |}" _continue if "`or'" ~= "" display as txt _col(16) "Odds Ratio" _continue if "`irr'" ~= "" display as txt _col(23) "IRR" _continue if "`rrr'" ~= "" display as txt _col(23) "RRR" _continue if "`or'" == "" & "`irr'" == "" & "`rrr'" == "" { if "`esttype'" == "mode" { display as txt _col(21) "Mode" _continue } else if "`esttype'" == "median" { display as txt _col(19) "Median" _continue } else { display as txt _col(21) "Mean" _continue } } display as txt _col(29) "Std. Dev." _continue if "`zratio'" ~= "" { display as txt _col(44) "z" _continue display as txt _col(49) "P>|z|" _continue } else { display as txt _col(43) "ESS" _continue display as txt _col(51) "P" _continue } display as txt _col(`=61 -`kk'') `"[`=strsubdp("`level'")'% Cred. Interval]"' } } local eqlist :coleq e(b) local eqlist :list uniq eqlist local fpeqlist foreach eq of local eqlist { if (substr("`eq'",1,2)=="FP") local fpeqlist `fpeqlist' `eq' } local eqnum 0 foreach eq in `fpeqlist' { local ++eqnum display as txt "{hline 13}{c +}{hline 64}" if "`mtype'" == "multivariate" && `:list sizeof responses' >= `eqnum'{ display as res "`=word("`responses'", `eqnum')'" as txt _col(14) "{c |}" } if "`mtype'" == "multinomial" && `:list sizeof respcats' > `eqnum'{ display as res "Contrast `eqnum'" as txt _col(14) "{c |}" } local r = 1 tempname matb matV matb_eq matV_eq matrix `matb' = e(b) matrix `matV' = e(V) matrix `matb_eq' = `matb'[1, "`eq':"] matrix `matV_eq' = `matV'["`eq':", "`eq':"] if e(method)=="MCMC" & e(mcmcdiagnostics)==1 { tempname matress matrlb matrub matrmode matrmedian matp matess_eq matlb_eq matub_eq matmode_eq matmedian_eq matp_eq matrix `matress' = e(ess) matrix `matrlb' = e(lb) matrix `matrub' = e(ub) matrix `matrmode' = e(mode) matrix `matrmedian' = e(quantiles) if "`esttype'" == "mode" { matrix `matp' = e(pvalmode) } else if "`esttype'" == "median" { matrix `matp' = e(pvalmedian) } else { matrix `matp' = e(pvalmean) } matrix `matess_eq' = `matress'[1, "`eq':"] matrix `matlb_eq' = `matrlb'[1, "`eq':"] matrix `matub_eq' = `matrub'[1, "`eq':"] matrix `matmode_eq' = `matrmode'[1, "`eq':"] * NOTE: This assumes that the median is always the fifth row matrix `matmedian_eq' = `matrmedian'[5, "`eq':"] matrix `matp_eq' = `matp'[1, "`eq':"] } local names :colnames `matb_eq' tempname matest matse matess matub matlb matmode matmedian foreach par of local names { * Exponential form if `eform' == 1 { * MCMC if e(method)=="MCMC" & e(mcmcdiagnostics)==1 { tempname expchain local colnames :colfullnames e(b) mata: `expchain' = exp(runmlwin_chains[ , `=`:list posof "`eq':`par'" in colnames' + 1']) preserve drop _all label drop _all if _caller() >= 11.1 { getmata (`expchain') = `expchain' } else { mata: (void) st_addvar("double", "`expchain'") mata: st_addobs(length(`expchain')) mata: st_store(., "`expchain'", `expchain') } mata: mata drop `expchain' local posit = 0 if regexm("`par'", "(var)[\(]([a-zA-Z0-9_]+)[\)]") == 1 { local posit = 1 } quietly runmlwin_mcmcdiag `expchain', level(`level') thinning(e(thinning)) posit(`posit') `eform' mat `matest' = r(mean) mat `matse' = r(sd)*r(sd) mat `matess' = r(ESS) mat `matlb' = r(lb) mat `matub' = r(ub) mat `matmode' = r(mode) mat `matmedian' = r(quantiles) * NOTE: This assumes that the median is always the fifth row mat `matmedian' = `matmedian'[5, 2] restore } * (R)IGLS else { capture quietly nlcom (eform: exp([`eq']`par')) if !_rc { mat `matlb' = exp(`matb_eq'[1, `r'] - `multiplier'*sqrt(`matV_eq'[`r',`r'])) mat `matub' = exp(`matb_eq'[1, `r'] + `multiplier'*sqrt(`matV_eq'[`r',`r'])) mat `matest' = r(b) mat `matse' = r(V) mat `matest' = `matest'[1,1] mat `matse' = `matse'[1,1] } else { mat `matest' = J(1, 1, .) mat `matse' = J(1, 1, .) mat `matlb' = J(1, 1, .) mat `matub' = J(1, 1, .) } } } * Original estimation metric else { matrix `matest' = `matb_eq'[1, `r'] matrix `matse' = `matV_eq'[`r',`r'] matrix `matlb' = `matest'[1, 1] - `multiplier'*sqrt(`matse'[1, 1]) matrix `matub' = `matest'[1, 1] + `multiplier'*sqrt(`matse'[1, 1]) * MCMC if e(method)=="MCMC" & e(mcmcdiagnostics)==1 { if e(level) == `level' { mat `matess' = `matess_eq'[1, `r'] mat `matlb' = `matlb_eq'[1, `r'] mat `matub' = `matub_eq'[1, `r'] mat `matmode' = `matmode_eq'[1, `r'] mat `matmedian' = `matmedian_eq'[1, `r'] } else { tempname estchain local colnames :colfullnames e(b) mata: `estchain' = runmlwin_chains[ , `=`:list posof "`eq':`par'" in colnames' + 1'] preserve drop _all label drop _all if _caller() >= 11.1 { getmata (`estchain') = `estchain' } else { mata: (void) st_addvar("double", "`estchain'") mata: st_addobs(length(`estchain')) mata: st_store(., "`estchain'", `estchain') } mata: mata drop `estchain' local posit = 0 if regexm("`par'", "(var)[\(]([a-zA-Z0-9_]+)[\)]") == 1 { local posit = 1 } quietly runmlwin_mcmcdiag `estchain', level(`level') thinning(e(thinning)) posit(`posit') `eform' mat `matlb' = r(lb) mat `matub' = r(ub) restore } } } local varname `=abbrev("`par'", 12)' local k = length("`varname'") local p = 13 - `k' if e(method)~="MCMC" { display as txt _col(`p') "`varname'" _continue display as txt _col(14) "{c |}" _continue display as res _col(17) `cformat' `matest'[1, 1] _continue display as res _col(28) `cformat' sqrt(`matse'[1, 1]) _continue display as res _col(36) `sformat' `matb_eq'[1, `r']/sqrt(`matV_eq'[`r',`r']) _continue display as res _col(49) `pformat' 2*normal(-abs(`matb_eq'[1, `r']/sqrt(`matV_eq'[`r',`r']))) _continue display as res _col(58) `cformat' `matlb'[1, 1] _continue display as res _col(70) `cformat' `matub'[1, 1] local ++r } if e(method)=="MCMC" { display as txt _col(`p') "`varname'" _continue display as txt _col(14) "{c |}" _continue if "`esttype'" == "mode" { display as res _col(17) `cformat' `matmode'[1, 1] _continue } else if "`esttype'" == "median" { display as res _col(17) `cformat' `matmedian'[1, 1] _continue } else { display as res _col(17) `cformat' `matest'[1, 1] _continue } display as res _col(28) `cformat' sqrt(`matse'[1, 1]) _continue if "`zratio'" == "" { if e(mcmcdiagnostics)==1 { display as res _col(36) %9.0f `matess'[1, 1] _continue display as res _col(49) `pformat' `matp_eq'[1, `r'] _continue } } else { display as res _col(36) `sformat' `matb_eq'[1, `r']/sqrt(`matV_eq'[`r',`r']) _continue display as res _col(49) `pformat' 2*normal(-abs(`matb_eq'[1, `r']/sqrt(`matV_eq'[`r',`r']))) _continue } if e(mcmcdiagnostics)==1 { display as res _col(58) `cformat' `matlb'[1, 1] _continue display as res _col(70) `cformat' `matub'[1, 1] _continue } display local ++r } } } display as txt "{hline 13}{c BT}{hline 64}" display "" } * RE Table // IGLS RP // 1 2 3 4 5 6 7 //123456789012345678901234567890123456789012345678901234567890123456789012345678 //------------------------------------------------------------------------------ // Random-effects Parameters | Estimate Std. Err. [95% Conf. Interval] //-----------------------------+------------------------------------------------ //Level 1: | // var(cons) | ######### ######### ######### ######### //------------------------------------------------------------------------------ // // MCMC RP // 1 2 3 4 5 6 7 //123456789012345678901234567890123456789012345678901234567890123456789012345678 //------------------------------------------------------------------------------ // Random-effects Parameters | Mean Std. Dev. ESS [95% Cred. Int.] //-----------------------------+------------------------------------------------ //Level 1: | // var(cons) | ######### ######### ###### ######### ######### //------------------------------------------------------------------------------ if "`retable'" == "" { * Display random part of the model // Need to allow the display at level 1 if we allow for extra binomial variation //if ~(`e(numlevels)'==1 & ~regexm("`e(distribution)'","normal")==1) { //if regexm("`e(distribution)'","normal")==1 | regexm("`e(distribution)'","nbinomial")==1 | `e(extrabinomial)' == 1 { local eqlist :coleq e(b) local eqlist :list uniq eqlist * Random part design * Change display order so parameter estimates are reported at their appropriate level local ordlist local i = 1 local maxlevels = e(numlevels) forvalues l = `maxlevels'(-1)1 { if `:list posof "RP`l'" in eqlist' > 0 { local ordlist `ordlist' RP`l' local ordlist`i'des Level `l': `e(level`l')' if `l' == 1 { local ordlist`i'des `ordlist`i'des' `e(level1var)' } else { local levnames `e(ivars)' local namepos = `:list sizeof levnames' - `=`l' - 2' local ordlist`i'des `ordlist`i'des' `:word `namepos' of `e(ivars)'' } local ++i } //if `:list posof "OD" in eqlist' > 0 { // local ordlist `ordlist' OD // local ordlist`i'des Overdispersion Parameters // local ++i //} if `:list posof "RP`l'D" in eqlist' > 0 { local ordlist `ordlist' RP`l'D local ordlist`i'des Level `l': `e(level`l')' (Design) local ++i } if `:list posof "RP`l'FL" in eqlist' > 0 { local ordlist `ordlist' RP`l'FL local ordlist`i'des Level `l' factors: local ++i } if `:list posof "RP`l'FV" in eqlist' > 0 { local ordlist `ordlist' RP`l'FV local ordlist`i'des Level `l' factor covariances: local ++i } } local i = 1 local iLAST = wordcount("`ordlist'") // Here we want to display the random part only if variables have been specified if `:list sizeof ordlist' > 0 { //if ~(`i'==`iLAST' & regexm("`e(distribution)'","normal")==0) { //if `:list sizeof ordlist' > 1 { // | regexm("`e(distribution)'","normal")==1 | regexm("`e(distribution)'","nbinomial")==1 | "`e(extrabinomial)'" == "1" { display as txt "{hline 29}{c TT}{hline 48}" if e(method)~="MCMC" { display as txt _col(4) "Random-effects Parameters" _continue display as txt _col(30) "{c |}" _continue display as txt _col(34) "Estimate" _continue display as txt _col(45) "Std. Err." _continue display as txt _col(`=61 -`kk'') `"[`=strsubdp("`level'")'% Conf. Interval]"' } if e(method)=="MCMC" { display as txt _col(4) "Random-effects Parameters" _continue display as txt _col(30) "{c |}" _continue if "`esttype'" == "mode" { display as txt _col(36) "Mode" _continue } else if "`esttype'" == "median" { display as txt _col(34) "Median" _continue } else { display as txt _col(36) "Mean" _continue } display as txt _col(43) "Std. Dev." _continue display as txt _col(55) "ESS" _continue display as txt _col(`=65 -`kk'') `"[`=strsubdp("`level'")'% Cred. Int]"' } foreach eq in `ordlist' { //if "`eq'"~="RP1" | wordcount("`e(distribution)'") ~= 1 | "`e(distribution)'"=="normal" | "`e(extrabinomial)'" == "1" { //if "`eq'"~="RP1" | regexm("`e(distribution)'","normal")==1 | regexm("`e(distribution)'","nbinomial")==1 | "`e(extrabinomial)'" == "1" { local r = 1 display as txt "{hline 29}{c +}{hline 48}" display as res "`ordlist`i'des'" _continue display as txt _col(30) "{c |}" tempname matb matv matb_eq matV_eq matrix `matb' = e(b) matrix `matV' = e(V) matrix `matb_eq' = `matb'[1, "`eq':"] matrix `matV_eq' = `matV'["`eq':", "`eq':"] if e(method)=="MCMC" & e(mcmcdiagnostics)==1 { tempname matress matrlb matrub matrmode matrmedian matess_eq matlb_eq matub_eq matmode_eq matmedian_eq matrix `matress' = e(ess) matrix `matrlb' = e(lb) matrix `matrub' = e(ub) matrix `matrmode' = e(mode) matrix `matrmedian' = e(quantiles) matrix `matess_eq' = `matress'[1, "`eq':"] matrix `matlb_eq' = `matrlb'[1, "`eq':"] matrix `matub_eq' = `matrub'[1, "`eq':"] matrix `matmode_eq' = `matrmode'[1, "`eq':"] * NOTE: This assumes that the median is always the fifth row matrix `matmedian_eq' = `matrmedian'[5, "`eq':"] } tempname matest matse matess matlb matub matmode matmedian local names :colnames `matb_eq' foreach par of local names { // Don't display when constrained to one //if "`eq'" == "RP1" & "`e(distribution)'"~="normal" & "`par'" == "var(bcons_1)" & "`e(extrabinomial)'" == "0" { // local ++r // continue //} local partype if regexm("`par'", "(var)[\(]([a-zA-Z0-9_]+)[\)]") == 1 { local partype `=regexs(1)' local par1 `=regexs(2)' local par2 `=regexs(2)' } if regexm("`par'", "(cov)[\(]([a-zA-Z0-9_~]+)[\\]([a-zA-Z0-9_~]+)[\)]") == 1 { local partype `=regexs(1)' local par1 `=regexs(2)' local par2 `=regexs(3)' } * SD specified and parameter is a variance if "`sd'" ~= "" & "`partype'" == "var" { * MCMC if e(method)=="MCMC" & e(mcmcdiagnostics)==1 { tempname sdchain local colnames :colfullnames e(b) mata: `sdchain' = sqrt(runmlwin_chains[ , `=`:list posof "`eq':`par'" in colnames' + 1']) preserve drop _all label drop _all if _caller() >= 11.1 { getmata (`sdchain') = `sdchain' } else { mata: (void) st_addvar("double", "`sdchain'") mata: st_addobs(length(`sdchain')) mata: st_store(., "`sdchain'", `sdchain') } mata: mata drop `sdchain' quietly runmlwin_mcmcdiag `sdchain', level(`level') thinning(e(thinning)) posit(1) `eform' mat `matest' = r(mean) mat `matse' = r(sd)*r(sd) mat `matess' = r(ESS) mat `matlb' = r(lb) mat `matub' = r(ub) mat `matmode' = r(mode) mat `matmedian' = r(quantiles) * NOTE: This assumes that the median is always the fifth row mat `matmedian' = `matmedian'[5, 2] restore } * (R)IGLS else { capture quietly nlcom (sd: sqrt([`eq']`par')) if !_rc { mat `matlb' = sqrt(`matb_eq'[1, `r'] - `multiplier'*sqrt(`matV_eq'[`r',`r'])) mat `matub' = sqrt(`matb_eq'[1, `r'] + `multiplier'*sqrt(`matV_eq'[`r',`r'])) mat `matest' = r(b) mat `matse' = r(V) mat `matest' = `matest'[1,1] mat `matse' = `matse'[1,1] } else { mat `matest' = J(1, 1, .) mat `matse' = J(1, 1, .) mat `matlb' = J(1, 1, .) mat `matub' = J(1, 1, .) } } local par sd(`=abbrev("`par1'", 24)') } * CORR specified and parameter is a covariance else if "`correlations'" ~= "" & "`partype'" == "cov" { // Search for corresponding variances local possnames :colnames `matb_eq' local posspar1 local posspar2 foreach poss of local possnames { if regexm("`poss'", "(var)[\(]([a-zA-Z0-9_]+)[\)]") == 1 { local poss `=regexs(2)' if "`=abbrev("`poss'", 12)'" == "`par1'" local posspar1 `posspar1' "`poss'" if "`=abbrev("`poss'", 12)'" == "`par2'" local posspar2 `posspar2' "`poss'" } } if `:list sizeof posspar1' != 1 | `:list sizeof posspar2' != 1 { display as error "Unable to identify unique variance parameters for `par'. Don't use the corr option." exit 198 } else { local par1 `posspar1' local par2 `posspar2' } * MCMC if e(method)=="MCMC" & e(mcmcdiagnostics)==1 { // Recalculate correlations from chain (There is an argument that the estimates and covariance should always be estimated from chains on display too, otherwise there is potential for wasted calculations) tempname corrchain local colnames :colfullnames e(b) mata: `corrchain' = runmlwin_chains[ , `=`:list posof "`eq':`par'" in colnames' + 1'] :/ sqrt(runmlwin_chains[ , `=`:list posof "`eq':var(`=abbrev("`par1'", 24)')" in colnames' + 1'] :* runmlwin_chains[ , `=`:list posof "`eq':var(`=abbrev("`par2'", 24)')" in colnames' + 1']) preserve drop _all label drop _all if _caller() >= 11.1 { getmata (`corrchain') = `corrchain' } else { mata: (void) st_addvar("double", "`corrchain'") mata: st_addobs(length(`corrchain')) mata: st_store(., "`corrchain'", `corrchain') } mata: mata drop `corrchain' quietly runmlwin_mcmcdiag `corrchain', level(`level') thinning(e(thinning)) posit(0) `eform' mat `matest' = r(mean) mat `matse' = r(sd)*r(sd) mat `matess' = r(ESS) mat `matlb' = r(lb) mat `matub' = r(ub) mat `matmode' = r(mode) mat `matmedian' = r(quantiles) * NOTE: This assumes that the median is always the fifth row mat `matmedian' = `matmedian'[5, 2] restore } * (R)IGLS else { capture quietly nlcom (corr: [`eq']`par' / sqrt([`eq']var(`=abbrev("`par1'", 24)') * [`eq']var(`=abbrev("`par2'", 24)'))) if !_rc { mat `matest' = r(b) mat `matse' = r(V) mat `matest' = `matest'[1,1] mat `matse' = `matse'[1,1] mat `matlb' = `matest'[1, 1] - `multiplier'*sqrt(`matse'[1, 1]) // This is correct! This is what xtmixed does when reporting covariance parameters (as opposed to the default of correlation parameters) mat `matub' = `matest'[1, 1] + `multiplier'*sqrt(`matse'[1, 1]) // So we can't simply transform the lb and up of the correlation parameter on the original estimation metric because the correlation is a non-linear combination of several other parameters. } else { mat `matest' = J(1, 1, .) mat `matse' = J(1, 1, .) mat `matlb' = J(1, 1, .) mat `matub' = J(1, 1, .) } } local par corr(`=abbrev("`par1'", 12)',`=abbrev("`par2'", 12)') } * All other cases else { if "`partype'" == "var" { local par var(`=abbrev("`par1'", 24)') } if "`partype'" == "cov" { local par cov(`=abbrev("`par1'", 12)',`=abbrev("`par2'", 12)') } mat `matest' = `matb_eq'[1, `r'] mat `matse' = `matV_eq'[`r',`r'] mat `matlb' = `matest'[1, 1] - `multiplier'*sqrt(`matse'[1, 1]) mat `matub' = `matest'[1, 1] + `multiplier'*sqrt(`matse'[1, 1]) if e(method)=="MCMC" & e(mcmcdiagnostics)==1 { mat `matess' = `matess_eq'[1, `r'] mat `matmode' = `matmode_eq'[1, `r'] mat `matmedian' = `matmedian_eq'[1, `r'] if e(level) == `level' { mat `matlb' = `matlb_eq'[1, `r'] mat `matub' = `matub_eq'[1, `r'] } else { tempname estchain local colnames :colfullnames e(b) mata: `estchain' = runmlwin_chains[ , `=`:list posof "`eq':`par'" in colnames' + 1'] preserve drop _all label drop _all if _caller() >= 11.1 { getmata (`estchain') = `estchain' } else { mata: (void) st_addvar("double", "`estchain'") mata: st_addobs(length(`estchain')) mata: st_store(., "`estchain'", `estchain') } mata: mata drop `estchain' local posit = 0 if "`partype'" == "var" { local posit = 1 } quietly runmlwin_mcmcdiag `estchain', level(`level') thinning(e(thinning)) posit(`posit') `eform' mat `matlb' = r(lb) mat `matub' = r(ub) restore } } } local k = length("`par'") local p = 29 - `k' if e(method)~="MCMC" { display as txt _col(`p') "`par'" _continue display as txt _col(30) "{c |}" _continue display as res _col(33) `cformat' `matest'[1, 1] _continue display as res _col(44) `cformat' sqrt(`matse'[1,1]) _continue display as res _col(58) `cformat' `matlb'[1, 1] _continue display as res _col(70) `cformat' `matub'[1, 1] local ++r } if e(method)=="MCMC" { display as txt _col(`p') "`par'" _continue display as txt _col(30) "{c |}" _continue if "`esttype'" == "mode" { display as res _col(32) `cformat' `matmode'[1, 1] _continue } else if "`esttype'" == "median" { display as res _col(32) `cformat' `matmedian'[1, 1] _continue } else { display as res _col(32) `cformat' `matest'[1, 1] _continue } display as res _col(42) `cformat' sqrt(`matse'[1, 1]) _continue if e(mcmcdiagnostics)==1 { display as res _col(52) %6.0f `matess'[1, 1] _continue display as res _col(60) `cformat' `matlb'[1, 1] _continue display as res _col(70) `cformat' `matub'[1, 1] _continue } display local ++r } } local ++i //} } * Horizontal line display as txt "{hline 29}{c BT}{hline 48} } //} //} } local eqlist :coleq e(b) local eqlist :list uniq eqlist if `:list posof "OD" in eqlist' > 0 & ("`e(extrabinomial)'" == "1" | "`e(distribution)'" == "nbinomial") { tempname matodb_eq tempname matodV_eq matrix `matodb_eq' = `matb'[1, "OD:"] matrix `matodV_eq' = `matV'["OD:", "OD:"] if e(method)=="MCMC" & e(mcmcdiagnostics)==1 { tempname matress matrlb matrub matrmode matrmedian matodess_eq matodlb_eq matodub_eq matodmode_eq matodmedian_eq matrix `matress' = e(ess) matrix `matrlb' = e(lb) matrix `matrub' = e(ub) matrix `matrmode' = e(mode) matrix `matrmedian' = e(quantiles) matrix `matodess_eq' = `matress'[1, "OD:"] matrix `matodlb_eq' = `matrlb'[1, "OD:"] matrix `matodub_eq' = `matrub'[1, "OD:"] matrix `matodmode_eq' = `matrmode'[1, "OD:"] * NOTE: This assumes that the median is always the fifth row matrix `matodmedian_eq' = `matrmedian'[5, "OD:"] } local names :colnames `matodb_eq' display as txt "{hline 29}{c TT}{hline 48}" if e(method)~="MCMC" { display as txt _col(4) "Overdispersion Parameters" _continue display as txt _col(30) "{c |}" _continue display as txt _col(34) "Estimate" _continue display as txt _col(45) "Std. Err." _continue display as txt _col(`=61 -`kk'') `"[`=strsubdp("`level'")'% Conf. Interval]"' } if e(method)=="MCMC" { display as txt _col(4) "Overdispersion Parameters" _continue display as txt _col(30) "{c |}" _continue if "`esttype'" == "mode" { display as txt _col(36) "Mode" _continue } else if "`esttype'" == "median" { display as txt _col(34) "Median" _continue } else { display as txt _col(36) "Mean" _continue } display as txt _col(43) "Std. Dev." _continue display as txt _col(55) "ESS" _continue display as txt _col(`=65 -`kk'') `"[`=strsubdp("`level'")'% Cred. Int]"' } * Horizontal line display as txt "{hline 29}{c +}{hline 48} local r = 1 foreach par of local names { if "`r'" == "1" && "`e(distribution)'" == "nbinomial" && "`e(extrabinomial)'" == "0" { local ++r continue } mat `matest' = `matodb_eq'[1, `r'] mat `matse' = `matodV_eq'[`r',`r'] mat `matlb' = `matest'[1, 1] - `multiplier'*sqrt(`matse'[1, 1]) mat `matub' = `matest'[1, 1] + `multiplier'*sqrt(`matse'[1, 1]) if e(method)=="MCMC" & e(mcmcdiagnostics)==1 { mat `matess' = `matodess_eq'[1, `r'] mat `matmode' = `matodmode_eq'[1, `r'] mat `matmedian' = `matodmedian_eq'[1, `r'] if e(level) == `level' { mat `matlb' = `matodlb_eq'[1, `r'] mat `matub' = `matodub_eq'[1, `r'] } else { tempname estchain local colnames :colfullnames e(b) mata: `estchain' = runmlwin_chains[ , `=`:list posof "`eq':`par'" in colnames' + 1'] preserve drop _all label drop _all if _caller() >= 11.1 { getmata (`estchain') = `estchain' } else { mata: (void) st_addvar("double", "`estchain'") mata: st_addobs(length(`estchain')) mata: st_store(., "`estchain'", `estchain') } mata: mata drop `estchain' local posit = 0 if "`partype'" == "var" { local posit = 1 } quietly runmlwin_mcmcdiag `estchain', level(`level') thinning(e(thinning)) posit(`posit') `eform' mat `matlb' = r(lb) mat `matub' = r(ub) restore } } local k = length("`par'") local p = 29 - `k' if e(method)~="MCMC" { display as txt _col(`p') "`par'" _continue display as txt _col(30) "{c |}" _continue display as res _col(33) `cformat' `matest'[1, 1] _continue display as res _col(44) `cformat' sqrt(`matse'[1,1]) _continue display as res _col(58) `cformat' `matlb'[1, 1] _continue display as res _col(70) `cformat' `matub'[1, 1] local ++r } if e(method)=="MCMC" { display as txt _col(`p') "`par'" _continue display as txt _col(30) "{c |}" _continue if "`esttype'" == "mode" { display as res _col(32) `cformat' `matmode'[1, 1] _continue } else if "`esttype'" == "median" { display as res _col(32) `cformat' `matmedian'[1, 1] _continue } else { display as res _col(32) `cformat' `matest'[1, 1] _continue } display as res _col(42) `cformat' sqrt(`matse'[1, 1]) _continue if e(mcmcdiagnostics)==1 { display as res _col(52) %6.0f `matess'[1, 1] _continue display as res _col(60) `cformat' `matlb'[1, 1] _continue display as res _col(70) `cformat' `matub'[1, 1] _continue } display local ++r } } * Horizontal line display as txt "{hline 29}{c BT}{hline 48} } * Notes if e(method)=="IGLS" & e(converged)==0 display _n as error "WARNING: IGLS algorithm failed to converge. Increase the number of iterations. See the maxiterations() option." if e(method)=="RIGLS" & e(converged)==0 display _n as error "WARNING: RIGLS algorithm failed to converge. Increase the number of iterations. See the maxiterations() option." end mata: void copymatrix(string scalar srcmat, string scalar srcrowidxmat, string scalar srccolidxmat, string scalar destmat, string scalar destrowidxmat, string scalar destcolidxmat) { real colvector srcrowidx; real colvector srccolidx; real colvector destrowidx; real colvector destcolidx; real matrix temp; src = st_matrix(srcmat); srcrowidx = st_matrix(srcrowidxmat); srccolidx = st_matrix(srccolidxmat); destrowidx = st_matrix(destrowidxmat); destcolidx = st_matrix(destcolidxmat); temp = st_matrix(destmat); temp[destrowidx, destcolidx] = src[srcrowidx, srccolidx]; _editmissing(temp, 0); st_replacematrix(destmat, temp); } void checkmm(string scalar mmids, string scalar mmweights) { real matrix idmat; real matrix weightmat; real scalar i; real scalar j; if (callersversion() >= 11) { st_view(idmat, ., mmids); st_view(weightmat, ., mmweights); } else { st_view(idmat, ., tokens(mmids)); st_view(weightmat, ., tokens(mmweights)); } for (i = 1; i <= rows(idmat); i++) { for (j = 1; j <= cols(idmat); j++) { if (idmat[i, j] != 0 && weightmat[i, j] == 0) { errprintf("Error, the MM ID variable %g for observation %g is present but a zero MM weight has been specified for it\n", j, i); exit(198); } if (idmat[i, j] == 0 && weightmat[i, j] != 0) { errprintf("Error, the MM ID variable %g for observation %g is absent but a positive MM weight has been specified for it\n", j, i); exit(198); } for (k = 1; k < j; k++) { if (idmat[i, j] == idmat[i, k] & idmat[i, j] != 0 ) { errprintf("Error, the MM ID variable %g for observation %g is duplicated in ID variable %g\n", j, i, k); exit(198) } } } } } string scalar validname(string scalar name) { real rowvector codes; real rowvector valid; codes = ascii(name); if (codes[1] >=48 && codes[1] <= 57) { codes = 95,codes; } valid = ((codes:<65 :| codes:>90) :& (codes:<97 :| codes:>122) :& (codes:<48 :| codes:>57)) for (i = 1; i <= length(codes); i++) { if (valid[i] == 1) { codes[i] = 95; } } // The following code would truncate to 32 characters /* if (length(codes) > 32) { codes = codes[|1\32|]; } */ name = char(codes); return(name); } void setsortorder(string scalar filename, string scalar sortorder) { string rowvector order; colvector C; real scalar fh; real scalar ver; real scalar byteorder; real scalar filetype; real scalar reserved; real scalar nvar; real scalar nobs; real scalar varlablen; real scalar colnamelen; real scalar recsize; real scalar fmtlen; string scalar data_label; string scalar time_stamp; real matrix typlist; string matrix varlist; real matrix srtlist; order = tokens(sortorder); if (length(order) ~= length(uniqrows(order))) { printf("variables in sort order are not unique"); exit(error(198)); } C = bufio() fh = fopen(filename, "rw"); ver = fbufget(C, fh, "%1bu"); byteorder = fbufget(C, fh, "%1bu"); filetype = fbufget(C, fh, "%1bu"); reserved = fbufget(C, fh, "%1bu"); bufbyteorder(C, byteorder); if (filetype != 1) { display("Invalid file"); exit(); } nvar = fbufget(C, fh, "%2bu"); nobs = fbufget(C, fh, "%4bu"); if (ver == 105) { varlablen = 32; colnamelen = 9; recsize = 16; fmtlen = 12; } else if (ver == 108) { varlablen = 81; colnamelen = 9; recsize = 16; fmtlen = 12; } else if (ver == 110 || ver == 111 || ver == 113) { varlablen = 81; colnamelen = 33; recsize = 32; fmtlen = 12; } else if (ver == 114 || ver == 115) { varlablen = 81; colnamelen = 33; recsize = 32; fmtlen = 49; } else { printf("unrecognised version: %f", ver); exit(error(198)); } data_label = fbufget(C, fh, "%" + strofreal(varlablen) + "s"); time_stamp = fbufget(C, fh, "%18s"); typlist = J(1, nvar, .); for (i = 1; i <= nvar; i++) { typlist[1, i] = fbufget(C, fh, "%1bu"); } varlist = J(1, nvar, ""); for (i = 1; i <= nvar; i++) { varlist[1, i] = fbufget(C, fh, "%" + strofreal(colnamelen) + "s"); } srtlist = J(1, nvar + 1, 0); for (i = 1; i <= length(order); i++) { found = 0; for (j = 1; j <= nvar; j++) { if (order[i] == varlist[1, j]) { found = 1; srtlist[1, i] = j break; } } if (found == 0) { printf("variable %s not found", order[i]); exit(error(198)); } } for (i = 1; i <= nvar + 1; i++) { fbufput(C, fh, "%2bu", srtlist[1, i]); } fclose(fh); } end ****************************************************************************** exit