diff --git a/Framework/Algorithms/inc/MantidAlgorithms/MonteCarloAbsorption.h b/Framework/Algorithms/inc/MantidAlgorithms/MonteCarloAbsorption.h
index c5fb1581c29308bea8940c7cc7358c15d7047115..179ca161b01bc2ec2207527a7bee08c921f96728 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/MonteCarloAbsorption.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/MonteCarloAbsorption.h
@@ -64,11 +64,10 @@ private:
   void exec() override;
   std::map<std::string, std::string> validateInputs() override;
 
-  API::MatrixWorkspace_uptr
-  doSimulation(const API::MatrixWorkspace &inputWS, const size_t nevents,
-               int nlambda, const int seed,
-               const InterpolationOption &interpolateOpt,
-               const bool useSparseInstrument);
+  API::MatrixWorkspace_uptr doSimulation(
+      const API::MatrixWorkspace &inputWS, const size_t nevents, int nlambda,
+      const int seed, const InterpolationOption &interpolateOpt,
+      const bool useSparseInstrument, const size_t maxScatterPtAttempts);
   API::MatrixWorkspace_uptr
   createOutputWorkspace(const API::MatrixWorkspace &inputWS) const;
   std::unique_ptr<IBeamProfile>
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/SampleCorrections/MCAbsorptionStrategy.h b/Framework/Algorithms/inc/MantidAlgorithms/SampleCorrections/MCAbsorptionStrategy.h
index d1c86cc11950b55c2eac4508799df003f263f878..c1db0c3b0aa71de6fdc4235e7c1ffb1dc1ba2c27 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/SampleCorrections/MCAbsorptionStrategy.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/SampleCorrections/MCAbsorptionStrategy.h
@@ -49,7 +49,8 @@ class IBeamProfile;
 class MANTID_ALGORITHMS_DLL MCAbsorptionStrategy {
 public:
   MCAbsorptionStrategy(const IBeamProfile &beamProfile,
-                       const API::Sample &sample, size_t nevents);
+                       const API::Sample &sample, size_t nevents,
+                       size_t maxScatterPtAttempts);
   std::tuple<double, double> calculate(Kernel::PseudoRandomNumberGenerator &rng,
                                        const Kernel::V3D &finalPos,
                                        double lambdaBefore,
@@ -59,6 +60,7 @@ private:
   const IBeamProfile &m_beamProfile;
   const MCInteractionVolume m_scatterVol;
   const size_t m_nevents;
+  const size_t m_maxScatterAttempts;
   const double m_error;
 };
 
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/SampleCorrections/MCInteractionVolume.h b/Framework/Algorithms/inc/MantidAlgorithms/SampleCorrections/MCInteractionVolume.h
index 05533afd2e1011eebe93cf44be17e12fbeef6a4a..651398733d9ff5b81e2065fda92c6551d91ee72b 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/SampleCorrections/MCInteractionVolume.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/SampleCorrections/MCInteractionVolume.h
@@ -48,7 +48,8 @@ class IBeamProfile;
 class MANTID_ALGORITHMS_DLL MCInteractionVolume {
 public:
   MCInteractionVolume(const API::Sample &sample,
-                      const Geometry::BoundingBox &activeRegion);
+                      const Geometry::BoundingBox &activeRegion,
+                      const size_t maxScatterAttempts = 5000);
   // No creation from temporaries as we store a reference to the object in
   // the sample
   MCInteractionVolume(const API::Sample &&sample,
@@ -64,6 +65,7 @@ private:
   const Geometry::Object &m_sample;
   const Geometry::SampleEnvironment *m_env;
   const Geometry::BoundingBox m_activeRegion;
+  const size_t m_maxScatterAttempts;
 };
 
 } // namespace Algorithms
diff --git a/Framework/Algorithms/src/MonteCarloAbsorption.cpp b/Framework/Algorithms/src/MonteCarloAbsorption.cpp
index 3251cc82c748b20dc9aaba475d9022b470cdea26..6e78629ef369fac809e2e01b9ca73a2987bee39e 100644
--- a/Framework/Algorithms/src/MonteCarloAbsorption.cpp
+++ b/Framework/Algorithms/src/MonteCarloAbsorption.cpp
@@ -134,6 +134,17 @@ void MonteCarloAbsorption::init() {
       "NumberOfDetectorColumns",
       Kernel::make_unique<EnabledWhenProperty>(
           "SparseInstrument", ePropertyCriterion::IS_NOT_DEFAULT));
