*! version 2.6, 9 Oct 2003, DGC
program define tdt, rclass
  version 7.0
  syntax varlist(min=2 max=2) [iweight/] [, /*
               */ Ped(varname) Id(varname) Mother(varname) Father(varname) /*
               */ Sex(varname) AFfect(varname) ACode(numlist) EMin(real 5) /*
               */ MOrigin POrigin PACode(numlist) MAle FEmale noWARN /*
               */ ROBust CLuster(string) ]
  preserve
  tempfile idord
  tempvar o1 o2 m1 m2 f1 f2 tid mid fid w sw mg fg o12 o21 inf use wt psel last
  tempvar chwt anum score var parent homoz
  if "`acode'"=="" {
    local acode 2
  }
  local origin "`porigin'`morigin'"
  if "`cluster'"!="" {
    local robust "robust"
  }
  if "`robust'"!="" {
    if "`cluster'"=="" {
      local cl "n"
    }
    else {
      local cl = substr("`cluster'", 1, 1)
    }
    if "`cl'"!="n" & "`cl'"!="p" & "`cl'"!="t" {
      di in red "Invalid cluster() option"
    }
  }
  if ("`porigin'"!="") & ("`morigin'"!="") {
    di in red "morigin and porigin options cannot be used together"
    exit
  }
  if ("`male'"!="") & ("`female'"!="") {
    di "male and female options cannot be used together"
    exit
  }
  di
  di "Analysis of"  _continue
  if "`morigin'"!="" {
    di " maternal"  _continue
  }
  if "`porigin'"!="" {
    di " paternal" _continue
  }
  di " transmissions to" _continue
  if "`male'"!="" {
    di " male" _continue
  }
  if "`female'"!="" {
    di " female" _continue
  }
  di " offspring with disease status codes `acode'"
  if "`pacode'"!="" {
    di "(restricted to transmissions from parents" _continue
    di " with disease status codes `pacode')"
  }
  if "`weight'" != "" {
    di "Weights will be used: `exp'"
    gen `wt' = `exp'
  }
  else {
    gen `wt' = 1
  }

  tokenize  `varlist'
  local v1 "`1'"
  local v2 "`2'"
  unab vars : _all
  tokenize `vars'
  if "`ped'"=="" {
    local ped "`1'"
  }
  if "`ped'"=="" {
    local ped "`1'"
  }
  if "`id'"=="" {
    local id "`2'"
  }
  if "`mother'"=="" {
    local mother "`4'"
  }
  if "`father'"=="" {
    local father "`3'"
  }
  if "`sex'"=="" {
    local sex "`5'"
  }
  if "`affect'"=="" {
    local affect "`6'"
  }

  keep `ped' `id' `mother' `father' `sex' `affect' `varlist' `wt'
  sort `ped' `id'
  quietly {
    if "`pacode'"!="" {
      gen `psel' = `affect'
      recode `psel' `pacode' = 1 * = 0
    }
    else {
      gen byte `psel' = 1
    }
    recode `affect' `acode' = 1 * = 0
    save "`idord'"
    gen byte `use' = (`affect' & `mother'!=. & `father'!=. /*
              */ & `v1'!=. & `v2'!=.)
    if "`male'"!="" {
      replace `use' = 0 if `sex'!=1
    }
    if "`female'"!="" {
      replace `use' = 0 if `sex'!=2
    }
    keep if `use'
    drop `affect' `psel' `use'
    rename `wt'  `chwt'
  }
  local naff = _N
  di
  di "Total number of genotyped affected offspring = `naff'"
  if "`weight'"!="" {
    quietly count if `chwt'==0
    local zerowt = r(N)
    if `zerowt'>0 {
      di "`zerowt' have zero weights"
      /* quietly drop if `chwt'==0 */
    }
  }
  quietly {
    rename `v1' `o1'
    rename `v2' `o2'
    rename `id' `tid'
    rename `mother' `mid'
    rename `father' `fid'

    rename `mid' `id'
    sort `ped' `id'
    merge `ped' `id' using "`idord'"
    drop if _merge==2
    drop _merge `mother' `father'
    rename `id' `mid'
    rename `v1' `m1'
    rename `v2' `m2'
    if "`porigin'"=="" {
      gen byte _PS_1 = `psel'
    }
    else {
      gen byte _PS_1 = 0
    }
    drop `psel'

    rename `fid' `id'
    sort `ped' `id'
    merge `ped' `id' using "`idord'", update
    drop if _merge==2
    drop _merge `mother' `father'
    rename `v1' `f1'
    rename `v2' `f2'
    if "`morigin'"=="" {
      gen byte _PS_3 = `psel'
    }
    else {
      gen byte _PS_3 = 0
    }
    drop `psel'

    rename `id' `father'
    rename `mid' `mother'
    rename `tid' `id'

    gen byte `mg' = (`m1'!=.) & (`m2'!=.)
    gen byte `fg' = (`f1'!=.) & (`f2'!=.)
    gen byte `o12' = ((!`mg')|`o1'==`m1'|`o1'==`m2') & /*
      */ ((!`fg')|`o2'==`f1'|`o2'==`f2')
    gen byte `o21' = ((!`mg')|`o2'==`m1'|`o2'==`m2') & /*
      */ ((!`fg')|`o1'==`f1'|`o1'==`f2')
    count if (!`o12')&(!`o21')
  }
  if r(N)>0 {
    if "`warn'"=="" {
      di
      di "Warning " r(N) " offspring with genotyping errors or ex-paternity :"
      list `ped' `id' if (!`o12')&(!`o21'), noobs
      di
    }
    quietly drop if (!`o12')&(!`o21')
  }
  if "`origin'"=="" {
    gen byte `inf' = ((`o12'&!`o21')|(`o21'&!`o12')|(`mg'&`fg'))
  }
  else {
    gen byte `inf' = ((`o12'&!`o21')|(`o21'&!`o12')|(`mg'&`fg'&(`o1'==`o2')))
  }
  quietly keep if `inf'
  gen byte `sw' = `o21'&!`o12'
  gen `w' = `o1'
  quietly replace `o1' = `o2' if `sw'
  quietly replace `o2' = `w' if `sw'
  quietly drop `w' `sw' `o12' `o21' `mg' `fg' `inf'
  /* PA, PT transmission of maternal Codes (1&2) or paternal Codes(3&4) */
  gen byte _PT_1 = (`o1'==`m1')
  rename `m1' Allele1
  gen byte _PT_2 = (`o1'==`m2')
  rename `m2' Allele2
  gen byte _PT_3 = (`o2'==`f1')
  rename `f1' Allele3
  gen byte _PT_4 = (`o2'==`f2')
  rename `f2' Allele4
  quietly {
    drop `o1' `o2'
    replace _PS_1 = 0 if (Allele1==Allele2)
    replace _PS_3 = 0 if (Allele3==Allele4)
    gen byte _PS_2 = _PS_1
    gen byte _PS_4 = _PS_3
    reshape long Allele _PT_ _PS_, i(`ped' `id') j(_PC_)
    gen byte `parent' = cond(_PC_ < 3, 1, 2)
    drop if Allele==. | !_PS_
    drop _PS_
  }
  if _N==0 {
    di "No informative transmissions"
    exit
  }

  /* Find and save allele value label and numeric codes,
     Merge infrequent alleles */

  quietly {
    summarize Allele, meanonly
    local allmiss = r(max) + 1
    di "`allmiss'"
    sort Allele
    by Allele: gen byte `last' = (_n==_N)
    local allab : value label Allele
    if "`allab'"=="" {
      local allab  _Allele
      label define `allab', modify
    }
    label define `allab' `allmiss' "Others", add
    tempfile labsave
    label save `allab' using "`labsave'"
    by Allele: gen E =  _N/2
  }
  quietly count if `last' & E<`emin'
  if r(N)>0 {
    if "`warn'"=="" {
      di
      di "There are alleles with expected transmission frequencies < " `emin'
    }
    local ezero 0
    local thresh 0
    while `ezero'<`emin' {
      quietly summarize E if `last' & E>`thresh'
      if r(N)==0 {
        di in red "Minimum number of expected transmissions cannot be achieved"
        exit
      }
      local thresh = r(min)
      local ezero = `ezero' + `thresh'
    }
    if "`warn'"=="" {
     di "The following alleles have been grouped together:"
     list  Allele if `last' & E<=`thresh', noobs
    }
    quietly {
      replace Allele = `allmiss' if E<=`thresh'
      sort `ped' `id' `parent'
      by `ped' `id' `parent': gen byte `homoz' = /*
        */ (Allele[1]==`allmiss'  & Allele[2]==`allmiss')
      count if `homoz'
      local nxh = r(N)/2
      drop if `homoz'
    }
    if `nxh'>0 & "`warn'"=="" {
      di "(`nxh' parents became effectively homozygous as a result)"
    }
  }
  di "Number of informative transmissions = "  _N/2
  if _N==0 {
    exit
  }

  quietly {
    sort Allele
    by Allele: gen byte `anum' = (_n==1)
    mkmat Allele if `anum', matrix(all)
    replace `anum' = sum(`anum')
    local numa = `anum'[_N]
    by Allele: replace `last' = (_n==_N)
    by Allele: gen O = sum(_PT_)
    by Allele: replace E =  _N/2
    gen _OmE = _PT_-0.5
    gen _Exp = 0.5
    by Allele: gen `score' = sum(`chwt'*_OmE)
    by Allele: gen `var' = sum((`chwt'*_Exp)^2)
    gen Chisq = `score'^2/`var' if `last'
    gen P_val = chiprob(1, Chisq) if `last'
  }
  di
  di "Observed and expected transmission counts, " _continue
  di "and 1 df chisquared tests"
  quietly do "`labsave'"
  label value Allele `allab'
  list Allele O E Chisq P_val if `last', noobs
  drop Chisq P_val

  /* Global test */

  quietly {
    keep `ped' `id' `mother' `father' `parent' `anum' `chwt' _OmE _Exp
    sort `ped' `id' `parent' `anum'
    reshape wide _OmE _Exp, i(`ped' `id' `parent') j(`anum')
    mvencode _OmE* _Exp*, mv(0) override
    matrix vecaccum u = `chwt' _OmE*, nocons
    matrix accum V = _Exp* [iw=`chwt'^2], nocons
  }
  /* Calculate score test */
  matrix def d = vecdiag(V)
  matrix def V = 2*diag(d) - V
  matrix def A = syminv(V)
  local df = 0
  local i = 0
  while `i'<`numa' {
    local i = `i'+1
    if A[`i',`i']>0 {
      local df = `df'+1
    }
  }
  matrix c = u*A*u'
  local chisq = c[1,1]
  di
  di "Global chi-squared (" `df' " df) = " `chisq' /*
     */ ", P-value = " chiprob(`df', `chisq')

  /* Robust tests */

  if "`robust'"!="" {
    quietly drop _Exp*
    di
    di "Robust tests allowing for clustering at the " _continue
    if "`cl'"=="n" {
      local by "`ped' `mother' `father'"
      di "nuclear family " _continue
    }
    else if "`cl'"=="p" {
      local by "`ped'"
      di "pedigree " _continue
    }
    else {
      local by "`ped' `id'"
      di "triad " _continue
    }
    di "level"
    sort `by'
    quietly {
      by `by': gen byte `last' = (_n==_N)
      local i 0
      while `i'<`numa' {
        local i = `i'+1
        by `by': replace _OmE`i' = sum(`chwt'*_OmE`i')
      }
      keep if `last'
    }
    di "(number of clusters = "  _N ")"
    quietly matrix accum V =  _OmE*, nocons /* dev */
    matrix V = V  /* * (_N/(_N-1)) */
    matrix def A = syminv(V)
    local i = 0
    quietly do "`labsave'"
    di
    di "1 df tests for each allele:"
    di
    di _column(5) "Allele" _column(15) "Chi-squared" _column(34) "P-value"
    local df = 0
    while `i'<`numa' {
      local i = `i'+1
      if A[`i',`i']>0 {
        local df = `df'+1
      }
      if V[`i',`i']>0 {
        local ai = all[`i',1]
        local anam : label `allab' `ai'
        local chisq = u[1,`i']^2/V[`i', `i']
        di %10s = "`anam'" _column(16) %10.4f = `chisq' /*
           */ _column(31) %10.3g =  chiprob(1, `chisq')
      }
    }
    matrix c = u*A*u'
    local chisq = c[1,1]
    di
    di "Global chi-squared (" `df' " df) = " `chisq' /*
     */ ", P-value = " chiprob(`df', `chisq')
  }
  return local chi2type "Score"
  return scalar p_val = chiprob(`df', `chisq')
  return scalar df = `df'
  return scalar chi2 = `chisq'
  end