/*-
* Copyright 2015 Diamond Light Source Ltd.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package uk.ac.diamond.scisoft.xpdf;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.january.dataset.Dataset;
/**
* @author Timothy Spain, timothy.spain@diamond.ac.uk
* @since 2015-09-11
*/
public class XPDFAbsorptionMaps {
private Map<Long, Dataset> theMaps;
private Dataset delta;
private Dataset gamma;
private List<XPDFComponentForm> formList;
private XPDFBeamData beamData;
private Map<Long, Boolean> isUpstreamMap;
private Map<Long, Boolean> isDownstreamMap;
/**
* Creates an empty Map.
*/
public XPDFAbsorptionMaps() {
theMaps = new HashMap<Long, Dataset>();
formList = new ArrayList<XPDFComponentForm>();
isUpstreamMap = new HashMap<Long, Boolean>();
isDownstreamMap = new HashMap<Long, Boolean>();
}
/**
* Copy constructor.
* <p>
* Performs a deep copy of the absorption maps, but a shallow copy of everything else.
* @param inMaps object to be copied.
*/
public XPDFAbsorptionMaps(XPDFAbsorptionMaps inMaps) {
if (inMaps.theMaps == null) {
this.theMaps = null;
} else {
this.theMaps = new HashMap<Long, Dataset>(inMaps.theMaps.size());
for (Map.Entry<Long, Dataset> entry : inMaps.theMaps.entrySet() )
this.theMaps.put(entry.getKey(), entry.getValue().clone());
}
this.delta = (inMaps.delta != null) ? inMaps.delta : null;
this.gamma = (inMaps.gamma != null) ? inMaps.gamma : null;
this.formList = (inMaps.formList != null) ? inMaps.formList : null;
this.beamData = (inMaps.beamData != null) ? inMaps.beamData : null;
this.isUpstreamMap = (inMaps.isUpstreamMap != null) ? inMaps.isUpstreamMap : null;
this.isDownstreamMap = (inMaps.isDownstreamMap != null) ? inMaps.isDownstreamMap : null;
}
/**
* Sets an absorption correction map in the map collection.
* @param iScatterer index of the scattering object in the list of XPDFTargetComponents.
* @param iAttenuator index of the attenuating object in the list of XPDFTargetComponents.
* @param inMap The Dataset holding the absorption map of the pair of objects.
*/
public void setAbsorptionMap(int iScatterer, int iAttenuator, Dataset inMap) {
theMaps.put(XPDFAbsorptionMaps.stringifier(iScatterer, iAttenuator), inMap);
}
/**
* Sets absorption maps by the target component form.
* <p>
* Given a pair of XPDFComponentForm objects for the scatterer and the
* attenuator, this method sets the corresponding absorption correction map
* in the map collection.
* @param formScatterer
* the XPDFComponentForm of the scattering object.
* @param formAttenuator
* the XPDFComponentForm of the attenuating object.
* @param inMap
* the absorption map to be set.
*/
public void setAbsorptionMap(XPDFComponentForm formScatterer, XPDFComponentForm formAttenuator, Dataset inMap) {
this.setAbsorptionMap(this.indexFromForm(formScatterer), this.indexFromForm(formAttenuator), inMap);
}
/**
* Calculates the absorption maps.
* <p>
* Given the stored list of target component form objects, this method
* will calculate and store the full set of absorption maps.
*/
public void calculateAbsorptionMaps() {
for (XPDFComponentForm formScatterer : formList) {
for (XPDFComponentForm formAttenuator : formList) {
this.setAbsorptionMap(formScatterer, formAttenuator,
formScatterer.getGeom().calculateAbsorptionCorrections(
gamma, delta, formAttenuator.getGeom(),
formAttenuator.getAttenuationCoefficient(beamData.getBeamEnergy()), beamData,
isUpstreamMap.get(XPDFAbsorptionMaps.stringifier(this.indexFromForm(formScatterer), this.indexFromForm(formAttenuator))),
isDownstreamMap.get(XPDFAbsorptionMaps.stringifier(this.indexFromForm(formScatterer), this.indexFromForm(formAttenuator)))));
}
}
}
/**
* Gets a stored absorption map.
* @param iScatterer index of the scattering object in the list of XPDFTargetComponents.
* @param iAttenuator index of the attenuating object in the list of XPDFTargetComponents.
* @return the requested Dataset if it exists, else null.
*/
public Dataset getAbsorptionMap(int iScatterer, int iAttenuator) {
return theMaps.get(XPDFAbsorptionMaps.stringifier(iScatterer, iAttenuator));
}
/**
* Gets a stored absorption map by the target component form.
* <p>
* Given a pair of XPDFComponentForm objects for the scatterer and the
* attenuator, this method returns the corresponding, previously stored
* absorption map.
* @param formScatterer
* the XPDFComponentForm of the scattering object.
* @param formAttenuator
* the XPDFComponentForm of the attenuating object.
* @return the requested absorption map.
*/
public Dataset getAbsorptionMap(XPDFComponentForm formScatterer, XPDFComponentForm formAttenuator) {
return this.getAbsorptionMap(this.indexFromForm(formScatterer), this.indexFromForm(formAttenuator));
}
/**
* Sets the horizontal scattering angle.
* <p>
* The angle of scattering perpendicular to the beam, and parallel to the
* cylinder axis. Measured in radians.
* @param delta
* Dataset containing the horizontal scattering angle for every point.
*/
public void setDelta(Dataset delta) {
this.delta = delta;
}
/**
* Sets the vertical scattering angle.
* <p>
* The angle of scattering perpendicular to both the beam and the cylinder
* axis. Measured in radians.
* @param gamma
* Dataset containing the vertical scattering angle for every point.
*/
public void setGamma(Dataset gamma) {
this.gamma = gamma;
}
/**
* Sets the beam data for the radiation that the absorption map.
* characterizes.
* @param beamData
* XPDFBeamData object describing the absorbed radiation.
*/
public void setBeamData(XPDFBeamData beamData) {
this.beamData = beamData;
}
/**
* Adds a form to the list of component forms.
* <p>
* The forms in this list are considered in order from inner to outer. The
* first, innermost form is taken to be that of the sample elsewhere, so it
* is best to observe this convention. This method also sets the default
* streamality: both up and downstream of every other component. Use
* this.setStreamality() to set it otherwise.
* @param format
* The target component form to add to the list.
*/
public void addForm(XPDFComponentForm form) {
this.formList.add(form);
for (XPDFComponentForm iComponent : formList) {
setStreamality(iComponent, form, true, true);
setStreamality(form, iComponent, true, true);
}
}
/**
* Gets the index of the Form from the list.
* <p>
* Given an XPDF target component form, this method returns the position in
* the list of forms at which it appears. Woe betide them that ask for the
* index of a form that is not in the list.
* @param form
* the XPDFComponentForm to find
* @return the index at which it appears.
*/
private int indexFromForm(XPDFComponentForm form) {
for (int iform = 0; iform < formList.size(); iform++)
if (formList.get(iform) == form) return iform;
return -1; // Ugh
}
/**
* Sets the streamality of the absorber relative to the scatterer.
* @param formScatterer
* scatterer the absorber is relative to
* @param formAttenuator
* the attenuator whose streamality is being set
* @param isAttenuatorUp
* is the attenuator upstream of the scatterer?
* @param isAttenuatorDown
* is the attenuator downstream of the scatterer?
*/
public void setStreamality(XPDFComponentForm formScatterer, XPDFComponentForm formAttenuator, boolean isAttenuatorUp, boolean isAttenuatorDown) {
isUpstreamMap.put(XPDFAbsorptionMaps.stringifier(this.indexFromForm(formScatterer), this.indexFromForm(formAttenuator)), isAttenuatorUp);
isDownstreamMap.put(XPDFAbsorptionMaps.stringifier(this.indexFromForm(formScatterer), this.indexFromForm(formAttenuator)), isAttenuatorDown);
}
/**
* Converts the pairs of integers to the keying string in a consistent manner.
* @param iScatterer index of the scattering object in the list of XPDFTargetComponents.
* @param iAttenuator index of the attenuating object in the list of XPDFTargetComponents.
* @return The encoded string.
*/
private static long stringifier(int iScatterer, int iAttenuator) {
return (((long) iScatterer) << (Long.SIZE - Integer.SIZE)) + iAttenuator;//Integer.toString(iScatterer, Character.MAX_RADIX)+" "+Integer.toString(iAttenuator, Character.MAX_RADIX);
}
public boolean checkFormList(List<XPDFComponentForm> inFormList) {
if (formList == null || inFormList == null) return false;
boolean sameForms = (inFormList.size() == formList.size());
for (int i = 0; i < formList.size(); i++) {
if (!sameForms) break;
sameForms &= formList.get(i).isEqualToForAbsorption(inFormList.get(i));
}
return sameForms;
}
}