+
+  // Control the number of attempts made to generate a random point in the
+  // object
+  declareProperty("MaxScatterPtAttempts", 5000, positiveInt,
+                  "Maximum number of tries made to generate a scattering point "
+                  "within the sample (+ optional container etc). Objects with "
+                  "holes in them, e.g. a thin annulus can cause problems "
+                  "if this number is too low.\n"
+                  "If a scattering point cannot be generated by increasing "
+                  "this value then there is most likely a problem with "
+                  "the sample geometry.");
 }
 
 /**
@@ -147,8 +158,10 @@ void MonteCarloAbsorption::exec() {
   InterpolationOption interpolateOpt;
   interpolateOpt.set(getPropertyValue("Interpolation"));
   const bool useSparseInstrument = getProperty("SparseInstrument");
+  const int maxScatterPtAttempts = getProperty("MaxScatterPtAttempts");
   auto outputWS = doSimulation(*inputWS, static_cast<size_t>(nevents), nlambda,
-                               seed, interpolateOpt, useSparseInstrument);
+                               seed, interpolateOpt, useSparseInstrument,
+                               static_cast<size_t>(maxScatterPtAttempts));
 
   setProperty("OutputWorkspace", std::move(outputWS));
 }
@@ -179,12 +192,14 @@ std::map<std::string, std::string> MonteCarloAbsorption::validateInputs() {
  * @param seed Seed value for the random number generator
  * @param interpolateOpt Method of interpolation to compute unsimulated points
  * @param useSparseInstrument If true, use sparse instrument in simulation
+ * @param maxScatterPtAttempts The maximum number of tries to generate a
+ * scatter point within the object
  * @return A new workspace containing the correction factors & errors
  */
 MatrixWorkspace_uptr MonteCarloAbsorption::doSimulation(
     const MatrixWorkspace &inputWS, const size_t nevents, int nlambda,
     const int seed, const InterpolationOption &interpolateOpt,
-    const bool useSparseInstrument) {
+    const bool useSparseInstrument, const size_t maxScatterPtAttempts) {
   auto outputWS = createOutputWorkspace(inputWS);
   const auto inputNbins = static_cast<int>(inputWS.blocksize());
   if (isEmpty(nlambda) || nlambda > inputNbins) {
@@ -223,7 +238,8 @@ MatrixWorkspace_uptr MonteCarloAbsorption::doSimulation(
   const std::string reportMsg = "Computing corrections";
 
   // Configure strategy
-  MCAbsorptionStrategy strategy(*beamProfile, inputWS.sample(), nevents);
+  MCAbsorptionStrategy strategy(*beamProfile, inputWS.sample(), nevents,
+                                maxScatterPtAttempts);
 
   const auto &spectrumInfo = simulationWS.spectrumInfo();
 
diff --git a/Framework/Algorithms/src/SampleCorrections/MCAbsorptionStrategy.cpp b/Framework/Algorithms/src/SampleCorrections/MCAbsorptionStrategy.cpp
index f4a73febff75595e268cc3eaf37e0d3bd7368279..d61bf84d50b378812f841c9f0e29ee30128b3cd6 100644
--- a/Framework/Algorithms/src/SampleCorrections/MCAbsorptionStrategy.cpp
+++ b/Framework/Algorithms/src/SampleCorrections/MCAbsorptionStrategy.cpp
@@ -6,11 +6,6 @@
 #include "MantidAlgorithms/SampleCorrections/RectangularBeamProfile.h"
 #include "MantidGeometry/Objects/Object.h"
 
-namespace {
-/// Maximum number of tries to generate a track through the sample
-unsigned int MAX_EVENT_ATTEMPTS = 100;
-}
-
 namespace Mantid {
 using Kernel::PseudoRandomNumberGenerator;
 
@@ -21,14 +16,18 @@ namespace Algorithms {
  * @param beamProfile A reference to the object the beam profile
  * @param sample A reference to the object defining details of the sample
  * @param nevents The number of Monte Carlo events used in the simulation
+ * @param maxScatterPtAttempts The maximum number of tries to generate a random
+ * point within the object.
  */
 MCAbsorptionStrategy::MCAbsorptionStrategy(const IBeamProfile &beamProfile,
                                            const API::Sample &sample,
-                                           size_t nevents)
+                                           size_t nevents,
+                                           size_t maxScatterPtAttempts)
     : m_beamProfile(beamProfile),
       m_scatterVol(
           MCInteractionVolume(sample, beamProfile.defineActiveRegion(sample))),
-      m_nevents(nevents), m_error(1.0 / std::sqrt(m_nevents)) {}
+      m_nevents(nevents), m_maxScatterAttempts(maxScatterPtAttempts),
+      m_error(1.0 / std::sqrt(m_nevents)) {}
 
 /**
  * Compute the correction for a final position of the neutron and wavelengths
@@ -59,9 +58,13 @@ MCAbsorptionStrategy::calculate(Kernel::PseudoRandomNumberGenerator &rng,
         factor += wgt;
         break;
       }
-      if (attempts == MAX_EVENT_ATTEMPTS) {
+      if (attempts == m_maxScatterAttempts) {
         throw std::runtime_error("Unable to generate valid track through "
-                                 "sample interaction volume.");
+                                 "sample interaction volume after " +
+                                 std::to_string(m_maxScatterAttempts) +
+                                 " attempts. Try increasing the maximum "
+                                 "threshold or if this does not help then "
+                                 "please check the defined shape.");
       }
     } while (true);
   }
diff --git a/Framework/Algorithms/src/SampleCorrections/MCInteractionVolume.cpp b/Framework/Algorithms/src/SampleCorrections/MCInteractionVolume.cpp
index 3d96995f6d11a9bc4dc6658ba936372f9207f064..d57b110310c6a4c48f2a108fba72ead00152729b 100644
--- a/Framework/Algorithms/src/SampleCorrections/MCInteractionVolume.cpp
+++ b/Framework/Algorithms/src/SampleCorrections/MCInteractionVolume.cpp
@@ -14,9 +14,6 @@ namespace Algorithms {
 
 namespace {
 
-// Maximum number of attempts to generate a scatter point
-constexpr size_t MAX_SCATTER_ATTEMPTS = 500;
-
 /**
  * Compute the attenuation factor for the given coefficients
  * @param rho Number density of the sample in \f$\\A^{-3}\f$
@@ -37,11 +34,14 @@ double attenuation(double rho, double sigma, double length) {
  * @param sample A reference to a sample object that defines a valid shape
  * & material
  * @param activeRegion Restrict scattering point sampling to this region
+ * @param maxScatterAttempts The maximum number of tries to generate a random
+ * point within the object. [Default=5000]
  */
 MCInteractionVolume::MCInteractionVolume(
-    const API::Sample &sample, const Geometry::BoundingBox &activeRegion)
-    : m_sample(sample.getShape()), m_env(nullptr),
-      m_activeRegion(activeRegion) {
+    const API::Sample &sample, const Geometry::BoundingBox &activeRegion,
+    const size_t maxScatterAttempts)
+    : m_sample(sample.getShape()), m_env(nullptr), m_activeRegion(activeRegion),
+      m_maxScatterAttempts(maxScatterAttempts) {
   if (!m_sample.hasValidShape()) {
     throw std::invalid_argument(
         "MCInteractionVolume() - Sample shape does not have a valid shape.");
@@ -90,10 +90,10 @@ double MCInteractionVolume::calculateAbsorption(
   V3D scatterPos;
   if (m_env && (rng.nextValue() > 0.5)) {
     scatterPos =
-        m_env->generatePoint(rng, m_activeRegion, MAX_SCATTER_ATTEMPTS);
+        m_env->generatePoint(rng, m_activeRegion, m_maxScatterAttempts);
   } else {
     scatterPos = m_sample.generatePointInObject(rng, m_activeRegion,
-                                                MAX_SCATTER_ATTEMPTS);
+                                                m_maxScatterAttempts);
   }
   auto toStart = startPos - scatterPos;
   toStart.normalize();
diff --git a/Framework/Algorithms/test/MCAbsorptionStrategyTest.h b/Framework/Algorithms/test/MCAbsorptionStrategyTest.h
index c352450a75e2761d2adc9628323145c909371834..6a8da3947062320d8ffa54aeaf6b62fa14f84655 100644
--- a/Framework/Algorithms/test/MCAbsorptionStrategyTest.h
+++ b/Framework/Algorithms/test/MCAbsorptionStrategyTest.h
@@ -3,9 +3,11 @@
 
 #include <cxxtest/TestSuite.h>
 
-#include "MantidAlgorithms/SampleCorrections/IBeamProfile.h"
 #include "MantidAlgorithms/SampleCorrections/MCAbsorptionStrategy.h"
+#include "MantidAlgorithms/SampleCorrections/RectangularBeamProfile.h"
 #include "MantidGeometry/Objects/BoundingBox.h"
+#include "MantidGeometry/Instrument/ReferenceFrame.h"
+#include "MantidKernel/MersenneTwister.h"
 #include "MantidKernel/WarningSuppressions.h"
 #include "MonteCarloTesting.h"
 
@@ -20,11 +22,6 @@ public:
   }
   static void destroySuite(MCAbsorptionStrategyTest *suite) { delete suite; }
 
-  MCAbsorptionStrategyTest()
-      : m_nevents(10), m_testBeamProfile(),
-        m_testSample(MonteCarloTesting::createTestSample(
-            MonteCarloTesting::TestSampleType::SolidSphere)) {}
-
   //----------------------------------------------------------------------------
   // Success cases
   //----------------------------------------------------------------------------
@@ -33,16 +30,23 @@ public:
     using namespace MonteCarloTesting;
     using namespace ::testing;
 
-    MockRNG rng;
-    auto mcabsorb = createTestObject();
+    auto testSampleSphere = MonteCarloTesting::createTestSample(
+        MonteCarloTesting::TestSampleType::SolidSphere);
+    MockBeamProfile testBeamProfile;
+    EXPECT_CALL(testBeamProfile, defineActiveRegion(_))
+        .WillOnce(Return(testSampleSphere.getShape().getBoundingBox()));
+    const size_t nevents(10), maxTries(100);
+    MCAbsorptionStrategy mcabsorb(testBeamProfile, testSampleSphere, nevents,
+                                  maxTries);
     // 3 random numbers per event expected
+    MockRNG rng;
     EXPECT_CALL(rng, nextValue())
         .Times(Exactly(30))
         .WillRepeatedly(Return(0.5));
     const Mantid::Algorithms::IBeamProfile::Ray testRay = {V3D(-2, 0, 0),
                                                            V3D(1, 0, 0)};
-    EXPECT_CALL(m_testBeamProfile, generatePoint(_, _))
-        .Times(Exactly(static_cast<int>(m_nevents)))
+    EXPECT_CALL(testBeamProfile, generatePoint(_, _))
+        .Times(Exactly(static_cast<int>(nevents)))
         .WillRepeatedly(Return(testRay));
     const V3D endPos(0.7, 0.7, 1.4);
     const double lambdaBefore(2.5), lambdaAfter(3.5);
@@ -51,13 +55,35 @@ public:
     std::tie(factor, error) =
         mcabsorb.calculate(rng, endPos, lambdaBefore, lambdaAfter);
     TS_ASSERT_DELTA(0.0043828472, factor, 1e-08);
-    TS_ASSERT_DELTA(1.0 / std::sqrt(m_nevents), error, 1e-08);
+    TS_ASSERT_DELTA(1.0 / std::sqrt(nevents), error, 1e-08);
   }
 
   //----------------------------------------------------------------------------
   // Failure cases
   //----------------------------------------------------------------------------
 
+  void test_thin_object_fails_to_generate_point_in_sample() {
+    using Mantid::Algorithms::RectangularBeamProfile;
+    using namespace Mantid::Geometry;
+    using namespace Mantid::Kernel;
+    using namespace MonteCarloTesting;
+    using namespace ::testing;
+
+    auto testThinAnnulus = MonteCarloTesting::createTestSample(
+        MonteCarloTesting::TestSampleType::ThinAnnulus);
+    RectangularBeamProfile testBeamProfile(
+        ReferenceFrame(Y, Z, Right, "source"), V3D(), 1, 1);
+    const size_t nevents(10), maxTries(1);
+    MCAbsorptionStrategy mcabs(testBeamProfile, testThinAnnulus, nevents,
+                               maxTries);
+    MersenneTwister rng;
+    rng.setSeed(1);
+    const double lambdaBefore(2.5), lambdaAfter(3.5);
+    const V3D endPos(0.7, 0.7, 1.4);
+    TS_ASSERT_THROWS(mcabs.calculate(rng, endPos, lambdaBefore, lambdaAfter),
+                     std::runtime_error)
+  }
+
 private:
   class MockBeamProfile final : public Mantid::Algorithms::IBeamProfile {
   public:
@@ -72,18 +98,6 @@ private:
                                                const Mantid::API::Sample &));
     GCC_DIAG_ON_SUGGEST_OVERRIDE
   };
-
-  MCAbsorptionStrategy createTestObject() {
-    using namespace ::testing;
-
-    EXPECT_CALL(m_testBeamProfile, defineActiveRegion(_))
-        .WillOnce(Return(m_testSample.getShape().getBoundingBox()));
-    return MCAbsorptionStrategy(m_testBeamProfile, m_testSample, m_nevents);
-  }
-
-  const size_t m_nevents;
-  MockBeamProfile m_testBeamProfile;
-  Mantid::API::Sample m_testSample;
 };
 
 #endif /* MANTID_ALGORITHMS_MCABSORPTIONSTRATEGYTEST_H_ */
diff --git a/Framework/Algorithms/test/MCInteractionVolumeTest.h b/Framework/Algorithms/test/MCInteractionVolumeTest.h
index fff2c55c0369fb80a7abae932521b504102a7767..5f807049a0a07793d4ae7eafdd6b1a8a93063d90 100644
--- a/Framework/Algorithms/test/MCInteractionVolumeTest.h
+++ b/Framework/Algorithms/test/MCInteractionVolumeTest.h
@@ -4,6 +4,7 @@
 #include <cxxtest/TestSuite.h>
 
 #include "MantidAlgorithms/SampleCorrections/MCInteractionVolume.h"
+#include "MantidKernel/MersenneTwister.h"
 #include "MonteCarloTesting.h"
 
 #include <gmock/gmock.h>
@@ -140,6 +141,26 @@ public:
     TS_ASSERT_THROWS_NOTHING(
         MCInteractionVolume mcv(sample, sample.getShape().getBoundingBox()));
   }
