/* This file is part of MAUS: http://micewww.pp.rl.ac.uk/projects/maus
*
* MAUS is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MAUS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MAUS. If not, see .
*/
#include
#include
#include
#include
#include "Utils/Squeak.hh"
#include "Utils/Exception.hh"
#include "src/legacy/Interface/Mesh.hh"
#include "src/legacy/Interface/STLUtils.hh"
#include "src/common_cpp/FieldTools/SectorMagneticFieldMap.hh"
namespace MAUS {
std::map SectorMagneticFieldMap::_fields;
SectorMagneticFieldMap::SectorMagneticFieldMap()
: SectorField(), _interpolator(NULL), _symmetry(none) {
}
SectorMagneticFieldMap::SectorMagneticFieldMap(std::string file_name,
std::string file_format, std::vector units, std::string symmetry)
: SectorField(), _interpolator(NULL), _symmetry(none), _units(units), _format(file_format),
_filename(file_name) {
SetSymmetry(symmetry);
if (_fields.find(file_name) == _fields.end()) {
Interpolator3dGridTo3d* interpolator = SectorMagneticFieldMapIO::ReadMap
(file_name, file_format, units, symmetry);
SetInterpolator(interpolator);
delete _interpolator->Clone();
_fields[file_name] = new SectorMagneticFieldMap(*this);
} else {
SectorMagneticFieldMap* tgt = _fields[file_name];
if (_symmetry != tgt-> _symmetry || _units != tgt->_units ||
_format != tgt->_format || _filename != tgt->_filename) {
throw(Exceptions::Exception(Exceptions::recoverable,
"Attempt to construct different SectorFieldMaps with same file "+
std::string("but different settings"),
"SectorMagneticFieldMap::SectorMagneticFieldMap(...)"));
}
SetInterpolator(tgt->_interpolator->Clone());
}
}
SectorMagneticFieldMap::SectorMagneticFieldMap
(const SectorMagneticFieldMap& field)
: SectorField(field), _interpolator(NULL), _symmetry(field._symmetry),
_units(field._units), _format(field._format),
_filename(field._filename) {
Interpolator3dGridTo3d* interpolator = NULL;
if (field._interpolator != NULL) {
interpolator = field._interpolator->Clone();
}
SetInterpolator(interpolator);
}
SectorMagneticFieldMap::~SectorMagneticFieldMap() {
delete _interpolator;
}
Interpolator3dGridTo3d* SectorMagneticFieldMap::GetInterpolator() {
return _interpolator;
}
void SectorMagneticFieldMap::SetInterpolator
(Interpolator3dGridTo3d* interpolator) {
if (_interpolator != NULL) {
delete _interpolator;
}
_interpolator = interpolator;
if (_interpolator != NULL) {
ThreeDGrid* grid = _interpolator->GetMesh();
SectorField::SetPolarBoundingBox
(grid->MinX(), grid->MinY(), grid->MinZ(),
grid->MaxX(), grid->MaxY(), grid->MaxZ());
}
delete _interpolator->Clone();
}
std::string SectorMagneticFieldMap::GetSymmetry() {
return SymmetryToString(_symmetry);
}
void SectorMagneticFieldMap::SetSymmetry(std::string name) {
_symmetry = StringToSymmetry(name);
}
SectorMagneticFieldMap::symmetry SectorMagneticFieldMap::StringToSymmetry
(std::string sym) {
if (sym == "None") {
return none;
}
if (sym == "Dipole") {
return dipole;
}
throw(Exceptions::Exception(Exceptions::recoverable,
"Didn't recognise symmetry type "+sym,
"SectorMagneticFieldMap::StringToSymmetry"));
}
std::string SectorMagneticFieldMap::SymmetryToString
(SectorMagneticFieldMap::symmetry sym) {
if (sym == none) {
return "None";
}
if (sym == dipole) {
return "Dipole";
}
throw(Exceptions::Exception(Exceptions::recoverable,
"Didn't recognise symmetry type",
"SectorMagneticFieldMap::SymmetryToString"));
}
void SectorMagneticFieldMap::GetFieldValuePolar
(const double* point, double* field) const {
_interpolator->F(&point[0], field);
SectorField::ConvertToPolar(point, field);
}
void SectorMagneticFieldMap::GetFieldValue
(const double* point, double* field) const {
std::vector _point(&point[0], &point[4]);
SectorField::ConvertToPolar(&_point[0]);
_interpolator->F(&_point[0], field);
}
void SectorMagneticFieldMap::ClearFieldCache() {
for (std::map::iterator it =
_fields.begin(); it != _fields.end(); ++it) {
delete (*it).second;
}
_fields = std::map();
}
const double SectorMagneticFieldMapIO::float_tolerance = 1e-3;
const int SectorMagneticFieldMapIO::sort_order[3] = {0, 1, 2};
Interpolator3dGridTo3d* SectorMagneticFieldMapIO::ReadMap
(std::string file_name, std::string file_type, std::vector units,
std::string symmetry) {
try {
file_name = STLUtils::ReplaceVariables(file_name);
Squeak::mout(Squeak::debug) << "Opening sector field map " << file_name
<< " type " << file_type << std::endl;
if (file_type == "tosca_sector_1") {
return ReadToscaMap(file_name, units, symmetry);
}
} catch (std::exception& exc) {
throw(Exceptions::Exception(Exceptions::recoverable,
"Failed to read file "+file_name+" with "+(&exc)->what(),
"SectorMagneticFieldMapIO::ReadMap"));
}
throw(Exceptions::Exception(Exceptions::recoverable,
"Didn't recognise map type "+file_type,
"SectorMagneticFieldMapIO::ReadMap"));
return NULL;
}
Interpolator3dGridTo3d* SectorMagneticFieldMapIO::ReadToscaMap
(std::string file_name, std::vector units,
std::string symmetry) {
SectorMagneticFieldMap::symmetry sym =
SectorMagneticFieldMap::StringToSymmetry(symmetry);
// set up
std::vector< std::vector > field_points = ReadLines
(file_name, units);
// build grid
ThreeDGrid* grid = GenerateGrid(field_points, sym);
// build interpolator
return GetInterpolator(field_points, grid, sym);
}
Interpolator3dGridTo3d* SectorMagneticFieldMapIO::GetInterpolator
(const std::vector< std::vector > field_points,
ThreeDGrid* grid,
SectorMagneticFieldMap::symmetry sym) {
int y_start = 0;
if (sym == SectorMagneticFieldMap::dipole) {
y_start = (grid->ySize()+1)/2-1;
}
// build field arrays
double *** Bx, *** By, *** Bz;
int index = 0;
Bx = new double**[grid->xSize()];
By = new double**[grid->xSize()];
Bz = new double**[grid->xSize()];
for (int i = 0; i < grid->xSize(); ++i) {
Bx[i] = new double*[grid->ySize()];
By[i] = new double*[grid->ySize()];
Bz[i] = new double*[grid->ySize()];
for (int j = 0; j < grid->ySize(); ++j) {
Bx[i][j] = new double[grid->zSize()];
By[i][j] = new double[grid->zSize()];
Bz[i][j] = new double[grid->zSize()];
for (int k = 0; k < grid->zSize() && j >= y_start; ++k) {
if (index >= static_cast(field_points.size())) {
throw Exceptions::Exception(Exceptions::recoverable,
"Field grid is not rectangular",
"SectorMagneticFieldMapIO::GetInterpolator");
}
Bx[i][j][k] = field_points[index][3];
By[i][j][k] = field_points[index][4];
Bz[i][j][k] = field_points[index][5];
++index;
}
}
}
// extend field array downwards if field is dipole
if (sym == SectorMagneticFieldMap::dipole) {
for (int i = 0; i < grid->xSize(); ++i) {
for (int j = 0; j < y_start; ++j) {
for (int k = 0; k < grid->zSize(); ++k) {
Bx[i][j][k] = -Bx[i][grid->ySize()-j-1][k];
By[i][j][k] = By[i][grid->ySize()-j-1][k];
Bz[i][j][k] = -Bz[i][grid->ySize()-j-1][k];
++index;
}
}
}
}
return new Interpolator3dGridTo3d(grid, Bx, By, Bz);
}
bool SectorMagneticFieldMapIO::Comparator(std::vector field_item1,
std::vector field_item2) {
const int* order = sort_order;
if (fabs(field_item1[order[0]] - field_item2[order[0]]) > float_tolerance) {
return field_item1[order[0]] < field_item2[order[0]];
}
if (fabs(field_item1[order[1]] - field_item2[order[1]]) > float_tolerance) {
return field_item1[order[1]] < field_item2[order[1]];
}
return field_item1[order[2]] < field_item2[order[2]];
}
std::vector< std::vector > SectorMagneticFieldMapIO::ReadLines
(std::string file_name, std::vector units) {
std::vector< std::vector > field_points;
std::string line;
if (units.size() != 6) {
throw(Exceptions::Exception(Exceptions::recoverable,
"Units should be of length 6",
"SectorMagneticFieldMapIO::ReadMap"));
}
std::ifstream fin(file_name.c_str());
if (!fin || !fin.is_open()) {
throw(Exceptions::Exception(Exceptions::recoverable,
"Failed to open file "+file_name,
"SectorMagneticFieldMapIO::ReadMap"));
}
// skip header lines
Squeak::mout(Squeak::debug) << "Opened "+file_name << std::endl;
for (size_t i = 0; i < 8; ++i) {
std::getline(fin, line);
}
// read in field map
int line_number = 0;
while (fin) {
std::vector field(6);
fin >> field[0] >> field[1] >> field[2] >> field[3] >> field[4]
>> field[5];
if (fin) {
for (size_t i = 0; i < 6; ++i) {
field[i] *= units[i];
}
field_points.push_back(field);
line_number++;
}
}
Squeak::mout(Squeak::debug) << "Read " << line_number << " lines"
<< std::endl;
// convert coordinates to polar; nb we leave field as cartesian
for (size_t i = 0; i < field_points.size(); ++i) {
SectorField::ConvertToPolar(&field_points[i][0]);
}
// force check sort order
std::sort(field_points.begin(), field_points.end(),
SectorMagneticFieldMapIO::Comparator);
return field_points;
}
ThreeDGrid* SectorMagneticFieldMapIO::GenerateGrid
(const std::vector< std::vector > field_points,
SectorMagneticFieldMap::symmetry sym) {
std::vector r_grid(1, field_points[0][0]);
std::vector y_grid(1, field_points[0][1]);
std::vector phi_grid(1, field_points[0][2]);
for (size_t i = 0; i < field_points.size(); ++i) {
if (field_points[i][0] > r_grid.back()*(1+float_tolerance)+float_tolerance) {
r_grid.push_back(field_points[i][0]);
}
if (field_points[i][1] > y_grid.back()*(1+float_tolerance)+float_tolerance) {
y_grid.push_back(field_points[i][1]);
}
if (field_points[i][2] > phi_grid.back()*(1+float_tolerance)+float_tolerance) {
phi_grid.push_back(field_points[i][2]);
}
}
// reflect about y if symmetry is dipole
int y_end = static_cast(y_grid.size());
if (sym == SectorMagneticFieldMap::dipole) {
for (int i = 0; i < y_end-1; ++i) {
y_grid.insert(y_grid.begin(), 2.*y_grid[i]-y_grid[2*i+1]);
}
y_end = y_grid.size();
}
Squeak::mout(Squeak::debug) << "Grid size (r, y, phi) = ("
<< r_grid.size() << ", " << y_grid.size()
<< ", " << phi_grid.size() << ")" << std::endl;
ThreeDGrid* grid = new ThreeDGrid(r_grid, y_grid, phi_grid);
return grid;
}
}