SimpleOrbitSegmentCalculator.java
// @formatter:off
/*******************************************************************************
* This file is part of JMad. Copyright (c) 2008-2011, CERN. All rights reserved. Licensed under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in
* writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
* OF ANY KIND, either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
// @formatter:on
package cern.accsoft.steering.jmad.tools.interpolate;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import Jama.Matrix;
import cern.accsoft.steering.jmad.domain.elem.Element;
import cern.accsoft.steering.jmad.domain.optics.Optic;
import cern.accsoft.steering.jmad.domain.optics.OpticPoint;
import cern.accsoft.steering.jmad.domain.optics.OpticPointImpl;
import cern.accsoft.steering.jmad.domain.orbit.Orbit;
import cern.accsoft.steering.jmad.domain.types.enums.JMadPlane;
import cern.accsoft.steering.jmad.domain.var.enums.JMadTwissVariable;
import cern.accsoft.steering.jmad.domain.var.enums.MadxTwissVariable;
/**
* This class does the actual interpolation of the orbit in one plane for one segment defined by two adjacent monitors.
*
* @author muellerg
*/
public class SimpleOrbitSegmentCalculator implements OrbitSegmentCalculator {
private static final Logger LOGGER = LoggerFactory.getLogger(SimpleOrbitSegmentCalculator.class);
/** the plane this orbit segment calculator works on */
private JMadPlane plane;
/** the monitor at the beginning of this segment */
private Element startMonitor;
/** the monitor at the end of the segment */
private Element endMonitor;
/** the transfer matrix between the start and end monitor */
private Matrix monitorTransferMatrix = null;
/** the transfer matrix mapping from the start monitor to all the elements of the segment */
private Map<Element, Matrix> elementMatrices;
/** the list of elements in the segment, including the monitors (first/last) */
private LinkedList<Element> segmentElements = new LinkedList<Element>();
/** flag to determine if segment contains start and end of circular machine */
private boolean isCycleStartSegment = false;
/** the maximum mu in the segment */
private double maxMu;
public SimpleOrbitSegmentCalculator(JMadPlane plane) {
this.plane = plane;
this.elementMatrices = new HashMap<Element, Matrix>();
}
@Override
public void setStartSegmentMonitor(Element element) {
this.startMonitor = element;
this.segmentElements.addFirst(element);
}
@Override
public void setEndSegmentMonitor(Element element) {
this.endMonitor = element;
this.segmentElements.addLast(element);
}
@Override
public void addElementToCalculate(Element element) {
this.segmentElements.add(element);
}
@Override
public boolean update(Optic optic) {
if (this.isCycleStartSegment()) {
this.updateMuMax(optic);
}
if (!this.updateMonitorTransferMatrix(optic)) {
return false;
}
OpticPoint from = optic.getPoint(this.startMonitor);
for (Element element : this.segmentElements) {
if (element.equals(startMonitor) || element.equals(endMonitor)) {
continue;
}
OpticPoint to = optic.getPoint(element);
if (to == null) {
LOGGER.error("Could not update transfer matrix in " + this.getName() + " no optic data for element ["
+ element.getName() + "] in plane [" + this.getPlane() + "].");
return false;
}
this.elementMatrices.put(element, this.calculateTransferMatrix(from, to));
}
return true;
}
private void updateMuMax(Optic optic) {
double maxMu = Double.MIN_VALUE;
for (Element element : this.segmentElements) {
double mu = optic.getPoint(element).getValue(JMadTwissVariable.MU, this.getPlane());
if (mu > maxMu) {
maxMu = mu;
}
}
this.setMaxMu(maxMu);
}
private void setMaxMu(double maxMu) {
this.maxMu = maxMu;
}
private double getMaxMu() {
return this.maxMu;
}
private Matrix calculateTransferMatrix(OpticPoint from, OpticPoint to) {
if (!this.isCycleStartSegment()) {
return TransferMatrixCalculator.calculate(getPlane(), from, to);
}
double muFrom = from.getValue(JMadTwissVariable.MU, this.getPlane());
double muTo = to.getValue(JMadTwissVariable.MU, this.getPlane());
if (muTo < muFrom) {
muTo = muTo + (this.getMaxMu() - muFrom);
muFrom = 0.0;
return TransferMatrixCalculator.calculate(getPlane(), this.adaptOpticPoint(from, muFrom), this
.adaptOpticPoint(to, muTo));
} else {
return TransferMatrixCalculator.calculate(getPlane(), from, to);
}
}
private OpticPoint adaptOpticPoint(OpticPoint point, double newMu) {
OpticPointImpl newPoint = new OpticPointImpl(point.getName());
for (JMadTwissVariable variable : TransferMatrixCalculator.REQUIRED_VARIABLES) {
newPoint.setValue(variable.getMadxTwissVariable(getPlane()), point.getValue(variable, this.getPlane()));
}
newPoint.setValue(JMadTwissVariable.MU.getMadxTwissVariable(getPlane()), newMu);
return newPoint;
}
private boolean updateMonitorTransferMatrix(Optic optic) {
OpticPoint from = optic.getPoint(this.startMonitor);
OpticPoint to = optic.getPoint(endMonitor);
if (from == null || to == null) {
LOGGER.error("Could not update monitor transfer matrix in " + this.getName()
+ " no optic data for monitors.");
this.monitorTransferMatrix = null;
return false;
}
this.monitorTransferMatrix = this.calculateTransferMatrix(from, to);
return true;
}
@Override
public Map<Element, Map<MadxTwissVariable, Double>> calculate(Orbit orbit) {
if (this.monitorTransferMatrix == null) {
LOGGER.error("Segment orbit interpolation calculator not initialized for " + this.getName());
return Collections.emptyMap();
}
Map<Element, Map<MadxTwissVariable, Double>> elementValueMapping = new HashMap<Element, Map<MadxTwissVariable, Double>>();
double pos_start = this.getMonitorPosition(this.startMonitor, orbit);
double pos_end = this.getMonitorPosition(this.endMonitor, orbit);
double c_seg = this.monitorTransferMatrix.get(0, 0);
double s_seg = this.monitorTransferMatrix.get(0, 1);
double factor = (pos_end - (c_seg * pos_start)) / s_seg;
for (Element element : this.segmentElements) {
Map<MadxTwissVariable, Double> valueMapping = new HashMap<MadxTwissVariable, Double>();
elementValueMapping.put(element, valueMapping);
/* for the monitors we just copy the reading */
boolean positionDone = false;
if (element.equals(startMonitor)) {
valueMapping.put(JMadTwissVariable.POS.getMadxTwissVariable(getPlane()), pos_start);
positionDone = true;
}
if (element.equals(endMonitor)) {
valueMapping.put(JMadTwissVariable.POS.getMadxTwissVariable(getPlane()), pos_end);
positionDone = true;
}
/* do the interpolation */
Matrix elementMatrix = this.elementMatrices.get(element);
if (!positionDone) {
double c_elem = elementMatrix.get(0, 0);
double s_elem = elementMatrix.get(0, 1);
double value = c_elem * pos_start + s_elem * factor;
valueMapping.put(JMadTwissVariable.POS.getMadxTwissVariable(getPlane()), value);
double cp_elem = elementMatrix.get(1, 0);
double sp_elem = elementMatrix.get(1, 1);
value = cp_elem * pos_start + sp_elem * factor;
valueMapping.put(JMadTwissVariable.P.getMadxTwissVariable(getPlane()), value);
} else {
double cp_elem = this.monitorTransferMatrix.get(1, 0);
double sp_elem = this.monitorTransferMatrix.get(1, 1);
double value = cp_elem * pos_start + sp_elem * factor;
valueMapping.put(JMadTwissVariable.P.getMadxTwissVariable(getPlane()), value);
}
}
return elementValueMapping;
}
private double getMonitorPosition(Element monitor, Orbit orbit) {
int index = orbit.getMonitorIndex(monitor.getName());
return orbit.getValues(this.getPlane()).get(index);
}
@Override
public String getName() {
return "segment [" + this.startMonitor.getName() + "-->" + this.endMonitor.getName() + "] for plane ["
+ this.getPlane() + "]";
}
@Override
public JMadPlane getPlane() {
return this.plane;
}
@Override
public void setIsCycleStartSegment(boolean isCycleStartSegment) {
this.isCycleStartSegment = isCycleStartSegment;
}
private boolean isCycleStartSegment() {
return isCycleStartSegment;
}
}