/** * * * <h2>Implementation of Abstract Tracker#doPropagation(IProbe, IElement)</h2> * * <p>This method is essentially the same implementation as the method <code> * EnvelopeTracker#doPropagation()</code>, only here the probe object is back-propagated. The * method calls <code>Tracker.retractProbe()</code> rather than <code>Tracker.advanceProbe() * </code>, and the implemented method <code>EnvelopeBacktracker.retractState()</code> rather than * <code>EnvelopeTracker.advanceState</code>. * * @author Christopher K. Allen * @since Feb 9, 2009 * @see xal.model.alg.Tracker#propagate(xal.model.IProbe, xal.model.IElement) * @see xal.model.alg.EnvelopeTracker#doPropagation(IProbe, IElement) */ @Override public void doPropagation(IProbe probe, IElement elem) throws ModelException { // sako double elemPos = this.getElemPosition(); double elemLen = elem.getLength(); double propLen = elemLen - elemPos; if (propLen < 0) { System.err.println("doPropagation, elemPos, elemLen = " + elemPos + " " + elemLen); return; } // Determine the number of integration steps and the step size int cntSteps; // number of steps through element double dblStep; // step size through element if (this.getUseSpacecharge()) cntSteps = (int) Math.max(Math.ceil(propLen / getStepSize()), 1); else cntSteps = 1; dblStep = elem.getLength() / cntSteps; // dblStep = propLen / cntSteps; for (int i = 0; i < cntSteps; i++) { this.retractState(probe, elem, dblStep); this.retractProbe(probe, elem, dblStep); } }
/** * Test for a <code>ChargeExchangeFoil</code> element. If found, the probe represent an * H<sup>+</sup> beam, the electrons are added and the beam becomes H<sup>-</sup>. * * <p>The opposite of {@link EnvelopeTracker#treatChargeExchange(EnvelopeProbe, IElement)} * * @param probe Propagating beam * @param ifcElem Element to tested for <code>ChargeExchangeFoil</code> type * @author Hiroyuki Sako * @see xal.model.elem.ChargeExchangeFoil * @see EnvelopeTracker#treatChargeExchange(EnvelopeProbe, IElement) */ private void treatChargeExchange(EnvelopeProbe probe, IElement ifcElem) { if (ifcElem instanceof ChargeExchangeFoil) { double q = probe.getSpeciesCharge(); if (q > 0) { System.out.println("charge exchanged at " + ifcElem.getId() + " from " + q + " to " + (-q)); probe.setSpeciesCharge(-q); } } }
/** * * * <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; }