/// Fetch the properties and set the appropriate member variables void AbsorptionCorrection::retrieveBaseProperties() { double sigma_atten = getProperty("AttenuationXSection"); // in barns double sigma_s = getProperty("ScatteringXSection"); // in barns double rho = getProperty("SampleNumberDensity"); // in Angstroms-3 const Material &sampleMaterial = m_inputWS->sample().getShape().material(); if (sampleMaterial.totalScatterXSection(NeutronAtom::ReferenceLambda) != 0.0) { if (rho == EMPTY_DBL()) rho = sampleMaterial.numberDensity(); if (sigma_s == EMPTY_DBL()) sigma_s = sampleMaterial.totalScatterXSection(NeutronAtom::ReferenceLambda); if (sigma_atten == EMPTY_DBL()) sigma_atten = sampleMaterial.absorbXSection(NeutronAtom::ReferenceLambda); } else // Save input in Sample with wrong atomic number and name { NeutronAtom neutron(0, 0, 0.0, 0.0, sigma_s, 0.0, sigma_s, sigma_atten); auto shape = boost::shared_ptr<IObject>( m_inputWS->sample().getShape().cloneWithMaterial( Material("SetInAbsorptionCorrection", neutron, rho))); m_inputWS->mutableSample().setShape(shape); } rho *= 100; // Will give right units in going from // mu in cm^-1 to m^-1 for mu*total flight path( in m ) // NOTE: the angstrom^-2 to barns and the angstrom^-1 to cm^-1 // will cancel for mu to give units: cm^-1 m_refAtten = -sigma_atten * rho / NeutronAtom::ReferenceLambda; m_scattering = -sigma_s * rho; n_lambda = getProperty("NumberOfWavelengthPoints"); std::string exp_string = getProperty("ExpMethod"); if (exp_string == "Normal") // Use the system exp function EXPONENTIAL = exp; else if (exp_string == "FastApprox") // Use the compact approximation EXPONENTIAL = fast_exp; // Get the energy mode const std::string emodeStr = getProperty("EMode"); // Convert back to an integer representation m_emode = 0; if (emodeStr == "Direct") m_emode = 1; else if (emodeStr == "Indirect") m_emode = 2; // If inelastic, get the fixed energy and convert it to a wavelength if (m_emode) { const double efixed = getProperty("Efixed"); Unit_const_sptr energy = UnitFactory::Instance().create("Energy"); double factor, power; energy->quickConversion(*UnitFactory::Instance().create("Wavelength"), factor, power); m_lambdaFixed = factor * std::pow(efixed, power); } // Call the virtual function for any further properties retrieveProperties(); }
/// Fetch the properties and set the appropriate member variables void AnvredCorrection::retrieveBaseProperties() { m_smu = getProperty("LinearScatteringCoef"); // in 1/cm m_amu = getProperty("LinearAbsorptionCoef"); // in 1/cm m_radius = getProperty("Radius"); // in cm m_power_th = getProperty("PowerLambda"); // in cm const Material &sampleMaterial = m_inputWS->sample().getMaterial(); if (sampleMaterial.totalScatterXSection(NeutronAtom::ReferenceLambda) != 0.0) { double rho = sampleMaterial.numberDensity(); if (m_smu == EMPTY_DBL()) m_smu = sampleMaterial.totalScatterXSection(NeutronAtom::ReferenceLambda) * rho; if (m_amu == EMPTY_DBL()) m_amu = sampleMaterial.absorbXSection(NeutronAtom::ReferenceLambda) * rho; } else // Save input in Sample with wrong atomic number and name { NeutronAtom neutron(static_cast<uint16_t>(EMPTY_DBL()), static_cast<uint16_t>(0), 0.0, 0.0, m_smu, 0.0, m_smu, m_amu); Object shape = m_inputWS->sample().getShape(); // copy shape.setMaterial(Material("SetInAnvredCorrection", neutron, 1.0)); m_inputWS->mutableSample().setShape(shape); } if (m_smu != EMPTY_DBL() && m_amu != EMPTY_DBL()) g_log.notice() << "LinearScatteringCoef = " << m_smu << " 1/cm\n" << "LinearAbsorptionCoef = " << m_amu << " 1/cm\n" << "Radius = " << m_radius << " cm\n" << "Power Lorentz corrections = " << m_power_th << " \n"; // Call the virtual function for any further properties retrieveProperties(); }
API::MatrixWorkspace_sptr HRPDSlabCanAbsorption::runFlatPlateAbsorption() { MatrixWorkspace_sptr m_inputWS = getProperty("InputWorkspace"); double sigma_atten = getProperty("SampleAttenuationXSection"); // in barns double sigma_s = getProperty("SampleScatteringXSection"); // in barns double rho = getProperty("SampleNumberDensity"); // in Angstroms-3 const Material &sampleMaterial = m_inputWS->sample().getMaterial(); if (sampleMaterial.totalScatterXSection(NeutronAtom::ReferenceLambda) != 0.0) { if (rho == EMPTY_DBL()) rho = sampleMaterial.numberDensity(); if (sigma_s == EMPTY_DBL()) sigma_s = sampleMaterial.totalScatterXSection(NeutronAtom::ReferenceLambda); if (sigma_atten == EMPTY_DBL()) sigma_atten = sampleMaterial.absorbXSection(NeutronAtom::ReferenceLambda); } else // Save input in Sample with wrong atomic number and name { NeutronAtom neutron(static_cast<uint16_t>(EMPTY_DBL()), static_cast<uint16_t>(0), 0.0, 0.0, sigma_s, 0.0, sigma_s, sigma_atten); Object shape = m_inputWS->sample().getShape(); // copy shape.setMaterial(Material("SetInSphericalAbsorption", neutron, rho)); m_inputWS->mutableSample().setShape(shape); } // Call FlatPlateAbsorption as a Child Algorithm IAlgorithm_sptr childAlg = createChildAlgorithm("FlatPlateAbsorption", 0.0, 0.9); // Pass through all the properties childAlg->setProperty<MatrixWorkspace_sptr>("InputWorkspace", m_inputWS); childAlg->setProperty<double>("AttenuationXSection", sigma_atten); childAlg->setProperty<double>("ScatteringXSection", sigma_s); childAlg->setProperty<double>("SampleNumberDensity", rho); childAlg->setProperty<int64_t>("NumberOfWavelengthPoints", getProperty("NumberOfWavelengthPoints")); childAlg->setProperty<std::string>("ExpMethod", getProperty("ExpMethod")); // The height and width of the sample holder are standard for HRPD const double HRPDCanHeight = 2.3; const double HRPDCanWidth = 1.8; childAlg->setProperty("SampleHeight", HRPDCanHeight); childAlg->setProperty("SampleWidth", HRPDCanWidth); // Valid values are 0.2,0.5,1.0 & 1.5 - would be nice to have a numeric list // validator const std::string thickness = getPropertyValue("Thickness"); childAlg->setPropertyValue("SampleThickness", thickness); childAlg->executeAsChildAlg(); return childAlg->getProperty("OutputWorkspace"); }
/* @brief function that generates a neutron and measures how far it travels before being absorbed. @details a neutron is created in the bounding box using sample_location() for the first batch and sample_fission_site() for the rest of the batches. It moves a distance determined by sample_distance(). It is then either absorbed or scattered as determined by sample_interaction(). When it is absorbed, its distance from its starting point is appended to crow_distances. If the absorption creates a fission event, the number of neutrons emited is sampled. The location of the fission event is added to a list of fission events. @param bounds a Boundaries object containing the limits of the bounding box @param tallies a dictionary containing tallies of crow distances, leakages, absorptions, and fissions @param mesh a Mesh object containing information about the mesh @param old_fission_banks containing the old fission bank @param new_fission_banks containing the new fission bank @param num_groups the number of neutron energy groups @param neutron_num an int used for indexing neutrons @param z_bounds a vector containing the minimum and maximum geometry boundaries along the z axis since OpenMOC only handles 2D geometries */ void transportNeutron(Boundaries bounds, std::vector <Tally> &tallies, bool first_round, Mesh &mesh, Lattice* lattice, Fission* fission_banks, int num_groups, int neutron_num, Universe* root_universe, Geometry* geometry) { const double BOUNDARY_ERROR = 1e-10; Point* neutron_position = new Point(); // new way to sample neutron and set its direction Neutron neutron(neutron_num); neutron.sampleDirection(); // get and set neutron starting poinit if (first_round) bounds.sampleLocation(&neutron); else { fission_banks->sampleSite(&neutron); } // get mesh cell Point* neutron_starting_point; neutron.getPositionVector(neutron_starting_point); std::vector <int> cell (3); cell[0] = lattice->getLatX(neutron_starting_point); cell[1] = lattice->getLatY(neutron_starting_point); cell[2] = lattice->getLatZ(neutron_starting_point); neutron.setCell(cell); // set neutron group Material* cell_mat; Cell* cell_obj; int group; // get cell material LocalCoords* neutron_coord_position = new LocalCoords( neutron_starting_point->getX(), neutron_starting_point->getY(), neutron_starting_point->getZ()); neutron_coord_position->setUniverse(root_universe); cell_obj = geometry->findCellContainingCoords(neutron_coord_position); cell_mat = cell_obj->getFillMaterial(); std::vector <double> chi(num_groups); for (int g=0; g<num_groups; ++g) { chi[g] = cell_mat->getChiByGroup(g+1); } group = neutron.sampleNeutronEnergyGroup(chi); neutron.setGroup(group); // follow neutron while it's alive while (neutron.alive()) { neutron_coord_position->setX(neutron_position->getX()); neutron_coord_position->setY(neutron_position->getY()); neutron_coord_position->setZ(neutron_position->getZ()); neutron_coord_position->setUniverse(root_universe); cell_obj = geometry->findCellContainingCoords(neutron_coord_position); cell_mat = cell_obj->getFillMaterial(); //cell_mat = mesh.getMaterial(cell); group = neutron.getGroup(); double neutron_distance; //sample a distance to travel in the material neutron_distance = -log(neutron.arand()) / cell_mat->getSigmaTByGroup(group+1); // track neutron until collision or leakage while (neutron_distance > BOUNDARY_ERROR) { neutron.getPositionVector(neutron_position); // get cell boundaries std::vector <double> cell_mins (3); std::vector <double> cell_maxes (3); cell_mins[0] = lattice->getMinX() + cell[0] * lattice->getWidthX(); cell_mins[1] = lattice->getMinY() + cell[1] * lattice->getWidthY(); cell_mins[2] = lattice->getMinZ() + cell[2] * lattice->getWidthZ(); cell_maxes[0] = lattice->getMinX() + (cell[0] + 1) * lattice->getWidthX(); cell_maxes[1] = lattice->getMinY() + (cell[1] + 1) * lattice->getWidthY(); cell_maxes[2] = lattice->getMinZ() + (cell[2] + 1) * lattice->getWidthZ(); // calculate distances to cell boundaries std::vector <std::vector <double> > distance_to_cell_edge(3); for (int axis=0; axis<3; ++axis) { distance_to_cell_edge[axis].resize(2); distance_to_cell_edge[axis][0] = cell_mins[axis] - neutron.getPosition(axis); distance_to_cell_edge[axis][1] = cell_maxes[axis] - neutron.getPosition(axis); } // create lim_bounds std::vector <int> cell_lim_bound; std::vector <int> box_lim_bound; // clear lim_bounds cell_lim_bound.clear(); box_lim_bound.clear(); // tempd contains the current smallest r double tempd; tempd = neutron_distance; // test each boundary double r; for (int axis=0; axis<3; ++axis) { for (int side=0; side<2; ++side) { // r is variable that contains the distance // along the direction vector to the boundary being tested. r = distance_to_cell_edge[axis][side] / neutron.getDirection(axis); if (r > BOUNDARY_ERROR & r < tempd) { tempd = r; cell_lim_bound.clear(); cell_lim_bound.push_back(axis*2+side); } else if (r == tempd) { cell_lim_bound.push_back(axis*2+side); } } } // move neutron neutron.move(tempd); // add distance to cell flux mesh.fluxAdd(cell, tempd, group); // shorten neutron distance to collision neutron_distance -= tempd; // determine potential geometry boundaries for (int sur_side=0; sur_side <6; ++sur_side) { int axis = sur_side/2; int side = sur_side%2; // if sur_side is in cell_lim_bound if (std::find(cell_lim_bound.begin(), cell_lim_bound.end(),sur_side) != cell_lim_bound.end()) { if (neutron.getCell()[axis] == 0 && side ==0) box_lim_bound.push_back(sur_side); // if the neutron is on the max side of the cell and the // cell is the highest cell in the geometry if (axis == 0) { if (neutron.getCell()[axis] == lattice->getNumX() - 1 && side == 1) box_lim_bound.push_back(sur_side); } if (axis == 1) { if (neutron.getCell()[axis] == lattice->getNumY() - 1 && side == 1) box_lim_bound.push_back(sur_side); } if (axis == 2) { if (neutron.getCell()[axis] == lattice->getNumZ() - 1 && side == 1) box_lim_bound.push_back(sur_side); } } } // check boundary conditions on all hit surfaces for (int sur_side=0; sur_side <6; ++sur_side) { int axis = sur_side/2; int side = sur_side%2; // if sur_side is in box_lim_bound if (std::find(box_lim_bound.begin(), box_lim_bound.end(),sur_side) != box_lim_bound.end()) { // if the neutron is reflected if (bounds.getSurfaceType(axis, side) == 1) { neutron.reflect(axis); // place neutron on boundary to eliminate roundoff error double bound_val; bound_val = bounds.getSurfaceCoord(axis, side); neutron.setPosition(axis, bound_val); } // if the neutron escapes if (bounds.getSurfaceType(axis, side) == 0) { neutron.kill(); neutron_distance = 0; tallies[LEAKS] += 1; break; } } } // get new neutron cell if (neutron_distance > 0) { cell[0] = lattice->getLatX(neutron_position); cell[1] = lattice->getLatY(neutron_position); cell[2] = lattice->getLatZ(neutron_position); // nudge neutron and find its cell neutron.move(1e-3); neutron.getPositionVector(neutron_position); // withinBounds seems to return true if the point is without if (lattice->withinBounds(neutron_position)) { cell[0] = lattice->getLatX(neutron_position); cell[1] = lattice->getLatY(neutron_position); cell[2] = lattice->getLatZ(neutron_position); } neutron.move(-1e-3); neutron.setCell(cell); } } // check interaction if (neutron.alive()) { neutron_coord_position->setX(neutron_position->getX()); neutron_coord_position->setY(neutron_position->getY()); neutron_coord_position->setZ(neutron_position->getZ()); neutron_coord_position->setUniverse(root_universe); cell_obj = geometry->findCellContainingCoords(neutron_coord_position); cell_mat = cell_obj->getFillMaterial(); // calculate sigma_s for a group in order to sample an interaction std::vector <double> sigma_s_group; double sum_sigma_s_group=0; for (int g=1; g<=cell_mat->getNumEnergyGroups(); ++g) { sigma_s_group.push_back(cell_mat->getSigmaSByGroup(group+1, g)); sum_sigma_s_group += cell_mat->getSigmaSByGroup(group+1, g); } // calculate sigma_a in order to sample an interaction double sigma_a; sigma_a = cell_mat->getSigmaTByGroup(group+1) - sum_sigma_s_group; // sample an interaction int neutron_interaction = (int) (neutron.arand() < (sigma_a / cell_mat->getSigmaTByGroup(group+1))); // scattering event if (neutron_interaction == 0) { // sample scattered direction neutron.sampleDirection(); // sample new energy group int new_group = neutron.sampleScatteredGroup(sigma_s_group, group); // set new group neutron.setGroup(new_group); } // absorption event else { // tally absorption tallies[ABSORPTIONS] += 1; // sample for fission event group = neutron.getGroup(); cell = neutron.getCell(); neutron_coord_position->setX(neutron_position->getX()); neutron_coord_position->setY(neutron_position->getY()); neutron_coord_position->setZ(neutron_position->getZ()); neutron_coord_position->setUniverse(root_universe); cell_obj = geometry->findCellContainingCoords(neutron_coord_position); cell_mat = cell_obj->getFillMaterial(); neutron.getPositionVector(neutron_position); // sample whether fission event occurs int fission_occurs = neutron.arand() < cell_mat->getSigmaFByGroup(group+1) / sigma_a; // fission event if (fission_occurs == 1) { // sample number of neutrons released during fission double nu = cell_mat->getNuSigmaFByGroup(1) / cell_mat->getSigmaFByGroup(1); int lower = (int) nu; int add = (int) (neutron.arand() < nu -lower); int num_neutrons = lower + add; for (int i=0; i<num_neutrons; ++i) { fission_banks->add(neutron_position); tallies[FISSIONS] += 1; } } // end neutron history neutron.kill(); } } } // tally crow distance double crow_distance; crow_distance = neutron.getDistance(neutron_starting_point); tallies[CROWS] += crow_distance; tallies[NUM_CROWS] += 1; }