Newer
Older
Ronald Fowler
committed
//----------------------------------------------------------------------
// Includes
//----------------------------------------------------------------------
#include "MantidDataHandling/LoadInstrumentFromNexus.h"
Gigg, Martyn Anthony
committed
#include "MantidGeometry/Instrument/Instrument.h"
#include "MantidGeometry/Instrument/Detector.h"
#include "MantidGeometry/Instrument/CompAssembly.h"
#include "MantidGeometry/Instrument/Component.h"
#include "MantidNexus/MuonNexusReader.h"
Gigg, Martyn Anthony
committed
#include "MantidKernel/ConfigService.h"
#include "MantidAPI/FileProperty.h"
Ronald Fowler
committed
#include <fstream>
namespace Mantid
{
namespace DataHandling
Ronald Fowler
committed
{
DECLARE_ALGORITHM(LoadInstrumentFromNexus)
Janik Zikovsky
committed
/// Sets documentation strings for this algorithm
void LoadInstrumentFromNexus::initDocs()
{
this->setWikiSummary(" Attempts to load information about the instrument from a Nexus file. In particular attempt to read L2 and 2-theta detector position values and add detectors which are positioned relative to the sample in spherical coordinates as (r,theta,phi)=(L2,2-theta,phi). Also adds dummy source and samplepos components to instrument. Later this will be extended to use any further available details about the instrument in the Nexus file. If the L1 source - sample distance is not available in the file then it may be read from the [[Properties File|mantid properties]] file using the key instrument.L1, as a final fallback a default distance of 10m will be used. ");
this->setOptionalMessage("Attempts to load information about the instrument from a Nexus file. In particular attempt to read L2 and 2-theta detector position values and add detectors which are positioned relative to the sample in spherical coordinates as (r,theta,phi)=(L2,2-theta,phi). Also adds dummy source and samplepos components to instrument. Later this will be extended to use any further available details about the instrument in the Nexus file. If the L1 source - sample distance is not available in the file then it may be read from the mantid properties file using the key instrument.L1, as a final fallback a default distance of 10m will be used.");
}
Ronald Fowler
committed
using namespace Kernel;
using namespace API;
Gigg, Martyn Anthony
committed
using Geometry::Instrument;
Ronald Fowler
committed
/// Empty default constructor
LoadInstrumentFromNexus::LoadInstrumentFromNexus()
{}
/// Initialisation method.
void LoadInstrumentFromNexus::init()
{
// When used as a sub-algorithm the workspace name is not used - hence the "Anonymous" to satisfy the validator
Steve Williams
committed
declareProperty(
new WorkspaceProperty<MatrixWorkspace>("Workspace","Anonymous",Direction::InOut),
"The name of the workspace in which to attach the imported instrument" );
Gigg, Martyn Anthony
committed
Peterson, Peter
committed
declareProperty(new FileProperty("Filename", "", FileProperty::Load, ".nxs"),
Gigg, Martyn Anthony
committed
"The name (including its full or relative path) of the Nexus file to\n"
"attempt to load the instrument from. The file extension must either be\n"
".nxs or .NXS" );
Ronald Fowler
committed
}
/** Executes the algorithm. Reading in the file and creating and populating
* the output workspace
*
* @throw FileError Thrown if unable to parse XML file
*/
void LoadInstrumentFromNexus::exec()
{
// Retrieve the filename from the properties
m_filename = getPropertyValue("Filename");
// Get the input workspace
Roman Tolchenov
committed
const MatrixWorkspace_sptr localWorkspace = getProperty("Workspace");
Ronald Fowler
committed
// open Nexus file
MuonNexusReader nxload;
if (nxload.readFromFile(m_filename.c_str()) != 0)
{
g_log.error("Unable to open file " + m_filename);
throw Exception::FileError("Unable to open File:" , m_filename);
}
Sofia Antony
committed
progress(0.5);
Ronald Fowler
committed
// Get reference to Instrument and set its name
Gigg, Martyn Anthony
committed
boost::shared_ptr<Geometry::Instrument> instrument = localWorkspace->getBaseInstrument();
Ronald Fowler
committed
instrument->setName(nxload.getInstrumentName());
// Add dummy source and samplepos to instrument
// The L2 and 2-theta values from nexus file assumed to be relative to sample position
Ronald Fowler
committed
Geometry::ObjComponent *samplepos = new Geometry::ObjComponent("Unknown",instrument.get());
instrument->add(samplepos);
instrument->markAsSamplePos(samplepos);
samplepos->setPos(0.0,0.0,0.0);
Geometry::ObjComponent *source = new Geometry::ObjComponent("Unknown",instrument.get());
instrument->add(source);
instrument->markAsSource(source);
double l1;
// If user has provided an L1, use that
if ( ! Kernel::ConfigService::Instance().getValue("instrument.L1", l1) )
{
// Otherwise try and get it from the nexus file - but not there at present!
// l1 = nxload.ivpb.i_l1;
// Default to 10 if the file doesn't have it set
Ronald Fowler
committed
if (l1 == 0) l1 = 10.0;
}
source->setPos(0.0,-1.0*l1,0.0);
Sofia Antony
committed
progress(1.0);
Ronald Fowler
committed
// add detectors
/* **** Ignoring all this for the moment - the sample Nexus files do not contain most of these values
const int numDetector = nxload.i_det; // number of detectors
const int* const detID = nxload.udet; // detector IDs
const float* const r = nxload.len2; // distance from sample
const float* const angle = nxload.tthe; // angle between indicent beam and direction from sample to detector (two-theta)
for (int i = 0; i < numDetector; ++i)
{
// Create a new detector. Instrument will take ownership of pointer so no need to delete.
Geometry::Detector *detector = new Geometry::Detector("det",samplepos);
Gigg, Martyn Anthony
committed
Kernel::V3D pos;
Ronald Fowler
committed
pos.spherical(r[i], angle[i], 0.0);
detector->setPos(pos);
// set detector ID, add copy to instrument and mark it
detector->setID(detID[i]);
instrument->add(detector);
instrument->markAsDetector(detector);
}
// Now mark the up the monitors
const int numMonitors = nxload.i_mon; // The number of monitors
const int* const monIndex = nxload.mdet; // Index into the udet array for each monitor
for (int j = 0; j < numMonitors; ++j)
{
const int detectorToMark = detID[monIndex[j]-1];
Geometry::Detector *det = dynamic_cast<Geometry::Detector*>(instrument->getDetector(detectorToMark));
det->markAsMonitor();
g_log.information() << "Detector with ID " << detectorToMark << " marked as a monitor." << std::endl;
}
// Information to the user about what info is extracted from nexus file
Ronald Fowler
committed
g_log.information() << "SamplePos component added with position set to (0,0,0).\n"
<< "Detector components added with position coordinates assumed to be relative to the position of the sample; \n"
<< "L2 and two-theta values were read from nexus file and used to set the r and theta spherical coordinates; \n"
Ronald Fowler
committed
<< "the remaining spherical coordinate phi was set to zero.\n"
<< "Source component added with position set to (0,-" << l1 << ",0). In standard configuration, with \n"
<< "the beam along y-axis pointing from source to sample, this implies the source is " << l1 << "m in front \n"
<< "of the sample. This value can be changed via the 'instrument.l1' configuration property.\n";
*/
return;
}
} // namespace DataHandling
Ronald Fowler
committed
} // namespace Mantid