Skip to content

Commit

Permalink
Make to support new XML format. Refs #4996.
Browse files Browse the repository at this point in the history
(1) GroupDetectors2 is enabled to support grouping file in 'new' XML
format.
(2) Original XML parser class is removed and replaced by the XML class
used by LoadDetectorsGroupingFile().
  • Loading branch information
wdzhou committed Mar 20, 2012
1 parent 2828591 commit 4c64657
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 208 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -142,59 +142,6 @@ typedef std::map<specid_t, std::vector<size_t> > storage_map;
typedef std::tr1::unordered_map<specid_t, std::vector<size_t> > storage_map;
#endif


/**
* This class implements the Poco SAX ContentHandler class for reading of detector grouping files.
* @author Michael Whitty, ISIS
* @date 16/03/2011
* For an explanation of the ContentHandler class, please see http://www.appinf.com/docs/poco/Poco.XML.ContentHandler.html
*/
class GroupXmlReader : public Poco::XML::ContentHandler
{
public:

/// Constructor
GroupXmlReader();
/// Signals start of XML document
void startDocument();
/// Signals start of element
void startElement(const Poco::XML::XMLString &, const Poco::XML::XMLString& localName, const Poco::XML::XMLString&, const Poco::XML::Attributes& attr);
/// Signals end of element
void endElement(const Poco::XML::XMLString&, const Poco::XML::XMLString& localName, const Poco::XML::XMLString&);
/// Used to return information to the GroupDetectors algorithm
void getItems(storage_map & map, std::vector<int64_t> & unused);
/// Provides some information that is needed for the process to work
void setMaps(spec2index_map spec, detid2index_map * det, std::vector<int64_t> & unused);

// These functions must be present as they are abstract in the base class. They are not used them here.
void setDocumentLocator(const Poco::XML::Locator*) {} ///< Not used
void endDocument() {} ///< Not used
void characters(const Poco::XML::XMLChar [], int, int) {} ///< Not used
void ignorableWhitespace(const Poco::XML::XMLChar [], int, int) {} ///< Not used
void processingInstruction(const Poco::XML::XMLString&, const Poco::XML::XMLString&) {} ///< Not used
void startPrefixMapping(const Poco::XML::XMLString&, const Poco::XML::XMLString&) {} ///< Not used
void endPrefixMapping(const Poco::XML::XMLString&) {} ///< Not used
void skippedEntity(const Poco::XML::XMLString&) {} ///< Not used

private:
/// Populates the group list
void getIDNumbers(const Poco::XML::Attributes& attr);
/// map of groups
storage_map m_groups;
/// group currently being read from file
std::vector<size_t> m_currentGroup;
/// whether reading spectra numbers or detector ids
bool m_specNo;
/// whether currently inside a group element
bool m_inGroup;
/// map of spectra number to workspace index
spec2index_map m_specnTOwi;
/// map of detector id to workspace index
detid2index_map * m_detidTOwi;
/// vector where value represent whether the workspace index corresponding to that position in the vector has been used
std::vector<int64_t> m_unused;
};

/// An estimate of the percentage of the algorithm runtimes that has been completed
double m_FracCompl;
/// stores lists of spectra indexes to group, although we never do an index search on it
Expand Down
241 changes: 86 additions & 155 deletions Code/Mantid/Framework/DataHandling/src/GroupDetectors2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "MantidAPI/FileProperty.h"
#include "MantidKernel/Exception.h"
#include "MantidKernel/ListValidator.h"
#include "MantidDataHandling/LoadDetectorsGroupingFile.h"

