SimpleOrbitSegmentCalculator.java

  1. // @formatter:off
  2. /*******************************************************************************
  3.  * This file is part of JMad. Copyright (c) 2008-2011, CERN. All rights reserved. Licensed under the Apache License,
  4.  * Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy
  5.  * of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in
  6.  * writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
  7.  * OF ANY KIND, either express or implied. See the License for the specific language governing permissions and
  8.  * limitations under the License.
  9.  ******************************************************************************/
  10. // @formatter:on

  11. package cern.accsoft.steering.jmad.tools.interpolate;

  12. import java.util.Collections;
  13. import java.util.HashMap;
  14. import java.util.LinkedList;
  15. import java.util.Map;

  16. import org.slf4j.Logger;
  17. import org.slf4j.LoggerFactory;

  18. import Jama.Matrix;
  19. import cern.accsoft.steering.jmad.domain.elem.Element;
  20. import cern.accsoft.steering.jmad.domain.optics.Optic;
  21. import cern.accsoft.steering.jmad.domain.optics.OpticPoint;
  22. import cern.accsoft.steering.jmad.domain.optics.OpticPointImpl;
  23. import cern.accsoft.steering.jmad.domain.orbit.Orbit;
  24. import cern.accsoft.steering.jmad.domain.types.enums.JMadPlane;
  25. import cern.accsoft.steering.jmad.domain.var.enums.JMadTwissVariable;
  26. import cern.accsoft.steering.jmad.domain.var.enums.MadxTwissVariable;

  27. /**
  28.  * This class does the actual interpolation of the orbit in one plane for one segment defined by two adjacent monitors.
  29.  *
  30.  * @author muellerg
  31.  */
  32. public class SimpleOrbitSegmentCalculator implements OrbitSegmentCalculator {
  33.     private static final Logger LOGGER = LoggerFactory.getLogger(SimpleOrbitSegmentCalculator.class);

  34.     /** the plane this orbit segment calculator works on */
  35.     private JMadPlane plane;

  36.     /** the monitor at the beginning of this segment */
  37.     private Element startMonitor;
  38.     /** the monitor at the end of the segment */
  39.     private Element endMonitor;

  40.     /** the transfer matrix between the start and end monitor */
  41.     private Matrix monitorTransferMatrix = null;

  42.     /** the transfer matrix mapping from the start monitor to all the elements of the segment */
  43.     private Map<Element, Matrix> elementMatrices;

  44.     /** the list of elements in the segment, including the monitors (first/last) */
  45.     private LinkedList<Element> segmentElements = new LinkedList<Element>();

  46.     /** flag to determine if segment contains start and end of circular machine */
  47.     private boolean isCycleStartSegment = false;

  48.     /** the maximum mu in the segment */
  49.     private double maxMu;

  50.     public SimpleOrbitSegmentCalculator(JMadPlane plane) {
  51.         this.plane = plane;
  52.         this.elementMatrices = new HashMap<Element, Matrix>();
  53.     }

  54.     @Override
  55.     public void setStartSegmentMonitor(Element element) {
  56.         this.startMonitor = element;
  57.         this.segmentElements.addFirst(element);
  58.     }

  59.     @Override
  60.     public void setEndSegmentMonitor(Element element) {
  61.         this.endMonitor = element;
  62.         this.segmentElements.addLast(element);
  63.     }

  64.     @Override
  65.     public void addElementToCalculate(Element element) {
  66.         this.segmentElements.add(element);
  67.     }

  68.     @Override
  69.     public boolean update(Optic optic) {
  70.         if (this.isCycleStartSegment()) {
  71.             this.updateMuMax(optic);
  72.         }

  73.         if (!this.updateMonitorTransferMatrix(optic)) {
  74.             return false;
  75.         }

  76.         OpticPoint from = optic.getPoint(this.startMonitor);
  77.         for (Element element : this.segmentElements) {
  78.             if (element.equals(startMonitor) || element.equals(endMonitor)) {
  79.                 continue;
  80.             }

  81.             OpticPoint to = optic.getPoint(element);
  82.             if (to == null) {
  83.                 LOGGER.error("Could not update transfer matrix in " + this.getName() + " no optic data for element ["
  84.                         + element.getName() + "] in plane [" + this.getPlane() + "].");
  85.                 return false;
  86.             }

  87.             this.elementMatrices.put(element, this.calculateTransferMatrix(from, to));
  88.         }

  89.         return true;
  90.     }

  91.     private void updateMuMax(Optic optic) {
  92.         double maxMu = Double.MIN_VALUE;
  93.         for (Element element : this.segmentElements) {
  94.             double mu = optic.getPoint(element).getValue(JMadTwissVariable.MU, this.getPlane());
  95.             if (mu > maxMu) {
  96.                 maxMu = mu;
  97.             }
  98.         }

  99.         this.setMaxMu(maxMu);
  100.     }

  101.     private void setMaxMu(double maxMu) {
  102.         this.maxMu = maxMu;
  103.     }

  104.     private double getMaxMu() {
  105.         return this.maxMu;
  106.     }

  107.     private Matrix calculateTransferMatrix(OpticPoint from, OpticPoint to) {
  108.         if (!this.isCycleStartSegment()) {
  109.             return TransferMatrixCalculator.calculate(getPlane(), from, to);
  110.         }

  111.         double muFrom = from.getValue(JMadTwissVariable.MU, this.getPlane());
  112.         double muTo = to.getValue(JMadTwissVariable.MU, this.getPlane());

  113.         if (muTo < muFrom) {
  114.             muTo = muTo + (this.getMaxMu() - muFrom);
  115.             muFrom = 0.0;
  116.             return TransferMatrixCalculator.calculate(getPlane(), this.adaptOpticPoint(from, muFrom), this
  117.                     .adaptOpticPoint(to, muTo));
  118.         } else {
  119.             return TransferMatrixCalculator.calculate(getPlane(), from, to);
  120.         }
  121.     }

  122.     private OpticPoint adaptOpticPoint(OpticPoint point, double newMu) {
  123.         OpticPointImpl newPoint = new OpticPointImpl(point.getName());
  124.         for (JMadTwissVariable variable : TransferMatrixCalculator.REQUIRED_VARIABLES) {
  125.             newPoint.setValue(variable.getMadxTwissVariable(getPlane()), point.getValue(variable, this.getPlane()));
  126.         }

  127.         newPoint.setValue(JMadTwissVariable.MU.getMadxTwissVariable(getPlane()), newMu);
  128.         return newPoint;
  129.     }

  130.     private boolean updateMonitorTransferMatrix(Optic optic) {

  131.         OpticPoint from = optic.getPoint(this.startMonitor);
  132.         OpticPoint to = optic.getPoint(endMonitor);

  133.         if (from == null || to == null) {
  134.             LOGGER.error("Could not update monitor transfer matrix in " + this.getName()
  135.                     + " no optic data for monitors.");
  136.             this.monitorTransferMatrix = null;
  137.             return false;
  138.         }

  139.         this.monitorTransferMatrix = this.calculateTransferMatrix(from, to);
  140.         return true;
  141.     }

  142.     @Override
  143.     public Map<Element, Map<MadxTwissVariable, Double>> calculate(Orbit orbit) {
  144.         if (this.monitorTransferMatrix == null) {
  145.             LOGGER.error("Segment orbit interpolation calculator not initialized for " + this.getName());
  146.             return Collections.emptyMap();
  147.         }

  148.         Map<Element, Map<MadxTwissVariable, Double>> elementValueMapping = new HashMap<Element, Map<MadxTwissVariable, Double>>();
  149.         double pos_start = this.getMonitorPosition(this.startMonitor, orbit);
  150.         double pos_end = this.getMonitorPosition(this.endMonitor, orbit);

  151.         double c_seg = this.monitorTransferMatrix.get(0, 0);
  152.         double s_seg = this.monitorTransferMatrix.get(0, 1);

  153.         double factor = (pos_end - (c_seg * pos_start)) / s_seg;

  154.         for (Element element : this.segmentElements) {
  155.             Map<MadxTwissVariable, Double> valueMapping = new HashMap<MadxTwissVariable, Double>();
  156.             elementValueMapping.put(element, valueMapping);

  157.             /* for the monitors we just copy the reading */
  158.             boolean positionDone = false;
  159.             if (element.equals(startMonitor)) {
  160.                 valueMapping.put(JMadTwissVariable.POS.getMadxTwissVariable(getPlane()), pos_start);
  161.                 positionDone = true;
  162.             }
  163.             if (element.equals(endMonitor)) {
  164.                 valueMapping.put(JMadTwissVariable.POS.getMadxTwissVariable(getPlane()), pos_end);
  165.                 positionDone = true;
  166.             }

  167.             /* do the interpolation */
  168.             Matrix elementMatrix = this.elementMatrices.get(element);

  169.             if (!positionDone) {
  170.                 double c_elem = elementMatrix.get(0, 0);
  171.                 double s_elem = elementMatrix.get(0, 1);
  172.                 double value = c_elem * pos_start + s_elem * factor;

  173.                 valueMapping.put(JMadTwissVariable.POS.getMadxTwissVariable(getPlane()), value);

  174.                 double cp_elem = elementMatrix.get(1, 0);
  175.                 double sp_elem = elementMatrix.get(1, 1);
  176.                 value = cp_elem * pos_start + sp_elem * factor;
  177.                 valueMapping.put(JMadTwissVariable.P.getMadxTwissVariable(getPlane()), value);
  178.                
  179.             } else {
  180.                 double cp_elem = this.monitorTransferMatrix.get(1, 0);
  181.                 double sp_elem = this.monitorTransferMatrix.get(1, 1);
  182.                 double value = cp_elem * pos_start + sp_elem * factor;
  183.                 valueMapping.put(JMadTwissVariable.P.getMadxTwissVariable(getPlane()), value);
  184.             }
  185.         }

  186.         return elementValueMapping;
  187.     }

  188.     private double getMonitorPosition(Element monitor, Orbit orbit) {
  189.         int index = orbit.getMonitorIndex(monitor.getName());
  190.         return orbit.getValues(this.getPlane()).get(index);
  191.     }

  192.     @Override
  193.     public String getName() {
  194.         return "segment [" + this.startMonitor.getName() + "-->" + this.endMonitor.getName() + "] for plane ["
  195.                 + this.getPlane() + "]";
  196.     }

  197.     @Override
  198.     public JMadPlane getPlane() {
  199.         return this.plane;
  200.     }

  201.     @Override
  202.     public void setIsCycleStartSegment(boolean isCycleStartSegment) {
  203.         this.isCycleStartSegment = isCycleStartSegment;
  204.     }

  205.     private boolean isCycleStartSegment() {
  206.         return isCycleStartSegment;
  207.     }
  208. }