@@ -91,6 +91,55 @@ namespace Mantid
throw std::invalid_argument("Unknown NeXus file format found in file '" + filename + "'");
}

///Use frequency start for Monitor19 and Special1_19 logs with "No Time" for SNAP
try
{
file.openGroup("DASlogs", "NXgroup");
try
{
file.openGroup("frequency", "NXlog");
try
{
file.openData("time");

//----- Start time is an ISO8601 string date and time. ------
try
{
file.getAttr("start", freqStart);

}
catch (::NeXus::Exception &)
{
//Some logs have "offset" instead of start
try
{
file.getAttr("offset", freqStart);
}
catch (::NeXus::Exception &)
{
g_log.warning() << "Log entry has no start time indicated.\n";
file.closeData();
throw;
}
}
file.closeData();
}
catch (::NeXus::Exception&)
{
// No time. This is not an SNS SNAP file
}
file.closeGroup();
}
catch (::NeXus::Exception&)
{
// No time. This is not an SNS frequency group
}
file.closeGroup();
}
catch (::NeXus::Exception&)
{
// No time. This is not an SNS group
}
// print out the entry level fields
std::map<std::string,std::string> entries = file.getEntries();
std::map<std::string,std::string>::const_iterator iend = entries.end();
@@ -453,6 +502,11 @@ namespace Mantid
throw;
}
}
if (start.compare("No Time") == 0)
{
start = freqStart;
}

//Convert to date and time
Kernel::DateAndTime start_time = Kernel::DateAndTime(start);
std::string time_units;
@@ -100,15 +100,13 @@ namespace DataHandling
UNUSED_ARG(header);

std::string ext = extension(filePath);
return (ext.rfind("_runinfo.xml") != std::string::npos);
return (filePath.compare(filePath.size()-12,12,"_runinfo.xml") == 0);
}

/// @copydoc Mantid::API::IDataFileChecker::fileCheck
int LoadPreNexus::fileCheck(const std::string& filePath)
{
std::string ext = extension(filePath);

if (ext.rfind("_runinfo.xml") != std::string::npos)
if( filePath.compare(filePath.size()-12,12,"_runinfo.xml") == 0)
return 80;
else
return 0;
@@ -62,6 +62,12 @@ int LoadSassena::fileCheck(const std::string &filePath)
return confidence;
}

void LoadSassena::registerWorkspace( API::WorkspaceGroup_sptr gws, const std::string wsName, DataObjects::Workspace2D_sptr ws, const std::string &description )
{
this->declareProperty(new API::WorkspaceProperty<DataObjects::Workspace2D>(wsName,"",Kernel::Direction::Output), description);
this->setProperty(wsName,ws);
gws->add(wsName); // Add the named workspace to the group
}
/**
* Initialise the algorithm. Declare properties which can be set before execution (input) or
* read from after the execution (output).
@@ -83,22 +89,17 @@ void LoadSassena::init()
*/
void LoadSassena::exec()
{
//this->GWS = API::WorkspaceFactory::Instance().create("WorkspaceGroup");
// WorkspaceGroup_sptr wsgroup = AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>(inputs_orig[i]);
// API::WorkspaceGroup_sptr gws = boost::dynamic_pointer_cast<API::WorkspaceGroup>(rws);
// MatrixWorkspace_sptr outputWS = boost::dynamic_pointer_cast<MatrixWorkspace>(WorkspaceFactory::Instance().create("Workspace2D",numSpectra,energies.size(),numBins));

API::WorkspaceGroup_sptr gws = this->getProperty("OutputWorkspace");
const std::string gwsName = gws->name();
const std::string gwsName = this->getPropertyValue("OutputWorkspace");
API::WorkspaceGroup_sptr gws(new API::WorkspaceGroup);

//populate m_validSets
int nvalidSets = 4;
const char* validSets[] = { "fq", "fq0", "fq2", "fqt"};
for(int iSet=0; iSet<nvalidSets; iSet++) this->m_validSets.push_back( validSets[iSet] );

//open the HDF5 file
this->m_filename = this->getPropertyValue("Filename");
hid_t h5file = H5Fopen(this->m_filename.c_str(),H5F_ACC_RDONLY,H5P_DEFAULT);
m_filename = this->getPropertyValue("Filename");
hid_t h5file = H5Fopen(m_filename.c_str(),H5F_ACC_RDONLY,H5P_DEFAULT);
herr_t status;

//find out the sassena version used
@@ -110,32 +111,35 @@ void LoadSassena::exec()
//to be done at a later time, maybe implement a Version class

int rank[3]; //store dimensions
H5T_class_t class_id;
size_t type_size;
hsize_t dims[3];
/*load vectors onto a Workspace2D with 3 bins (the three components of the vectors)
* dataX for the origin of the vector (assumed (0,0,0) )
* dataY for the tip of the vector
* dataE is assumed (0,0,0), no errors
*/
std::string setName("qvectors");
status = H5LTget_dataset_ndims( h5file, setName.c_str(), rank );
int nq = rank[0]; //number of q-vectors
DataObjects::Workspace2D_sptr ws = boost::dynamic_pointer_cast<DataObjects::Workspace2D>(API::WorkspaceFactory::Instance().create("Workspace2D", nq, 3, 3));
std::string wsName = gwsName + std::string(".qvectors") + setName;
ws->setTitle(wsName);
ws->getAxis(0)->setUnit("MomemtumTransfer");
ws->setYUnit("MomemtumTransfer");
status = H5LTget_dataset_info( h5file, setName.c_str(), dims, &class_id, &type_size );
int nq = static_cast<int>( dims[0] ); //number of q-vectors
double* buf = new double[nq*3];
H5LTread_dataset_double(h5file,"qvectors",buf);

DataObjects::Workspace2D_sptr ws = boost::dynamic_pointer_cast<DataObjects::Workspace2D>(API::WorkspaceFactory::Instance().create("Workspace2D", nq, 3, 3));
std::string wsName = gwsName + std::string(".") + setName;
ws->setTitle(wsName);
MantidVec qvmod; //store the modulus of the vector

double* curr = buf;
for(int iq=0; iq<nq; iq++){
MantidVec& Y = ws->dataY(iq);
Y.assign(curr,curr+3);
qvmod.push_back( sqrt( curr[0]*curr[0] + curr[1]*curr[1] + curr[2]*curr[2] ) );
curr += 3;
}
delete buf;
gws->add(wsName); // Add the named workspace to the group

delete buf;
this->registerWorkspace(gws,setName,ws, "X-axis: origin of Q-vectors; Y-axis: tip of Q-vectors");


//iterate over the valid sets
@@ -164,7 +168,8 @@ void LoadSassena::exec()
curr += 2;
}
delete buf;
gws->add(wsName); // Add the named workspace to the group

this->registerWorkspace(gws,setName,ws, "X-axis: Q-vector modulus; Y-axis: intermediate structure factor");
}

else if(setName == "fqt")
@@ -204,12 +209,14 @@ void LoadSassena::exec()
}
}
delete buf;
gws->add(wsReName); // Add the named workspace to the group
gws->add(wsImName);
this->registerWorkspace(gws,wsReName,wsRe, "X-axis: time; Y-axis: real part of intermediate structure factor");
this->registerWorkspace(gws,wsImName,wsIm, "X-axis: time; Y-axis: imaginary part of intermediate structure factor");
}
}
}

this->setProperty( "OutputWorkspace", gws ); //register the groupWorkspace in the analysis data service

} // end of LoadSassena::exec()


@@ -7,13 +7,48 @@
class LoadSassenaTest : public CxxTest::TestSuite
{
public:
void test_Init()
static LoadSassenaTest *createSuite() { return new LoadSassenaTest(); }
static void destroySuite( LoadSassenaTest *suite ) { delete suite; }

LoadSassenaTest()
{
m_inputFile = "outputSassena_1.4.1.h5";
}

void testInit()
{
TS_ASSERT_THROWS_NOTHING( m_alg.initialize() )
TS_ASSERT( m_alg.isInitialized() )
}

void testFileCheck()
{
Mantid::DataHandling::LoadSassena alg;
TS_ASSERT_THROWS_NOTHING( alg.initialize() )
TS_ASSERT( alg.isInitialized() )
if( !m_alg.isInitialized() ) m_alg.initialize();
m_alg.setPropertyValue( "Filename", m_inputFile );
TS_ASSERT_EQUALS(m_alg.fileCheck(m_alg.getPropertyValue("Filename")), 99);
}

};
void testExec()
{
std::string result;
if( !m_alg.isInitialized() ) m_alg.initialize();

m_alg.setPropertyValue( "Filename", m_inputFile );

const std::string outSpace = "outGWS";
m_alg.setPropertyValue( "OutputWorkSpace", outSpace );
TS_ASSERT_THROWS_NOTHING( result = m_alg.getPropertyValue("OutputWorkspace") )
TS_ASSERT( result == outSpace );

TS_ASSERT_THROWS_NOTHING( m_alg.execute() );
TS_ASSERT( m_alg.isExecuted() );

} // end of testExec

private:
std::string m_inputFile;
Mantid::DataHandling::LoadSassena m_alg;

}; // end of class LoadSassenaTest

#endif // MANTID_DATAHANDLING_LOADSASSENATEST_H_
@@ -50,7 +50,7 @@ namespace Geometry

void construct(const Mantid::Kernel::VMD & min, const Mantid::Kernel::VMD & max);

~MDBoxImplicitFunction();
virtual ~MDBoxImplicitFunction();

};

