/** * * * <h2>Back-propagates the Defining State of the Probe Object</h2> * * <p>This method uses the same basic algorithm as in <code>EnvelopeTracker#advanceState()</code>, * only the probe object is back-propagated. The method utilizes all the space charge mechanisms * of the base class <code>EnvelopeTracker</code>. * * @param ifcElem interface to the beam element * @param ifcProbe interface to the probe * @param dblLen length of element subsection to retract * @throws ModelException bad element transfer matrix/corrupt probe state * @author Christopher K. Allen * @since Feb 9, 2009 * @see xal.model.alg.EnvelopeTracker#advanceState(xal.model.IProbe, xal.model.IElement, double) */ protected void retractState(IProbe ifcProbe, IElement ifcElem, double dblLen) throws ModelException { // Identify probe EnvelopeProbe probe = (EnvelopeProbe) ifcProbe; // Get initial conditions of probe // R3 vecPhs0 = probe.getBetatronPhase(); // Twiss[] twiss0 = probe.getCovariance().computeTwiss(); PhaseMatrix matResp0 = probe.getResponseMatrix(); PhaseMatrix matTau0 = probe.getCovariance(); // Remove the emittance growth if (this.getEmittanceGrowth()) matTau0 = this.removeEmittanceGrowth(probe, ifcElem, matTau0); // Compute the transfer matrix // def PhaseMatrix matPhi = compTransferMatrix(dblLen, probe, ifcElem); PhaseMatrix matPhi = compTransferMatrix(dblLen, probe, ifcElem); // Advance the probe states PhaseMatrix matResp1 = matPhi.times(matResp0); PhaseMatrix matTau1 = matTau0.conjugateTrans(matPhi); // Save the new state variables in the probe probe.setResponseMatrix(matResp1); probe.setCurrentResponseMatrix(matPhi); probe.setCovariance(new CovarianceMatrix(matTau1)); // probe.advanceTwiss(matPhi, ifcElem.energyGain(probe, dblLen) ); // phase update: // Twiss [] twiss1 = probe.getCovariance().computeTwiss(); // R3 vecPhs1 = vecPhs0.plus( matPhi.compPhaseAdvance(twiss0, twiss1) ); // probe.setBetatronPhase(vecPhs1); /** sako treatment of ChargeExchangeFoil */ treatChargeExchange(probe, ifcElem); }
/** * * * <h2>Compute Transfer Matrix Including Space Charge</h2> * * <p>Computes the back-propagating transfer matrix over the incremental distance <code>dblLen * </code> for the beamline modeling element <code>ifcElem</code>, and for the given <code>probe * </code>. We include space charge and emittance growth effects if specified. * * <p><strong>NOTE</strong>: (CKA) <br> * · If space charge is included, the space charge matrix is computed for length <code> * dblLen</code>, but at a half-step location behind the current probe position. This method is * the same technique used by Trace3D. The space charge matrix is then pre- and post- multiplied * by the element transfer matrix for a half-step before and after the mid-step position, * respectively. <br> * · I do not know if this (leap-frog) technique buys us much more accuracy then full * stepping. * * @param dblLen incremental path length * @param probe beam probe under simulation * @param ifcElem beamline element propagating probe * @return transfer matrix for given element * @throws ModelException bubbles up from IElement#transferMap() * @see EnvelopeTracker#compScheffMatrix(double, EnvelopeProbe, PhaseMatrix) * @see EnvelopeTracker#transferEmitGrowth(EnvelopeProbe, IElement, PhaseMatrix) * @see EnvelopeTracker#modTransferMatrixForDisplError(double, double, double, PhaseMatrix) */ private PhaseMatrix compTransferMatrix(double dblLen, EnvelopeProbe probe, IElement ifcElem) throws ModelException { // Returned value PhaseMatrix matPhi; // transfer matrix including all effects // Check for exceptional circumstance and modify transfer matrix accordingly if (ifcElem instanceof IdealRfGap) { IdealRfGap elemRfGap = (IdealRfGap) ifcElem; double dW = elemRfGap.energyGain(probe, dblLen); double W = probe.getKineticEnergy(); probe.setKineticEnergy(W - dW); PhaseMatrix matPhiI = elemRfGap.transferMap(probe, dblLen).getFirstOrder(); if (this.getEmittanceGrowth()) { double dphi = this.effPhaseSpread(probe, elemRfGap); matPhiI = super.modTransferMatrixForEmitGrowth(dphi, matPhiI); } matPhi = matPhiI.inverse(); probe.setKineticEnergy(W); return matPhi; } if (dblLen == 0.0) { matPhi = ifcElem.transferMap(probe, dblLen).getFirstOrder(); return matPhi; } // Check for easy case of no space charge if (!this.getUseSpacecharge()) { matPhi = ifcElem.transferMap(probe, dblLen).getFirstOrder(); // we must treat space charge } else { // Store the current probe state (for rollback) EnvelopeProbeState state0 = probe.cloneCurrentProbeState(); // ProbeState state0 = probe.createProbeState(); // Get half-step back-propagation matrix at current probe location // NOTE: invert by computing for negative propagation length PhaseMap mapElem0 = ifcElem.transferMap(probe, -dblLen / 2.0); PhaseMatrix matPhi0 = mapElem0.getFirstOrder(); // Get the RMS envelopes at probe location CovarianceMatrix covTau0 = probe.getCovariance(); // covariance matrix at entrance // Move probe back a half step for position-dependent transfer maps double pos = probe.getPosition() - dblLen / 2.0; PhaseMatrix matTau1 = covTau0.conjugateTrans(matPhi0); CovarianceMatrix covTau1 = new CovarianceMatrix(matTau1); probe.setPosition(pos); probe.setCovariance(covTau1); // space charge transfer matrix // NOTE: invert by computing for negative propagation length PhaseMatrix matPhiSc = this.compScheffMatrix(-dblLen, probe, ifcElem); // Compute half-step transfer matrix at new probe location PhaseMap mapElem1 = ifcElem.transferMap(probe, -dblLen / 2.0); PhaseMatrix matPhi1 = mapElem1.getFirstOrder(); // Restore original probe state probe.applyState(state0); // Compute the full transfer matrix for the distance dblLen matPhi = matPhi1.times(matPhiSc.times(matPhi0)); } if (ifcElem instanceof IdealMagQuad) { // sako put alignment error in sigma matrix // NOTE the use of negative displacements for back-propagation IdealMagQuad elemQuad = (IdealMagQuad) ifcElem; double delx = -elemQuad.getAlignX(); double dely = -elemQuad.getAlignY(); double delz = -elemQuad.getAlignZ(); matPhi = this.modTransferMatrixForDisplError(delx, dely, delz, matPhi); } return matPhi; }