1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
|
/*
* Copyright (C) 2014-2021 Brian L. Browning
*
* This file is part of Beagle
*
* Beagle is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Beagle is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package phase;
import blbutil.FloatArray;
import java.util.stream.IntStream;
import main.Par;
import vcf.MarkerMap;
/**
* <p>Class {@code PhaseData} stores the current genotype phase estimates
* and parameter values.</p>
*
* <p>Instances of class {@code PhaseData} are thread-safe.</p>
*
* @author Brian L. Browning {@code <browning@uw.edu>}
*/
public class PhaseData {
private final EstPhase estPhase;
private final float[] leaveUnphProp;
private final long seed;
private volatile int it;
private volatile float lrThreshold;
private volatile TrProb trProb;
private volatile float pMismatch;
/**
* Constructs a new {@code PhaseData} instance from the specified data.
* @param fpd the input data for phasing that is the same in each iteration
* @param seed a seed for generating pseudorandom number
*
* @throws NullPointerException if {@code fpd == null}
*/
public PhaseData(FixedPhaseData fpd, long seed) {
Par par = fpd.par();
this.estPhase = new EstPhase(fpd, seed);
this.leaveUnphProp = leaveUnphasedProp(fpd, estPhase);
this.seed = seed;
this.it = 0;
this.lrThreshold = lrThreshold(par, it);
float recombIntensity = (float) 0.04f*fpd.par().ne()/fpd.nHaps();
this.trProb = new TrProb(fpd.stage1Map(), recombIntensity);
this.pMismatch = Par.liStephensPMismatch(fpd.nHaps());
}
static float lrThreshold(Par par, int it) {
int nBurninIts = par.burnin();
int nItsM1 = par.iterations() - 1;
if (it<nBurninIts) {
return Float.POSITIVE_INFINITY;
}
else if (it==(nItsM1 + nBurninIts)) {
return 1f;
}
else {
double lastVal = 4.0;
double exp = (double) (nItsM1 - (it-nBurninIts)) / nItsM1;
double base = par.initial_lr()/lastVal;
return (float) (lastVal*Math.pow(base, exp));
}
}
private static float[] leaveUnphasedProp(FixedPhaseData fpd,
EstPhase estPhase) {
int nIterations = fpd.par().iterations();
int[] floatBits = IntStream.range(0, fpd.targGT().nSamples())
.parallel()
.map(s -> estPhase.get(s).nUnphased())
.mapToDouble(cnt -> Math.pow(cnt, -1.0/nIterations))
.mapToInt(p -> Float.floatToRawIntBits((float) p))
.toArray();
float[] fa = new float[floatBits.length];
for (int j=0; j<fa.length; ++j) {
fa[j] = Float.intBitsToFloat(floatBits[j]);
}
return fa;
}
/**
* Returns the recombination intensity.
* @return the recombination intensity
*/
public float recombIntensity() {
return trProb.recombIntensity;
}
/**
* Updates the recombination intensity.
* @param recombIntensity the updated recombination intensity.
* @throws IllegalArgumentException if
* {@code recombIntensity <= 0f || Float.isFinite(recombIntensity) == false}
*/
public void updateRecombIntensity(float recombIntensity) {
if (recombIntensity<=0f || Float.isFinite(recombIntensity)==false) {
throw new IllegalArgumentException(String.valueOf(recombIntensity));
}
trProb = new TrProb(estPhase.fpd().stage1Map(), recombIntensity);
}
/**
* Returns the effective population size.
* @return the effective population size
*/
public long ne() {
return ne(trProb.recombIntensity);
}
/**
* Returns the effective population size.
* @param recombIntensity the recombination intensity
* @return the effective population size
*/
private long ne(float recombIntensity) {
return (long) Math.ceil(25*recombIntensity*estPhase.fpd().nHaps());
}
/**
* Return a {@code FloatArray} of size
* {@code this.fpd().stage1TargXGT().nMarkers()}
* whose {@code k}-th element is the probability of transitioning to a
* random HMM state between the {@code (k-1)}-st and {@code k}-th
* markers.
* @return the probability of transitioning to a random HMM state between
* pair of consecutive markers
*/
public FloatArray pRecomb() {
return trProb.pRecomb;
}
/**
* Returns the allele mismatch probability.
* @return the allele mismatch probability
*/
public float pMismatch() {
return pMismatch;
}
/**
* Sets the allele mismatch probability to the specified value.
* @param pMismatch the allele mismatch probability
* @throws IllegalArgumentException if
* {@code pMismatch < 0.0 || pMismatch > 1.0
* || Float.isFinite(pMismatch) == false}
*/
public void updatePMismatch(float pMismatch) {
if (pMismatch < 0.0 || pMismatch > 1.0
|| Float.isFinite(pMismatch)==false) {
throw new IllegalArgumentException(String.valueOf(pMismatch));
}
this.pMismatch = pMismatch;
}
/**
* Increments the iteration by one.
*/
public void incrementIt() {
++it;
lrThreshold = lrThreshold(estPhase.fpd().par(), it);
}
/**
* Returns the current iteration. The initial iteration is 0.
* @return the current iteration
*/
public int it() {
return it;
}
/**
* Sets the iteration equal to the maximum of {@code this.it()}
* and {@code this.fpd().par().burnin()}.
*/
public void advanceToFirstPhasingIt() {
int nBurninIts = estPhase.fpd().par().burnin();
if (it<nBurninIts) {
it = nBurninIts;
lrThreshold = lrThreshold(estPhase.fpd().par(), it);
}
}
/**
* Returns the input data for phasing that is the same in each iteration.
* @return the input data for phasing that is the same in each iteration
*/
public FixedPhaseData fpd() {
return estPhase.fpd();
}
/**
* Returns the estimated phased genotypes.
* @return the estimated phased genotypes
*/
public EstPhase estPhase() {
return estPhase;
}
/**
* Constructs and returns the coded steps. Since a {@code CodedSteps}
* object can consume substantial memory, the returned object is not
* pre-computed, but is constructed upon invocation of this method.
* @return the coded steps
*/
public CodedSteps codedSteps() {
return new CodedSteps(estPhase);
}
/**
* Returns the proportion of unphased heterozygotes at the start of a
* phasing iteration that will be left unphased at the end of a
* phasing iteration.
* @param sample the sample index
* @return the proportion of unphased heterozygotes at the start of a
* phasing iteration that will be left unphased at the end of a
* phasing iteration
* @throws IndexOutOfBoundsException if
* {@code sample < 0 || sample >= this.fpd().targGT().nSamples()}
*/
public float leaveUnphasedProp(int sample) {
return leaveUnphProp[sample];
}
/**
* Returns the threshold on the phasing likelihood ratio that
* determines whether a pair of heterozygotes will be marked as phased.
* @return the threshold on the phasing likelihood ratio that
* determines whether a pair of heterozygotes will be marked as phased
*/
public float lrThreshold() {
return lrThreshold;
}
/**
* Returns an iteration-dependent seed for generating pseudorandom numbers.
* @return an iteration-dependent seed for generating pseudorandom numbers
*/
public long seed() {
return seed + it;
}
private static class TrProb {
private final float recombIntensity;
private final FloatArray pRecomb;
public TrProb(MarkerMap map, float recombItensity) {
this.recombIntensity = recombItensity;
this.pRecomb = map.pRecomb(recombIntensity);
}
}
}
|