+
+  void test_Throws_If_Point_Cannot_Be_Generated() {
+    using namespace Mantid::Kernel;
+    using namespace MonteCarloTesting;
+    using namespace ::testing;
+
+    // Testing inputs
+    const V3D startPos(-2.0, 0.0, 0.0), endPos(2.0, 0.0, 0.0);
+    const double lambdaBefore(2.5), lambdaAfter(3.5);
+
+    auto sample = createTestSample(TestSampleType::ThinAnnulus);
+    MersenneTwister rng;
+    rng.setSeed(1);
+    const size_t maxTries(1);
+    MCInteractionVolume interactor(sample, sample.getShape().getBoundingBox(),
+                                   maxTries);
+    TS_ASSERT_THROWS(interactor.calculateAbsorption(rng, startPos, endPos,
+                                                    lambdaBefore, lambdaAfter),
+                     std::runtime_error);
+  }
 };
 
 #endif /* MANTID_ALGORITHMS_MCINTERACTIONVOLUMETEST_H_ */
diff --git a/Framework/Algorithms/test/MonteCarloTesting.h b/Framework/Algorithms/test/MonteCarloTesting.h
index 249d477724744ade2eb0ee478bbf7d0ef1950acb..b8d8f65416f9b37d1b88e02fe82cf9672ae3a48c 100644
--- a/Framework/Algorithms/test/MonteCarloTesting.h
+++ b/Framework/Algorithms/test/MonteCarloTesting.h
@@ -41,7 +41,12 @@ public:
 // -----------------------------------------------------------------------------
 // Create test samples
 // -----------------------------------------------------------------------------