@@ -64,6 +64,7 @@ namespace Geometry
{
public:
MDImplicitFunction();
MDImplicitFunction(const MDImplicitFunction & other);
virtual ~MDImplicitFunction();

void addPlane(const MDPlane & plane);
@@ -22,6 +22,13 @@ namespace Geometry
{
}

/** Copy constructor
* @param other :: copy this
*/
MDImplicitFunction::MDImplicitFunction(const MDImplicitFunction & other)
: m_nd(other.m_nd), m_planes(other.m_planes), m_numPlanes(other.m_numPlanes)
{
}

//----------------------------------------------------------------------------------------------
/** Add a bounded plane to this implicit function
@@ -87,65 +87,6 @@ void splitPath(const std::string &path, std::vector<std::string> &splitted)
}
}

/**
* Verify that two paths are equal. This can be two directories or two
* semicolon separated paths.
*
* @param left The left path for comparison.
* @param right The right path for comparison.
*
* @return True if the paths match.
*/
bool pathsEqual(const std::string &left, const std::string &right)
{
if (left == right)
return true;

// deal with silly case of empty paths
if (left.empty())
return false;
if (right.empty())
return false;

// check for path rather than simple directory
if ((left.find(";") != std::string::npos) || (right.find(";") != std::string::npos))
{
// at least one has a semicolons

std::vector<std::string> leftDirs;
splitPath(left, leftDirs);

std::vector<std::string> rightDirs;
splitPath(right, rightDirs);

// confirm they have the same number of items
if (leftDirs.size() != rightDirs.size())
return false;

// sort the vectors
std::sort(leftDirs.begin(), leftDirs.end());
std::sort(rightDirs.begin(), rightDirs.end());

// assume that they are in the same order now
std::size_t numpaths = leftDirs.size();
for (std::size_t i = 0; i < numpaths; i++)
{
if (!pathsEqual(leftDirs[i], rightDirs[i]))
return false;
}
return true;
}

Poco::File leftDir(left);
if (!leftDir.isDirectory())
return false;
Poco::File rightDir(right);
if (!rightDir.isDirectory())
return false;

return (leftDir == rightDir);
}

} // end of anonymous namespace

/** Inner templated class to wrap the poco library objects that have protected
@@ -1083,14 +1024,9 @@ void ConfigServiceImpl::launchProcess(const std::string& programFilePath, const
*/
void ConfigServiceImpl::setString(const std::string & key, const std::string & value)
{
std::string old;
try
{
old = m_pConf->getString(key);
} catch (Poco::NotFoundException &)
{
old = "";
}
// If the value is unchanged (after any path conversions), there's nothing to do.
const std::string old = getString(key);
if ( value == old ) return;

//Ensure we keep a correct full path
std::map<std::string, bool>::const_iterator itr = m_ConfigPaths.find(key);
@@ -1114,27 +1050,8 @@ void ConfigServiceImpl::setString(const std::string & key, const std::string & v

m_pConf->setString(key, value);

if (value != old)
{
// if the property ends in "directory"
const std::string dirKey("directory");
if (key.size() > dirKey.size() && key.rfind(dirKey) != std::string::npos)
{
if (pathsEqual(value, old))
return;
}

// if the property ends in "directories"
const std::string dirsKey("directories");
if (key.size() > dirsKey.size() && key.rfind(dirsKey) != std::string::npos)
{
if (pathsEqual(value, old))
return;
}

m_notificationCenter.postNotification(new ValueChanged(key, value, old));
m_changed_keys.insert(key);
}
m_notificationCenter.postNotification(new ValueChanged(key, value, old));
m_changed_keys.insert(key);
}

/** Searches for a string within the currently loaded configuaration values and
@@ -1453,6 +1370,8 @@ void ConfigServiceImpl::setDataSearchDirs(const std::string &searchDirs)
*/
void ConfigServiceImpl::appendDataSearchDir(const std::string & path)
{
if ( path.empty() ) return;

Poco::Path dirPath;
try
{
@@ -54,7 +54,7 @@ class DLLExport CompositeImplicitFunction: public Mantid::Geometry::MDImplicitFu
//-----------------------------------------------------------------

CompositeImplicitFunction();
~CompositeImplicitFunction();
virtual ~CompositeImplicitFunction();
bool addFunction(Mantid::Geometry::MDImplicitFunction_sptr constituentFunction);
std::string getName() const;
std::string toXMLString() const;
@@ -45,7 +45,7 @@ namespace Mantid
{
public:
NullImplicitFunction();
~NullImplicitFunction();
virtual ~NullImplicitFunction();
virtual std::string getName() const;
virtual std::string toXMLString() const;
//----------------------MDImplicit function methods ------------
@@ -32,7 +32,7 @@ namespace MDEvents
SkippingPolicy* skippingPolicy, Mantid::Geometry::MDImplicitFunction * function = NULL);
MDBoxIterator(std::vector<MDBoxBase<MDE,nd>*> & boxes, size_t begin, size_t end);
void init(std::vector<MDBoxBase<MDE,nd>*> & boxes, size_t begin, size_t end);
~MDBoxIterator();
virtual ~MDBoxIterator();

/// Return a pointer to the current box pointed to by the iterator.
MDBoxBase<MDE,nd> * getBox() const
@@ -51,7 +51,7 @@ namespace MDEvents
size_t beginPos = 0, size_t endPos = size_t(-1));
MDHistoWorkspaceIterator(const MDHistoWorkspace * workspace, Mantid::Geometry::MDImplicitFunction * function = NULL,
size_t beginPos = 0, size_t endPos = size_t(-1));
~MDHistoWorkspaceIterator();
virtual ~MDHistoWorkspaceIterator();

void init(const MDHistoWorkspace * workspace, Mantid::Geometry::MDImplicitFunction * function,
size_t beginPos = 0, size_t endPos = size_t(-1));
@@ -284,6 +284,10 @@ namespace Mantid
// MDHistoWorkspace case.
this->loadHisto();
}
if(!fileBacked)
{
delete file;
}
}


@@ -328,6 +332,8 @@ namespace Mantid
this->loadSlab("num_events", ws->getNumEventsArray(), ws, ::NeXus::FLOAT64);
this->loadSlab("mask", ws->getMaskArray(), ws, ::NeXus::INT8);

file->close();

// Save to output
setProperty("OutputWorkspace", boost::dynamic_pointer_cast<IMDWorkspace>(ws));
}
@@ -387,7 +387,7 @@ namespace MDEvents
/** Create IMDIterators from this MDHistoWorkspace
*
* @param suggestedNumCores :: split the iterators into this many cores (if threadsafe)
* @param function :: implicit function to limit range
* @param function :: implicit function to limit range. NOT owned by this method call.
* @return MDHistoWorkspaceIterator vector
*/
std::vector<Mantid::API::IMDIterator*> MDHistoWorkspace::createIterators(size_t suggestedNumCores,
@@ -407,7 +407,13 @@ namespace MDEvents
size_t end = ((i+1) * numElements) / numCores;
if (end > numElements)
end = numElements;
out.push_back(new MDHistoWorkspaceIterator(this, function, begin, end));

// Clone the MDImplicitFunction if necessary.
Mantid::Geometry::MDImplicitFunction * clonedFunction = function;
if (function)
clonedFunction = new Mantid::Geometry::MDImplicitFunction(*function);

out.push_back(new MDHistoWorkspaceIterator(this, clonedFunction, begin, end));
}
return out;
}
@@ -18,7 +18,7 @@ namespace MDEvents
/** Constructor
*
* @param workspace :: MDHistoWorkspace_sptr being iterated
* @param function :: The implicit function to use
* @param function :: The implicit function to use. Becomes owned by this object.
* @return
*/
MDHistoWorkspaceIterator::MDHistoWorkspaceIterator(MDHistoWorkspace_const_sptr workspace, Mantid::Geometry::MDImplicitFunction * function,
@@ -31,7 +31,7 @@ namespace MDEvents
/** Constructor
*
* @param workspace :: MDHistoWorkspace_sptr being iterated
* @param function :: The implicit function to use
* @param function :: The implicit function to use. Becomes owned by this object.
* @return
*/
MDHistoWorkspaceIterator::MDHistoWorkspaceIterator(const MDHistoWorkspace * workspace, Mantid::Geometry::MDImplicitFunction * function,
@@ -44,7 +44,7 @@ namespace MDEvents
/** Constructor
*
* @param workspace :: MDHistoWorkspace_sptr being iterated
* @param function :: The implicit function to use
* @param function :: The implicit function to use. Becomes owned by this object.
* @param skippingPolicy :: The skipping policy to use
* @return
*/
@@ -58,7 +58,7 @@ namespace MDEvents
/** Constructor
*
* @param workspace :: MDHistoWorkspace_sptr being iterated
* @param function :: The implicit function to use
* @param function :: The implicit function to use. Becomes owned by this object.
* @param skippingPolicy :: The skipping policy to use
* @return
*/
@@ -139,6 +139,7 @@ namespace MDEvents
delete [] m_indexMax;

if (m_function) delete m_function;
m_function = NULL;
}


@@ -504,26 +504,18 @@ class LoadMDTest : public CxxTest::TestSuite

void test_histo2()
{
// Fails on windows with file access error
#ifndef _WIN32
MDHistoWorkspace_sptr ws = MDEventsTestHelper::makeFakeMDHistoWorkspace(2.5, 2, 10, 10.0, 3.5, "histo2", 4.5);
doTestHisto(ws);
#endif
}

void test_histo3()
{
// Fails on windows with file access error
#ifndef _WIN32
MDHistoWorkspace_sptr ws = MDEventsTestHelper::makeFakeMDHistoWorkspace(2.5, 3, 4, 10.0, 3.5, "histo3", 4.5);
doTestHisto(ws);
#endif
}


};


#endif /* MANTID_MDEVENTS_LOADMDEWTEST_H_ */


@@ -152,6 +152,8 @@ def PyExec(self):

# Load the data into its workspace
allow_multiple = True
print run_numbers

if len(run_numbers)>1 and allow_multiple:

for _run in run_numbers:
@@ -231,80 +231,49 @@ def PyInit(self):
self.declareProperty("NormalizeByCurrent", True, Description="Normalized by Current")
self.declareProperty("FinalDataUnits", "dSpacing", ListValidator(["dSpacing","MomentumTransfer"]))

def _loadPreNeXusData(self, runnumber, extension, **chunk):
chunkNo = 1
if chunk.has_key("ChunkNumber"):
chunkNo = int(chunk["ChunkNumber"])

# generate the workspace name
name = "%s_%d" % (self._instrument, runnumber)
filename = name + extension
self.log().debug(filename)

name += "_%02d" % (chunkNo)
alg = LoadPreNexus(Filename=filename, OutputWorkspace=name, **chunk)
wksp = alg['OutputWorkspace']

return wksp

def _loadEventNeXusData(self, runnumber, extension, filterWall=None, **chunk):
chunkNo = 1
if chunk.has_key("ChunkNumber"):
chunkNo = int(chunk["ChunkNumber"])
chunk["Precount"] = True
if filterWall is not None:
if filterWall[0] > 0.:
chunk["FilterByTimeStart"] = filterWall[0]
if filterWall[1] > 0.:
chunk["FilterByTimeStop"] = filterWall[1]

name = "%s_%d" % (self._instrument, runnumber)
filename = name + extension