#include <boost/lexical_cast.hpp>
#include <boost/shared_ptr.hpp>
Expand Down Expand Up @@ -195,7 +196,7 @@ void GroupDetectors2::getGroups(API::MatrixWorkspace_const_sptr workspace,
g_log.debug() << "Converted " << spectraList.size() << " spectra numbers into spectra indices to be combined\n";
}
else
{// go thorugh the rest of the properties in order of decreasing presidence, abort when we get the data we need ignore the rest
{// go through the rest of the properties in order of decreasing presidence, abort when we get the data we need ignore the rest
if ( ! detectorList.empty() )
{
// we are going to group on the basis of detector IDs, convert from detectors to workspace indices
Expand Down Expand Up @@ -332,32 +333,102 @@ void GroupDetectors2::processFile(std::string fname,
void GroupDetectors2::processXMLFile(std::string fname,
API::MatrixWorkspace_const_sptr workspace, std::vector<int64_t> &unUsedSpec)
{
// 1. Get maps for spectrum ID and detector ID
spec2index_map specs2index;
const SpectraAxis* axis = dynamic_cast<const SpectraAxis*>(workspace->getAxis(1));
if (axis)
{
axis->getSpectraIndexMap(specs2index);
}

detid2index_map* detIdToWiMap = workspace->getDetectorIDToWorkspaceIndexMap(false);

GroupXmlReader groupReader;
Poco::XML::SAXParser parser;
parser.setContentHandler(&groupReader);

groupReader.setMaps(specs2index, detIdToWiMap, unUsedSpec);

try
// 2. Load XML file
DataHandling::LoadGroupXMLFile loader;
loader.setDefaultStartingGroupID(0);
loader.loadXMLFile(fname);
std::map<int, std::vector<detid_t> > mGroupDetectorsMap = loader.getGroupDetectorsMap();
std::map<int, std::vector<int> > mGroupSpectraMap = loader.getGroupSpectraMap();

// 3. Build m_GroupSpecInds
std::map<int, std::vector<detid_t> >::iterator dit;
for (dit = mGroupDetectorsMap.begin(); dit != mGroupDetectorsMap.end(); ++ dit)
{
parser.parse(fname);
int groupid = dit->first;
std::vector<size_t> tempv;
m_GroupSpecInds.insert(std::make_pair(groupid, tempv));
}
catch ( Poco::Exception & e )

// 4. Detector IDs
for (dit = mGroupDetectorsMap.begin(); dit != mGroupDetectorsMap.end(); ++ dit)
{
g_log.error() << "GroupDetectors XML error: " << e.displayText() << std::endl;
throw std::runtime_error("Error parsing XML file");
}
int groupid = dit->first;
std::vector<detid_t> detids = dit->second;

storage_map::iterator sit;
sit = m_GroupSpecInds.find(groupid);
if (sit == m_GroupSpecInds.end())
continue;

std::vector<size_t>& wsindexes = sit->second;

for (size_t i = 0; i < detids.size(); i++)
{
detid_t detid = detids[i];
detid2index_map::iterator ind =detIdToWiMap->find(detid);
size_t wsid;
if ( ind != detIdToWiMap->end() )
{
wsid = ind->second;
wsindexes.push_back(wsid);
if ( unUsedSpec[wsid] != ( 1000 - INT_MAX ) )
{
unUsedSpec[wsid] = ( 1000 - INT_MAX );
}
}
else
{
g_log.error() << "Detector with ID " << detid << " is not found in instrument " << std::endl;
}
} // for index
} // for group

// 5. Spectrum IDs
std::map<int, std::vector<int> >::iterator pit;
for (pit = mGroupSpectraMap.begin(); pit != mGroupSpectraMap.end(); ++pit)
{
int groupid = pit->first;
std::vector<int> spectra = pit->second;

storage_map::iterator sit;
sit = m_GroupSpecInds.find(groupid);
if (sit == m_GroupSpecInds.end())
continue;

std::vector<size_t>& wsindexes = sit->second;

for (size_t i = 0; i < spectra.size(); i++)
{
int specid = spectra[i];
spec2index_map::iterator ind = specs2index.find(specid);
size_t wsid;
if ( ind != specs2index.end() )
{
wsid = ind->second;
wsindexes.push_back(wsid);
if ( unUsedSpec[wsid] != ( 1000 - INT_MAX ) )
{
unUsedSpec[wsid] = ( 1000 - INT_MAX );
}
}
else
{
g_log.error() << "Spectrum with ID " << specid<< " is not found in instrument " << std::endl;
}
} // for index
} // for group

groupReader.getItems(m_GroupSpecInds, unUsedSpec);
return;
}

/** The function expects that the string passed to it contains an integer number,
Expand Down Expand Up @@ -766,145 +837,5 @@ void GroupDetectors2::RangeHelper::getList(const std::string &line, std::vector<
}
}

/**
* This is the constructor for the GroupXmlReader class. It simply initialises the boolean member variables
* and calls the parent's constructor.
*/
GroupDetectors2::GroupXmlReader::GroupXmlReader() : ContentHandler(), m_specNo(true), m_inGroup(false)
{}

/**
* This method is called when the parser starts reading a document. It is used hear to ensure that the m_groups
* and m_currentGroup members are clean to begin with.
*/
void GroupDetectors2::GroupXmlReader::startDocument()
{
m_groups.clear();
m_currentGroup.clear();
}
/**
* This function is called at the start of each element. It checks whether the element signals the start of a group,
* the values in a group, or can be ignored.
* @param localName the name of the element. for example in \<group name="a"\>, this would be "group"
* @param attr the attributes of the element, in the above example this would be an object linking "name" and "a".
*/
void GroupDetectors2::GroupXmlReader::startElement(const Poco::XML::XMLString &, const Poco::XML::XMLString& localName, const Poco::XML::XMLString&, const Poco::XML::Attributes& attr)
{
if ( localName == "group" )
{
m_inGroup = true;
}
else if ( m_inGroup && ( localName == "ids" || localName == "detids" ) )
{
m_specNo = ( localName == "ids" );
getIDNumbers(attr);
}
}
/**
* This function is called at the end of each element. It only matters here when signifying the end of a group.
* @param localName the name of the element ending. For example, in \</group\> this would be "group".
*/
void GroupDetectors2::GroupXmlReader::endElement(const Poco::XML::XMLString&, const Poco::XML::XMLString& localName, const Poco::XML::XMLString&)
{
if ( m_inGroup && localName == "group" )
{
m_groups[static_cast<int>(m_groups.size())] = m_currentGroup;
m_currentGroup.clear();
m_inGroup = false;
}
}
/**
* Provides the results that GroupDetectors requires from the XML file. A set of groups, and the vector detailing which spectra are / are not used.
* @param map mapping of groups
* @param unused vector where value represent whether the workspace index corresponding to that position in the vector has been used
*/
void GroupDetectors2::GroupXmlReader::getItems(storage_map & map, std::vector<int64_t> & unused)
{
map = m_groups;
unused = m_unused;
}
/**
* Used by GroupDetectors to provide the maps that the parser needs to translate spectra number/detector id into workspace index.
* @param spec map of spectra number to workspace index
* @param det map of detector id to workspace index
* @param unused vector where value represent whether the workspace index corresponding to that position in the vector has been used
*/
void GroupDetectors2::GroupXmlReader::setMaps(spec2index_map spec, detid2index_map * det, std::vector<int64_t> & unused)
{
m_specnTOwi = spec;
m_detidTOwi = det;
m_unused = unused;
}
/**
* Parses string "val" values into a list of number, expanding any ranges, then converts those from either detector id/spectra number into
* the correct workspace index.
* @param attr attributes from the xml element
*/
void GroupDetectors2::GroupXmlReader::getIDNumbers(const Poco::XML::Attributes& attr)
{
for ( int i = 0; i < attr.getLength(); ++i ) // poco requires bare int
{
if ( attr.getLocalName(i) == "val" )
{
std::vector<specid_t> idlist;
// Read from string list into std::vector<int> using Poco StringTokenizer
Poco::StringTokenizer list(attr.getValue(i), ",", Poco::StringTokenizer::TOK_TRIM);
for( Poco::StringTokenizer::Iterator itr = list.begin(); itr != list.end(); ++itr )
{
int id;
try
{
id = boost::lexical_cast<specid_t>(*itr);
idlist.push_back(id);
}
catch ( boost::bad_lexical_cast & )
{
std::vector<size_t> temp;
RangeHelper::getList(*itr, temp);
for ( std::vector<size_t>::iterator it = temp.begin(); it != temp.end(); ++it )
{
idlist.push_back(static_cast<specid_t>(*it));
}
}
}
for ( std::vector<specid_t>::iterator itr = idlist.begin(); itr != idlist.end(); ++itr )
{
int64_t id;
if ( m_specNo )
{
// Spectra No
spec2index_map::iterator ind = m_specnTOwi.find(*itr);
if ( ind == m_specnTOwi.end() )
{
continue;
}
else
{
id = ind->second;
}
}
else
{
// Detector ID
detid2index_map::iterator ind = m_detidTOwi->find(*itr);
if ( ind == m_detidTOwi->end() )
{
continue;
}
else
{
id = ind->second;
}
}
m_currentGroup.push_back(id);
if ( m_unused[id] != ( 1000 - INT_MAX ) )
{
m_unused[id] = ( 1000 - INT_MAX );
}
}
}
}
}

} // namespace DataHandling
} // namespace Mantid

0 comments on commit 4c64657

Please sign in to comment.