-enum class TestSampleType { SolidSphere, Annulus, SamplePlusContainer };
+enum class TestSampleType {
+  SolidSphere,
+  Annulus,
+  ThinAnnulus,
+  SamplePlusContainer
+};
 
 inline std::string annulusXML(double innerRadius, double outerRadius,
                               double height,
@@ -49,7 +54,9 @@ inline std::string annulusXML(double innerRadius, double outerRadius,
   using Mantid::Kernel::V3D;
 
   // Cylinders oriented along up, with origin at centre of cylinder
-  const V3D centre(0, 0, -0.5 * height);
+  // Assume upAxis is a unit vector
+  V3D centre(upAxis);
+  centre *= -0.5 * height;
   const std::string inner = ComponentCreationHelper::cappedCylinderXML(
       innerRadius, height, centre, upAxis, "inner");
   const std::string outer = ComponentCreationHelper::cappedCylinderXML(
@@ -117,6 +124,8 @@ inline Mantid::API::Sample createTestSample(TestSampleType sampleType) {
       shape = ComponentCreationHelper::createSphere(0.1);
     } else if (sampleType == TestSampleType::Annulus) {
       shape = createAnnulus(0.1, 0.15, 0.15, V3D(0, 0, 1));
+    } else if (sampleType == TestSampleType::ThinAnnulus) {
+      shape = createAnnulus(0.01, 0.0101, 0.4, V3D(0, 1, 0));
     } else {
       throw std::invalid_argument("Unknown testing shape type requested");
     }
diff --git a/Framework/DataHandling/src/LoadLog.cpp b/Framework/DataHandling/src/LoadLog.cpp
index 96e1840d73f7309fd9c3e15b01b8495660373a34..ca1aec58167ac0b5f3857282396ed4b051e6ca90 100644
--- a/Framework/DataHandling/src/LoadLog.cpp
+++ b/Framework/DataHandling/src/LoadLog.cpp
@@ -209,7 +209,7 @@ void LoadLog::loadThreeColumnLogFile(std::ifstream &logFileStream,
   }
 
   while (Mantid::Kernel::Strings::extractToEOL(logFileStream, str)) {
-    if (!isDateTimeString(str)) {
+    if (!isDateTimeString(str) && !str.empty()) {
       throw std::invalid_argument("File" + logFileName +
                                   " is not a standard ISIS log file. Expected "
                                   "to be a file starting with DateTime String "
@@ -217,8 +217,8 @@ void LoadLog::loadThreeColumnLogFile(std::ifstream &logFileStream,
     }
 
     if (!Kernel::TimeSeriesProperty<double>::isTimeString(str) ||
-        (str[0] ==
-         '#')) { // if the line doesn't start with a time read the next line
+        (str.empty() || str[0] == '#')) {
+      // if the line doesn't start with a time read the next line
       continue;
     }
 
@@ -230,6 +230,12 @@ void LoadLog::loadThreeColumnLogFile(std::ifstream &logFileStream,
     line >> blockcolumn;
     l_kind = classify(blockcolumn);
 
+    if (LoadLog::empty == l_kind) {
+      g_log.warning() << "Failed to parse line in log file: " << timecolumn
+                      << "\t" << blockcolumn;
+      continue;
+    }
+
     if (LoadLog::string != l_kind) {
       throw std::invalid_argument(
           "ISIS log file contains unrecognised second column entries:" +
@@ -404,9 +410,23 @@ LoadLog::kind LoadLog::classify(const std::string &s) const {
 
   if (letters.find_first_of(s) != string::npos) {
     return LoadLog::string;
-  } else {
-    return LoadLog::number;
   }
+
+  const auto isNumber = [](const std::string &str) {
+    // try and get stold to parse a number out of the string
+    // if this throws then we don't have a number
+    try {
+      // cppcheck-suppress ignoredReturnValue
+      std::stold(str);
+      return true;
+    } catch (const std::invalid_argument &e) {
+      return false;
+    } catch (const std::out_of_range &e) {
+      return false;
+    }
+  };
+
+  return (isNumber(s)) ? LoadLog::number : LoadLog::empty;
 }
 
 /**
diff --git a/Framework/DataHandling/test/LoadLogTest.h b/Framework/DataHandling/test/LoadLogTest.h
index 675ee09c68706dee549777fd58ca2a2b38ae841f..6b0c4ec43259ff75313537662c478ca154ebf944 100644
--- a/Framework/DataHandling/test/LoadLogTest.h
+++ b/Framework/DataHandling/test/LoadLogTest.h
@@ -223,6 +223,20 @@ public:
     TS_ASSERT_EQUALS(tsp->size(), 33);
   }
 
+  void test_ISISTextFile_withRubbishLogFileInput_fails() {
+    auto ws = WorkspaceFactory::Instance().create("Workspace2D", 1, 1, 1);
+
+    LoadLog alg;
+    alg.initialize();
+    alg.setPropertyValue("Filename", "ENGINX00275776_ICPputlog.txt");
+    alg.setProperty("Workspace", ws);
+
+    TS_ASSERT_THROWS_NOTHING(alg.execute());
+
+    const auto props = ws->run().getProperties();
+    TS_ASSERT_EQUALS(props.size(), 2);
+  };
+
   void test_SNSTextFile_noNames_fails() { do_test_SNSTextFile("", "", true); }
 
   void test_SNSTextFile_tooFewNames_fails() {
diff --git a/Framework/PythonInterface/plugins/algorithms/ComputeIncoherentDOS.py b/Framework/PythonInterface/plugins/algorithms/ComputeIncoherentDOS.py
index f6fdce2b1ac8a8c593ba3b8d504ae2cf0931fd67..19052612d62ec2e6a0d64ea88cb209b22c2f57c8 100644
--- a/Framework/PythonInterface/plugins/algorithms/ComputeIncoherentDOS.py
+++ b/Framework/PythonInterface/plugins/algorithms/ComputeIncoherentDOS.py
@@ -9,11 +9,23 @@ from mantid.simpleapi import *
 
 
 def evaluateEbin(Emin, Emax, Ei, strn):
-    return [eval(estr) for estr in strn.split(',')]
+    if strn.count(',') != 2:
+        raise ValueError('EnergyBinning must be a comma separated string with three values.')
+    try:
+        out = [eval(estr, None, {'Emax':Emax, 'Emin':Emin, 'Ei':Ei}) for estr in strn.split(',')]
+    except NameError:
+        raise ValueError('Only the variables ''Emin'', ''Emax'' or ''Ei'' are allowed in EnergyBinning.')
+    return out
 
 
 def evaluateQRange(Qmin, Qmax, strn):
-    return [eval(qstr) for qstr in strn.split(',')]
+    if strn.count(',') != 1:
+        raise ValueError('QSumRange must be a comma separated string with two values.')
+    try:
+        out = [eval(qstr, None, {'Qmin':Qmin, 'Qmax':Qmax}) for qstr in strn.split(',')]
+    except NameError:
+        raise ValueError('Only the variables ''Qmin'' and ''Qmax'' is allowed in QSumRange.')
+    return out
 
 
 class ComputeIncoherentDOS(PythonAlgorithm):
@@ -97,14 +109,8 @@ class ComputeIncoherentDOS(PythonAlgorithm):
         qq = (qq[1:len(qq)]+qq[0:len(qq)-1])/2
         en = (en[1:len(en)]+en[0:len(en)-1])/2
 
-        # Checks qrange is valid
-        if QSumRange.count(',') != 1:
-            raise ValueError('QSumRange must be a comma separated string with two values.')
-        try:
-            # Do this in a member function to make sure no other variables can be evaluated other than Qmin and Qmax.
-            dq = evaluateQRange(min(qq), max(qq), QSumRange)
-        except NameError:
-            raise ValueError('Only the variables ''Qmin'' and ''Qmax'' is allowed in QSumRange.')
+        # Checks qrange is valid. Do it in a member function so no variables can be evaluated other than Qmin and Qmax.
+        dq = evaluateQRange(min(qq), max(qq), QSumRange)
 
         # Gets meV to cm^-1 conversion
         mev2cm = (constants.elementary_charge / 1000) / (constants.h * constants.c * 100)
@@ -118,21 +124,16 @@ class ComputeIncoherentDOS(PythonAlgorithm):
             en = en / mev2cm
             input_en_in_meV = 0
 
-        # Checks energy bins are ok.
-        if EnergyBinning.count(',') != 2:
-            raise ValueError('EnergyBinning must be a comma separated string with three values.')
+        # Gets the incident energy from the workspace - either if it is set as an attribute or from the energy axis.
         try:
             ei = inws.getEFixed(1)
         except RuntimeError:
             ei = max(en)
-        try:
-            # Do this in a function to make sure no other variables can be evaluated other than Emin, Emax and Ei.
-            if not input_en_in_meV:
-                dosebin = evaluateEbin(min(en*mev2cm), max(en*mev2cm), ei*mev2cm, EnergyBinning)
-            else:
-                dosebin = evaluateEbin(min(en), max(en), ei, EnergyBinning)
-        except NameError:
-            raise ValueError('Only the variables ''Emin'', ''Emax'' or ''Ei'' are allowed in EnergyBinning.')
+        # Checks energy bins are ok. Do it in a function so no variables can be evaluated except Emin, Emax and Ei.
+        if not input_en_in_meV:
+            dosebin = evaluateEbin(min(en*mev2cm), max(en*mev2cm), ei*mev2cm, EnergyBinning)
+        else:
+            dosebin = evaluateEbin(min(en), max(en), ei, EnergyBinning)
 
         # Extracts the intensity (y) and errors (e) from inws.
         y = inws.extractY()
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/CMakeLists.txt b/Framework/PythonInterface/test/python/plugins/algorithms/CMakeLists.txt
index 7e5a5a4768d2de524e592e04f3b91021ec036109..4a0b0cca90f7a9b025925df4509c63069979d38b 100644
--- a/Framework/PythonInterface/test/python/plugins/algorithms/CMakeLists.txt
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/CMakeLists.txt
@@ -16,6 +16,7 @@ set ( TEST_PY_FILES
   ConjoinSpectraTest.py
   CompareSampleLogsTest.py
   ComputeCalibrationCoefVanTest.py
+  ComputeIncoherentDOSTest.py
   CorrectLogTimesTest.py
   CreateLeBailFitInputTest.py
   CorrectTOFTest.py
diff --git a/Testing/Data/UnitTest/ENGINX00275776_ICPputlog.txt.md5 b/Testing/Data/UnitTest/ENGINX00275776_ICPputlog.txt.md5
new file mode 100644
index 0000000000000000000000000000000000000000..c75683223a57290e05c8df2ca0f2e4e841b62f3a
--- /dev/null
+++ b/Testing/Data/UnitTest/ENGINX00275776_ICPputlog.txt.md5
@@ -0,0 +1 @@
+ade333d2cf33b2432b425ecb6288a3ff
diff --git a/buildconfig/Jenkins/buildscript b/buildconfig/Jenkins/buildscript
index d0b9e959b0ee2ec95a02623b23f5f58dc2461d9d..4391de0553b4020d7bc98ee35a4e851a231f5afa 100755
--- a/buildconfig/Jenkins/buildscript
+++ b/buildconfig/Jenkins/buildscript
@@ -95,16 +95,6 @@ if [[ "$CLEANBUILD" == true ]]; then
 fi
 if [ -d $BUILD_DIR ]; then
   rm -rf $BUILD_DIR/bin $BUILD_DIR/ExternalData
-  ###############################################################################
-  # Temporary fix to clean build directories while
-  # https://github.com/mantidproject/mantid/pull/20617 is pushed through
-  ###############################################################################
-  _main_generator=$(grep "CMAKE_GENERATOR:INTERNAL" ${BUILD_DIR}/CMakeCache.txt)
-  _eigen_generator=$(grep "CMAKE_GENERATOR:INTERNAL"  ${BUILD_DIR}/eigen-download/CMakeCache.txt)
-  if [ "${_main_generator}" != "${_eigen_generator}" ]; then
-    echo "External project generator mismatch. Cleaning external projects"
-    CLEAN_EXTERNAL_PROJECTS=true
-  fi
   if [[ -n ${CLEAN_EXTERNAL_PROJECTS} && "${CLEAN_EXTERNAL_PROJECTS}" == true ]]; then
       rm -rf $BUILD_DIR/eigen-*
       rm -rf $BUILD_DIR/googletest-*
diff --git a/buildconfig/Jenkins/buildscript.bat b/buildconfig/Jenkins/buildscript.bat
index 83d48ac6aae02ee3030069925258b227a2a3e990..789b139e2701f947bf3c7fe42f3e65357b9cd6c8 100755
--- a/buildconfig/Jenkins/buildscript.bat
+++ b/buildconfig/Jenkins/buildscript.bat
@@ -80,12 +80,6 @@ if "!CLEANBUILD!" == "yes" (
 
 if EXIST %BUILD_DIR% (
   rmdir /S /Q %BUILD_DIR%\bin %BUILD_DIR%\ExternalData
-  call "%GREP_EXE%" CMAKE_GENERATOR:INTERNAL %BUILD_DIR%\eigen-download\CMakeCache.txt > eigen_generator.log
-  call "%GREP_EXE%" "%CM_GENERATOR%" eigen_generator.log
-  if ERRORLEVEL 1 (
-    echo External project generator mismatch. Cleaning external projects
-    set CLEAN_EXTERNAL_PROJECTS=true
-  )
   if "!CLEAN_EXTERNAL_PROJECTS!" == "true" (
     rmdir /S /Q %BUILD_DIR%\eigen-download %BUILD_DIR%\eigen-src
     rmdir /S /Q %BUILD_DIR%\googletest-download %BUILD_DIR%\googletest-src
diff --git a/docs/source/release/v3.11.0/framework.rst b/docs/source/release/v3.11.0/framework.rst
index 31ec178d4b5a790250e8b16c7cfb891b2524b229..706b00ba8e4b38d2aa73427361fae0c8411c0a75 100644
--- a/docs/source/release/v3.11.0/framework.rst
+++ b/docs/source/release/v3.11.0/framework.rst
@@ -46,7 +46,11 @@ Improved
 - :ref:`IntegreatePeaksMD <algm-IntegratePeaksMD-v2>` makes the culling of the top one percent of the background events optional.
 - :ref:`Load <algm-Load-v1>` now supports use of tilde in file paths in Python, for example Load(Filename="~/data/test.nxs", ...)
 - :ref:`LoadBBY <algm-LoadBBY-v1>` is now better at handling sample information.
-- :ref:`algm-MonteCarloAbsorption` now supports approximating the input instrument with a sparse grid of detectors enabling quick simulation of huge pixel arrays. Also, the NumberOfWavelengthPoints input property is now validated more rigorously.
+- :ref:`MonteCarloAbsorption <algm-MonteCarloAbsorption-v1>` has had several improvements:
+
+  * it now supports approximating the input instrument with a sparse grid of detectors enabling quick simulation of huge pixel arrays
+  * the NumberOfWavelengthPoints input property is now validated more rigorously
+  * a new MaxScatterPtAttempts input has been added to control how many tries are made to generate a random point in the object. Useful for cases such as thin annuli that require a higher number of tries. The previous version was hard coded internally.
 - :ref:`SaveGSS <algm-SaveGSS-v1>` now supports saving in the legacy GSAS ALT format. This is useful for older tools however the default format FXYE should be used whenever possible.
 - :ref:`SaveMDWorkspaceToVTK <algm-SaveMDWorkspaceToVTK-v1>` and :ref:`LoadVTK <algm-LoadVTK-v1>` algorithms are now accessible from python.
 - :ref:`MergeRuns <algm-MergeRuns-v1>` will now merge workspaces with detector scans.
diff --git a/docs/source/release/v3.11.0/muon.rst b/docs/source/release/v3.11.0/muon.rst
index 208e731721f65344c0f82d31426aad7287848b2d..1a5e381f153be3f3c0b1b2247dbbd0bc900d6d8c 100644
--- a/docs/source/release/v3.11.0/muon.rst
+++ b/docs/source/release/v3.11.0/muon.rst
@@ -24,6 +24,7 @@ Fit Functions
 Bug Fixes
 ---------
 - Mantid would crash when multiple period data was used in single fits (in muon analysis). This has been fixed. 
+- Fixed crash when loading data into MuonAnalysis after using Add/Remove curves.
 
 
 |
diff --git a/qt/scientific_interfaces/Muon/MuonAnalysis.cpp b/qt/scientific_interfaces/Muon/MuonAnalysis.cpp
index 9b28c77e54de823e9d90dd297753824d26e654ce..75be0f243f653879a3dc3b5107d909827a349e82 100644
--- a/qt/scientific_interfaces/Muon/MuonAnalysis.cpp
+++ b/qt/scientific_interfaces/Muon/MuonAnalysis.cpp
@@ -1701,7 +1701,7 @@ void MuonAnalysis::plotSpectrum(const QString &wsName, bool logScale) {
   s << "  layer = window.activeLayer()";
   s << "  if layer is not None:";
   s << "    kept_fits = 0";
-  s << "    for i in range(layer.numCurves() - 1, -1, -1):"; // reversed
+  s << "    for i in range(layer.numCurves() - 1, 0, -1):"; // reversed
   s << "      title = layer.curveTitle(i)";
   s << "      if title == \"CompositeFunction\":";
   s << "        continue"; // keep all guesses
@@ -1764,8 +1764,15 @@ void MuonAnalysis::plotSpectrum(const QString &wsName, bool logScale) {
   // Plot the data!
   s << "win = get_window('%WSNAME%', '%PREV%', %USEPREV%)";
   s << "if %FITSTOKEEP% != -1:";
+  // leave the 0th layer -> layer is not empty
   s << "  remove_data(win, %FITSTOKEEP%)";
   s << "g = plot_data('%WSNAME%', %ERRORS%, %CONNECT%, win)";
+  // if there is more than one layer delete the oldest one manually
+  s << "if %FITSTOKEEP% != -1:";
+  s << "  layer = win.activeLayer()";
+  s << "  if layer.numCurves()>1:";
+  s << "     layer.removeCurve(0)";
+
   s << "format_graph(g, '%WSNAME%', %LOGSCALE%, %YAUTO%, '%YMIN%', '%YMAX%')";
 
   QString pyS;