name += "_%02d" % (chunkNo)
alg = LoadEventNexus(Filename=filename, OutputWorkspace=name, **chunk)
return alg.workspace()

def _loadHistoNeXusData(self, runnumber, extension):
name = "%s_%d" % (self._instrument, runnumber)
filename = name + extension

name += "_%02d" % 1
alg = LoadTOFRawNexus(Filename=filename, OutputWorkspace=name)
return alg.workspace()

def _loadData(self, runnumber, extension, filterWall=None, **chunk):
if runnumber is None or runnumber <= 0:
return None

name = "%s_%d" % (self._instrument, runnumber)
filename = name + extension
# EMPTY_INT() from C++
if int(chunk["ChunkNumber"]) < 2147483647:
name += "_%02d" % (int(chunk["ChunkNumber"]))
else:
name += "_%02d" % 0

if extension.endswith("_event.nxs"):
return self._loadEventNeXusData(runnumber, extension, filterWall, **chunk)
chunk["Precount"] = True
if filterWall is not None:
if filterWall[0] > 0.:
chunk["FilterByTimeStart"] = filterWall[0]
if filterWall[1] > 0.:
chunk["FilterByTimeStop"] = filterWall[1]
elif extension.endswith("_histo.nxs"):
return self._loadHistoNeXusData(runnumber, extension)
else:
return self._loadPreNeXusData(runnumber, extension, **chunk)
chunk = {}

alg = Load(Filename=filename, OutputWorkspace=name, **chunk)
return alg.workspace()

def _getStrategy(self, runnumber, extension):
# generate the workspace name
wksp = "%s_%d" % (self._instrument, runnumber)
strategy = []
if HAVE_MPI:
comm = mpi.world
if self._chunks > 0 and not "histo" in extension and comm.size > 1:
Chunks = DetermineChunking(Filename=wksp+extension,MaxChunkSize=self._chunks,OutputWorkspace='Chunks').workspace()
for row in Chunks:
if (int(row["ChunkNumber"])-1)%comm.size == comm.rank:
strategy.append(row)
elif comm.size > 1:
strategy.append({'ChunkNumber':comm.rank+1,'TotalChunks':comm.size})
Chunks = DetermineChunking(Filename=wksp+extension,MaxChunkSize=self._chunks,OutputWorkspace='Chunks').workspace()
# What about no chunks for parallel?
if len(Chunks) == 1:
strategy.append({'ChunkNumber':comm.rank+1,'TotalChunks':comm.size})
else:
strategy.append({})
for row in Chunks:
if (int(row["ChunkNumber"])-1)%comm.size == comm.rank:
strategy.append(row)

else:
if self._chunks > 0 and not "histo" in extension:
Chunks = DetermineChunking(Filename=wksp+extension,MaxChunkSize=self._chunks,OutputWorkspace='Chunks').workspace()
for row in Chunks: strategy.append(row)
else:
strategy.append({})
Chunks = DetermineChunking(Filename=wksp+extension,MaxChunkSize=self._chunks,OutputWorkspace='Chunks').workspace()
for row in Chunks: strategy.append(row)

return strategy

@@ -335,10 +304,10 @@ def _focusChunks(self, runnumber, extension, filterWall, calib, filterLogs=None,
if HAVE_MPI and len(strategy) > 1:
alg = GatherWorkspaces(InputWorkspace=wksp, PreserveEvents=preserveEvents, AccumulationMethod="Add", OutputWorkspace=wksp)
wksp = alg['OutputWorkspace']
if self._chunks > 0 and not "histo" in extension:
if self._chunks > 0:
# When chunks are added, proton charge is summed for all chunks
wksp.getRun().integrateProtonCharge()
mtd.deleteWorkspace('Chunks')
mtd.deleteWorkspace('Chunks')
if preserveEvents and not "histo" in self.getProperty("Extension"):
CompressEvents(InputWorkspace=wksp, OutputWorkspace=wksp, Tolerance=COMPRESS_TOL_TOF) # 100ns
if normByCurrent:
@@ -143,16 +143,22 @@ void EQSANSDarkCurrentSubtraction::exec()
if (loadAlg->existsProperty("LoadMonitors"))
loadAlg->setProperty("LoadMonitors", false);
loadAlg->executeAsSubAlg();
darkWS = loadAlg->getProperty("OutputWorkspace");
} else {
loadAlg = reductionManager->getProperty("LoadAlgorithm");
// Get load algorithm as a string so that we can create a completely
// new proxy and ensure that we don't overwrite existing properties
IAlgorithm_sptr loadAlg0 = reductionManager->getProperty("LoadAlgorithm");
const std::string loadString = loadAlg0->toString();
loadAlg = Algorithm::fromString(loadString);
loadAlg->setChild(true);
loadAlg->setProperty("Filename", fileName);
if (loadAlg->existsProperty("LoadMonitors"))
loadAlg->setProperty("LoadMonitors", false);
loadAlg->setPropertyValue("OutputWorkspace", darkWSName);
loadAlg->execute();
darkWS = loadAlg->getProperty("OutputWorkspace");
}
darkWS = loadAlg->getProperty("OutputWorkspace");

output_message += "\n Loaded " + fileName + "\n";
if (loadAlg->existsProperty("OutputMessage"))
{
@@ -73,7 +73,7 @@ void EQSANSLoad::init()
declareProperty(new WorkspaceProperty<>("OutputWorkspace","",Direction::Output),
"Then name of the output EventWorkspace");
declareProperty("NoBeamCenter", false, "If true, the detector will not be moved according to the beam center");
declareProperty("UseConfigBeam", true, "If true, the beam center defined in the configuration file will be used");
declareProperty("UseConfigBeam", false, "If true, the beam center defined in the configuration file will be used");
declareProperty("BeamCenterX", EMPTY_DBL(), "Beam position in X pixel coordinates (used only if UseConfigBeam is false)");
declareProperty("BeamCenterY", EMPTY_DBL(), "Beam position in Y pixel coordinates (used only if UseConfigBeam is false)");
declareProperty("UseConfigTOFCuts", false, "If true, the edges of the TOF distribution will be cut according to the configuration file");
@@ -337,7 +337,7 @@ void EQSANSLoad::getSourceSlitSize()
}
}
dataWS->mutableRun().addProperty("source-aperture-diameter", S1, "mm", true);
m_output_message += " Source aperture diameter = ";
m_output_message += " Source aperture diameter: ";
Poco::NumberFormatter::append(m_output_message, S1, 1);
m_output_message += " mm\n";
}
@@ -590,6 +590,14 @@ void EQSANSLoad::exec()
bool use_config = getProperty("UseConfig");
if (use_config && config_file.size()>0)
{
// Special case to force reading the beam center from the config file
// We're adding this to be compatible with the original EQSANS load
// written in python
if (m_center_x==0.0 && m_center_y==0.0)
{
setProperty("UseConfigBeam", true);
}

readConfigFile(config_file);
} else if (use_config) {
use_config = false;
@@ -734,6 +742,7 @@ void EQSANSLoad::exec()

dataWS->mutableRun().addProperty("event_ws", getPropertyValue("OutputWorkspace"), true);
setProperty<MatrixWorkspace_sptr>("OutputWorkspace", boost::dynamic_pointer_cast<MatrixWorkspace>(dataWS));
//m_output_message = "Loaded " + fileName + '\n' + m_output_message;
setPropertyValue("OutputMessage", m_output_message);
}

@@ -127,7 +127,9 @@ void HFIRDarkCurrentSubtraction::exec()
loadAlg->setProperty("ReductionProperties", reductionManagerName);
loadAlg->executeAsSubAlg();
} else {
loadAlg = reductionManager->getProperty("LoadAlgorithm");
IAlgorithm_sptr loadAlg0 = reductionManager->getProperty("LoadAlgorithm");
const std::string loadString = loadAlg0->toString();
loadAlg = Algorithm::fromString(loadString);
loadAlg->setChild(true);
loadAlg->setProperty("Filename", fileName);
loadAlg->setProperty("ReductionProperties", reductionManagerName);
@@ -50,6 +50,7 @@ void HFIRLoad::init()
"The name of the input file to load");
declareProperty(new WorkspaceProperty<>("OutputWorkspace","",Direction::Output),
"Then name of the output workspace");
declareProperty("NoBeamCenter", false, "If true, the detector will not be moved according to the beam center");
declareProperty("BeamCenterX", EMPTY_DBL(), "Beam position in X pixel coordinates");
declareProperty("BeamCenterY", EMPTY_DBL(), "Beam position in Y pixel coordinates");
declareProperty("SampleDetectorDistance", EMPTY_DBL(), "Sample to detector distance to use (overrides meta data), in mm");
@@ -71,10 +72,6 @@ void HFIRLoad::init()
/// Move the detector according to the beam center
void HFIRLoad::moveToBeamCenter()
{
double beam_ctr_x = 0.0;
double beam_ctr_y = 0.0;
HFIRInstrument::getCoordinateFromPixel(m_center_x, m_center_y, dataWS, beam_ctr_x, beam_ctr_y);

double default_ctr_x_pix = 0.0;
double default_ctr_y_pix = 0.0;
double default_ctr_x = 0.0;
@@ -83,6 +80,22 @@ void HFIRLoad::moveToBeamCenter()
HFIRInstrument::getCoordinateFromPixel(default_ctr_x_pix, default_ctr_y_pix, dataWS,
default_ctr_x, default_ctr_y);

// Check that we have a beam center defined, otherwise set the
// default beam center
if (isEmpty(m_center_x) || isEmpty(m_center_y))
{
m_center_x = default_ctr_x_pix;
m_center_y = default_ctr_y_pix;
g_log.information() << "Setting beam center to ["
<< Poco::NumberFormatter::format(m_center_x, 1) << ", "
<< Poco::NumberFormatter::format(m_center_y, 1) << "]" << std::endl;
return;
}

double beam_ctr_x = 0.0;
double beam_ctr_y = 0.0;
HFIRInstrument::getCoordinateFromPixel(m_center_x, m_center_y, dataWS, beam_ctr_x, beam_ctr_y);

IAlgorithm_sptr mvAlg = createSubAlgorithm("MoveInstrumentComponent", 0.5, 0.50);
mvAlg->setProperty<MatrixWorkspace_sptr>("Workspace", dataWS);
mvAlg->setProperty("ComponentName", "detector1");
@@ -193,13 +206,22 @@ void HFIRLoad::exec()
dataWS->mutableRun().addProperty("beam-diameter", beam_diameter, "mm", true);

// Move the beam center to its proper position
const double pixel_ctr_x = getProperty("BeamCenterX");
const double pixel_ctr_y = getProperty("BeamCenterY");
if (!isEmpty(pixel_ctr_x) && !isEmpty(pixel_ctr_y))
const bool noBeamCenter = getProperty("NoBeamCenter");
if (!noBeamCenter)
{
m_center_x = pixel_ctr_x;
m_center_y = pixel_ctr_y;
m_center_x = getProperty("BeamCenterX");
m_center_y = getProperty("BeamCenterY");
if (isEmpty(m_center_x) && isEmpty(m_center_y))
{
if (reductionManager->existsProperty("LatestBeamCenterX") &&
reductionManager->existsProperty("LatestBeamCenterY"))
{
m_center_x = reductionManager->getProperty("LatestBeamCenterX");
m_center_y = reductionManager->getProperty("LatestBeamCenterY");
}
}
moveToBeamCenter();

// Add beam center to reduction properties, as the last beam center position that was used.
// This will give us our default position next time.
if (!reductionManager->existsProperty("LatestBeamCenterX"))
@@ -208,17 +230,21 @@ void HFIRLoad::exec()
if (!reductionManager->existsProperty("LatestBeamCenterY"))
reductionManager->declareProperty(new PropertyWithValue<double>("LatestBeamCenterY", m_center_y) );
else reductionManager->setProperty("LatestBeamCenterY", m_center_y);
} else {
HFIRInstrument::getDefaultBeamCenter(dataWS, m_center_x, m_center_y);
g_log.information() << "No beam finding method: setting to default ["
<< Poco::NumberFormatter::format(m_center_x, 1) << ", "
<< Poco::NumberFormatter::format(m_center_y, 1) << "]" << std::endl;

dataWS->mutableRun().addProperty("beam_center_x", m_center_x, "pixel", true);
dataWS->mutableRun().addProperty("beam_center_y", m_center_y, "pixel", true);
m_output_message += " Beam center: " + Poco::NumberFormatter::format(m_center_x, 1)
+ ", " + Poco::NumberFormatter::format(m_center_y, 1) + "\n";
}
else
{
HFIRInstrument::getDefaultBeamCenter(dataWS, m_center_x, m_center_y);

dataWS->mutableRun().addProperty("beam_center_x", m_center_x, "pixel", true);
dataWS->mutableRun().addProperty("beam_center_y", m_center_y, "pixel", true);
m_output_message += " Beam center: " + Poco::NumberFormatter::format(m_center_x, 1)
+ ", " + Poco::NumberFormatter::format(m_center_y, 1) + "\n";
dataWS->mutableRun().addProperty("beam_center_x", m_center_x, "pixel", true);
dataWS->mutableRun().addProperty("beam_center_y", m_center_y, "pixel", true);
m_output_message += " Default beam center: " + Poco::NumberFormatter::format(m_center_x, 1)
+ ", " + Poco::NumberFormatter::format(m_center_y, 1) + "\n";
}

setProperty<MatrixWorkspace_sptr>("OutputWorkspace", boost::dynamic_pointer_cast<MatrixWorkspace>(dataWS));
setPropertyValue("OutputMessage", m_output_message);
@@ -94,18 +94,21 @@ MatrixWorkspace_sptr SANSBeamFinder::loadBeamFinderFile(const std::string& beamC
std::string msg = loadAlg->getPropertyValue("OutputMessage");
m_output_message += " |" + Poco::replace(msg, "\n", "\n |") + "\n";
} else {
IAlgorithm_sptr loadAlg = m_reductionManager->getProperty("LoadAlgorithm");
loadAlg->setChild(true);
loadAlg->setChildStartProgress(0.1);
loadAlg->setChildEndProgress(0.3);
// Get load algorithm as a string so that we can create a completely
// new proxy and ensure that we don't overwrite existing properties
IAlgorithm_sptr loadAlg0 = m_reductionManager->getProperty("LoadAlgorithm");
const std::string loadString = loadAlg0->toString();
IAlgorithm_sptr loadAlg = Algorithm::fromString(loadString);

loadAlg->setProperty("Filename", beamCenterFile);
if (loadAlg->existsProperty("NoBeamCenter")) loadAlg->setProperty("NoBeamCenter", true);
if (loadAlg->existsProperty("BeamCenterX")) loadAlg->setProperty("BeamCenterX", EMPTY_DBL());
if (loadAlg->existsProperty("BeamCenterY")) loadAlg->setProperty("BeamCenterY", EMPTY_DBL());
loadAlg->setProperty("ReductionProperties", reductionManagerName);
loadAlg->setPropertyValue("OutputWorkspace", finderWSName);
loadAlg->execute();
finderWS = loadAlg->getProperty("OutputWorkspace");
boost::shared_ptr<Workspace> wks = AnalysisDataService::Instance().retrieve(finderWSName);
finderWS = boost::dynamic_pointer_cast<MatrixWorkspace>(wks);

m_output_message += " |Loaded " + beamCenterFile + "\n";
if (loadAlg->existsProperty("OutputMessage"))
@@ -242,6 +245,8 @@ void SANSBeamFinder::exec()

/*
* The standard HFIR reduction masks the edges of the detector
* This is here mostly to allow a direct comparison with old HFIR code
* and ensure that we reproduce the same results
*/
void SANSBeamFinder::maskEdges(MatrixWorkspace_sptr beamCenterWS, int high, int low, int left, int right)
{
@@ -220,16 +220,18 @@ void SANSSensitivityCorrection::exec()
rawFloodWS = loadAlg->getProperty("OutputWorkspace");
m_output_message += " | Loaded " + fileName + " (Load algorithm)\n";
} else {
IAlgorithm_sptr loadAlg = reductionManager->getProperty("LoadAlgorithm");
// Get load algorithm as a string so that we can create a completely
// new proxy and ensure that we don't overwrite existing properties
IAlgorithm_sptr loadAlg0 = reductionManager->getProperty("LoadAlgorithm");
const std::string loadString = loadAlg0->toString();
IAlgorithm_sptr loadAlg = Algorithm::fromString(loadString);
loadAlg->setChild(true);
loadAlg->setProperty("Filename", fileName);
loadAlg->setPropertyValue("OutputWorkspace", rawFloodWSName);
if (!isEmpty(center_x) && loadAlg->existsProperty("BeamCenterX")) loadAlg->setProperty("BeamCenterX", center_x);
if (!isEmpty(center_y) && loadAlg->existsProperty("BeamCenterY")) loadAlg->setProperty("BeamCenterY", center_y);
loadAlg->execute();
rawFloodWS = loadAlg->getProperty("OutputWorkspace");
// rawFloodWS = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(rawFloodWSName);
//AnalysisDataService::Instance().addOrReplace(rawFloodWSName, rawFloodWS);
m_output_message += " |Loaded " + fileName + "\n";
if (loadAlg->existsProperty("OutputMessage"))
{
@@ -74,6 +74,7 @@ void SetupEQSANSReduction::init()
// Beam center
std::string center_grp = "Beam Center";
declareProperty("FindBeamCenter", false, "If True, the beam center will be calculated");
declareProperty("UseConfigBeam", false, "If True, the beam center will be taken from the config file");

// Option 1: Set beam center by hand
declareProperty("BeamCenterX", EMPTY_DBL(), "Position of the beam center, in pixel");
@@ -91,6 +92,7 @@ void SetupEQSANSReduction::init()
"the center of mass of the scattering pattern [pixels]. Default=3.0");

setPropertyGroup("FindBeamCenter", center_grp);
setPropertyGroup("UseConfigBeam", center_grp);
setPropertyGroup("BeamCenterX", center_grp);
setPropertyGroup("BeamCenterY", center_grp);
setPropertyGroup("BeamCenterFile", center_grp);
@@ -148,7 +150,8 @@ void SetupEQSANSReduction::exec()

// Load algorithm
IAlgorithm_sptr loadAlg = createSubAlgorithm("EQSANSLoad");
loadAlg->setProperty("UseConfigBeam", false);
const bool useConfigBeam = getProperty("UseConfigBeam");
loadAlg->setProperty("UseConfigBeam", useConfigBeam);
const bool useConfigTOFCuts = getProperty("UseConfigTOFCuts");
loadAlg->setProperty("UseConfigTOFCuts", useConfigTOFCuts);
if (!useConfigTOFCuts)
@@ -230,7 +233,8 @@ void SetupEQSANSReduction::exec()

reductionManager->declareProperty(new AlgorithmProperty("SANSBeamFinderAlgorithm"));
reductionManager->setProperty("SANSBeamFinderAlgorithm", ctrAlg);
} else {
} else if (!isEmpty(beamCenterX) && !isEmpty(beamCenterY))
{
reductionManager->declareProperty(new PropertyWithValue<double>("LatestBeamCenterX", beamCenterX) );
reductionManager->declareProperty(new PropertyWithValue<double>("LatestBeamCenterY", beamCenterY) );
}
@@ -48,6 +48,15 @@ void SetupHFIRReduction::init()
declareProperty("WavelengthSpread", 0.1, mustBePositive,
"Wavelength spread to use when loading the data file (default 0.0)" );

// Beam center
std::string center_grp = "Beam Center";
declareProperty("FindBeamCenter", false, "If True, the beam center will be calculated");
declareProperty("BeamCenterX", EMPTY_DBL(), "Position of the beam center, in pixel");
declareProperty("BeamCenterY", EMPTY_DBL(), "Position of the beam center, in pixel");
setPropertyGroup("FindBeamCenter", center_grp);
setPropertyGroup("BeamCenterX", center_grp);
setPropertyGroup("BeamCenterY", center_grp);

declareProperty("OutputMessage","",Direction::Output);
declareProperty("ReductionProperties","__sans_reduction_properties", Direction::Input);
}
@@ -84,6 +93,16 @@ void SetupHFIRReduction::exec()
reductionManager->declareProperty(new AlgorithmProperty("LoadAlgorithm"));
reductionManager->setProperty("LoadAlgorithm", loadAlg);

// Beam center
const double beamCenterX = getProperty("BeamCenterX");
const double beamCenterY = getProperty("BeamCenterY");
const bool calcBeamCenter = getProperty("FindBeamCenter");
if (!calcBeamCenter)
{
reductionManager->declareProperty(new PropertyWithValue<double>("LatestBeamCenterX", beamCenterX) );
reductionManager->declareProperty(new PropertyWithValue<double>("LatestBeamCenterY", beamCenterY) );
}

// Store default dark current algorithm
IAlgorithm_sptr darkAlg = createSubAlgorithm("HFIRDarkCurrentSubtraction");
darkAlg->setProperty("OutputDarkCurrentWorkspace", "");
@@ -61,7 +61,7 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="techniques">
<property name="techniques" stdset="0">
<stringlist>
<string>Muon spectroscopy</string>
</stringlist>
@@ -98,7 +98,7 @@
<item>
<widget class="QLineEdit" name="timeZeroFront">
<property name="enabled">
<bool>false</bool>
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
@@ -207,12 +207,12 @@
</item>
<item>
<property name="text">
<string>From file</string>
<string>From Data File</string>
</property>
</item>
<item>
<property name="text">
<string>Choose table</string>
<string>From Disk</string>
</property>
</item>
</widget>
@@ -240,7 +240,7 @@
</layout>
</item>
<item row="2" column="2">
<widget class="MantidQt::MantidWidgets::MWRunFiles" name="mwRunDeadTimeFile">
<widget class="MantidQt::MantidWidgets::MWRunFiles" name="mwRunDeadTimeFile" native="true">
<property name="label" stdset="0">
<string>Load Dead Time Table:</string>
</property>
@@ -301,7 +301,7 @@
<item>
<layout class="QHBoxLayout" name="fileInputLayout">
<item>
<widget class="MantidQt::MantidWidgets::MWRunFiles" name="mwRunFiles">
<widget class="MantidQt::MantidWidgets::MWRunFiles" name="mwRunFiles" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Minimum">
<horstretch>0</horstretch>
@@ -1681,11 +1681,13 @@
<class>MantidQt::MantidWidgets::FitPropertyBrowser</class>
<extends>QDockWidget</extends>
<header>MantidQtMantidWidgets/FitPropertyBrowser.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>MantidQt::MantidWidgets::MuonFitPropertyBrowser</class>
<extends>MantidQt::MantidWidgets::FitPropertyBrowser</extends>
<header>MantidQtMantidWidgets/MuonFitPropertyBrowser.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<tabstops>

Large diffs are not rendered by default.

@@ -221,7 +221,7 @@ void SANSRunWindow::initAnalysDetTab()
m_uiForm.wavlength_lb->setText(QString("Wavelength (%1)").arg(ANGSROM_SYM));
m_uiForm.qx_lb->setText(QString("Qx (%1^-1)").arg(ANGSROM_SYM));
m_uiForm.qxy_lb->setText(QString("Qxy (%1^-1)").arg(ANGSROM_SYM));
m_uiForm.transFit_ck->setText(QString("Trans Fit (%1)").arg(ANGSROM_SYM));
m_uiForm.transFitOnOff->setText(QString("Trans Fit (%1)").arg(ANGSROM_SYM));
m_uiForm.q_rebin->setToolTip("Any string allowed by the Rebin algorithm may be used");


@@ -733,6 +733,10 @@ bool SANSRunWindow::loadUserFile()
{
m_uiForm.trans_opt->setCurrentIndex(index);
}
if ( text == "Off" )
m_uiForm.transFitOnOff->setChecked(false);
else
m_uiForm.transFitOnOff->setChecked(true);

//Monitor spectra
m_uiForm.monitor_spec->setText(runReduceScriptFunction(
@@ -1214,7 +1218,8 @@ void SANSRunWindow::addUserMaskStrings(QString& exec_script,const QString& impor
{

exec_script += importCommand + "('" + m_uiForm.mask_table->item(row, 2)->text()
+ "')\n";
+ "')\n";
continue;
}

temp = importCommand + "('MASK";
@@ -1914,15 +1919,23 @@ QString SANSRunWindow::readUserFileGUIChanges(const States type)
{
issueWarning("Flood file may not work", "Flood files have not always been compatible with the HAB detector you might want to check '"+floodFile+"'.\nThe reduction will continue");
}
//Set the wavelength ranges, equal to those for the sample unless this box is checked
// Set the wavelength ranges, equal to those for the sample unless this box is checked
// Also check if the Trans Fit on/off tick is on or off. If Off then set the trans_opt to off
if (m_uiForm.transFit_ck->isChecked())
{
exec_reduce += "i.TransFit('" + m_uiForm.trans_opt->currentText() + "','" +
m_uiForm.trans_min->text().trimmed()+"','"+m_uiForm.trans_max->text().trimmed()+"')\n";
if ( m_uiForm.transFitOnOff->isChecked() )
exec_reduce += "i.TransFit('" + m_uiForm.trans_opt->currentText() + "','" +
m_uiForm.trans_min->text().trimmed()+"','"+m_uiForm.trans_max->text().trimmed()+"')\n";
else
exec_reduce += "i.TransFit('Off','" +
m_uiForm.trans_min->text().trimmed()+"','"+m_uiForm.trans_max->text().trimmed()+"')\n";
}
else
{
exec_reduce += "i.TransFit('" + m_uiForm.trans_opt->currentText() + "')\n";
if ( m_uiForm.transFitOnOff->isChecked() )
exec_reduce += "i.TransFit('" + m_uiForm.trans_opt->currentText() + "')\n";
else
exec_reduce += "i.TransFit('Off')\n";
}

//Gravity correction
@@ -12,20 +12,17 @@ set ( SRC_FILES
src/RangeHandler.cpp
src/ImageDataSource.cpp
src/IVConnections.cpp
src/TestDataSource.cpp
src/EventWSDataSource.cpp
src/EventWSImageView.cpp
src/MatrixWSDataSource.cpp
src/MatrixWSImageView.cpp
src/ArrayDataSource.cpp
src/ErrorHandler.cpp
)

# Include files aren't required, but this makes them appear in Visual Studio
set ( INC_FILES
inc/MantidQtImageViewer/ColorMaps.h
inc/MantidQtImageViewer/ImageDisplay.h
inc/MantidQtImageViewer/IVConnections.h
inc/MantidQtImageViewer/TestDataSource.h
inc/MantidQtImageViewer/DataArray.h
inc/MantidQtImageViewer/ImagePlotItem.h
inc/MantidQtImageViewer/IVUtils.h
@@ -36,12 +33,10 @@ set ( INC_FILES
inc/MantidQtImageViewer/ImageDataSource.h
inc/MantidQtImageViewer/SliderHandler.h
inc/MantidQtImageViewer/RangeHandler.h
inc/MantidQtImageViewer/TestDataSource.h
inc/MantidQtImageViewer/EventWSDataSource.h
inc/MantidQtImageViewer/EventWSImageView.h
inc/MantidQtImageViewer/MatrixWSDataSource.h
inc/MantidQtImageViewer/MatrixWSImageView.h
inc/MantidQtImageViewer/ArrayDataSource.h
inc/MantidQtImageViewer/ErrorHandler.h
)

set ( MOC_FILES
@@ -66,7 +66,7 @@ class EXPORT_OPT_MANTIDQT_IMAGEVIEWER DataArray
double GetYMax() const;

/// Check if the returned array is binned logarithmically in 'x'
bool GetIsLogX() const;
bool IsLogX() const;

/// Get smallest value recorded in this DataArray
double GetDataMin() const;
@@ -1,19 +1,16 @@
#ifndef EVENT_WS_IMAGE_VIEW_H
#define EVENT_WS_IMAGE_VIEW_H
#ifndef ERROR_HANDLER_H
#define ERROR_HANDLER_H

#include "MantidQtImageViewer/DllOptionIV.h"
#include "MantidAPI/IEventWorkspace.h"

#include "MantidQtImageViewer/ImageView.h"

/**
@class EventWSDataSource
@class ErrorHandler
This is the top level class for showing an event workspace
using an ImageViewer.
This class has static methods that do various basic calculations
needed by other parts of the ImageView package.
@author Dennis Mikkelson
@date 2012-04-18
@date 2012-05-18
Copyright © 2012 ORNL, STFC Rutherford Appleton Laboratories
@@ -41,20 +38,24 @@ namespace MantidQt
namespace ImageView
{

class EXPORT_OPT_MANTIDQT_IMAGEVIEWER EventWSImageView

class EXPORT_OPT_MANTIDQT_IMAGEVIEWER ErrorHandler
{
public:

/// Construct an image viewer for the specifed EventWorkspace
EventWSImageView( Mantid::API::IEventWorkspace_sptr ev_ws );
/// Display the specified string in an error message
static void Error( std::string text );

~EventWSImageView();
/// Display the specified string in a warning message
static void Warning( std::string text );

/// Display the specified string in a notice message
static void Notice( std::string text );

private:
ImageView *image_view;
};

} // namespace MantidQt
} // namespace ImageView

#endif // EVENT_WS_IMAGE_VIEW_H

#endif // ERROR_HANLDER_H

This file was deleted.

@@ -63,6 +63,12 @@ class EXPORT_OPT_MANTIDQT_IMAGEVIEWER GraphDisplay
double image_x,
double image_y );

/// Set up axes using the specified scale factor and replot the graph
void SetRangeScale( double range_scale );

/// Set flag indicating whether or not to use a log scale on the x-axis
void SetLogX( bool is_log_x );

/// Record the point that the user is currently pointing at with the mouse
void SetPointedAtPoint( QPoint point );

@@ -76,8 +82,14 @@ class EXPORT_OPT_MANTIDQT_IMAGEVIEWER GraphDisplay
ImageDataSource* data_source;

bool is_vertical;
bool is_log_x;
double image_x;
double image_y;
double range_scale; // fraction of data range to be graphed
double min_x,
max_x;
double min_y,
max_y;
};

} // namespace MantidQt
@@ -72,7 +72,8 @@ public slots:
void close_viewer();
void toggle_Hscroll();
void toggle_Vscroll();
void range_changed();
void image_horizontal_range_changed();
void graph_range_changed();
void v_scroll_bar_moved();
void h_scroll_bar_moved();
void imageSplitter_moved();
@@ -64,15 +64,21 @@ class EXPORT_OPT_MANTIDQT_IMAGEVIEWER IVUtils
std::vector<std::string> & list );

/// find a non-degenerate interval containing all the specified values
static void FindValidInterval( const QVector<double> & values,
static bool FindValidInterval( const QVector<double> & values,
double & min,
double & max );

/// Adjust min and max so that min is strictly less than max
static void FindValidInterval( double & min,
static bool FindValidInterval( double & min,
double & max );

/// find point new_val that is spaced between new_min and new_max in the
/// Adjust min and max so they can be used to form a log scale
static bool FindValidLogInterval( double & min, double & max );

/// Find the number of steps from min to max on a linear or log scale
static int NumSteps( double min, double max, double step );

/// Find point new_val that is spaced between new_min and new_max in the
/// same proportion as val is between min and max. Return false if
/// new_val is outside [new_min,new_max].
static bool Interpolate( double min,
@@ -82,6 +88,15 @@ class EXPORT_OPT_MANTIDQT_IMAGEVIEWER IVUtils
double new_max,
double & new_val );

/// Find the value in [new_min,new_max] on a logarithmic scale that
/// would correspond to the point val on a linear scale on [min,max].
static bool LogInterpolate( double min,
double max,
double val,
double new_min,
double new_max,
double & new_val );

/// adjust the values defining a subinterval to match the boundaries of
/// the global data. (Currently only for uniformly spaced bins.)
static bool CalculateInterval( double global_min,
@@ -86,7 +86,7 @@
<item row="2" column="0">
<widget class="QLabel" name="Step_Label">
<property name="text">
<string>Uniform Step</string>
<string>Step(-if Log)</string>
</property>
</widget>
</item>

This file was deleted.

@@ -70,7 +70,9 @@ ArrayDataSource::~ArrayDataSource()
* @param n_cols The event data will be rebinned using the specified
* number of colums.
* @param is_log_x Flag indicating whether or not the data should be
* binned logarithmically in the X-direction. (NOT USED)
* binned logarithmically in the X-direction. This
* DataSource does not support rebinning to a log axis, so
* the DataArray is always returned with is_log_x = false.
*/
DataArray * ArrayDataSource::GetDataArray( double xmin, double xmax,
double ymin, double ymax,
@@ -114,7 +116,7 @@ DataArray * ArrayDataSource::GetDataArray( double xmin, double xmax,
}
}
// The calling code is responsible
// for deleting the DataArray
is_log_x = false; // for deleting the DataArray
DataArray* new_data_array = new DataArray( xmin, xmax, ymin, ymax,
is_log_x, n_rows, n_cols, new_data);
return new_data_array;
@@ -127,10 +129,13 @@ DataArray * ArrayDataSource::GetDataArray( double xmin, double xmax,
* returned, when it is no longer needed.
*
* @param is_log_x Flag indicating whether or not the data should be
* binned logarithmically. (NOT USED)
* binned logarithmically. This DataSource does not
* support rebinning to a log axis, so the DataArray is
* always returned with is_log_x = false.
*/
DataArray * ArrayDataSource::GetDataArray( bool is_log_x )
{
is_log_x = false;
return GetDataArray( total_xmin, total_xmax, total_ymin, total_ymax,
total_rows, total_cols, is_log_x );
}
@@ -109,7 +109,7 @@ double DataArray::GetYMax() const
/**
* Check if the returned array is binned logarithmically in 'x'.
*/
bool DataArray::GetIsLogX() const
bool DataArray::IsLogX() const
{
return is_log_x;
}
@@ -0,0 +1,50 @@
#include <iostream>

#include "MantidKernel/Logger.h"

#include "MantidQtImageViewer/ErrorHandler.h"

namespace MantidQt
{
namespace ImageView
{

using namespace Mantid;

Kernel::Logger& g_log = Kernel::Logger::get("ImageView");

/**
* Display the specified string in an error message.
*
* @param text The string containing the text of the error message
*/
void ErrorHandler::Error( std::string text )
{
g_log.error( "ERROR: " + text );
}


/**
* Display the specified string in a warning message.
*
* @param text The string containing the text of the warning message
*/
void ErrorHandler::Warning( std::string text )
{
g_log.warning( "WARNING: " + text );
}


/**
* Display the specified string in a warning message.
*
* @param text The string containing the text of the warning message
*/
void ErrorHandler::Notice( std::string text )
{
g_log.notice( "Notice: " + text );
}


} // namespace MantidQt
} // namespace ImageView

This file was deleted.

This file was deleted.

@@ -3,6 +3,7 @@
#include <QtGui>
#include <QVector>
#include <QString>
#include <qwt_scale_engine.h>

#include "MantidQtImageViewer/GraphDisplay.h"
#include "MantidQtImageViewer/QtUtils.h"
@@ -30,10 +31,12 @@ GraphDisplay::GraphDisplay( QwtPlot* graph_plot,
this->graph_plot = graph_plot;
this->graph_table = graph_table;
this->data_source = 0;

this->is_vertical = is_vertical;
image_x = 0;
image_y = 0;

is_log_x = false;
image_x = 0;
image_y = 0;
range_scale = 1.0;

if ( is_vertical )
{
@@ -64,6 +67,18 @@ void GraphDisplay::SetDataSource( ImageDataSource* data_source )
}


/**
* Set flag indicating whether or not to use a log scale on the x-axis
*
* @param is_log_x Pass in true to use a log scale on the x-axis and false
* to use a linear scale.
*/
void GraphDisplay::SetLogX( bool is_log_x )
{
this->is_log_x = is_log_x;
}


/**
* Set the actual data that will be displayed on the graph and the
* coordinates on the image corresponding to this data. The image
@@ -97,35 +112,65 @@ void GraphDisplay::SetData(const QVector<double> & xData,
// the data and attaching
if ( is_vertical )
{
double min_y = yData[0];
double max_y = yData[yData.size()-1];

double min_x;
double max_x;
min_y = yData[0];
max_y = yData[yData.size()-1];
IVUtils::FindValidInterval( xData, min_x, max_x );

graph_plot->setAxisScale( QwtPlot::xBottom, min_x, max_x );
graph_plot->setAxisScale( QwtPlot::yLeft, min_y, max_y );
}
else
{
double min_x = xData[0];
double max_x = xData[xData.size()-1];

double min_y;
double max_y;
min_x = xData[0];
max_x = xData[xData.size()-1];
IVUtils::FindValidInterval( yData, min_y, max_y );
graph_plot->setAxisScale( QwtPlot::yLeft, min_y, max_y );
graph_plot->setAxisScale( QwtPlot::xBottom, min_x, max_x );
}


if ( is_log_x )
{
QwtLog10ScaleEngine* log_engine = new QwtLog10ScaleEngine();
graph_plot->setAxisScaleEngine( QwtPlot::xBottom, log_engine );
}
else
{
QwtLinearScaleEngine* linear_engine = new QwtLinearScaleEngine();
graph_plot->setAxisScaleEngine( QwtPlot::xBottom, linear_engine );
}

curve->setData( xData, yData );
curve->attach( graph_plot );
graph_plot->replot();

SetRangeScale( range_scale );

graph_plot->setAutoReplot(true);
}


/**
* Set up axes using the specified scale factor and replot the graph.
* This is useful for seeing low-level values, by clipping off the higher
* magnitude values.
*
* @param range_scale Value between 0 and 1 indicating what fraction of
* graph value range should be plotted.
*/
void GraphDisplay::SetRangeScale( double range_scale )
{
this->range_scale = range_scale;
if ( is_vertical )
{
double axis_max = range_scale * ( max_x - min_x ) + min_x;
graph_plot->setAxisScale( QwtPlot::xBottom, min_x, axis_max );
graph_plot->setAxisScale( QwtPlot::yLeft, min_y, max_y );
}
else
{
double axis_max = range_scale * ( max_y - min_y ) + min_y;
graph_plot->setAxisScale( QwtPlot::yLeft, min_y, axis_max );
graph_plot->setAxisScale( QwtPlot::xBottom, min_x, max_x );
}
graph_plot->replot();
}


/**
* Show information about the specified point.
*
@@ -141,8 +186,14 @@ void GraphDisplay::SetPointedAtPoint( QPoint point )
double x = graph_plot->invTransform( QwtPlot::xBottom, point.x() );
double y = graph_plot->invTransform( QwtPlot::yLeft, point.y() );

data_source->RestrictX( x );
data_source->RestrictY( y );
if ( is_vertical ) // x can be anywhere on graph, y must be
{ // a valid data source position, vertically
data_source->RestrictY( y );
}
else // y can be anywhere on graph, x must be
{ // a valid data source position, horizontally
data_source->RestrictX( x );
}

ShowInfoList( x, y );
}
@@ -41,8 +41,6 @@ IVConnections::IVConnections( Ui_MainWindow* ui,
iv_ui->actionOffset_Diagonally->setDisabled(true);
iv_ui->actionGraph_Rebinned_Data->setDisabled(true);
iv_ui->menuHelp->setDisabled(true);
iv_ui->graph_max_slider->setDisabled(true);
iv_ui->graph_max_label->setDisabled(true);
iv_ui->label_2->setDisabled(true);

this->iv_main_window = iv_main_window;
@@ -96,6 +94,10 @@ IVConnections::IVConnections( Ui_MainWindow* ui,
iv_ui->intensity_slider->setTickPosition(QSlider::TicksBelow);
iv_ui->intensity_slider->setSliderPosition(30);

iv_ui->graph_max_slider->setTickInterval(10);
iv_ui->graph_max_slider->setTickPosition(QSlider::TicksBelow);
iv_ui->graph_max_slider->setSliderPosition(100);

image_picker = new TrackingPicker( iv_ui->imagePlot->canvas() );
image_picker->setMousePattern(QwtPicker::MouseSelect1, Qt::LeftButton);
image_picker->setTrackerMode(QwtPicker::ActiveOnly);
@@ -142,13 +144,13 @@ IVConnections::IVConnections( Ui_MainWindow* ui,
this, SLOT(imageSplitter_moved()) );

QObject::connect(iv_ui->x_min_input, SIGNAL( returnPressed() ),
this, SLOT(range_changed()) );
this, SLOT(image_horizontal_range_changed()) );

QObject::connect(iv_ui->x_max_input, SIGNAL( returnPressed() ),
this, SLOT(range_changed()) );
this, SLOT(image_horizontal_range_changed()) );

QObject::connect(iv_ui->step_input, SIGNAL( returnPressed() ),
this, SLOT(range_changed()) );
this, SLOT(image_horizontal_range_changed()) );

QObject::connect(iv_ui->imageVerticalScrollBar, SIGNAL(valueChanged(int)),
this, SLOT(v_scroll_bar_moved()) );
@@ -164,6 +166,10 @@ IVConnections::IVConnections( Ui_MainWindow* ui,

QObject::connect(iv_ui->intensity_slider, SIGNAL(valueChanged(int)),
this, SLOT(intensity_slider_moved()) );

QObject::connect(iv_ui->graph_max_slider, SIGNAL(valueChanged(int)),
this, SLOT(graph_range_changed()) );

// color scale selections
iv_ui->actionHeat->setCheckable(true);
iv_ui->actionHeat->setChecked(true);
@@ -219,7 +225,7 @@ IVConnections::IVConnections( Ui_MainWindow* ui,
QObject::connect( h_graph_picker, SIGNAL(mouseMoved()),
this, SLOT(h_graphPicker_moved()) );

// NOTE: This initialization could be (static?) method ih TrackingPicker
// NOTE: This initialization could be a (static?) method in TrackingPicker
v_graph_picker = new TrackingPicker( iv_ui->v_graphPlot->canvas() );
v_graph_picker->setMousePattern(QwtPicker::MouseSelect1, Qt::LeftButton);
v_graph_picker->setTrackerMode(QwtPicker::ActiveOnly);
@@ -267,12 +273,27 @@ void IVConnections::toggle_Vscroll()
}


void IVConnections::range_changed()
void IVConnections::image_horizontal_range_changed()
{
image_display->UpdateRange();
}


void IVConnections::graph_range_changed()
{
double value = (double)iv_ui->graph_max_slider->value();
double min = (double)iv_ui->graph_max_slider->minimum();
double max = (double)iv_ui->graph_max_slider->maximum();

double range_scale = (value - min)/(max - min);
if ( range_scale < 0.01 )
range_scale = 0.01;

h_graph_display->SetRangeScale( range_scale );
v_graph_display->SetRangeScale( range_scale );
}


void IVConnections::v_scroll_bar_moved()
{
image_display->UpdateImage();
@@ -97,7 +97,7 @@ void IVUtils::PushNameValue( const std::string & name,
* @param max Set to be greater than or equal to all values in the list
* and strictly more than min.
*/
void IVUtils::FindValidInterval( const QVector<double> & values,
bool IVUtils::FindValidInterval( const QVector<double> & values,
double & min,
double & max )
{
@@ -112,7 +112,7 @@ void IVUtils::FindValidInterval( const QVector<double> & values,
if ( max < val )
max = val;
}
FindValidInterval( min, max );
return FindValidInterval( min, max );
}


@@ -124,13 +124,18 @@ void IVUtils::FindValidInterval( const QVector<double> & values,
*
* @param min Set to be strictly less than max.
* @param max Set to be strictly greater than min.
*
* @return true if the original values were OK and are unchanged, return
* false if min or max was altered to make a valid interval.
*/
void IVUtils::FindValidInterval( double & min,
bool IVUtils::FindValidInterval( double & min,
double & max )
{
bool values_OK = true;

if ( max == min ) // adjust values so they are not equal
{
values_OK = false;
if ( min == 0 )
{
min = -1,
@@ -145,10 +150,114 @@ void IVUtils::FindValidInterval( double & min,

if ( min > max ) // fix the order
{
values_OK = false;
double temp = min;
min = max;
max = temp;
}

return values_OK;
}


/**
* Adjust min and max so that min is strictly less than max, and both are
* greater than 0. If min > max the values are swapped. If min = max > 0,
* they will be shifted off from their initial common value by factors of 10.
* If min = max = 0, they will be set to 0.1 and 10, respectively.
*
* @param min Set to be strictly less than max and more than 0.
* @param max Set to be strictly greater than min.
*
* @return true if the original values were OK and are unchanged, return
* false if min or max was altered to make a valid interval.
*/
bool IVUtils::FindValidLogInterval( double & min,
double & max )
{
bool values_OK = true;
if ( min < 0 )
{
std::cout << "min < 0 " << min << std::endl;
values_OK = false;
min = -min;
}

if ( max < 0 )
{
std::cout << "max < 0 " << max << std::endl;
values_OK = false;
max = -max;
}

if ( min > max ) // fix the order
{
std::cout << "min > max " << min << " > " << max << std::endl;
values_OK = false;
double temp = min;
min = max;
max = temp;
}

if ( min == 0 && max > 0 ) // raise min, so the interval covers 2 orders
{ // of magnitude
std::cout << "min == 0, max > 0 " << min << ", " << max << std::endl;
values_OK = false;
min = 0.01 * max;
}
else if ( max == min ) // adjust values so they are not equal
{
values_OK = false;
std::cout << "min == max " << min << " == " << max << std::endl;
if ( min == 0 )
{
min = 0.1,
max = 10;
}
else
{
max = 10 * max;
min = 0.1 * min;
}
}

return values_OK;
}


/**
* Calculate the number of steps required to go from min to max on either
* a linear or logarithmic scale.
* @param min Lowest value on scale, must be positive for log scale, and
* must always be less than max.
* @param max Highest value on scale, must be positive for log scale, and
* must always be more than min.
* @param step Must be more than zero for linear scale and less than zero
* for log scale. This must NOT be zero and should be less
* than max - min in absolute value.
* @return the number of bins from min to max, if the interval is divided
* linearly or "lograrithmically". If the data is invalid, this
* will return 0.
*/
int IVUtils::NumSteps( double min, double max, double step )
{
int n_bins = 0;

if ( step == 0 || (max-min) <= 0 || (step < 0 && min <= 0) )
{
return 0;
}

if ( step > 0 ) // uniform steps
{
n_bins = (int)(( max - min ) / step);
}
else if ( step < 0 ) // log steps
{
n_bins = (int)ceil(( (log(max) - log(min))/log(1 - step/min) ));
}

return n_bins;
}


@@ -161,9 +270,9 @@ void IVUtils::FindValidInterval( double & min,
* @param new_min Left endpoint of new interval
* @param new_max Right endpoint of new interval
* @param new_val Point in new interval that is placed in [new_min,new_max]
* in the same proportion as val is in [min,max]. The
* resulting new_val will be clamped to be in the new
* interval, even if val is outside of the original interval.
* in the same proportion as val is in [min,max].
* @return true if the calculated value is in [new_min,new_max] and false
* if it is outside of the interval.
*/
bool IVUtils::Interpolate( double min,
double max,
@@ -173,6 +282,40 @@ bool IVUtils::Interpolate( double min,
double & new_val )
{
new_val = (val - min)/( max - min ) * (new_max - new_min) + new_min;

if ( new_val < new_min || new_val > new_max )
return false;
else
return true;
}


/**
* Calculate the value in [new_min,new_max] on a logarithmic scale that
* would correspond to the point val on a linear scale on [min,max].
* For example, if val was half way from min to max, and the log scale
* extended from new_min = 1 to new_max = 100, then new_val would return 10,
* since 10 is half way along a log scale from 1 to 100.
* Clamp the result to be in the interval [new_min,new_max].
* @param min Left endpoint of original interval with linear scale
* @param max Right endpoint of original interval with linear scale
* @param val Reference point in orignal interval
* @param new_min Left endpoint of new interval with log scale
* @param new_max Right endpoint of new interval with log scale
* @param new_val Point in new interval that is placed in [new_min,new_max]
* in the same proportion as val is in [min,max].
* @return true if the calculated value is in [new_min,new_max] and false
* if it is outside of the interval.
*/
bool IVUtils::LogInterpolate( double min,
double max,
double val,
double new_min,
double new_max,
double & new_val )
{
new_val = new_min * exp( (val-min)/(max-min) * log ( new_max/new_min ));

if ( new_val < new_min || new_val > new_max )
return false;
else
@@ -185,7 +328,8 @@ bool IVUtils::Interpolate( double min,
* data bin boundaries, then set first_index to the index of the bin,
* corresponding to the min value and set the number of steps to the smaller
* of the number of steps in the data, and the initial value of the number
* of steps.
* of steps. NOTE: This calculation is needed for displaying a fixed array
* of data that should not be rebinned.
*
* @param global_min Smallest value covered by the underlying data
* @param global_max Largest value covered by the underlying data
@@ -203,7 +347,7 @@ bool IVUtils::Interpolate( double min,
* max value, if max is in the interior of a bin.
* @param steps On input this should be the number of bins desired
* between the min and max values. This will be adjusted
* to be more than the number of steps available.
* to be no more than the number of steps available.
*/
bool IVUtils::CalculateInterval( double global_min,
double global_max,
@@ -251,31 +395,5 @@ bool IVUtils::CalculateInterval( double global_min,
return true;
}

/*
int main()
{
double new_val;
IVUtils::Interpolate( -10, 20, 9, -100, 200, new_val );
std::cout << "new_val = " << new_val << std::endl;
size_t first_index;
double min = 150;
double max = 160;
size_t steps = 10;
IVUtils::CalculateInterval(100, 200, 100,
first_index, min, max, steps);
std::cout << "first_index = " << first_index << std::endl;
std::cout << "min = " << min << std::endl;
std::cout << "max = " << max << std::endl;
std::cout << "steps = " << steps << std::endl;
return 0;
}
*/


} // namespace MantidQt
} // namespace ImageView
@@ -5,6 +5,7 @@
#include <QVector>
#include <QString>
#include <qimage.h>
#include <qwt_scale_engine.h>

#include "MantidQtImageViewer/ImageDisplay.h"
#include "MantidQtImageViewer/ImageDataSource.h"
@@ -129,16 +130,21 @@ void ImageDisplay::UpdateRange()
SetDataSource( data_source ); // re-initialize with the altered source
}

QRect display_rect;
GetDisplayRectangle( display_rect );
// range controls now determine
// the number of bins
double min = 0;
double max = 0;
double step = 0;
range_handler->GetRange( min, max, step );

int n_bins = (int)(( max - min ) / step); // range controls now determine
// the number of bins
QRect display_rect;
GetDisplayRectangle( display_rect );

int n_bins = IVUtils::NumSteps( min, max, step );
if ( n_bins == 0 )
{
return;
}

slider_handler->ConfigureHSlider( n_bins, display_rect.width() );

UpdateImage();
@@ -170,11 +176,17 @@ void ImageDisplay::UpdateImage()

double scale_x_min = 0;
double scale_x_max = 0;
double step = 0;
range_handler->GetRange( scale_x_min, scale_x_max, step );
double x_step = 0;
range_handler->GetRange( scale_x_min, scale_x_max, x_step );

int n_rows = (int)data_source->GetNRows();
int n_cols = (int)( ( scale_x_max - scale_x_min ) / step );
int n_cols = IVUtils::NumSteps( scale_x_min, scale_x_max, x_step );
// This works for linear or log scales

if ( n_rows == 0 )
{
return;
}

if ( slider_handler->VSliderOn() )
{
@@ -198,15 +210,26 @@ void ImageDisplay::UpdateImage()
{
int x_min;
int x_max;
slider_handler->GetHSliderInterval( x_min, x_max );

slider_handler->GetHSliderInterval( x_min, x_max );
// NOTE: The interval [xmin,xmax] is always
// found linearly. For log_x, we need to adjust it
double new_x_min = 0;
double new_x_max = 0;

IVUtils::Interpolate( 0, n_cols, x_min,
scale_x_min, scale_x_max, new_x_min );
IVUtils::Interpolate( 0, n_cols, x_max,
scale_x_min, scale_x_max, new_x_max );
if ( x_step > 0 ) // linear scale, so interpolate linearly
{
IVUtils::Interpolate( 0, n_cols, x_min,
scale_x_min, scale_x_max, new_x_min );
IVUtils::Interpolate( 0, n_cols, x_max,
scale_x_min, scale_x_max, new_x_max );
}
else // log scale, so interpolate "logarithmically"
{
IVUtils::LogInterpolate( 0, n_cols, x_min,
scale_x_min, scale_x_max, new_x_min );
IVUtils::LogInterpolate( 0, n_cols, x_max,
scale_x_min, scale_x_max, new_x_max );
}

scale_x_min = new_x_min;
scale_x_max = new_x_max;
@@ -221,15 +244,31 @@ void ImageDisplay::UpdateImage()
{
n_cols = display_rect.width();
}

bool is_log_x = ( x_step < 0 );
// NOTE: The DataArray is deleted
// in the ImagePlotItem.
data_array = data_source->GetDataArray( scale_x_min, scale_x_max,
scale_y_min, scale_y_max,
n_rows, n_cols,
false );
is_log_x );

is_log_x = data_array->IsLogX(); // Data source might not be able to
// provide log binned data, so check
// if log binned data was returned.

image_plot->setAxisScale( QwtPlot::xBottom, data_array->GetXMin(),
data_array->GetXMax() );
if ( is_log_x )
{
QwtLog10ScaleEngine* log_engine = new QwtLog10ScaleEngine();
image_plot->setAxisScaleEngine( QwtPlot::xBottom, log_engine );
}
else
{
QwtLinearScaleEngine* linear_engine = new QwtLinearScaleEngine();
image_plot->setAxisScaleEngine( QwtPlot::xBottom, linear_engine );
}

image_plot->setAxisScale( QwtPlot::yLeft, data_array->GetYMin(),
data_array->GetYMax() );
@@ -319,10 +358,18 @@ void ImageDisplay::SetPointedAtPoint( QPoint point )
double x_val;
for ( size_t col = 0; col < n_cols; col++ )
{
x_val = (double)col/(double)(n_cols-1) * (x_max-x_min) + x_min;
if ( data_array->IsLogX() )
{
x_val = x_min * exp( (double)col/double(n_cols-1)*log(x_max/x_min));
}
else
{
x_val = (double)col/(double)(n_cols-1) * (x_max-x_min) + x_min;
}
xData.push_back( x_val );
yData.push_back( data[ row * n_cols + col ] );
}
h_graph_display->SetLogX( data_array->IsLogX() );
h_graph_display->SetData( xData, yData, x, y );

double relative_x = (x-x_min)/(x_max-x_min); // in 0 to 1
@@ -1,7 +1,7 @@

#include <iostream>

#include <qapplication.h>
#include <qapplication.h>
#include <QMainWindow>
#include <QtGui>

@@ -10,7 +10,9 @@
#include "MantidKernel/System.h"
#include "MantidGeometry/IDTypes.h"
#include "MantidNexusCPP/NeXusFile.hpp"
#include "MantidQtImageViewer/EventWSImageView.h"
#include "MantidAPI/IEventWorkspace.h"

#include "MantidQtImageViewer/MatrixWSImageView.h"

using namespace MantidQt;
using namespace ImageView;
@@ -50,7 +52,7 @@ int main( int argc, char** argv )

std::cout << "Got EventWorkspace, making EventWSDataSource..." << std::endl;

MantidQt::ImageView::EventWSImageView image_view( WS );
MantidQt::ImageView::MatrixWSImageView image_view( WS );

return a.exec();
}
@@ -125,24 +125,33 @@ DataArray* MatrixWSDataSource::GetDataArray( double xmin, double xmax,
<< " n_rows = " << n_rows
<< " n_cols = " << n_cols << std::endl;
*/
size_t first_col;
IVUtils::CalculateInterval( total_xmin, total_xmax, total_cols,
first_col, xmin, xmax, n_cols );

// since we're rebinning, the
// columns can be arbitrary
// but rows must be aligned
// to get whole spectra
size_t first_row;
IVUtils::CalculateInterval( total_ymin, total_ymax, total_rows,
first_row, ymin, ymax, n_rows );

float* new_data = new float[n_rows * n_cols]; // this is deleted in the
// DataArrray destructor
float* new_data = new float[n_rows * n_cols]; // this array is deleted in
// the DataArrray destructor
MantidVec x_scale;
x_scale.resize(n_cols+1);
double dx = (xmax - xmin)/((double)n_cols + 1.0);
for ( size_t i = 0; i < n_cols+1; i++ )
if ( is_log_x )
{
x_scale[i] = xmin + (double)i * dx;;
for ( size_t i = 0; i < n_cols+1; i++ )
{
x_scale[i] = xmin * exp ( (double)i / (double)n_cols * log(xmax/xmin) );
}
}
// choose spectra from
else
{
double dx = (xmax - xmin)/((double)n_cols + 1.0);
for ( size_t i = 0; i < n_cols+1; i++ )
{
x_scale[i] = xmin + (double)i * dx;
}
} // choose spectra from
// required range of
// spectrum indexes
double y_step = (ymax - ymin) / (double)n_rows;
@@ -176,7 +185,8 @@ DataArray* MatrixWSDataSource::GetDataArray( double xmin, double xmax,
// The calling code is responsible for deleting
// the DataArray when it is done with it
DataArray* new_data_array = new DataArray( xmin, xmax, ymin, ymax,
is_log_x, n_rows, n_cols, new_data);
is_log_x,
n_rows, n_cols, new_data);
return new_data_array;
}

@@ -5,6 +5,7 @@
#include "MantidQtImageViewer/RangeHandler.h"
#include "MantidQtImageViewer/QtUtils.h"
#include "MantidQtImageViewer/IVUtils.h"
#include "MantidQtImageViewer/ErrorHandler.h"

namespace MantidQt
{
@@ -36,7 +37,7 @@ void RangeHandler::ConfigureRangeControls( ImageDataSource* data_source )
double default_step = (total_max_x - total_min_x)/(double)total_n_steps;
if ( total_n_steps > 2000 )
{
default_step = (total_max_x - total_min_x)/2000;
default_step = (total_max_x - total_min_x)/2000.0;
}

SetRange( total_min_x, total_max_x, default_step );
@@ -55,62 +56,86 @@ void RangeHandler::ConfigureRangeControls( ImageDataSource* data_source )
* to display. This will be adjusted so that it is larger
* than min by an integer number of steps.
* @param step This is size of the step to use between min and max.
* If it is less than zero, a log scale is requested.
*/
void RangeHandler::GetRange( double &min, double &max, double &step )
{
QLineEdit* min_control = iv_ui->x_min_input;
QLineEdit* max_control = iv_ui->x_max_input;
QLineEdit* step_control = iv_ui->step_input;

IVUtils::StringToDouble( min_control->text().toStdString(), min );
IVUtils::StringToDouble( max_control->text().toStdString(), max );
IVUtils::StringToDouble( step_control->text().toStdString(), step );

IVUtils::FindValidInterval( min, max );
if ( !IVUtils::StringToDouble( min_control->text().toStdString(), min ) )
{
ErrorHandler::Error("X Min is not a NUMBER! Value reset.");
}
if ( !IVUtils::StringToDouble( max_control->text().toStdString(), max ) )
{
ErrorHandler::Error("X Max is not a NUMBER! Value reset.");
}
if ( !IVUtils::StringToDouble( step_control->text().toStdString(), step ) )
{
ErrorHandler::Error("Step is not a NUMBER! Value reset.");
}

if ( step < 0 ) // just require step to be > 0, no other
{ // bounds
step = -step;
// just require step to be non-zero, no other
// bounds. If zero, take a default step size
if ( step == 0 )
{
ErrorHandler::Error("Step = 0, resetting to default step");
step = (total_max_x - total_min_x) / 2000.0;
}

if ( step == 0 ) // take a default step size
if ( step > 0 )
{
step = (total_max_x - total_min_x) / 2000;
if ( !IVUtils::FindValidInterval( min, max ) )
{
ErrorHandler::Warning( "[Min,Max] interval invalid, values adjusted" );
}
}
else
{
if ( !IVUtils::FindValidLogInterval( min, max ) )
{
ErrorHandler::Warning("[Min,Max] log interval invalid, values adjusted");
}
}

SetRange( min, max, step );
}


/**
* Adjust the values to be consistent with the avaliable data and
* Adjust the values to be consistent with the available data and
* diplay them in the controls.
*
* @param min This is the x value at the left edge of the first bin.
* @param max This is an x value at the right edge of the last bin.
* @param step This is size of the step to use between min and max.
* @param step This is size of the step to use between min and max.
* If it is less than zero, a log scale is requested.
*/
void RangeHandler::SetRange( double min, double max, double step )
{
IVUtils::FindValidInterval( min, max );

if ( min < total_min_x )
if ( !IVUtils::FindValidInterval( min, max ) )
{
min = total_min_x;
ErrorHandler::Warning( "[Min,Max] interval invalid, values adjusted" );
}
if ( max > total_max_x )

if ( min < total_min_x || min > total_max_x )
{
max = total_max_x;
// ErrorHandler::Warning("X Min out of range, resetting to range min.");
min = total_min_x;
}

if ( step < 0 )
if ( max < total_min_x || max > total_max_x )
{
step = -step;
// ErrorHandler::Warning("X Max out of range, resetting to range max.");
max = total_max_x;
}

if ( step == 0 )
{
step = (max-min)/(double)total_n_steps;
ErrorHandler::Error("Step = 0, resetting to default step");
step = (max-min)/2000.0;
}

QtUtils::SetText( 8, 2, min, iv_ui->x_min_input );